2
2
3
3
use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
4
4
use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
5
+ use crate :: infer:: { SubregionOrigin , TypeTrace } ;
6
+ use crate :: traits:: ObligationCauseCode ;
5
7
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
6
- use rustc_hir:: def:: { DefKind , Res } ;
7
8
use 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 ;
13
13
14
14
impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
15
15
/// 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> {
27
27
) if * * sub_r == RegionKind :: ReStatic => {
28
28
( var_origin, sub_origin, sub_r, sup_origin, sup_r)
29
29
}
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
+ }
30
63
_ => return None ,
31
64
} ;
32
65
debug ! (
@@ -96,7 +129,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
96
129
) ;
97
130
}
98
131
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
+ }
100
137
101
138
let fn_returns = tcx. return_type_impl_or_dyn_traits ( anon_reg_sup. def_id ) ;
102
139
debug ! ( "try_report_static_impl_trait: fn_return={:?}" , fn_returns) ;
@@ -222,63 +259,86 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
222
259
223
260
/// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
224
261
/// `'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 {
226
268
let tcx = self . tcx ( ) ;
269
+ let mut suggested = false ;
227
270
228
271
// Find the trait object types in the argument.
229
272
let mut v = TraitObjectVisitor ( vec ! [ ] ) ;
230
273
v. visit_ty ( ty) ;
231
- debug ! ( "TraitObjectVisitor {:?}" , v. 0 ) ;
232
274
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.
235
311
let impl_self_tys = tcx
236
312
. all_traits ( LOCAL_CRATE )
237
313
. iter ( )
238
314
. flat_map ( |trait_did| tcx. hir ( ) . trait_impls ( * trait_did) )
239
315
. filter_map ( |impl_node| {
240
316
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 ,
247
323
}
248
324
} ) ;
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.
250
328
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 ;
279
341
}
280
- err. emit ( ) ;
281
- return Some ( ErrorReported ) ;
282
342
}
283
343
}
284
344
suggested
@@ -301,3 +361,31 @@ impl TypeVisitor<'_> for TraitObjectVisitor {
301
361
}
302
362
}
303
363
}
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