1
1
//! Error reporting machinery for lifetime errors.
2
2
3
- use rustc_errors:: { Diagnostic , DiagnosticBuilder , ErrorGuaranteed } ;
3
+ use rustc_data_structures:: stable_set:: FxHashSet ;
4
+ use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed , MultiSpan } ;
5
+ use rustc_hir:: def_id:: DefId ;
6
+ use rustc_hir:: intravisit:: Visitor ;
7
+ use rustc_hir:: { self as hir, Item , ItemKind , Node } ;
4
8
use rustc_infer:: infer:: {
5
9
error_reporting:: nice_region_error:: {
6
10
self , find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
7
- NiceRegionError ,
11
+ HirTraitObjectVisitor , NiceRegionError , TraitObjectVisitor ,
8
12
} ,
9
13
error_reporting:: unexpected_hidden_region_diagnostic,
10
14
NllRegionVariableOrigin , RelateParamBound ,
11
15
} ;
12
16
use rustc_middle:: hir:: place:: PlaceBase ;
13
17
use rustc_middle:: mir:: { ConstraintCategory , ReturnConstraint } ;
14
18
use rustc_middle:: ty:: subst:: InternalSubsts ;
19
+ use rustc_middle:: ty:: Region ;
20
+ use rustc_middle:: ty:: TypeVisitor ;
15
21
use rustc_middle:: ty:: { self , RegionVid , Ty } ;
16
22
use rustc_span:: symbol:: sym;
23
+ use rustc_span:: symbol:: Ident ;
17
24
use rustc_span:: Span ;
18
25
19
26
use crate :: borrowck_errors;
@@ -27,7 +34,7 @@ use crate::{
27
34
MirBorrowckCtxt ,
28
35
} ;
29
36
30
- impl ConstraintDescription for ConstraintCategory {
37
+ impl < ' tcx > ConstraintDescription for ConstraintCategory < ' tcx > {
31
38
fn description ( & self ) -> & ' static str {
32
39
// Must end with a space. Allows for empty names to be provided.
33
40
match self {
@@ -37,7 +44,7 @@ impl ConstraintDescription for ConstraintCategory {
37
44
ConstraintCategory :: UseAsConst => "using this value as a constant " ,
38
45
ConstraintCategory :: UseAsStatic => "using this value as a static " ,
39
46
ConstraintCategory :: Cast => "cast " ,
40
- ConstraintCategory :: CallArgument => "argument " ,
47
+ ConstraintCategory :: CallArgument ( _ ) => "argument " ,
41
48
ConstraintCategory :: TypeAnnotation => "type annotation " ,
42
49
ConstraintCategory :: ClosureBounds => "closure body " ,
43
50
ConstraintCategory :: SizedBound => "proving this value is `Sized` " ,
@@ -101,15 +108,15 @@ pub(crate) enum RegionErrorKind<'tcx> {
101
108
102
109
/// Information about the various region constraints involved in a borrow checker error.
103
110
#[ derive( Clone , Debug ) ]
104
- pub struct ErrorConstraintInfo {
111
+ pub struct ErrorConstraintInfo < ' tcx > {
105
112
// fr: outlived_fr
106
113
pub ( super ) fr : RegionVid ,
107
114
pub ( super ) fr_is_local : bool ,
108
115
pub ( super ) outlived_fr : RegionVid ,
109
116
pub ( super ) outlived_fr_is_local : bool ,
110
117
111
118
// Category and span for best blame constraint
112
- pub ( super ) category : ConstraintCategory ,
119
+ pub ( super ) category : ConstraintCategory < ' tcx > ,
113
120
pub ( super ) span : Span ,
114
121
}
115
122
@@ -256,6 +263,70 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
256
263
outlives_suggestion. add_suggestion ( self ) ;
257
264
}
258
265
266
+ fn get_impl_ident_and_self_ty_from_trait (
267
+ & self ,
268
+ def_id : DefId ,
269
+ trait_objects : & FxHashSet < DefId > ,
270
+ ) -> Option < ( Ident , & ' tcx hir:: Ty < ' tcx > ) > {
271
+ let tcx = self . infcx . tcx ;
272
+ match tcx. hir ( ) . get_if_local ( def_id) {
273
+ Some ( Node :: ImplItem ( impl_item) ) => {
274
+ match tcx. hir ( ) . find_by_def_id ( tcx. hir ( ) . get_parent_item ( impl_item. hir_id ( ) ) ) {
275
+ Some ( Node :: Item ( Item {
276
+ kind : ItemKind :: Impl ( hir:: Impl { self_ty, .. } ) ,
277
+ ..
278
+ } ) ) => Some ( ( impl_item. ident , self_ty) ) ,
279
+ _ => None ,
280
+ }
281
+ }
282
+ Some ( Node :: TraitItem ( trait_item) ) => {
283
+ let trait_did = tcx. hir ( ) . get_parent_item ( trait_item. hir_id ( ) ) ;
284
+ match tcx. hir ( ) . find_by_def_id ( trait_did) {
285
+ Some ( Node :: Item ( Item { kind : ItemKind :: Trait ( ..) , .. } ) ) => {
286
+ // The method being called is defined in the `trait`, but the `'static`
287
+ // obligation comes from the `impl`. Find that `impl` so that we can point
288
+ // at it in the suggestion.
289
+ let trait_did = trait_did. to_def_id ( ) ;
290
+ match tcx
291
+ . hir ( )
292
+ . trait_impls ( trait_did)
293
+ . iter ( )
294
+ . filter_map ( |& impl_did| {
295
+ match tcx. hir ( ) . get_if_local ( impl_did. to_def_id ( ) ) {
296
+ Some ( Node :: Item ( Item {
297
+ kind : ItemKind :: Impl ( hir:: Impl { self_ty, .. } ) ,
298
+ ..
299
+ } ) ) if trait_objects. iter ( ) . all ( |did| {
300
+ // FIXME: we should check `self_ty` against the receiver
301
+ // type in the `UnifyReceiver` context, but for now, use
302
+ // this imperfect proxy. This will fail if there are
303
+ // multiple `impl`s for the same trait like
304
+ // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
305
+ // In that case, only the first one will get suggestions.
306
+ let mut traits = vec ! [ ] ;
307
+ let mut hir_v = HirTraitObjectVisitor ( & mut traits, * did) ;
308
+ hir_v. visit_ty ( self_ty) ;
309
+ !traits. is_empty ( )
310
+ } ) =>
311
+ {
312
+ Some ( self_ty)
313
+ }
314
+ _ => None ,
315
+ }
316
+ } )
317
+ . next ( )
318
+ {
319
+ Some ( self_ty) => Some ( ( trait_item. ident , self_ty) ) ,
320
+ _ => None ,
321
+ }
322
+ }
323
+ _ => None ,
324
+ }
325
+ }
326
+ _ => None ,
327
+ }
328
+ }
329
+
259
330
/// Report an error because the universal region `fr` was required to outlive
260
331
/// `outlived_fr` but it is not known to do so. For example:
261
332
///
@@ -279,6 +350,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
279
350
} ) ;
280
351
281
352
debug ! ( "report_region_error: category={:?} {:?} {:?}" , category, cause, variance_info) ;
353
+
282
354
// Check if we can use one of the "nice region errors".
283
355
if let ( Some ( f) , Some ( o) ) = ( self . to_error_region ( fr) , self . to_error_region ( outlived_fr) ) {
284
356
let nice = NiceRegionError :: new_from_span ( self . infcx , cause. span , o, f) ;
@@ -312,7 +384,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
312
384
self . report_fnmut_error ( & errci, kind)
313
385
}
314
386
( ConstraintCategory :: Assignment , true , false )
315
- | ( ConstraintCategory :: CallArgument , true , false ) => {
387
+ | ( ConstraintCategory :: CallArgument ( _ ) , true , false ) => {
316
388
let mut db = self . report_escaping_data_error ( & errci) ;
317
389
318
390
outlives_suggestion. intermediate_suggestion ( self , & errci, & mut db) ;
@@ -405,7 +477,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
405
477
/// ```
406
478
fn report_fnmut_error (
407
479
& self ,
408
- errci : & ErrorConstraintInfo ,
480
+ errci : & ErrorConstraintInfo < ' tcx > ,
409
481
kind : ReturnConstraint ,
410
482
) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > {
411
483
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
@@ -486,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
486
558
/// ```
487
559
fn report_escaping_data_error (
488
560
& self ,
489
- errci : & ErrorConstraintInfo ,
561
+ errci : & ErrorConstraintInfo < ' tcx > ,
490
562
) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > {
491
563
let ErrorConstraintInfo { span, category, .. } = errci;
492
564
@@ -548,24 +620,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
548
620
// Only show an extra note if we can find an 'error region' for both of the region
549
621
// variables. This avoids showing a noisy note that just mentions 'synthetic' regions
550
622
// that don't help the user understand the error.
551
- if self . to_error_region ( errci. fr ) . is_some ( )
552
- && self . to_error_region ( errci. outlived_fr ) . is_some ( )
553
- {
554
- let fr_region_name = self . give_region_a_name ( errci. fr ) . unwrap ( ) ;
555
- fr_region_name. highlight_region_name ( & mut diag) ;
556
- let outlived_fr_region_name = self . give_region_a_name ( errci. outlived_fr ) . unwrap ( ) ;
557
- outlived_fr_region_name. highlight_region_name ( & mut diag) ;
623
+ match ( self . to_error_region ( errci. fr ) , self . to_error_region ( errci. outlived_fr ) ) {
624
+ ( Some ( f) , Some ( o) ) => {
625
+ self . maybe_suggest_constrain_dyn_trait_impl ( & mut diag, f, o, category) ;
558
626
559
- diag. span_label (
560
- * span,
561
- format ! (
562
- "{}requires that `{}` must outlive `{}`" ,
563
- category. description( ) ,
564
- fr_region_name,
565
- outlived_fr_region_name,
566
- ) ,
567
- ) ;
627
+ let fr_region_name = self . give_region_a_name ( errci. fr ) . unwrap ( ) ;
628
+ fr_region_name. highlight_region_name ( & mut diag) ;
629
+ let outlived_fr_region_name = self . give_region_a_name ( errci. outlived_fr ) . unwrap ( ) ;
630
+ outlived_fr_region_name. highlight_region_name ( & mut diag) ;
631
+
632
+ diag. span_label (
633
+ * span,
634
+ format ! (
635
+ "{}requires that `{}` must outlive `{}`" ,
636
+ category. description( ) ,
637
+ fr_region_name,
638
+ outlived_fr_region_name,
639
+ ) ,
640
+ ) ;
641
+ }
642
+ _ => { }
568
643
}
644
+
569
645
diag
570
646
}
571
647
@@ -586,7 +662,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
586
662
/// ```
587
663
fn report_general_error (
588
664
& self ,
589
- errci : & ErrorConstraintInfo ,
665
+ errci : & ErrorConstraintInfo < ' tcx > ,
590
666
) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > {
591
667
let ErrorConstraintInfo {
592
668
fr,
@@ -699,6 +775,99 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
699
775
}
700
776
}
701
777
778
+ fn maybe_suggest_constrain_dyn_trait_impl (
779
+ & self ,
780
+ diag : & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ,
781
+ f : Region < ' tcx > ,
782
+ o : Region < ' tcx > ,
783
+ category : & ConstraintCategory < ' tcx > ,
784
+ ) {
785
+ if !o. is_static ( ) {
786
+ return ;
787
+ }
788
+
789
+ let tcx = self . infcx . tcx ;
790
+
791
+ let instance = if let ConstraintCategory :: CallArgument ( Some ( ( fn_did, substs) ) ) = category {
792
+ debug ! ( ?fn_did, ?substs) ;
793
+
794
+ // Only suggest this on function calls, not closures
795
+ let ty = tcx. type_of ( fn_did) ;
796
+ debug ! ( "ty: {:?}, ty.kind: {:?}" , ty, ty. kind( ) ) ;
797
+ if let ty:: Closure ( _, _) = ty. kind ( ) {
798
+ return ;
799
+ }
800
+
801
+ if let Ok ( Some ( instance) ) = ty:: Instance :: resolve (
802
+ tcx,
803
+ self . param_env ,
804
+ * fn_did,
805
+ self . infcx . resolve_vars_if_possible ( substs) ,
806
+ ) {
807
+ instance
808
+ } else {
809
+ return ;
810
+ }
811
+ } else {
812
+ return ;
813
+ } ;
814
+
815
+ let param = match find_param_with_region ( tcx, f, o) {
816
+ Some ( param) => param,
817
+ None => return ,
818
+ } ;
819
+ debug ! ( ?param) ;
820
+
821
+ let mut visitor = TraitObjectVisitor ( FxHashSet :: default ( ) ) ;
822
+ visitor. visit_ty ( param. param_ty ) ;
823
+
824
+ if let Some ( ( ident, self_ty) ) =
825
+ self . get_impl_ident_and_self_ty_from_trait ( instance. def_id ( ) , & visitor. 0 )
826
+ {
827
+ self . suggest_constrain_dyn_trait_in_impl ( diag, & visitor. 0 , ident, self_ty)
828
+ } else {
829
+ return ;
830
+ } ;
831
+ }
832
+
833
+ #[ instrument( skip( self , err) , level = "debug" ) ]
834
+ fn suggest_constrain_dyn_trait_in_impl (
835
+ & self ,
836
+ err : & mut Diagnostic ,
837
+ found_dids : & FxHashSet < DefId > ,
838
+ ident : Ident ,
839
+ self_ty : & hir:: Ty < ' _ > ,
840
+ ) -> bool {
841
+ debug ! ( "err: {:#?}" , err) ;
842
+ let mut suggested = false ;
843
+ for found_did in found_dids {
844
+ let mut traits = vec ! [ ] ;
845
+ let mut hir_v = HirTraitObjectVisitor ( & mut traits, * found_did) ;
846
+ hir_v. visit_ty ( & self_ty) ;
847
+ debug ! ( "trait spans found: {:?}" , traits) ;
848
+ for span in & traits {
849
+ let mut multi_span: MultiSpan = vec ! [ * span] . into ( ) ;
850
+ multi_span. push_span_label (
851
+ * span,
852
+ "this has an implicit `'static` lifetime requirement" . to_string ( ) ,
853
+ ) ;
854
+ multi_span. push_span_label (
855
+ ident. span ,
856
+ "calling this method introduces the `impl`'s 'static` requirement" . to_string ( ) ,
857
+ ) ;
858
+ err. span_note ( multi_span, "the used `impl` has a `'static` requirement" ) ;
859
+ err. span_suggestion_verbose (
860
+ span. shrink_to_hi ( ) ,
861
+ "consider relaxing the implicit `'static` requirement" ,
862
+ " + '_" . to_string ( ) ,
863
+ Applicability :: MaybeIncorrect ,
864
+ ) ;
865
+ suggested = true ;
866
+ }
867
+ }
868
+ suggested
869
+ }
870
+
702
871
fn suggest_adding_lifetime_params (
703
872
& self ,
704
873
diag : & mut Diagnostic ,
0 commit comments