3
3
use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
4
4
use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
5
5
use crate :: infer:: { SubregionOrigin , TypeTrace } ;
6
- use crate :: traits:: ObligationCauseCode ;
6
+ use crate :: traits:: { ObligationCauseCode , UnifyReceiverContext } ;
7
7
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
8
- use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
8
+ use rustc_hir:: def_id:: DefId ;
9
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 :: {
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 ,
13
13
} ;
14
+ use rustc_middle:: ty:: { self , AssocItemContainer , RegionKind , Ty , TypeFoldable , TypeVisitor } ;
14
15
use rustc_span:: { MultiSpan , Span } ;
15
16
16
17
impl < ' 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.
18
20
pub ( super ) fn try_report_static_impl_trait ( & self ) -> Option < ErrorReported > {
19
21
debug ! ( "try_report_static_impl_trait(error={:?})" , self . error) ;
20
22
let tcx = self . tcx ( ) ;
@@ -34,8 +36,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
34
36
sub_r,
35
37
sup_r,
36
38
) 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 {
39
41
let param = self . find_param_with_region ( sup_r, sub_r) ?;
40
42
let lifetime = if sup_r. has_name ( ) {
41
43
format ! ( "lifetime `{}`" , sup_r)
@@ -55,23 +57,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
55
57
. map( |s| format!( "`{}`" , s) )
56
58
. unwrap_or_else( || "`fn` parameter" . to_string( ) ) ,
57
59
lifetime,
58
- assoc . ident,
60
+ ctxt . assoc_item . ident,
59
61
) ;
60
62
err. span_label ( param. param_ty_span , & format ! ( "this data with {}..." , lifetime) ) ;
61
63
err. span_label (
62
64
cause. span ,
63
65
& format ! (
64
66
"...is captured and required to live as long as `'static` here \
65
67
because of an implicit lifetime bound on the {}",
66
- match assoc . container {
68
+ match ctxt . assoc_item . container {
67
69
AssocItemContainer :: TraitContainer ( id) =>
68
70
format!( "`impl` of `{}`" , tcx. def_path_str( id) ) ,
69
71
AssocItemContainer :: ImplContainer ( _) =>
70
72
"inherent `impl`" . to_string( ) ,
71
73
} ,
72
74
) ,
73
75
) ;
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 ) {
75
77
err. emit ( ) ;
76
78
return Some ( ErrorReported ) ;
77
79
} else {
@@ -117,25 +119,26 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
117
119
118
120
let mut postfix = String :: new ( ) ;
119
121
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 )
122
124
&& fn_returns. is_empty ( )
123
125
{
124
126
err. code ( rustc_errors:: error_code!( E0767 ) ) ;
125
127
err. set_primary_message ( & format ! (
126
128
"{} has {} but calling `{}` introduces an implicit `'static` lifetime \
127
129
requirement",
128
- param_name, lifetime, assoc . ident,
130
+ param_name, lifetime, ctxt . assoc_item . ident,
129
131
) ) ;
130
132
postfix = format ! (
131
133
" because of an implicit lifetime on the {}" ,
132
- match assoc . container {
134
+ match ctxt . assoc_item . container {
133
135
AssocItemContainer :: TraitContainer ( id) =>
134
136
format!( "`impl` of `{}`" , tcx. def_path_str( id) ) ,
135
137
AssocItemContainer :: ImplContainer ( _) => "inherent `impl`" . to_string( ) ,
136
138
} ,
137
139
) ;
138
140
}
141
+ // }
139
142
}
140
143
}
141
144
@@ -316,128 +319,104 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
316
319
}
317
320
318
321
/// 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.
320
323
fn find_impl_on_dyn_trait (
321
324
& self ,
322
325
err : & mut DiagnosticBuilder < ' _ > ,
323
326
ty : Ty < ' _ > ,
324
- assoc : & AssocItem ,
327
+ ctxt : & UnifyReceiverContext < ' tcx > ,
325
328
) -> bool {
326
329
let tcx = self . tcx ( ) ;
327
330
let mut suggested = false ;
328
331
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
+ } ;
340
342
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)
376
350
}
351
+ _ => return false ,
377
352
}
378
- return suggested;
379
353
}
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)
399
363
. 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
+ } )
402
374
. 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 ,
406
381
}
407
- } ) ;
382
+ }
383
+ _ => return false ,
384
+ } ;
408
385
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 ;
441
420
}
442
421
}
443
422
suggested
0 commit comments