2
2
3
3
use rustc_data_structures:: fx:: FxHashSet ;
4
4
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed , MultiSpan } ;
5
+ use rustc_hir:: def:: DefKind ;
5
6
use rustc_hir:: def_id:: DefId ;
6
7
use rustc_hir:: intravisit:: Visitor ;
7
8
use rustc_hir:: { self as hir, Item , ItemKind , Node } ;
@@ -18,7 +19,7 @@ use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
18
19
use rustc_middle:: ty:: subst:: InternalSubsts ;
19
20
use rustc_middle:: ty:: Region ;
20
21
use rustc_middle:: ty:: TypeVisitor ;
21
- use rustc_middle:: ty:: { self , RegionVid , Ty } ;
22
+ use rustc_middle:: ty:: { self , DefIdTree , RegionVid , Ty , TyCtxt } ;
22
23
use rustc_span:: symbol:: { kw, sym, Ident } ;
23
24
use rustc_span:: Span ;
24
25
@@ -715,12 +716,53 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
715
716
}
716
717
}
717
718
719
+ if let ConstraintCategory :: TypeAnnotation = category {
720
+ self . handle_annotation_error ( errci, & mut diag) ;
721
+ }
718
722
self . add_static_impl_trait_suggestion ( & mut diag, * fr, fr_name, * outlived_fr) ;
719
723
self . suggest_adding_lifetime_params ( & mut diag, * fr, * outlived_fr) ;
720
724
721
725
diag
722
726
}
723
727
728
+ /// Adds a secondary label to lifetime annotation errors:
729
+ /// ```
730
+ /// fn test<'a, 'b>(s: &'a str) {
731
+ /// let closure = |_: &'b str| {}; // Primary label: type annotation requires 'a: 'b.
732
+ /// closure(s); // Secondary label: because of this call.
733
+ /// }
734
+ /// ```
735
+ ///
736
+ /// Also Suggests replacing `Self`. See `suggest_relax_self`.
737
+ fn handle_annotation_error ( & self , errci : & ErrorConstraintInfo < ' tcx > , err : & mut Diagnostic ) {
738
+ let ErrorConstraintInfo { fr, outlived_fr, span, category : _, .. } = errci. clone ( ) ;
739
+
740
+ // Try to report the second most relevant constraint to provide more context.
741
+ let constraint2 = self . regioncx . best_blame_constraint_filtered (
742
+ & self . body ,
743
+ fr,
744
+ NllRegionVariableOrigin :: FreeRegion ,
745
+ |r| self . regioncx . provides_universal_region ( r, fr, outlived_fr) ,
746
+ |constraint| match constraint. category {
747
+ ConstraintCategory :: TypeAnnotation => false ,
748
+ _ => true ,
749
+ } ,
750
+ ) ;
751
+ debug ! ( "suggest_relax_annotation: constraint2={:?}" , constraint2) ;
752
+ let map = self . infcx . tcx . sess . source_map ( ) ;
753
+ let same_line = map
754
+ . lookup_line ( constraint2. cause . span . hi ( ) )
755
+ . and_then ( |line1| map. lookup_line ( span. hi ( ) ) . map ( |line2| line1. line == line2. line ) )
756
+ . unwrap_or ( false ) ;
757
+ let desc = constraint2. category . description ( ) ;
758
+ if !desc. is_empty ( ) && !same_line {
759
+ err. span_label ( constraint2. cause . span , format ! ( "because of {desc}here" ) ) ;
760
+ }
761
+
762
+ let body_did = self . body . source . def_id ( ) ;
763
+ suggest_relax_self ( self . infcx . tcx , err, body_did, span) ;
764
+ }
765
+
724
766
/// Adds a suggestion to errors where an `impl Trait` is returned.
725
767
///
726
768
/// ```text
@@ -903,3 +945,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
903
945
suggest_adding_lifetime_params ( self . infcx . tcx , sub, ty_sup, ty_sub, diag) ;
904
946
}
905
947
}
948
+
949
+ /// Use of `Self` can impose unnecessary region constraints:
950
+ /// ```
951
+ /// struct MyStruct<'a>(&'a str);
952
+ /// impl<'a> MyStruct<'a> {
953
+ /// fn test<'x>(s: &'x str) {
954
+ /// let _ = Self(s); // requires 'x: 'a.
955
+ /// }
956
+ /// }
957
+ /// ```
958
+ /// Here we suggest replacing `Self` with `MyStruct<'_>`.
959
+ /// Assumes that `span` points to hir::Path that may name `Self`.
960
+ pub ( crate ) fn suggest_relax_self < ' tcx > (
961
+ tcx : TyCtxt < ' tcx > ,
962
+ err : & mut Diagnostic ,
963
+ body_did : DefId ,
964
+ span : Span ,
965
+ ) {
966
+ use rustc_lexer as lex;
967
+ fn tokenize ( mut input : & str ) -> impl Iterator < Item = ( lex:: TokenKind , & str ) > {
968
+ std:: iter:: from_fn ( move || {
969
+ if input. is_empty ( ) {
970
+ return None ;
971
+ }
972
+ let token = lex:: first_token ( input) ;
973
+ let token_str = & input[ ..( token. len as usize ) ] ;
974
+ input = & input[ ( token. len as usize ) ..] ;
975
+ Some ( ( token. kind , token_str) )
976
+ } )
977
+ }
978
+
979
+ let snippet = tcx. sess . source_map ( ) . span_to_snippet ( span) . unwrap_or_default ( ) ;
980
+ let has_self = tokenize ( & snippet)
981
+ . find ( |( tok, s) | * tok == lex:: TokenKind :: Ident && * s == "Self" )
982
+ . and_then ( |_| tcx. opt_parent ( tcx. typeck_root_def_id ( body_did) ) )
983
+ . filter ( |parent_did| tcx. def_kind ( parent_did) == DefKind :: Impl ) ;
984
+
985
+ if let Some ( impl_did) = has_self {
986
+ let suggested_ty =
987
+ tcx. fold_regions ( tcx. type_of ( impl_did) , |_, _| tcx. mk_region ( ty:: ReErased ) ) ;
988
+ err. help ( format ! ( "consider replacing `Self` with `{suggested_ty}`" ) ) ;
989
+ }
990
+ }
0 commit comments