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