22
33use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
44use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
5+ use crate :: infer:: { SubregionOrigin , TypeTrace } ;
6+ use crate :: traits:: ObligationCauseCode ;
57use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
6- use rustc_hir:: def:: { DefKind , Res } ;
78use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
8- use rustc_hir:: {
9- GenericBound , Item , ItemKind , Lifetime , LifetimeName , Node , Path , PolyTraitRef , TraitRef ,
10- TyKind ,
11- } ;
12- use rustc_middle:: ty:: { self , RegionKind , Ty , TypeFoldable , TypeVisitor } ;
9+ use rustc_hir:: intravisit:: { walk_ty, ErasedMap , NestedVisitorMap , Visitor } ;
10+ use rustc_hir:: { self as hir, GenericBound , Item , ItemKind , Lifetime , LifetimeName , Node , TyKind } ;
11+ use rustc_middle:: ty:: { self , AssocItemContainer , RegionKind , Ty , TypeFoldable , TypeVisitor } ;
12+ use rustc_span:: Span ;
1313
1414impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
1515 /// Print the error message for lifetime errors when the return type is a static impl Trait.
@@ -27,6 +27,39 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
2727 ) if * * sub_r == RegionKind :: ReStatic => {
2828 ( var_origin, sub_origin, sub_r, sup_origin, sup_r)
2929 }
30+ RegionResolutionError :: ConcreteFailure (
31+ SubregionOrigin :: Subtype ( box TypeTrace { cause, .. } ) ,
32+ sub_r,
33+ sup_r,
34+ ) if * * sub_r == RegionKind :: ReStatic => {
35+ // This is for the implicit `'static` requirement coming from `impl dyn Trait {}`.
36+ if let ObligationCauseCode :: UnifyReceiver ( assoc) = & cause. code {
37+ let param = self . find_param_with_region ( sup_r, sub_r) ?;
38+ let lifetime = if sup_r. has_name ( ) {
39+ format ! ( "lifetime `{}`" , sup_r)
40+ } else {
41+ "an anonymous lifetime `'_`" . to_string ( )
42+ } ;
43+ let mut err = struct_span_err ! (
44+ tcx. sess,
45+ cause. span,
46+ E0759 ,
47+ "cannot infer an appropriate lifetime"
48+ ) ;
49+ err. span_label ( param. param_ty_span , & format ! ( "this data with {}..." , lifetime) ) ;
50+ err. span_label (
51+ cause. span ,
52+ "...is captured and required to live as long as `'static` here" ,
53+ ) ;
54+ if self . find_impl_on_dyn_trait ( & mut err, param. param_ty , & assoc. container ) {
55+ err. emit ( ) ;
56+ return Some ( ErrorReported ) ;
57+ } else {
58+ err. cancel ( ) ;
59+ }
60+ }
61+ return None ;
62+ }
3063 _ => return None ,
3164 } ;
3265 debug ! (
@@ -96,7 +129,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
96129 ) ;
97130 }
98131
99- self . find_impl_on_dyn_trait ( & mut err, param. param_ty ) ;
132+ if let SubregionOrigin :: Subtype ( box TypeTrace { cause, .. } ) = & sup_origin {
133+ if let ObligationCauseCode :: UnifyReceiver ( assoc) = & cause. code {
134+ self . find_impl_on_dyn_trait ( & mut err, param. param_ty , & assoc. container ) ;
135+ }
136+ }
100137
101138 let fn_returns = tcx. return_type_impl_or_dyn_traits ( anon_reg_sup. def_id ) ;
102139 debug ! ( "try_report_static_impl_trait: fn_return={:?}" , fn_returns) ;
@@ -222,63 +259,86 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
222259
223260 /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
224261 /// `'static` obligation. Find `impl` blocks that are implemented
225- fn find_impl_on_dyn_trait ( & self , err : & mut DiagnosticBuilder < ' _ > , ty : Ty < ' _ > ) -> bool {
262+ fn find_impl_on_dyn_trait (
263+ & self ,
264+ err : & mut DiagnosticBuilder < ' _ > ,
265+ ty : Ty < ' _ > ,
266+ container : & AssocItemContainer ,
267+ ) -> bool {
226268 let tcx = self . tcx ( ) ;
269+ let mut suggested = false ;
227270
228271 // Find the trait object types in the argument.
229272 let mut v = TraitObjectVisitor ( vec ! [ ] ) ;
230273 v. visit_ty ( ty) ;
231- debug ! ( "TraitObjectVisitor {:?}" , v. 0 ) ;
232274
233- // Find all the `impl`s in the local scope that can be called on the type parameter.
234- // FIXME: this doesn't find `impl dyn Trait { /**/ }`.
275+ let container_id = match container {
276+ // When the obligation comes from an `impl Foo for dyn Bar {}`, we
277+ // have the `DefId` of the `trait` itself, not the relevant `impl`
278+ // block. Because of this, we have to look at all the `trait`s
279+ // available, and filter out all that are not of `Foo` (this `def_id`)
280+ // and not of `Bar` (the `filter_map` later in this method).
281+ AssocItemContainer :: TraitContainer ( def_id) => def_id,
282+
283+ // When the obligation comes from an `impl dyn Trait {}`, we already
284+ // have the `DefId` of the relevant `Item`, so we use it directly.
285+ AssocItemContainer :: ImplContainer ( def_id) => {
286+ if let Some ( Node :: Item ( Item { kind : ItemKind :: Impl { self_ty, .. } , .. } ) ) =
287+ tcx. hir ( ) . get_if_local ( * def_id)
288+ {
289+ for found_did in & v. 0 {
290+ let mut hir_v = HirTraitObjectVisitor ( vec ! [ ] , * found_did) ;
291+ hir_v. visit_ty ( self_ty) ;
292+ if let [ span] = & hir_v. 0 [ ..] {
293+ err. span_suggestion_verbose (
294+ span. shrink_to_hi ( ) ,
295+ "this `impl` introduces an implicit `'static` requirement, \
296+ consider changing it",
297+ " + '_" . to_string ( ) ,
298+ Applicability :: MaybeIncorrect ,
299+ ) ;
300+ suggested = true ;
301+ }
302+ }
303+ }
304+ return suggested;
305+ }
306+ } ;
307+
308+ // Find all the `impl`s in the local scope that can be called on the type parameter. And
309+ // retain all that are `impl`s of the trait that originated the `'static` obligation.
310+ // This doesn't find `impl dyn Trait { /**/ }`, but that case is handled above.
235311 let impl_self_tys = tcx
236312 . all_traits ( LOCAL_CRATE )
237313 . iter ( )
238314 . flat_map ( |trait_did| tcx. hir ( ) . trait_impls ( * trait_did) )
239315 . filter_map ( |impl_node| {
240316 let impl_did = tcx. hir ( ) . local_def_id ( * impl_node) ;
241- if let Some ( Node :: Item ( Item { kind : ItemKind :: Impl { self_ty , .. } , .. } ) ) =
242- tcx . hir ( ) . get_if_local ( impl_did . to_def_id ( ) )
243- {
244- Some ( self_ty )
245- } else {
246- None
317+ match tcx . hir ( ) . get_if_local ( impl_did . to_def_id ( ) ) {
318+ Some ( Node :: Item ( Item {
319+ kind : ItemKind :: Impl { self_ty , of_trait : Some ( of_trait ) , .. } ,
320+ ..
321+ } ) ) if of_trait . trait_def_id ( ) == Some ( * container_id ) => Some ( self_ty ) ,
322+ _ => None ,
247323 }
248324 } ) ;
249- let mut suggested = false ;
325+
326+ // Given all the `impl`s of the relevant `trait`, look for those that are implemented for
327+ // the trait object in the `fn` parameter type.
250328 for self_ty in impl_self_tys {
251- if let TyKind :: TraitObject (
252- poly_trait_refs,
253- Lifetime { name : LifetimeName :: ImplicitObjectLifetimeDefault , .. } ,
254- ) = self_ty. kind
255- {
256- for p in poly_trait_refs {
257- if let PolyTraitRef {
258- trait_ref :
259- TraitRef { path : Path { res : Res :: Def ( DefKind :: Trait , did) , .. } , .. } ,
260- ..
261- } = p
262- {
263- for found_did in & v. 0 {
264- if did == found_did {
265- // We've found an `impl Foo for dyn Bar {}`.
266- // FIXME: we should change this so it also works for
267- // `impl Foo for Box<dyn Bar> {}`.
268- err. span_suggestion_verbose (
269- self_ty. span . shrink_to_hi ( ) ,
270- "this `impl` introduces an implicit `'static` requirement, \
271- consider changing it",
272- " + '_" . to_string ( ) ,
273- Applicability :: MaybeIncorrect ,
274- ) ;
275- suggested = true ;
276- }
277- }
278- }
329+ for found_did in & v. 0 {
330+ let mut hir_v = HirTraitObjectVisitor ( vec ! [ ] , * found_did) ;
331+ hir_v. visit_ty ( self_ty) ;
332+ if let [ span] = & hir_v. 0 [ ..] {
333+ err. span_suggestion_verbose (
334+ span. shrink_to_hi ( ) ,
335+ "this `impl` introduces an implicit `'static` requirement, \
336+ consider changing it",
337+ " + '_" . to_string ( ) ,
338+ Applicability :: MaybeIncorrect ,
339+ ) ;
340+ suggested = true ;
279341 }
280- err. emit ( ) ;
281- return Some ( ErrorReported ) ;
282342 }
283343 }
284344 suggested
@@ -301,3 +361,31 @@ impl TypeVisitor<'_> for TraitObjectVisitor {
301361 }
302362 }
303363}
364+
365+ /// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
366+ struct HirTraitObjectVisitor ( Vec < Span > , DefId ) ;
367+
368+ impl < ' tcx > Visitor < ' tcx > for HirTraitObjectVisitor {
369+ type Map = ErasedMap < ' tcx > ;
370+
371+ fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
372+ NestedVisitorMap :: None
373+ }
374+
375+ fn visit_ty ( & mut self , t : & ' tcx hir:: Ty < ' tcx > ) {
376+ match t. kind {
377+ TyKind :: TraitObject (
378+ poly_trait_refs,
379+ Lifetime { name : LifetimeName :: ImplicitObjectLifetimeDefault , .. } ,
380+ ) => {
381+ for ptr in poly_trait_refs {
382+ if Some ( self . 1 ) == ptr. trait_ref . trait_def_id ( ) {
383+ self . 0 . push ( ptr. span ) ;
384+ }
385+ }
386+ }
387+ _ => { }
388+ }
389+ walk_ty ( self , t) ;
390+ }
391+ }
0 commit comments