]>
Commit | Line | Data |
---|---|---|
5099ac24 | 1 | //! Diagnostics related methods for `Ty`. |
60c5eb7d | 2 | |
a2a8927a | 3 | use crate::ty::subst::{GenericArg, GenericArgKind}; |
dfeec247 | 4 | use crate::ty::TyKind::*; |
a2a8927a XL |
5 | use crate::ty::{ |
6 | ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy, | |
5099ac24 | 7 | ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, |
a2a8927a XL |
8 | }; |
9 | ||
5e7ed085 FG |
10 | use rustc_data_structures::fx::FxHashMap; |
11 | use rustc_errors::{Applicability, Diagnostic}; | |
f9f354fc XL |
12 | use rustc_hir as hir; |
13 | use rustc_hir::def_id::DefId; | |
14 | use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; | |
a2a8927a | 15 | use rustc_span::Span; |
60c5eb7d | 16 | |
5099ac24 FG |
17 | impl<'tcx> Ty<'tcx> { |
18 | /// Similar to `Ty::is_primitive`, but also considers inferred numeric values to be primitive. | |
19 | pub fn is_primitive_ty(self) -> bool { | |
29967ef6 XL |
20 | matches!( |
21 | self.kind(), | |
5869c6ff XL |
22 | Bool | Char |
23 | | Str | |
24 | | Int(_) | |
25 | | Uint(_) | |
26 | | Float(_) | |
27 | | Infer( | |
28 | InferTy::IntVar(_) | |
29 | | InferTy::FloatVar(_) | |
30 | | InferTy::FreshIntTy(_) | |
31 | | InferTy::FreshFloatTy(_) | |
32 | ) | |
29967ef6 | 33 | ) |
60c5eb7d XL |
34 | } |
35 | ||
36 | /// Whether the type is succinctly representable as a type instead of just referred to with a | |
37 | /// description in error messages. This is used in the main error message. | |
5099ac24 | 38 | pub fn is_simple_ty(self) -> bool { |
1b1a35ee | 39 | match self.kind() { |
dfeec247 XL |
40 | Bool |
41 | | Char | |
42 | | Str | |
43 | | Int(_) | |
44 | | Uint(_) | |
45 | | Float(_) | |
ba9703b0 XL |
46 | | Infer( |
47 | InferTy::IntVar(_) | |
48 | | InferTy::FloatVar(_) | |
49 | | InferTy::FreshIntTy(_) | |
50 | | InferTy::FreshFloatTy(_), | |
51 | ) => true, | |
60c5eb7d XL |
52 | Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(), |
53 | Tuple(tys) if tys.is_empty() => true, | |
54 | _ => false, | |
55 | } | |
56 | } | |
57 | ||
58 | /// Whether the type is succinctly representable as a type instead of just referred to with a | |
59 | /// description in error messages. This is used in the primary span label. Beyond what | |
60 | /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to | |
61 | /// ADTs with no type arguments. | |
5099ac24 | 62 | pub fn is_simple_text(self) -> bool { |
1b1a35ee | 63 | match self.kind() { |
17df50a5 | 64 | Adt(_, substs) => substs.non_erasable_generics().next().is_none(), |
60c5eb7d XL |
65 | Ref(_, ty, _) => ty.is_simple_text(), |
66 | _ => self.is_simple_ty(), | |
67 | } | |
68 | } | |
69 | ||
70 | /// Whether the type can be safely suggested during error recovery. | |
5099ac24 | 71 | pub fn is_suggestable(self) -> bool { |
a2a8927a XL |
72 | fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool { |
73 | match arg.unpack() { | |
74 | GenericArgKind::Type(ty) => ty.is_suggestable(), | |
5099ac24 | 75 | GenericArgKind::Const(c) => const_is_suggestable(c.val()), |
a2a8927a XL |
76 | _ => true, |
77 | } | |
78 | } | |
79 | ||
80 | fn const_is_suggestable(kind: ConstKind<'_>) -> bool { | |
81 | match kind { | |
82 | ConstKind::Infer(..) | |
83 | | ConstKind::Bound(..) | |
84 | | ConstKind::Placeholder(..) | |
85 | | ConstKind::Error(..) => false, | |
86 | _ => true, | |
87 | } | |
88 | } | |
89 | ||
90 | // FIXME(compiler-errors): Some types are still not good to suggest, | |
91 | // specifically references with lifetimes within the function. Not | |
92 | //sure we have enough information to resolve whether a region is | |
93 | // temporary, so I'll leave this as a fixme. | |
94 | ||
95 | match self.kind() { | |
29967ef6 | 96 | Opaque(..) |
a2a8927a XL |
97 | | FnDef(..) |
98 | | Closure(..) | |
99 | | Infer(..) | |
100 | | Generator(..) | |
101 | | GeneratorWitness(..) | |
102 | | Bound(_, _) | |
103 | | Placeholder(_) | |
104 | | Error(_) => false, | |
105 | Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() { | |
106 | ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => { | |
107 | substs.iter().all(generic_arg_is_suggestible) | |
108 | } | |
5099ac24 FG |
109 | ExistentialPredicate::Projection(ExistentialProjection { |
110 | substs, term, .. | |
111 | }) => { | |
112 | let term_is_suggestable = match term { | |
113 | Term::Ty(ty) => ty.is_suggestable(), | |
114 | Term::Const(c) => const_is_suggestable(c.val()), | |
115 | }; | |
116 | term_is_suggestable && substs.iter().all(generic_arg_is_suggestible) | |
a2a8927a XL |
117 | } |
118 | _ => true, | |
119 | }), | |
5e7ed085 | 120 | Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => { |
a2a8927a XL |
121 | args.iter().all(generic_arg_is_suggestible) |
122 | } | |
5e7ed085 | 123 | Tuple(args) => args.iter().all(|ty| ty.is_suggestable()), |
a2a8927a | 124 | Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(), |
5099ac24 | 125 | Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()), |
a2a8927a XL |
126 | _ => true, |
127 | } | |
60c5eb7d XL |
128 | } |
129 | } | |
f9f354fc | 130 | |
6a06907d XL |
131 | pub fn suggest_arbitrary_trait_bound( |
132 | generics: &hir::Generics<'_>, | |
5e7ed085 | 133 | err: &mut Diagnostic, |
6a06907d XL |
134 | param_name: &str, |
135 | constraint: &str, | |
136 | ) -> bool { | |
137 | let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); | |
138 | match (param, param_name) { | |
139 | (Some(_), "Self") => return false, | |
140 | _ => {} | |
141 | } | |
5e7ed085 | 142 | // Suggest a where clause bound for a non-type parameter. |
6a06907d XL |
143 | let (action, prefix) = if generics.where_clause.predicates.is_empty() { |
144 | ("introducing a", " where ") | |
145 | } else { | |
146 | ("extending the", ", ") | |
147 | }; | |
148 | err.span_suggestion_verbose( | |
149 | generics.where_clause.tail_span_for_suggestion(), | |
150 | &format!( | |
151 | "consider {} `where` bound, but there might be an alternative better way to express \ | |
152 | this requirement", | |
153 | action, | |
154 | ), | |
155 | format!("{}{}: {}", prefix, param_name, constraint), | |
156 | Applicability::MaybeIncorrect, | |
157 | ); | |
158 | true | |
159 | } | |
160 | ||
5e7ed085 FG |
161 | #[derive(Debug)] |
162 | enum SuggestChangingConstraintsMessage<'a> { | |
163 | RestrictBoundFurther, | |
164 | RestrictType { ty: &'a str }, | |
165 | RestrictTypeFurther { ty: &'a str }, | |
166 | RemovingQSized, | |
167 | } | |
168 | ||
94222f64 XL |
169 | fn suggest_removing_unsized_bound( |
170 | generics: &hir::Generics<'_>, | |
5e7ed085 | 171 | suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>, |
94222f64 XL |
172 | param_name: &str, |
173 | param: &hir::GenericParam<'_>, | |
174 | def_id: Option<DefId>, | |
175 | ) { | |
176 | // See if there's a `?Sized` bound that can be removed to suggest that. | |
c295e0f8 XL |
177 | // First look at the `where` clause because we can have `where T: ?Sized`, |
178 | // then look at params. | |
94222f64 XL |
179 | for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() { |
180 | match predicate { | |
181 | WherePredicate::BoundPredicate(WhereBoundPredicate { | |
182 | bounded_ty: | |
183 | hir::Ty { | |
184 | kind: | |
185 | hir::TyKind::Path(hir::QPath::Resolved( | |
186 | None, | |
187 | hir::Path { | |
188 | segments: [segment], | |
189 | res: hir::def::Res::Def(hir::def::DefKind::TyParam, _), | |
190 | .. | |
191 | }, | |
192 | )), | |
193 | .. | |
194 | }, | |
195 | bounds, | |
196 | span, | |
197 | .. | |
198 | }) if segment.ident.as_str() == param_name => { | |
199 | for (pos, bound) in bounds.iter().enumerate() { | |
200 | match bound { | |
94222f64 XL |
201 | hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) |
202 | if poly.trait_ref.trait_def_id() == def_id => {} | |
203 | _ => continue, | |
204 | } | |
205 | let sp = match ( | |
206 | bounds.len(), | |
207 | pos, | |
208 | generics.where_clause.predicates.len(), | |
209 | where_pos, | |
210 | ) { | |
211 | // where T: ?Sized | |
212 | // ^^^^^^^^^^^^^^^ | |
213 | (1, _, 1, _) => generics.where_clause.span, | |
214 | // where Foo: Bar, T: ?Sized, | |
215 | // ^^^^^^^^^^^ | |
216 | (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates | |
217 | [pos - 1] | |
218 | .span() | |
219 | .shrink_to_hi() | |
220 | .to(*span), | |
221 | // where T: ?Sized, Foo: Bar, | |
222 | // ^^^^^^^^^^^ | |
223 | (1, _, _, pos) => { | |
224 | span.until(generics.where_clause.predicates[pos + 1].span()) | |
225 | } | |
226 | // where T: ?Sized + Bar, Foo: Bar, | |
227 | // ^^^^^^^^^ | |
228 | (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()), | |
229 | // where T: Bar + ?Sized, Foo: Bar, | |
230 | // ^^^^^^^^^ | |
231 | (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()), | |
232 | }; | |
5e7ed085 FG |
233 | |
234 | suggestions.push(( | |
94222f64 | 235 | sp, |
94222f64 | 236 | String::new(), |
5e7ed085 FG |
237 | SuggestChangingConstraintsMessage::RemovingQSized, |
238 | )); | |
94222f64 XL |
239 | } |
240 | } | |
241 | _ => {} | |
242 | } | |
243 | } | |
244 | for (pos, bound) in param.bounds.iter().enumerate() { | |
245 | match bound { | |
246 | hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) | |
c295e0f8 | 247 | if poly.trait_ref.trait_def_id() == def_id => |
94222f64 XL |
248 | { |
249 | let sp = match (param.bounds.len(), pos) { | |
250 | // T: ?Sized, | |
251 | // ^^^^^^^^ | |
252 | (1, _) => param.span.shrink_to_hi().to(bound.span()), | |
253 | // T: ?Sized + Bar, | |
254 | // ^^^^^^^^^ | |
255 | (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()), | |
256 | // T: Bar + ?Sized, | |
257 | // ^^^^^^^^^ | |
258 | (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()), | |
259 | }; | |
5e7ed085 FG |
260 | |
261 | suggestions.push(( | |
94222f64 | 262 | sp, |
94222f64 | 263 | String::new(), |
5e7ed085 FG |
264 | SuggestChangingConstraintsMessage::RemovingQSized, |
265 | )); | |
94222f64 XL |
266 | } |
267 | _ => {} | |
268 | } | |
269 | } | |
270 | } | |
271 | ||
f9f354fc XL |
272 | /// Suggest restricting a type param with a new bound. |
273 | pub fn suggest_constraining_type_param( | |
274 | tcx: TyCtxt<'_>, | |
275 | generics: &hir::Generics<'_>, | |
5e7ed085 | 276 | err: &mut Diagnostic, |
f9f354fc XL |
277 | param_name: &str, |
278 | constraint: &str, | |
279 | def_id: Option<DefId>, | |
280 | ) -> bool { | |
5e7ed085 FG |
281 | suggest_constraining_type_params( |
282 | tcx, | |
283 | generics, | |
284 | err, | |
285 | [(param_name, constraint, def_id)].into_iter(), | |
286 | ) | |
287 | } | |
f9f354fc | 288 | |
5e7ed085 FG |
289 | /// Suggest restricting a type param with a new bound. |
290 | pub fn suggest_constraining_type_params<'a>( | |
291 | tcx: TyCtxt<'_>, | |
292 | generics: &hir::Generics<'_>, | |
293 | err: &mut Diagnostic, | |
294 | param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>, | |
295 | ) -> bool { | |
296 | let mut grouped = FxHashMap::default(); | |
297 | param_names_and_constraints.for_each(|(param_name, constraint, def_id)| { | |
298 | grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id)) | |
299 | }); | |
f9f354fc | 300 | |
5e7ed085 FG |
301 | let mut applicability = Applicability::MachineApplicable; |
302 | let mut suggestions = Vec::new(); | |
f9f354fc | 303 | |
5e7ed085 FG |
304 | for (param_name, mut constraints) in grouped { |
305 | let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); | |
306 | let Some(param) = param else { return false }; | |
f9f354fc | 307 | |
5e7ed085 FG |
308 | { |
309 | let mut sized_constraints = | |
310 | constraints.drain_filter(|(_, def_id)| *def_id == tcx.lang_items().sized_trait()); | |
311 | if let Some((constraint, def_id)) = sized_constraints.next() { | |
312 | applicability = Applicability::MaybeIncorrect; | |
f9f354fc | 313 | |
5e7ed085 FG |
314 | err.span_label( |
315 | param.span, | |
316 | &format!("this type parameter needs to be `{}`", constraint), | |
317 | ); | |
318 | suggest_removing_unsized_bound( | |
319 | generics, | |
320 | &mut suggestions, | |
321 | param_name, | |
322 | param, | |
323 | def_id, | |
324 | ); | |
325 | } | |
326 | } | |
327 | ||
328 | if constraints.is_empty() { | |
329 | continue; | |
330 | } | |
331 | ||
332 | let constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>().join(" + "); | |
333 | let mut suggest_restrict = |span| { | |
334 | suggestions.push(( | |
335 | span, | |
336 | format!(" + {}", constraint), | |
337 | SuggestChangingConstraintsMessage::RestrictBoundFurther, | |
338 | )) | |
339 | }; | |
340 | ||
341 | if param_name.starts_with("impl ") { | |
342 | // If there's an `impl Trait` used in argument position, suggest | |
343 | // restricting it: | |
f9f354fc | 344 | // |
5e7ed085 FG |
345 | // fn foo(t: impl Foo) { ... } |
346 | // -------- | |
f9f354fc XL |
347 | // | |
348 | // help: consider further restricting this bound with `+ Bar` | |
349 | // | |
350 | // Suggestion for tools in this case is: | |
351 | // | |
5e7ed085 FG |
352 | // fn foo(t: impl Foo) { ... } |
353 | // -------- | |
354 | // | | |
355 | // replace with: `impl Foo + Bar` | |
356 | ||
357 | suggest_restrict(param.span.shrink_to_hi()); | |
358 | continue; | |
f9f354fc XL |
359 | } |
360 | ||
5e7ed085 FG |
361 | if generics.where_clause.predicates.is_empty() |
362 | // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the | |
363 | // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`. | |
364 | && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) | |
1b1a35ee | 365 | { |
5e7ed085 FG |
366 | if let Some(span) = param.bounds_span_for_suggestions() { |
367 | // If user has provided some bounds, suggest restricting them: | |
368 | // | |
369 | // fn foo<T: Foo>(t: T) { ... } | |
370 | // --- | |
371 | // | | |
372 | // help: consider further restricting this bound with `+ Bar` | |
373 | // | |
374 | // Suggestion for tools in this case is: | |
375 | // | |
376 | // fn foo<T: Foo>(t: T) { ... } | |
377 | // -- | |
378 | // | | |
379 | // replace with: `T: Bar +` | |
380 | suggest_restrict(span); | |
381 | } else { | |
382 | // If user hasn't provided any bounds, suggest adding a new one: | |
383 | // | |
384 | // fn foo<T>(t: T) { ... } | |
385 | // - help: consider restricting this type parameter with `T: Foo` | |
386 | suggestions.push(( | |
387 | param.span.shrink_to_hi(), | |
388 | format!(": {}", constraint), | |
389 | SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, | |
390 | )); | |
391 | } | |
1b1a35ee | 392 | } else { |
5e7ed085 FG |
393 | // This part is a bit tricky, because using the `where` clause user can |
394 | // provide zero, one or many bounds for the same type parameter, so we | |
395 | // have following cases to consider: | |
396 | // | |
397 | // 1) When the type parameter has been provided zero bounds | |
398 | // | |
399 | // Message: | |
400 | // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } | |
401 | // - help: consider restricting this type parameter with `where X: Bar` | |
402 | // | |
403 | // Suggestion: | |
404 | // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } | |
405 | // - insert: `, X: Bar` | |
406 | // | |
407 | // | |
408 | // 2) When the type parameter has been provided one bound | |
409 | // | |
410 | // Message: | |
411 | // fn foo<T>(t: T) where T: Foo { ... } | |
412 | // ^^^^^^ | |
413 | // | | |
414 | // help: consider further restricting this bound with `+ Bar` | |
415 | // | |
416 | // Suggestion: | |
417 | // fn foo<T>(t: T) where T: Foo { ... } | |
418 | // ^^ | |
419 | // | | |
420 | // replace with: `T: Bar +` | |
421 | // | |
422 | // | |
423 | // 3) When the type parameter has been provided many bounds | |
424 | // | |
425 | // Message: | |
426 | // fn foo<T>(t: T) where T: Foo, T: Bar {... } | |
427 | // - help: consider further restricting this type parameter with `where T: Zar` | |
428 | // | |
429 | // Suggestion: | |
430 | // fn foo<T>(t: T) where T: Foo, T: Bar {... } | |
431 | // - insert: `, T: Zar` | |
432 | // | |
433 | // Additionally, there may be no `where` clause whatsoever in the case that this was | |
434 | // reached because the generic parameter has a default: | |
435 | // | |
436 | // Message: | |
437 | // trait Foo<T=()> {... } | |
438 | // - help: consider further restricting this type parameter with `where T: Zar` | |
439 | // | |
440 | // Suggestion: | |
441 | // trait Foo<T=()> where T: Zar {... } | |
442 | // - insert: `where T: Zar` | |
443 | ||
444 | if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) | |
445 | && generics.where_clause.predicates.len() == 0 | |
446 | { | |
447 | // Suggest a bound, but there is no existing `where` clause *and* the type param has a | |
448 | // default (`<T=Foo>`), so we suggest adding `where T: Bar`. | |
449 | suggestions.push(( | |
450 | generics.where_clause.tail_span_for_suggestion(), | |
451 | format!(" where {}: {}", param_name, constraint), | |
452 | SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, | |
453 | )); | |
454 | } else { | |
455 | let mut param_spans = Vec::new(); | |
456 | ||
457 | for predicate in generics.where_clause.predicates { | |
458 | if let WherePredicate::BoundPredicate(WhereBoundPredicate { | |
459 | span, | |
460 | bounded_ty, | |
461 | .. | |
462 | }) = predicate | |
463 | { | |
464 | if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { | |
465 | if let Some(segment) = path.segments.first() { | |
466 | if segment.ident.to_string() == param_name { | |
467 | param_spans.push(span); | |
468 | } | |
1b1a35ee | 469 | } |
f9f354fc XL |
470 | } |
471 | } | |
472 | } | |
f9f354fc | 473 | |
5e7ed085 FG |
474 | match param_spans[..] { |
475 | [¶m_span] => suggest_restrict(param_span.shrink_to_hi()), | |
476 | _ => { | |
477 | suggestions.push(( | |
478 | generics.where_clause.tail_span_for_suggestion(), | |
479 | constraints | |
480 | .iter() | |
481 | .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint)) | |
482 | .collect::<String>(), | |
483 | SuggestChangingConstraintsMessage::RestrictTypeFurther { | |
484 | ty: param_name, | |
485 | }, | |
486 | )); | |
487 | } | |
1b1a35ee | 488 | } |
f9f354fc XL |
489 | } |
490 | } | |
5e7ed085 FG |
491 | } |
492 | ||
493 | if suggestions.len() == 1 { | |
494 | let (span, suggestion, msg) = suggestions.pop().unwrap(); | |
f9f354fc | 495 | |
5e7ed085 FG |
496 | let s; |
497 | let msg = match msg { | |
498 | SuggestChangingConstraintsMessage::RestrictBoundFurther => { | |
499 | "consider further restricting this bound" | |
500 | } | |
501 | SuggestChangingConstraintsMessage::RestrictType { ty } => { | |
502 | s = format!("consider restricting type parameter `{}`", ty); | |
503 | &s | |
504 | } | |
505 | SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => { | |
506 | s = format!("consider further restricting type parameter `{}`", ty); | |
507 | &s | |
508 | } | |
509 | SuggestChangingConstraintsMessage::RemovingQSized => { | |
510 | "consider removing the `?Sized` bound to make the type parameter `Sized`" | |
511 | } | |
512 | }; | |
513 | ||
514 | err.span_suggestion_verbose(span, msg, suggestion, applicability); | |
515 | } else if suggestions.len() > 1 { | |
516 | err.multipart_suggestion_verbose( | |
517 | "consider restricting type parameters", | |
518 | suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(), | |
519 | applicability, | |
520 | ); | |
f9f354fc | 521 | } |
5e7ed085 FG |
522 | |
523 | true | |
f9f354fc XL |
524 | } |
525 | ||
f035d41b XL |
526 | /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. |
527 | pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>); | |
528 | ||
529 | impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { | |
f035d41b XL |
530 | fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { |
531 | match ty.kind { | |
532 | hir::TyKind::TraitObject( | |
533 | _, | |
534 | hir::Lifetime { | |
535 | name: | |
536 | hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, | |
537 | .. | |
538 | }, | |
6a06907d | 539 | _, |
f035d41b XL |
540 | ) => { |
541 | self.0.push(ty); | |
542 | } | |
543 | hir::TyKind::OpaqueDef(item_id, _) => { | |
544 | self.0.push(ty); | |
6a06907d | 545 | let item = self.1.item(item_id); |
f035d41b XL |
546 | hir::intravisit::walk_item(self, item); |
547 | } | |
548 | _ => {} | |
f9f354fc | 549 | } |
f035d41b | 550 | hir::intravisit::walk_ty(self, ty); |
f9f354fc XL |
551 | } |
552 | } | |
a2a8927a XL |
553 | |
554 | /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. | |
555 | pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>); | |
556 | ||
557 | impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { | |
a2a8927a XL |
558 | fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) { |
559 | if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = | |
560 | lt.name | |
561 | { | |
562 | self.0.push(lt.span); | |
563 | } | |
564 | } | |
565 | } |