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