33use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
44use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
55use crate :: infer:: { SubregionOrigin , TypeTrace } ;
6- use crate :: traits:: ObligationCauseCode ;
6+ use crate :: traits:: { ObligationCauseCode , UnifyReceiverContext } ;
77use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
8- use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
8+ use rustc_hir:: def_id:: DefId ;
99use 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 :: {
12- self , AssocItem , AssocItemContainer , RegionKind , Ty , TypeFoldable , TypeVisitor ,
10+ use rustc_hir:: {
11+ self as hir , GenericBound , ImplItem , Item , ItemKind , Lifetime , LifetimeName , Node , TraitItem ,
12+ TyKind ,
1313} ;
14+ use rustc_middle:: ty:: { self , AssocItemContainer , RegionKind , Ty , TypeFoldable , TypeVisitor } ;
1415use rustc_span:: { MultiSpan , Span } ;
1516
1617impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
17- /// Print the error message for lifetime errors when the return type is a static impl Trait.
18+ /// Print the error message for lifetime errors when the return type is a static `impl Trait`,
19+ /// `dyn Trait` or if a method call on a trait object introduces a static requirement.
1820 pub ( super ) fn try_report_static_impl_trait ( & self ) -> Option < ErrorReported > {
1921 debug ! ( "try_report_static_impl_trait(error={:?})" , self . error) ;
2022 let tcx = self . tcx ( ) ;
@@ -34,8 +36,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
3436 sub_r,
3537 sup_r,
3638 ) if * * sub_r == RegionKind :: ReStatic => {
37- // This is for the implicit `'static` requirement coming from `impl dyn Trait {}`.
38- if let ObligationCauseCode :: UnifyReceiver ( assoc ) = & cause. code {
39+ // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
40+ if let ObligationCauseCode :: UnifyReceiver ( ctxt ) = & cause. code {
3941 let param = self . find_param_with_region ( sup_r, sub_r) ?;
4042 let lifetime = if sup_r. has_name ( ) {
4143 format ! ( "lifetime `{}`" , sup_r)
@@ -55,23 +57,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
5557 . map( |s| format!( "`{}`" , s) )
5658 . unwrap_or_else( || "`fn` parameter" . to_string( ) ) ,
5759 lifetime,
58- assoc . ident,
60+ ctxt . assoc_item . ident,
5961 ) ;
6062 err. span_label ( param. param_ty_span , & format ! ( "this data with {}..." , lifetime) ) ;
6163 err. span_label (
6264 cause. span ,
6365 & format ! (
6466 "...is captured and required to live as long as `'static` here \
6567 because of an implicit lifetime bound on the {}",
66- match assoc . container {
68+ match ctxt . assoc_item . container {
6769 AssocItemContainer :: TraitContainer ( id) =>
6870 format!( "`impl` of `{}`" , tcx. def_path_str( id) ) ,
6971 AssocItemContainer :: ImplContainer ( _) =>
7072 "inherent `impl`" . to_string( ) ,
7173 } ,
7274 ) ,
7375 ) ;
74- if self . find_impl_on_dyn_trait ( & mut err, param. param_ty , assoc ) {
76+ if self . find_impl_on_dyn_trait ( & mut err, param. param_ty , & ctxt ) {
7577 err. emit ( ) ;
7678 return Some ( ErrorReported ) ;
7779 } else {
@@ -117,25 +119,26 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
117119
118120 let mut postfix = String :: new ( ) ;
119121 if let SubregionOrigin :: Subtype ( box TypeTrace { cause, .. } ) = & sup_origin {
120- if let ObligationCauseCode :: UnifyReceiver ( assoc ) = & cause. code {
121- if self . find_impl_on_dyn_trait ( & mut err, param. param_ty , assoc )
122+ if let ObligationCauseCode :: UnifyReceiver ( ctxt ) = & cause. code {
123+ if self . find_impl_on_dyn_trait ( & mut err, param. param_ty , & ctxt )
122124 && fn_returns. is_empty ( )
123125 {
124126 err. code ( rustc_errors:: error_code!( E0767 ) ) ;
125127 err. set_primary_message ( & format ! (
126128 "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
127129 requirement",
128- param_name, lifetime, assoc . ident,
130+ param_name, lifetime, ctxt . assoc_item . ident,
129131 ) ) ;
130132 postfix = format ! (
131133 " because of an implicit lifetime on the {}" ,
132- match assoc . container {
134+ match ctxt . assoc_item . container {
133135 AssocItemContainer :: TraitContainer ( id) =>
134136 format!( "`impl` of `{}`" , tcx. def_path_str( id) ) ,
135137 AssocItemContainer :: ImplContainer ( _) => "inherent `impl`" . to_string( ) ,
136138 } ,
137139 ) ;
138140 }
141+ // }
139142 }
140143 }
141144
@@ -316,128 +319,104 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
316319 }
317320
318321 /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
319- /// `'static` obligation. Find `impl` blocks that are implemented
322+ /// `'static` obligation. Suggest relaxing that implicit bound.
320323 fn find_impl_on_dyn_trait (
321324 & self ,
322325 err : & mut DiagnosticBuilder < ' _ > ,
323326 ty : Ty < ' _ > ,
324- assoc : & AssocItem ,
327+ ctxt : & UnifyReceiverContext < ' tcx > ,
325328 ) -> bool {
326329 let tcx = self . tcx ( ) ;
327330 let mut suggested = false ;
328331
329- // Find the trait object types in the argument.
330- let mut v = TraitObjectVisitor ( vec ! [ ] ) ;
331- v. visit_ty ( ty) ;
332-
333- let container_id = match assoc. container {
334- // When the obligation comes from an `impl Foo for dyn Bar {}`, we
335- // have the `DefId` of the `trait` itself, not the relevant `impl`
336- // block. Because of this, we have to look at all the `trait`s
337- // available, and filter out all that are not of `Foo` (this `def_id`)
338- // and not of `Bar` (the `filter_map` later in this method).
339- AssocItemContainer :: TraitContainer ( def_id) => def_id,
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+ } ;
340342
341- // When the obligation comes from an `impl dyn Trait {}`, we already
342- // have the `DefId` of the relevant `Item`, so we use it directly.
343- AssocItemContainer :: ImplContainer ( def_id) => {
344- if let Some ( Node :: Item ( Item { kind : ItemKind :: Impl { self_ty, .. } , .. } ) ) =
345- tcx. hir ( ) . get_if_local ( def_id)
346- {
347- for found_did in & v. 0 {
348- let mut hir_v = HirTraitObjectVisitor ( vec ! [ ] , * found_did) ;
349- hir_v. visit_ty ( self_ty) ;
350- if let [ span] = & hir_v. 0 [ ..] {
351- let mut multi_span: MultiSpan = vec ! [ * span] . into ( ) ;
352- multi_span. push_span_label (
353- * span,
354- "this has an implicit `'static` lifetime requirement" . to_string ( ) ,
355- ) ;
356- multi_span. push_span_label (
357- assoc. ident . span ,
358- "`'static` requirement is introduced when calling this method"
359- . to_string ( ) ,
360- ) ;
361- err. span_note (
362- multi_span,
363- & format ! (
364- "`{}`'s inherent `impl` has a `'static` requirement" ,
365- tcx. def_path_str( * found_did) ,
366- ) ,
367- ) ;
368- err. span_suggestion_verbose (
369- span. shrink_to_hi ( ) ,
370- "consider relaxing the implicit `'static` requirement" ,
371- " + '_" . to_string ( ) ,
372- Applicability :: MaybeIncorrect ,
373- ) ;
374- suggested = true ;
375- }
343+ // Get the `Ident` of the method being called and the corresponding `impl` (to point at
344+ // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
345+ let ( ident, self_ty) = match tcx. hir ( ) . get_if_local ( instance. def_id ( ) ) {
346+ Some ( Node :: ImplItem ( ImplItem { ident, hir_id, .. } ) ) => {
347+ match tcx. hir ( ) . find ( tcx. hir ( ) . get_parent_item ( * hir_id) ) {
348+ Some ( Node :: Item ( Item { kind : ItemKind :: Impl { self_ty, .. } , .. } ) ) => {
349+ ( ident, self_ty)
376350 }
351+ _ => return false ,
377352 }
378- return suggested;
379353 }
380- } ;
381-
382- // Find all the `impl`s in the local scope that can be called on the type parameter. And
383- // retain all that are `impl`s of the trait that originated the `'static` obligation.
384- // This doesn't find `impl dyn Trait { /**/ }`, but that case is handled above.
385- let impl_self_tys = tcx
386- . all_traits ( LOCAL_CRATE )
387- . iter ( )
388- . flat_map ( |trait_did| tcx. hir ( ) . trait_impls ( * trait_did) )
389- . filter_map ( |impl_node| {
390- let impl_did = tcx. hir ( ) . local_def_id ( * impl_node) ;
391- match tcx. hir ( ) . get_if_local ( impl_did. to_def_id ( ) ) {
392- Some ( Node :: Item ( Item {
393- kind : ItemKind :: Impl { self_ty, of_trait : Some ( of_trait) , items, .. } ,
394- ..
395- } ) ) if of_trait. trait_def_id ( ) == Some ( container_id) => Some ( (
396- self_ty,
397- // Get the ident of the method, in order to use its `Span`.
398- items
354+ Some ( Node :: TraitItem ( TraitItem { ident, hir_id, .. } ) ) => {
355+ let parent_id = tcx. hir ( ) . get_parent_item ( * hir_id) ;
356+ match tcx. hir ( ) . find ( parent_id) {
357+ Some ( Node :: Item ( Item { kind : ItemKind :: Trait ( ..) , .. } ) ) => {
358+ // The method being called is defined in the `trait`, but the `'static`
359+ // obligation comes from the `impl`. Find that `impl` so that we can point
360+ // at it in the suggestion.
361+ let trait_did = tcx. hir ( ) . local_def_id ( parent_id) . to_def_id ( ) ;
362+ match tcx. hir ( ) . trait_impls ( trait_did)
399363 . iter ( )
400- . filter ( |item| item. ident == assoc. ident )
401- . map ( |item| item. ident )
364+ . filter_map ( |impl_node| {
365+ let impl_did = tcx. hir ( ) . local_def_id ( * impl_node) ;
366+ match tcx. hir ( ) . get_if_local ( impl_did. to_def_id ( ) ) {
367+ Some ( Node :: Item ( Item {
368+ kind : ItemKind :: Impl { self_ty, of_trait : Some ( of_trait) , .. } ,
369+ ..
370+ } ) ) if of_trait. trait_def_id ( ) == Some ( trait_did) => Some ( self_ty) ,
371+ _ => None ,
372+ }
373+ } )
402374 . next ( )
403- . unwrap_or ( assoc. ident ) ,
404- ) ) ,
405- _ => None ,
375+ {
376+ Some ( self_ty) => ( ident, self_ty) ,
377+ _ => return false ,
378+ }
379+ }
380+ _ => return false ,
406381 }
407- } ) ;
382+ }
383+ _ => return false ,
384+ } ;
408385
409- // Given all the `impl`s of the relevant `trait`, look for those that are implemented for
410- // the trait object in the `fn` parameter type.
411- for ( self_ty, method) in impl_self_tys {
412- for found_did in & v. 0 {
413- let mut hir_v = HirTraitObjectVisitor ( vec ! [ ] , * found_did) ;
414- hir_v. visit_ty ( self_ty) ;
415- if let [ span] = & hir_v. 0 [ ..] {
416- let mut multi_span: MultiSpan = vec ! [ * span] . into ( ) ;
417- multi_span. push_span_label (
418- * span,
419- "this has an implicit `'static` lifetime requirement" . to_string ( ) ,
420- ) ;
421- multi_span. push_span_label (
422- method. span ,
423- "`'static` requirement is introduced when calling this method" . to_string ( ) ,
424- ) ;
425- err. span_note (
426- multi_span,
427- & format ! (
428- "`{}`'s `impl` of `{}` has an implicit `'static` requirement" ,
429- tcx. def_path_str( * found_did) ,
430- tcx. def_path_str( container_id) ,
431- ) ,
432- ) ;
433- err. span_suggestion_verbose (
434- span. shrink_to_hi ( ) ,
435- "consider relaxing the implicit `'static` requirement" ,
436- " + '_" . to_string ( ) ,
437- Applicability :: MaybeIncorrect ,
438- ) ;
439- suggested = true ;
440- }
386+ // Find the trait object types in the argument, so we point at *only* the trait object.
387+ let mut v = TraitObjectVisitor ( vec ! [ ] ) ;
388+ v. visit_ty ( ty) ;
389+ for found_did in & v. 0 {
390+ let mut hir_v = HirTraitObjectVisitor ( vec ! [ ] , * found_did) ;
391+ hir_v. visit_ty ( self_ty) ;
392+ for span in & hir_v. 0 {
393+ let mut multi_span: MultiSpan = vec ! [ * span] . into ( ) ;
394+ multi_span. push_span_label (
395+ * span,
396+ "this has an implicit `'static` lifetime requirement" . to_string ( ) ,
397+ ) ;
398+ multi_span. push_span_label (
399+ ident. span ,
400+ "calling this method introduces the `impl`'s 'static` requirement" . to_string ( ) ,
401+ ) ;
402+ err. span_note (
403+ multi_span,
404+ & format ! (
405+ "{} has a `'static` requirement" ,
406+ match ctxt. assoc_item. container {
407+ AssocItemContainer :: TraitContainer ( id) =>
408+ format!( "`impl` of `{}`" , tcx. def_path_str( id) ) ,
409+ AssocItemContainer :: ImplContainer ( _) => "inherent `impl`" . to_string( ) ,
410+ } ,
411+ ) ,
412+ ) ;
413+ err. span_suggestion_verbose (
414+ span. shrink_to_hi ( ) ,
415+ "consider relaxing the implicit `'static` requirement" ,
416+ " + '_" . to_string ( ) ,
417+ Applicability :: MaybeIncorrect ,
418+ ) ;
419+ suggested = true ;
441420 }
442421 }
443422 suggested
0 commit comments