]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
Auto merge of #106474 - erikdesjardins:noalias, r=bjorn3
[rust.git] / compiler / rustc_infer / src / infer / error_reporting / nice_region_error / static_impl_trait.rs
1 //! Error Reporting for static impl Traits.
2
3 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
4 use crate::infer::lexical_region_resolve::RegionResolutionError;
5 use crate::infer::{SubregionOrigin, TypeTrace};
6 use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
7 use rustc_data_structures::fx::FxIndexSet;
8 use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
9 use rustc_hir::def_id::DefId;
10 use rustc_hir::intravisit::{walk_ty, Visitor};
11 use rustc_hir::{
12     self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
13     TyKind,
14 };
15 use rustc_middle::ty::{
16     self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
17 };
18 use rustc_span::symbol::Ident;
19 use rustc_span::Span;
20
21 use rustc_span::def_id::LocalDefId;
22 use std::ops::ControlFlow;
23
24 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
25     /// Print the error message for lifetime errors when the return type is a static `impl Trait`,
26     /// `dyn Trait` or if a method call on a trait object introduces a static requirement.
27     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorGuaranteed> {
28         debug!("try_report_static_impl_trait(error={:?})", self.error);
29         let tcx = self.tcx();
30         let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? {
31             RegionResolutionError::SubSupConflict(
32                 _,
33                 var_origin,
34                 sub_origin,
35                 sub_r,
36                 sup_origin,
37                 sup_r,
38                 spans,
39             ) if sub_r.is_static() => (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans),
40             RegionResolutionError::ConcreteFailure(
41                 SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
42                 sub_r,
43                 sup_r,
44             ) if sub_r.is_static() => {
45                 // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
46                 if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
47                     // This may have a closure and it would cause ICE
48                     // through `find_param_with_region` (#78262).
49                     let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
50                     let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
51                     if fn_returns.is_empty() {
52                         return None;
53                     }
54
55                     let param = self.find_param_with_region(*sup_r, *sub_r)?;
56                     let lifetime = if sup_r.has_name() {
57                         format!("lifetime `{}`", sup_r)
58                     } else {
59                         "an anonymous lifetime `'_`".to_string()
60                     };
61                     let mut err = struct_span_err!(
62                         tcx.sess,
63                         cause.span,
64                         E0772,
65                         "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
66                          requirement",
67                         param
68                             .param
69                             .pat
70                             .simple_ident()
71                             .map(|s| format!("`{}`", s))
72                             .unwrap_or_else(|| "`fn` parameter".to_string()),
73                         lifetime,
74                         ctxt.assoc_item.name,
75                     );
76                     err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
77                     err.span_label(
78                         cause.span,
79                         &format!(
80                             "...is used and required to live as long as `'static` here \
81                              because of an implicit lifetime bound on the {}",
82                             match ctxt.assoc_item.container {
83                                 AssocItemContainer::TraitContainer => {
84                                     let id = ctxt.assoc_item.container_id(tcx);
85                                     format!("`impl` of `{}`", tcx.def_path_str(id))
86                                 }
87                                 AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
88                             },
89                         ),
90                     );
91                     if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
92                         let reported = err.emit();
93                         return Some(reported);
94                     } else {
95                         err.cancel();
96                     }
97                 }
98                 return None;
99             }
100             _ => return None,
101         };
102         debug!(
103             "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
104             var_origin, sub_origin, sub_r, sup_origin, sup_r
105         );
106         let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
107         debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
108         let sp = var_origin.span();
109         let return_sp = sub_origin.span();
110         let param = self.find_param_with_region(*sup_r, *sub_r)?;
111         let (lifetime_name, lifetime) = if sup_r.has_name() {
112             (sup_r.to_string(), format!("lifetime `{}`", sup_r))
113         } else {
114             ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
115         };
116         let param_name = param
117             .param
118             .pat
119             .simple_ident()
120             .map(|s| format!("`{}`", s))
121             .unwrap_or_else(|| "`fn` parameter".to_string());
122         let mut err = struct_span_err!(
123             tcx.sess,
124             sp,
125             E0759,
126             "{} has {} but it needs to satisfy a `'static` lifetime requirement",
127             param_name,
128             lifetime,
129         );
130
131         let (mention_influencer, influencer_point) =
132             if sup_origin.span().overlaps(param.param_ty_span) {
133                 // Account for `async fn` like in `async-await/issues/issue-62097.rs`.
134                 // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
135                 // place (but with different `ctxt`, hence `overlaps` instead of `==` above).
136                 //
137                 // This avoids the following:
138                 //
139                 // LL |     pub async fn run_dummy_fn(&self) {
140                 //    |                               ^^^^^
141                 //    |                               |
142                 //    |                               this data with an anonymous lifetime `'_`...
143                 //    |                               ...is captured here...
144                 (false, sup_origin.span())
145             } else {
146                 (!sup_origin.span().overlaps(return_sp), param.param_ty_span)
147             };
148         err.span_label(influencer_point, &format!("this data with {}...", lifetime));
149
150         debug!("try_report_static_impl_trait: param_info={:?}", param);
151
152         let mut spans = spans.clone();
153
154         if mention_influencer {
155             spans.push(sup_origin.span());
156         }
157         // We dedup the spans *ignoring* expansion context.
158         spans.sort();
159         spans.dedup_by_key(|span| (span.lo(), span.hi()));
160
161         // We try to make the output have fewer overlapping spans if possible.
162         let require_msg = if spans.is_empty() {
163             "...is used and required to live as long as `'static` here"
164         } else {
165             "...and is required to live as long as `'static` here"
166         };
167         let require_span =
168             if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
169
170         for span in &spans {
171             err.span_label(*span, "...is used here...");
172         }
173
174         if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
175             // If any of the "captured here" labels appears on the same line or after
176             // `require_span`, we put it on a note to ensure the text flows by appearing
177             // always at the end.
178             err.span_note(require_span, require_msg);
179         } else {
180             // We don't need a note, it's already at the end, it can be shown as a `span_label`.
181             err.span_label(require_span, require_msg);
182         }
183
184         if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
185             err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
186         }
187         if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
188             if let ObligationCauseCode::ReturnValue(hir_id)
189             | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
190             {
191                 let parent_id = tcx.hir().get_parent_item(*hir_id);
192                 if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
193                     let mut span: MultiSpan = fn_decl.output.span().into();
194                     let mut add_label = true;
195                     if let hir::FnRetTy::Return(ty) = fn_decl.output {
196                         let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
197                         v.visit_ty(ty);
198                         if !v.0.is_empty() {
199                             span = v.0.clone().into();
200                             for sp in v.0 {
201                                 span.push_span_label(sp, "`'static` requirement introduced here");
202                             }
203                             add_label = false;
204                         }
205                     }
206                     if add_label {
207                         span.push_span_label(
208                             fn_decl.output.span(),
209                             "requirement introduced by this return type",
210                         );
211                     }
212                     span.push_span_label(cause.span, "because of this returned expression");
213                     err.span_note(
214                         span,
215                         "`'static` lifetime requirement introduced by the return type",
216                     );
217                 }
218             }
219         }
220
221         let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
222
223         let mut override_error_code = None;
224         if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin
225             && let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code()
226             // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
227             // `'static` lifetime when called as a method on a binding: `bar.qux()`.
228             && self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt)
229         {
230             override_error_code = Some(ctxt.assoc_item.name);
231         }
232
233         if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin
234             && let code = match cause.code() {
235                 ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
236                 _ => cause.code(),
237             }
238             && let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code)
239         {
240             // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
241             // lifetime as above, but called using a fully-qualified path to the method:
242             // `Foo::qux(bar)`.
243             let mut v = TraitObjectVisitor(FxIndexSet::default());
244             v.visit_ty(param.param_ty);
245             if let Some((ident, self_ty)) =
246                 NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
247                 && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
248             {
249                 override_error_code = Some(ident.name);
250             }
251         }
252         if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
253             // Provide a more targeted error code and description.
254             err.code(rustc_errors::error_code!(E0772));
255             err.set_primary_message(&format!(
256                 "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
257                 requirement",
258                 param_name, lifetime, ident,
259             ));
260         }
261
262         let arg = match param.param.pat.simple_ident() {
263             Some(simple_ident) => format!("argument `{}`", simple_ident),
264             None => "the argument".to_string(),
265         };
266         let captures = format!("captures data from {}", arg);
267         suggest_new_region_bound(
268             tcx,
269             &mut err,
270             fn_returns,
271             lifetime_name,
272             Some(arg),
273             captures,
274             Some((param.param_ty_span, param.param_ty.to_string())),
275             Some(anon_reg_sup.def_id),
276         );
277
278         let reported = err.emit();
279         Some(reported)
280     }
281 }
282
283 pub fn suggest_new_region_bound(
284     tcx: TyCtxt<'_>,
285     err: &mut Diagnostic,
286     fn_returns: Vec<&rustc_hir::Ty<'_>>,
287     lifetime_name: String,
288     arg: Option<String>,
289     captures: String,
290     param: Option<(Span, String)>,
291     scope_def_id: Option<LocalDefId>,
292 ) {
293     debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
294     // FIXME: account for the need of parens in `&(dyn Trait + '_)`
295     let consider = "consider changing";
296     let declare = "to declare that";
297     let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
298     let explicit_static =
299         arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
300     let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
301     let plus_lt = format!(" + {}", lifetime_name);
302     for fn_return in fn_returns {
303         if fn_return.span.desugaring_kind().is_some() {
304             // Skip `async` desugaring `impl Future`.
305             continue;
306         }
307         match fn_return.kind {
308             TyKind::OpaqueDef(item_id, _, _) => {
309                 let item = tcx.hir().item(item_id);
310                 let ItemKind::OpaqueTy(opaque) = &item.kind else {
311                     return;
312                 };
313
314                 // Get the identity type for this RPIT
315                 let did = item_id.owner_id.to_def_id();
316                 let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
317
318                 if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
319                     GenericBound::Outlives(Lifetime {
320                         res: LifetimeName::Static, ident, ..
321                     }) => Some(ident.span),
322                     _ => None,
323                 }) {
324                     if let Some(explicit_static) = &explicit_static {
325                         err.span_suggestion_verbose(
326                             span,
327                             &format!("{consider} `{ty}`'s {explicit_static}"),
328                             &lifetime_name,
329                             Applicability::MaybeIncorrect,
330                         );
331                     }
332                     if let Some((param_span, ref param_ty)) = param {
333                         err.span_suggestion_verbose(
334                             param_span,
335                             add_static_bound,
336                             param_ty,
337                             Applicability::MaybeIncorrect,
338                         );
339                     }
340                 } else if opaque.bounds.iter().any(|arg| match arg {
341                     GenericBound::Outlives(Lifetime { ident, .. })
342                         if ident.name.to_string() == lifetime_name =>
343                     {
344                         true
345                     }
346                     _ => false,
347                 }) {
348                 } else {
349                     // get a lifetime name of existing named lifetimes if any
350                     let existing_lt_name = if let Some(id) = scope_def_id
351                         && let Some(generics) = tcx.hir().get_generics(id)
352                         && let named_lifetimes = generics
353                         .params
354                         .iter()
355                         .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
356                         .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
357                         .filter(|n| ! matches!(n, None))
358                         .collect::<Vec<_>>()
359                         && named_lifetimes.len() > 0 {
360                         named_lifetimes[0].clone()
361                     } else {
362                         None
363                     };
364                     let name = if let Some(name) = &existing_lt_name {
365                         format!("{}", name)
366                     } else {
367                         format!("'a")
368                     };
369                     // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
370                     // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
371                     if let Some(id) = scope_def_id
372                         && let Some(generics) = tcx.hir().get_generics(id)
373                         && let mut spans_suggs = generics
374                             .params
375                             .iter()
376                             .filter(|p| p.is_elided_lifetime())
377                             .map(|p|
378                                   if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
379                                       (p.span.shrink_to_hi(),format!("{name} "))
380                                   } else { // Underscore (elided with '_)
381                                       (p.span, format!("{name}"))
382                                   }
383                             )
384                             .collect::<Vec<_>>()
385                         && spans_suggs.len() > 1
386                     {
387                         let use_lt =
388                         if existing_lt_name == None {
389                             spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
390                             format!("you can introduce a named lifetime parameter `{name}`")
391                         } else {
392                             // make use the existing named lifetime
393                             format!("you can use the named lifetime parameter `{name}`")
394                         };
395                         spans_suggs
396                             .push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
397                         err.multipart_suggestion_verbose(
398                             &format!(
399                                 "{declare} `{ty}` {captures}, {use_lt}",
400                             ),
401                             spans_suggs,
402                             Applicability::MaybeIncorrect,
403                         );
404                     } else {
405                         err.span_suggestion_verbose(
406                             fn_return.span.shrink_to_hi(),
407                             &format!("{declare} `{ty}` {captures}, {explicit}",),
408                             &plus_lt,
409                             Applicability::MaybeIncorrect,
410                         );
411                     }
412                 }
413             }
414             TyKind::TraitObject(_, lt, _) => {
415                 if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
416                     err.span_suggestion_verbose(
417                         fn_return.span.shrink_to_hi(),
418                         &format!(
419                             "{declare} the trait object {captures}, {explicit}",
420                             declare = declare,
421                             captures = captures,
422                             explicit = explicit,
423                         ),
424                         &plus_lt,
425                         Applicability::MaybeIncorrect,
426                     );
427                 } else if lt.ident.name.to_string() != lifetime_name {
428                     // With this check we avoid suggesting redundant bounds. This
429                     // would happen if there are nested impl/dyn traits and only
430                     // one of them has the bound we'd suggest already there, like
431                     // in `impl Foo<X = dyn Bar> + '_`.
432                     if let Some(explicit_static) = &explicit_static {
433                         err.span_suggestion_verbose(
434                             lt.ident.span,
435                             &format!("{} the trait object's {}", consider, explicit_static),
436                             &lifetime_name,
437                             Applicability::MaybeIncorrect,
438                         );
439                     }
440                     if let Some((param_span, param_ty)) = param.clone() {
441                         err.span_suggestion_verbose(
442                             param_span,
443                             add_static_bound,
444                             param_ty,
445                             Applicability::MaybeIncorrect,
446                         );
447                     }
448                 }
449             }
450             _ => {}
451         }
452     }
453 }
454
455 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
456     pub fn get_impl_ident_and_self_ty_from_trait(
457         tcx: TyCtxt<'tcx>,
458         def_id: DefId,
459         trait_objects: &FxIndexSet<DefId>,
460     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
461         match tcx.hir().get_if_local(def_id)? {
462             Node::ImplItem(impl_item) => {
463                 let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
464                 if let hir::OwnerNode::Item(Item {
465                     kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
466                     ..
467                 }) = tcx.hir().owner(impl_did)
468                 {
469                     Some((impl_item.ident, self_ty))
470                 } else {
471                     None
472                 }
473             }
474             Node::TraitItem(trait_item) => {
475                 let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
476                 debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
477                 // The method being called is defined in the `trait`, but the `'static`
478                 // obligation comes from the `impl`. Find that `impl` so that we can point
479                 // at it in the suggestion.
480                 let trait_did = trait_id.to_def_id();
481                 tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
482                     if let Node::Item(Item {
483                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
484                         ..
485                     }) = tcx.hir().find_by_def_id(impl_did)?
486                         && trait_objects.iter().all(|did| {
487                             // FIXME: we should check `self_ty` against the receiver
488                             // type in the `UnifyReceiver` context, but for now, use
489                             // this imperfect proxy. This will fail if there are
490                             // multiple `impl`s for the same trait like
491                             // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
492                             // In that case, only the first one will get suggestions.
493                             let mut traits = vec![];
494                             let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
495                             hir_v.visit_ty(self_ty);
496                             !traits.is_empty()
497                         })
498                     {
499                         Some((trait_item.ident, *self_ty))
500                     } else {
501                         None
502                     }
503                 })
504             }
505             _ => None,
506         }
507     }
508
509     /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
510     /// `'static` obligation. Suggest relaxing that implicit bound.
511     fn find_impl_on_dyn_trait(
512         &self,
513         err: &mut Diagnostic,
514         ty: Ty<'_>,
515         ctxt: &UnifyReceiverContext<'tcx>,
516     ) -> bool {
517         let tcx = self.tcx();
518
519         // Find the method being called.
520         let Ok(Some(instance)) = ty::Instance::resolve(
521             tcx,
522             ctxt.param_env,
523             ctxt.assoc_item.def_id,
524             self.cx.resolve_vars_if_possible(ctxt.substs),
525         ) else {
526             return false;
527         };
528
529         let mut v = TraitObjectVisitor(FxIndexSet::default());
530         v.visit_ty(ty);
531
532         // Get the `Ident` of the method being called and the corresponding `impl` (to point at
533         // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
534         let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
535             return false;
536         };
537
538         // Find the trait object types in the argument, so we point at *only* the trait object.
539         self.suggest_constrain_dyn_trait_in_impl(err, &v.0, ident, self_ty)
540     }
541
542     fn suggest_constrain_dyn_trait_in_impl(
543         &self,
544         err: &mut Diagnostic,
545         found_dids: &FxIndexSet<DefId>,
546         ident: Ident,
547         self_ty: &hir::Ty<'_>,
548     ) -> bool {
549         let mut suggested = false;
550         for found_did in found_dids {
551             let mut traits = vec![];
552             let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
553             hir_v.visit_ty(&self_ty);
554             for span in &traits {
555                 let mut multi_span: MultiSpan = vec![*span].into();
556                 multi_span
557                     .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
558                 multi_span.push_span_label(
559                     ident.span,
560                     "calling this method introduces the `impl`'s 'static` requirement",
561                 );
562                 err.span_note(multi_span, "the used `impl` has a `'static` requirement");
563                 err.span_suggestion_verbose(
564                     span.shrink_to_hi(),
565                     "consider relaxing the implicit `'static` requirement",
566                     " + '_",
567                     Applicability::MaybeIncorrect,
568                 );
569                 suggested = true;
570             }
571         }
572         suggested
573     }
574 }
575
576 /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
577 pub struct TraitObjectVisitor(pub FxIndexSet<DefId>);
578
579 impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
580     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
581         match t.kind() {
582             ty::Dynamic(preds, re, _) if re.is_static() => {
583                 if let Some(def_id) = preds.principal_def_id() {
584                     self.0.insert(def_id);
585                 }
586                 ControlFlow::CONTINUE
587             }
588             _ => t.super_visit_with(self),
589         }
590     }
591 }
592
593 /// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
594 pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec<Span>, pub DefId);
595
596 impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
597     fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
598         if let TyKind::TraitObject(
599             poly_trait_refs,
600             Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. },
601             _,
602         ) = t.kind
603         {
604             for ptr in poly_trait_refs {
605                 if Some(self.1) == ptr.trait_ref.trait_def_id() {
606                     self.0.push(ptr.span);
607                 }
608             }
609         }
610         walk_ty(self, t);
611     }
612 }