@@ -12,6 +12,7 @@ use rustc_hir::{
12
12
TyKind ,
13
13
} ;
14
14
use rustc_middle:: ty:: { self , AssocItemContainer , RegionKind , Ty , TypeFoldable , TypeVisitor } ;
15
+ use rustc_span:: symbol:: Ident ;
15
16
use rustc_span:: { MultiSpan , Span } ;
16
17
17
18
impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
@@ -115,33 +116,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
115
116
err. span_label ( param. param_ty_span , & format ! ( "this data with {}..." , lifetime) ) ;
116
117
debug ! ( "try_report_static_impl_trait: param_info={:?}" , param) ;
117
118
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
-
145
119
// We try to make the output have fewer overlapping spans if possible.
146
120
if ( sp == sup_origin. span ( ) || !return_sp. overlaps ( sup_origin. span ( ) ) )
147
121
&& sup_origin. span ( ) != return_sp
@@ -168,35 +142,68 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
168
142
// | ---- ^
169
143
err. span_label (
170
144
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`" ,
175
146
) ;
176
147
} else {
177
148
err. span_label ( sup_origin. span ( ) , "...is captured here..." ) ;
178
149
if return_sp < sup_origin. span ( ) {
179
150
err. span_note (
180
151
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" ,
182
153
) ;
183
154
} else {
184
155
err. span_label (
185
156
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" ,
187
158
) ;
188
159
}
189
160
}
190
161
} else {
191
162
err. span_label (
192
163
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" ,
197
165
) ;
198
166
}
199
167
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
+
200
207
debug ! ( "try_report_static_impl_trait: fn_return={:?}" , fn_returns) ;
201
208
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
202
209
let consider = "consider changing the" ;
@@ -318,40 +325,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
318
325
Some ( ErrorReported )
319
326
}
320
327
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 (
324
329
& 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 > ) > {
329
333
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) {
349
335
Some ( Node :: ImplItem ( ImplItem { ident, hir_id, .. } ) ) => {
350
336
match tcx. hir ( ) . find ( tcx. hir ( ) . get_parent_item ( * hir_id) ) {
351
337
Some ( Node :: Item ( Item { kind : ItemKind :: Impl { self_ty, .. } , .. } ) ) => {
352
- ( ident, self_ty)
338
+ Some ( ( * ident, self_ty) )
353
339
}
354
- _ => return false ,
340
+ _ => None ,
355
341
}
356
342
}
357
343
Some ( Node :: TraitItem ( TraitItem { ident, hir_id, .. } ) ) => {
@@ -372,7 +358,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
372
358
Some ( Node :: Item ( Item {
373
359
kind : ItemKind :: Impl { self_ty, .. } ,
374
360
..
375
- } ) ) if v . 0 . iter ( ) . all ( |did| {
361
+ } ) ) if trait_objects . iter ( ) . all ( |did| {
376
362
// FIXME: we should check `self_ty` against the receiver
377
363
// type in the `UnifyReceiver` context, but for now, use
378
364
// this imperfect proxy. This will fail if there are
@@ -391,20 +377,64 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
391
377
} )
392
378
. next ( )
393
379
{
394
- Some ( self_ty) => ( ident, self_ty) ,
395
- _ => return false ,
380
+ Some ( self_ty) => Some ( ( * ident, self_ty) ) ,
381
+ _ => None ,
396
382
}
397
383
}
398
- _ => return false ,
384
+ _ => None ,
399
385
}
400
386
}
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,
401
409
_ => return false ,
402
410
} ;
403
411
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
+
404
423
// 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 {
406
436
let mut hir_v = HirTraitObjectVisitor ( vec ! [ ] , * found_did) ;
407
- hir_v. visit_ty ( self_ty) ;
437
+ hir_v. visit_ty ( & self_ty) ;
408
438
for span in & hir_v. 0 {
409
439
let mut multi_span: MultiSpan = vec ! [ * span] . into ( ) ;
410
440
multi_span. push_span_label (
@@ -415,17 +445,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
415
445
ident. span ,
416
446
"calling this method introduces the `impl`'s 'static` requirement" . to_string ( ) ,
417
447
) ;
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" ) ;
429
449
err. span_suggestion_verbose (
430
450
span. shrink_to_hi ( ) ,
431
451
"consider relaxing the implicit `'static` requirement" ,
0 commit comments