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