@@ -12,6 +12,7 @@ use rustc_hir::{
1212 TyKind ,
1313} ;
1414use rustc_middle:: ty:: { self , AssocItemContainer , RegionKind , Ty , TypeFoldable , TypeVisitor } ;
15+ use rustc_span:: symbol:: Ident ;
1516use rustc_span:: { MultiSpan , Span } ;
1617
1718impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
@@ -115,33 +116,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
115116 err. span_label ( param. param_ty_span , & format ! ( "this data with {}..." , lifetime) ) ;
116117 debug ! ( "try_report_static_impl_trait: param_info={:?}" , param) ;
117118
118- let fn_returns = tcx. return_type_impl_or_dyn_traits ( anon_reg_sup. def_id ) ;
119-
120- let mut postfix = String :: new ( ) ;
121- if let SubregionOrigin :: Subtype ( box TypeTrace { cause, .. } ) = & sup_origin {
122- if let ObligationCauseCode :: UnifyReceiver ( ctxt) = & cause. code {
123- if self . find_impl_on_dyn_trait ( & mut err, param. param_ty , & ctxt)
124- && fn_returns. is_empty ( )
125- {
126- err. code ( rustc_errors:: error_code!( E0767 ) ) ;
127- err. set_primary_message ( & format ! (
128- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
129- requirement",
130- param_name, lifetime, ctxt. assoc_item. ident,
131- ) ) ;
132- postfix = format ! (
133- " because of an implicit lifetime on the {}" ,
134- match ctxt. assoc_item. container {
135- AssocItemContainer :: TraitContainer ( id) =>
136- format!( "`impl` of `{}`" , tcx. def_path_str( id) ) ,
137- AssocItemContainer :: ImplContainer ( _) => "inherent `impl`" . to_string( ) ,
138- } ,
139- ) ;
140- }
141- // }
142- }
143- }
144-
145119 // We try to make the output have fewer overlapping spans if possible.
146120 if ( sp == sup_origin. span ( ) || !return_sp. overlaps ( sup_origin. span ( ) ) )
147121 && sup_origin. span ( ) != return_sp
@@ -168,35 +142,68 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
168142 // | ---- ^
169143 err. span_label (
170144 sup_origin. span ( ) ,
171- & format ! (
172- "...is captured here, requiring it to live as long as `'static`{}" ,
173- postfix
174- ) ,
145+ "...is captured here, requiring it to live as long as `'static`" ,
175146 ) ;
176147 } else {
177148 err. span_label ( sup_origin. span ( ) , "...is captured here..." ) ;
178149 if return_sp < sup_origin. span ( ) {
179150 err. span_note (
180151 return_sp,
181- & format ! ( "...and is required to live as long as `'static` here{}" , postfix ) ,
152+ "...and is required to live as long as `'static` here" ,
182153 ) ;
183154 } else {
184155 err. span_label (
185156 return_sp,
186- & format ! ( "...and is required to live as long as `'static` here{}" , postfix ) ,
157+ "...and is required to live as long as `'static` here" ,
187158 ) ;
188159 }
189160 }
190161 } else {
191162 err. span_label (
192163 return_sp,
193- & format ! (
194- "...is captured and required to live as long as `'static` here{}" ,
195- postfix
196- ) ,
164+ "...is captured and required to live as long as `'static` here" ,
197165 ) ;
198166 }
199167
168+ let fn_returns = tcx. return_type_impl_or_dyn_traits ( anon_reg_sup. def_id ) ;
169+
170+ let mut override_error_code = None ;
171+ if let SubregionOrigin :: Subtype ( box TypeTrace { cause, .. } ) = & sup_origin {
172+ if let ObligationCauseCode :: UnifyReceiver ( ctxt) = & cause. code {
173+ // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
174+ // `'static` lifetime when called as a method on a binding: `bar.qux()`.
175+ if self . find_impl_on_dyn_trait ( & mut err, param. param_ty , & ctxt) {
176+ override_error_code = Some ( ctxt. assoc_item . ident ) ;
177+ }
178+ }
179+ }
180+ if let SubregionOrigin :: Subtype ( box TypeTrace { cause, .. } ) = & sub_origin {
181+ if let ObligationCauseCode :: ItemObligation ( item_def_id) = cause. code {
182+ // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
183+ // lifetime as above, but called using a fully-qualified path to the method:
184+ // `Foo::qux(bar)`.
185+ let mut v = TraitObjectVisitor ( vec ! [ ] ) ;
186+ v. visit_ty ( param. param_ty ) ;
187+ if let Some ( ( ident, self_ty) ) =
188+ self . get_impl_ident_and_self_ty_from_trait ( item_def_id, & v. 0 [ ..] )
189+ {
190+ if self . suggest_constrain_dyn_trait_in_impl ( & mut err, & v. 0 [ ..] , ident, self_ty)
191+ {
192+ override_error_code = Some ( ident) ;
193+ }
194+ }
195+ }
196+ }
197+ if let ( Some ( ident) , true ) = ( override_error_code, fn_returns. is_empty ( ) ) {
198+ // Provide a more targetted error code and description.
199+ err. code ( rustc_errors:: error_code!( E0767 ) ) ;
200+ err. set_primary_message ( & format ! (
201+ "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
202+ requirement",
203+ param_name, lifetime, ident,
204+ ) ) ;
205+ }
206+
200207 debug ! ( "try_report_static_impl_trait: fn_return={:?}" , fn_returns) ;
201208 // FIXME: account for the need of parens in `&(dyn Trait + '_)`
202209 let consider = "consider changing the" ;
@@ -318,40 +325,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
318325 Some ( ErrorReported )
319326 }
320327
321- /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
322- /// `'static` obligation. Suggest relaxing that implicit bound.
323- fn find_impl_on_dyn_trait (
328+ fn get_impl_ident_and_self_ty_from_trait (
324329 & self ,
325- err : & mut DiagnosticBuilder < ' _ > ,
326- ty : Ty < ' _ > ,
327- ctxt : & UnifyReceiverContext < ' tcx > ,
328- ) -> bool {
330+ def_id : DefId ,
331+ trait_objects : & [ DefId ] ,
332+ ) -> Option < ( Ident , & ' tcx hir:: Ty < ' tcx > ) > {
329333 let tcx = self . tcx ( ) ;
330- let mut suggested = false ;
331-
332- // Find the method being called.
333- let instance = match ty:: Instance :: resolve (
334- tcx,
335- ctxt. param_env ,
336- ctxt. assoc_item . def_id ,
337- self . infcx . resolve_vars_if_possible ( & ctxt. substs ) ,
338- ) {
339- Ok ( Some ( instance) ) => instance,
340- _ => return false ,
341- } ;
342-
343- let mut v = TraitObjectVisitor ( vec ! [ ] ) ;
344- v. visit_ty ( ty) ;
345-
346- // Get the `Ident` of the method being called and the corresponding `impl` (to point at
347- // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
348- let ( ident, self_ty) = match tcx. hir ( ) . get_if_local ( instance. def_id ( ) ) {
334+ match tcx. hir ( ) . get_if_local ( def_id) {
349335 Some ( Node :: ImplItem ( ImplItem { ident, hir_id, .. } ) ) => {
350336 match tcx. hir ( ) . find ( tcx. hir ( ) . get_parent_item ( * hir_id) ) {
351337 Some ( Node :: Item ( Item { kind : ItemKind :: Impl { self_ty, .. } , .. } ) ) => {
352- ( ident, self_ty)
338+ Some ( ( * ident, self_ty) )
353339 }
354- _ => return false ,
340+ _ => None ,
355341 }
356342 }
357343 Some ( Node :: TraitItem ( TraitItem { ident, hir_id, .. } ) ) => {
@@ -372,7 +358,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
372358 Some ( Node :: Item ( Item {
373359 kind : ItemKind :: Impl { self_ty, .. } ,
374360 ..
375- } ) ) if v . 0 . iter ( ) . all ( |did| {
361+ } ) ) if trait_objects . iter ( ) . all ( |did| {
376362 // FIXME: we should check `self_ty` against the receiver
377363 // type in the `UnifyReceiver` context, but for now, use
378364 // this imperfect proxy. This will fail if there are
@@ -391,20 +377,64 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
391377 } )
392378 . next ( )
393379 {
394- Some ( self_ty) => ( ident, self_ty) ,
395- _ => return false ,
380+ Some ( self_ty) => Some ( ( * ident, self_ty) ) ,
381+ _ => None ,
396382 }
397383 }
398- _ => return false ,
384+ _ => None ,
399385 }
400386 }
387+ _ => None ,
388+ }
389+ }
390+
391+ /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
392+ /// `'static` obligation. Suggest relaxing that implicit bound.
393+ fn find_impl_on_dyn_trait (
394+ & self ,
395+ err : & mut DiagnosticBuilder < ' _ > ,
396+ ty : Ty < ' _ > ,
397+ ctxt : & UnifyReceiverContext < ' tcx > ,
398+ ) -> bool {
399+ let tcx = self . tcx ( ) ;
400+
401+ // Find the method being called.
402+ let instance = match ty:: Instance :: resolve (
403+ tcx,
404+ ctxt. param_env ,
405+ ctxt. assoc_item . def_id ,
406+ self . infcx . resolve_vars_if_possible ( & ctxt. substs ) ,
407+ ) {
408+ Ok ( Some ( instance) ) => instance,
401409 _ => return false ,
402410 } ;
403411
412+ let mut v = TraitObjectVisitor ( vec ! [ ] ) ;
413+ v. visit_ty ( ty) ;
414+
415+ // Get the `Ident` of the method being called and the corresponding `impl` (to point at
416+ // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
417+ let ( ident, self_ty) =
418+ match self . get_impl_ident_and_self_ty_from_trait ( instance. def_id ( ) , & v. 0 [ ..] ) {
419+ Some ( ( ident, self_ty) ) => ( ident, self_ty) ,
420+ None => return false ,
421+ } ;
422+
404423 // Find the trait object types in the argument, so we point at *only* the trait object.
405- for found_did in & v. 0 {
424+ self . suggest_constrain_dyn_trait_in_impl ( err, & v. 0 [ ..] , ident, self_ty)
425+ }
426+
427+ fn suggest_constrain_dyn_trait_in_impl (
428+ & self ,
429+ err : & mut DiagnosticBuilder < ' _ > ,
430+ found_dids : & [ DefId ] ,
431+ ident : Ident ,
432+ self_ty : & hir:: Ty < ' _ > ,
433+ ) -> bool {
434+ let mut suggested = false ;
435+ for found_did in found_dids {
406436 let mut hir_v = HirTraitObjectVisitor ( vec ! [ ] , * found_did) ;
407- hir_v. visit_ty ( self_ty) ;
437+ hir_v. visit_ty ( & self_ty) ;
408438 for span in & hir_v. 0 {
409439 let mut multi_span: MultiSpan = vec ! [ * span] . into ( ) ;
410440 multi_span. push_span_label (
@@ -415,17 +445,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
415445 ident. span ,
416446 "calling this method introduces the `impl`'s 'static` requirement" . to_string ( ) ,
417447 ) ;
418- err. span_note (
419- multi_span,
420- & format ! (
421- "{} has a `'static` requirement" ,
422- match ctxt. assoc_item. container {
423- AssocItemContainer :: TraitContainer ( id) =>
424- format!( "`impl` of `{}`" , tcx. def_path_str( id) ) ,
425- AssocItemContainer :: ImplContainer ( _) => "inherent `impl`" . to_string( ) ,
426- } ,
427- ) ,
428- ) ;
448+ err. span_note ( multi_span, "the used `impl` has a `'static` requirement" ) ;
429449 err. span_suggestion_verbose (
430450 span. shrink_to_hi ( ) ,
431451 "consider relaxing the implicit `'static` requirement" ,
0 commit comments