• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Diagnostics related methods for `Ty`.
2 
3 use std::borrow::Cow;
4 use std::ops::ControlFlow;
5 
6 use crate::ty::{
7     AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, PolyTraitPredicate,
8     Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
9     TypeVisitor,
10 };
11 
12 use rustc_data_structures::fx::FxHashMap;
13 use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
14 use rustc_hir as hir;
15 use rustc_hir::def::DefKind;
16 use rustc_hir::def_id::DefId;
17 use rustc_hir::{PredicateOrigin, WherePredicate};
18 use rustc_span::{BytePos, Span};
19 use rustc_type_ir::sty::TyKind::*;
20 
21 impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
into_diagnostic_arg(self) -> DiagnosticArgValue<'static>22     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
23         self.to_string().into_diagnostic_arg()
24     }
25 }
26 
27 impl<'tcx> Ty<'tcx> {
28     /// Similar to `Ty::is_primitive`, but also considers inferred numeric values to be primitive.
is_primitive_ty(self) -> bool29     pub fn is_primitive_ty(self) -> bool {
30         matches!(
31             self.kind(),
32             Bool | Char
33                 | Str
34                 | Int(_)
35                 | Uint(_)
36                 | Float(_)
37                 | Infer(
38                     InferTy::IntVar(_)
39                         | InferTy::FloatVar(_)
40                         | InferTy::FreshIntTy(_)
41                         | InferTy::FreshFloatTy(_)
42                 )
43         )
44     }
45 
46     /// Whether the type is succinctly representable as a type instead of just referred to with a
47     /// description in error messages. This is used in the main error message.
is_simple_ty(self) -> bool48     pub fn is_simple_ty(self) -> bool {
49         match self.kind() {
50             Bool
51             | Char
52             | Str
53             | Int(_)
54             | Uint(_)
55             | Float(_)
56             | Infer(
57                 InferTy::IntVar(_)
58                 | InferTy::FloatVar(_)
59                 | InferTy::FreshIntTy(_)
60                 | InferTy::FreshFloatTy(_),
61             ) => true,
62             Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(),
63             Tuple(tys) if tys.is_empty() => true,
64             _ => false,
65         }
66     }
67 
68     /// Whether the type is succinctly representable as a type instead of just referred to with a
69     /// description in error messages. This is used in the primary span label. Beyond what
70     /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
71     /// ADTs with no type arguments.
is_simple_text(self) -> bool72     pub fn is_simple_text(self) -> bool {
73         match self.kind() {
74             Adt(_, substs) => substs.non_erasable_generics().next().is_none(),
75             Ref(_, ty, _) => ty.is_simple_text(),
76             _ => self.is_simple_ty(),
77         }
78     }
79 }
80 
81 pub trait IsSuggestable<'tcx>: Sized {
82     /// Whether this makes sense to suggest in a diagnostic.
83     ///
84     /// We filter out certain types and constants since they don't provide
85     /// meaningful rendered suggestions when pretty-printed. We leave some
86     /// nonsense, such as region vars, since those render as `'_` and are
87     /// usually okay to reinterpret as elided lifetimes.
88     ///
89     /// Only if `infer_suggestable` is true, we consider type and const
90     /// inference variables to be suggestable.
is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool91     fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
92 
make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>93     fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>;
94 }
95 
96 impl<'tcx, T> IsSuggestable<'tcx> for T
97 where
98     T: TypeVisitable<TyCtxt<'tcx>> + TypeFoldable<TyCtxt<'tcx>>,
99 {
is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool100     fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool {
101         self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
102     }
103 
make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T>104     fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> {
105         self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok()
106     }
107 }
108 
suggest_arbitrary_trait_bound<'tcx>( tcx: TyCtxt<'tcx>, generics: &hir::Generics<'_>, err: &mut Diagnostic, trait_pred: PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, ) -> bool109 pub fn suggest_arbitrary_trait_bound<'tcx>(
110     tcx: TyCtxt<'tcx>,
111     generics: &hir::Generics<'_>,
112     err: &mut Diagnostic,
113     trait_pred: PolyTraitPredicate<'tcx>,
114     associated_ty: Option<(&'static str, Ty<'tcx>)>,
115 ) -> bool {
116     if !trait_pred.is_suggestable(tcx, false) {
117         return false;
118     }
119 
120     let param_name = trait_pred.skip_binder().self_ty().to_string();
121     let mut constraint = trait_pred.to_string();
122 
123     if let Some((name, term)) = associated_ty {
124         // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
125         // That should be extracted into a helper function.
126         if constraint.ends_with('>') {
127             constraint = format!("{}, {} = {}>", &constraint[..constraint.len() - 1], name, term);
128         } else {
129             constraint.push_str(&format!("<{} = {}>", name, term));
130         }
131     }
132 
133     let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
134 
135     // Skip, there is a param named Self
136     if param.is_some() && param_name == "Self" {
137         return false;
138     }
139 
140     // Suggest a where clause bound for a non-type parameter.
141     err.span_suggestion_verbose(
142         generics.tail_span_for_predicate_suggestion(),
143         format!(
144             "consider {} `where` clause, but there might be an alternative better way to express \
145              this requirement",
146             if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" },
147         ),
148         format!("{} {constraint}", generics.add_where_or_trailing_comma()),
149         Applicability::MaybeIncorrect,
150     );
151     true
152 }
153 
154 #[derive(Debug)]
155 enum SuggestChangingConstraintsMessage<'a> {
156     RestrictBoundFurther,
157     RestrictType { ty: &'a str },
158     RestrictTypeFurther { ty: &'a str },
159     RemoveMaybeUnsized,
160     ReplaceMaybeUnsizedWithSized,
161 }
162 
suggest_changing_unsized_bound( generics: &hir::Generics<'_>, suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>, param: &hir::GenericParam<'_>, def_id: Option<DefId>, )163 fn suggest_changing_unsized_bound(
164     generics: &hir::Generics<'_>,
165     suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
166     param: &hir::GenericParam<'_>,
167     def_id: Option<DefId>,
168 ) {
169     // See if there's a `?Sized` bound that can be removed to suggest that.
170     // First look at the `where` clause because we can have `where T: ?Sized`,
171     // then look at params.
172     for (where_pos, predicate) in generics.predicates.iter().enumerate() {
173         let WherePredicate::BoundPredicate(predicate) = predicate else {
174             continue;
175         };
176         if !predicate.is_param_bound(param.def_id.to_def_id()) {
177             continue;
178         };
179 
180         for (pos, bound) in predicate.bounds.iter().enumerate() {
181             let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
182                 continue;
183             };
184             if poly.trait_ref.trait_def_id() != def_id {
185                 continue;
186             }
187             if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 {
188                 // For `impl ?Sized` with no other bounds, suggest `impl Sized` instead.
189                 let bound_span = bound.span();
190                 if bound_span.can_be_used_for_suggestions() {
191                     let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1));
192                     suggestions.push((
193                         question_span,
194                         String::new(),
195                         SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized,
196                     ));
197                 }
198             } else {
199                 let sp = generics.span_for_bound_removal(where_pos, pos);
200                 suggestions.push((
201                     sp,
202                     String::new(),
203                     SuggestChangingConstraintsMessage::RemoveMaybeUnsized,
204                 ));
205             }
206         }
207     }
208 }
209 
210 /// Suggest restricting a type param with a new bound.
211 ///
212 /// If `span_to_replace` is provided, then that span will be replaced with the
213 /// `constraint`. If one wasn't provided, then the full bound will be suggested.
suggest_constraining_type_param( tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, err: &mut Diagnostic, param_name: &str, constraint: &str, def_id: Option<DefId>, span_to_replace: Option<Span>, ) -> bool214 pub fn suggest_constraining_type_param(
215     tcx: TyCtxt<'_>,
216     generics: &hir::Generics<'_>,
217     err: &mut Diagnostic,
218     param_name: &str,
219     constraint: &str,
220     def_id: Option<DefId>,
221     span_to_replace: Option<Span>,
222 ) -> bool {
223     suggest_constraining_type_params(
224         tcx,
225         generics,
226         err,
227         [(param_name, constraint, def_id)].into_iter(),
228         span_to_replace,
229     )
230 }
231 
232 /// Suggest restricting a type param with a new bound.
suggest_constraining_type_params<'a>( tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, err: &mut Diagnostic, param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>, span_to_replace: Option<Span>, ) -> bool233 pub fn suggest_constraining_type_params<'a>(
234     tcx: TyCtxt<'_>,
235     generics: &hir::Generics<'_>,
236     err: &mut Diagnostic,
237     param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>,
238     span_to_replace: Option<Span>,
239 ) -> bool {
240     let mut grouped = FxHashMap::default();
241     param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
242         grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id))
243     });
244 
245     let mut applicability = Applicability::MachineApplicable;
246     let mut suggestions = Vec::new();
247 
248     for (param_name, mut constraints) in grouped {
249         let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
250         let Some(param) = param else { return false };
251 
252         {
253             let mut sized_constraints =
254                 constraints.extract_if(|(_, def_id)| *def_id == tcx.lang_items().sized_trait());
255             if let Some((_, def_id)) = sized_constraints.next() {
256                 applicability = Applicability::MaybeIncorrect;
257 
258                 err.span_label(param.span, "this type parameter needs to be `Sized`");
259                 suggest_changing_unsized_bound(generics, &mut suggestions, param, def_id);
260             }
261         }
262 
263         if constraints.is_empty() {
264             continue;
265         }
266 
267         let mut constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>();
268         constraint.sort();
269         constraint.dedup();
270         let constraint = constraint.join(" + ");
271         let mut suggest_restrict = |span, bound_list_non_empty| {
272             suggestions.push((
273                 span,
274                 if span_to_replace.is_some() {
275                     constraint.clone()
276                 } else if bound_list_non_empty {
277                     format!(" + {}", constraint)
278                 } else {
279                     format!(" {}", constraint)
280                 },
281                 SuggestChangingConstraintsMessage::RestrictBoundFurther,
282             ))
283         };
284 
285         if let Some(span) = span_to_replace {
286             suggest_restrict(span, true);
287             continue;
288         }
289 
290         // When the type parameter has been provided bounds
291         //
292         //    Message:
293         //      fn foo<T>(t: T) where T: Foo { ... }
294         //                            ^^^^^^
295         //                            |
296         //                            help: consider further restricting this bound with `+ Bar`
297         //
298         //    Suggestion:
299         //      fn foo<T>(t: T) where T: Foo { ... }
300         //                                  ^
301         //                                  |
302         //                                  replace with: ` + Bar`
303         //
304         // Or, if user has provided some bounds, suggest restricting them:
305         //
306         //   fn foo<T: Foo>(t: T) { ... }
307         //             ---
308         //             |
309         //             help: consider further restricting this bound with `+ Bar`
310         //
311         // Suggestion for tools in this case is:
312         //
313         //   fn foo<T: Foo>(t: T) { ... }
314         //          --
315         //          |
316         //          replace with: `T: Bar +`
317         if let Some(span) = generics.bounds_span_for_suggestions(param.def_id) {
318             suggest_restrict(span, true);
319             continue;
320         }
321 
322         if generics.has_where_clause_predicates {
323             // This part is a bit tricky, because using the `where` clause user can
324             // provide zero, one or many bounds for the same type parameter, so we
325             // have following cases to consider:
326             //
327             // When the type parameter has been provided zero bounds
328             //
329             //    Message:
330             //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
331             //             - help: consider restricting this type parameter with `where X: Bar`
332             //
333             //    Suggestion:
334             //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
335             //                                           - insert: `, X: Bar`
336             suggestions.push((
337                 generics.tail_span_for_predicate_suggestion(),
338                 constraints
339                     .iter()
340                     .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
341                     .collect::<String>(),
342                 SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
343             ));
344             continue;
345         }
346 
347         // Additionally, there may be no `where` clause but the generic parameter has a default:
348         //
349         //    Message:
350         //      trait Foo<T=()> {... }
351         //                - help: consider further restricting this type parameter with `where T: Zar`
352         //
353         //    Suggestion:
354         //      trait Foo<T=()> {... }
355         //                     - insert: `where T: Zar`
356         if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) {
357             // Suggest a bound, but there is no existing `where` clause *and* the type param has a
358             // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
359             suggestions.push((
360                 generics.tail_span_for_predicate_suggestion(),
361                 format!(" where {}: {}", param_name, constraint),
362                 SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
363             ));
364             continue;
365         }
366 
367         // If user has provided a colon, don't suggest adding another:
368         //
369         //   fn foo<T:>(t: T) { ... }
370         //            - insert: consider restricting this type parameter with `T: Foo`
371         if let Some(colon_span) = param.colon_span {
372             suggestions.push((
373                 colon_span.shrink_to_hi(),
374                 format!(" {}", constraint),
375                 SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
376             ));
377             continue;
378         }
379 
380         // If user hasn't provided any bounds, suggest adding a new one:
381         //
382         //   fn foo<T>(t: T) { ... }
383         //          - help: consider restricting this type parameter with `T: Foo`
384         suggestions.push((
385             param.span.shrink_to_hi(),
386             format!(": {}", constraint),
387             SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
388         ));
389     }
390 
391     // FIXME: remove the suggestions that are from derive, as the span is not correct
392     suggestions = suggestions
393         .into_iter()
394         .filter(|(span, _, _)| !span.in_derive_expansion())
395         .collect::<Vec<_>>();
396 
397     if suggestions.len() == 1 {
398         let (span, suggestion, msg) = suggestions.pop().unwrap();
399         let msg = match msg {
400             SuggestChangingConstraintsMessage::RestrictBoundFurther => {
401                 Cow::from("consider further restricting this bound")
402             }
403             SuggestChangingConstraintsMessage::RestrictType { ty } => {
404                 Cow::from(format!("consider restricting type parameter `{}`", ty))
405             }
406             SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => {
407                 Cow::from(format!("consider further restricting type parameter `{}`", ty))
408             }
409             SuggestChangingConstraintsMessage::RemoveMaybeUnsized => {
410                 Cow::from("consider removing the `?Sized` bound to make the type parameter `Sized`")
411             }
412             SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized => {
413                 Cow::from("consider replacing `?Sized` with `Sized`")
414             }
415         };
416 
417         err.span_suggestion_verbose(span, msg, suggestion, applicability);
418     } else if suggestions.len() > 1 {
419         err.multipart_suggestion_verbose(
420             "consider restricting type parameters",
421             suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(),
422             applicability,
423         );
424     }
425 
426     true
427 }
428 
429 /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
430 pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
431 
432 impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
visit_ty(&mut self, ty: &'v hir::Ty<'v>)433     fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
434         match ty.kind {
435             hir::TyKind::TraitObject(
436                 _,
437                 hir::Lifetime {
438                     res:
439                         hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
440                     ..
441                 },
442                 _,
443             ) => {
444                 self.0.push(ty);
445             }
446             hir::TyKind::OpaqueDef(item_id, _, _) => {
447                 self.0.push(ty);
448                 let item = self.1.item(item_id);
449                 hir::intravisit::walk_item(self, item);
450             }
451             _ => {}
452         }
453         hir::intravisit::walk_ty(self, ty);
454     }
455 }
456 
457 /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
458 pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
459 
460 impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
visit_lifetime(&mut self, lt: &'v hir::Lifetime)461     fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
462         if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res
463         {
464             self.0.push(lt.ident.span);
465         }
466     }
467 }
468 
469 pub struct IsSuggestableVisitor<'tcx> {
470     tcx: TyCtxt<'tcx>,
471     infer_suggestable: bool,
472 }
473 
474 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
475     type BreakTy = ();
476 
visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy>477     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
478         match *t.kind() {
479             Infer(InferTy::TyVar(_)) if self.infer_suggestable => {}
480 
481             FnDef(..)
482             | Closure(..)
483             | Infer(..)
484             | Generator(..)
485             | GeneratorWitness(..)
486             | Bound(_, _)
487             | Placeholder(_)
488             | Error(_) => {
489                 return ControlFlow::Break(());
490             }
491 
492             Alias(Opaque, AliasTy { def_id, .. }) => {
493                 let parent = self.tcx.parent(def_id);
494                 let parent_ty = self.tcx.type_of(parent).subst_identity();
495                 if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent)
496                     && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
497                     && parent_opaque_def_id == def_id
498                 {
499                     // Okay
500                 } else {
501                     return ControlFlow::Break(());
502                 }
503             }
504 
505             Alias(Projection, AliasTy { def_id, .. }) => {
506                 if self.tcx.def_kind(def_id) != DefKind::AssocTy {
507                     return ControlFlow::Break(());
508                 }
509             }
510 
511             Param(param) => {
512                 // FIXME: It would be nice to make this not use string manipulation,
513                 // but it's pretty hard to do this, since `ty::ParamTy` is missing
514                 // sufficient info to determine if it is synthetic, and we don't
515                 // always have a convenient way of getting `ty::Generics` at the call
516                 // sites we invoke `IsSuggestable::is_suggestable`.
517                 if param.name.as_str().starts_with("impl ") {
518                     return ControlFlow::Break(());
519                 }
520             }
521 
522             _ => {}
523         }
524 
525         t.super_visit_with(self)
526     }
527 
visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy>528     fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
529         match c.kind() {
530             ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
531 
532             ConstKind::Infer(..)
533             | ConstKind::Bound(..)
534             | ConstKind::Placeholder(..)
535             | ConstKind::Error(..) => {
536                 return ControlFlow::Break(());
537             }
538             _ => {}
539         }
540 
541         c.super_visit_with(self)
542     }
543 }
544 
545 pub struct MakeSuggestableFolder<'tcx> {
546     tcx: TyCtxt<'tcx>,
547     infer_suggestable: bool,
548 }
549 
550 impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
551     type Error = ();
552 
interner(&self) -> TyCtxt<'tcx>553     fn interner(&self) -> TyCtxt<'tcx> {
554         self.tcx
555     }
556 
try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error>557     fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
558         let t = match *t.kind() {
559             Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
560 
561             FnDef(def_id, substs) => {
562                 Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).subst(self.tcx, substs))
563             }
564 
565             // FIXME(compiler-errors): We could replace these with infer, I guess.
566             Closure(..)
567             | Infer(..)
568             | Generator(..)
569             | GeneratorWitness(..)
570             | Bound(_, _)
571             | Placeholder(_)
572             | Error(_) => {
573                 return Err(());
574             }
575 
576             Alias(Opaque, AliasTy { def_id, .. }) => {
577                 let parent = self.tcx.parent(def_id);
578                 let parent_ty = self.tcx.type_of(parent).subst_identity();
579                 if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
580                     && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind()
581                     && parent_opaque_def_id == def_id
582                 {
583                     t
584                 } else {
585                     return Err(());
586                 }
587             }
588 
589             Param(param) => {
590                 // FIXME: It would be nice to make this not use string manipulation,
591                 // but it's pretty hard to do this, since `ty::ParamTy` is missing
592                 // sufficient info to determine if it is synthetic, and we don't
593                 // always have a convenient way of getting `ty::Generics` at the call
594                 // sites we invoke `IsSuggestable::is_suggestable`.
595                 if param.name.as_str().starts_with("impl ") {
596                     return Err(());
597                 }
598 
599                 t
600             }
601 
602             _ => t,
603         };
604 
605         t.try_super_fold_with(self)
606     }
607 
try_fold_const(&mut self, c: Const<'tcx>) -> Result<Const<'tcx>, ()>608     fn try_fold_const(&mut self, c: Const<'tcx>) -> Result<Const<'tcx>, ()> {
609         let c = match c.kind() {
610             ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => c,
611 
612             ConstKind::Infer(..)
613             | ConstKind::Bound(..)
614             | ConstKind::Placeholder(..)
615             | ConstKind::Error(..) => {
616                 return Err(());
617             }
618 
619             _ => c,
620         };
621 
622         c.try_super_fold_with(self)
623     }
624 }
625 
626 #[derive(Diagnostic)]
627 #[diag(middle_const_not_used_in_type_alias)]
628 pub(super) struct ConstNotUsedTraitAlias {
629     pub ct: String,
630     #[primary_span]
631     pub span: Span,
632 }
633