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:: { Subtype , ValuePairs } ;
5
+ use crate :: infer:: { Subtype , TyCtxtInferExt , ValuePairs } ;
6
6
use crate :: traits:: ObligationCauseCode :: CompareImplMethodObligation ;
7
7
use rustc_errors:: ErrorReported ;
8
- use rustc_middle:: ty:: Ty ;
9
- use rustc_span:: Span ;
8
+ use rustc_hir as hir;
9
+ use rustc_hir:: def:: Res ;
10
+ use rustc_hir:: def_id:: DefId ;
11
+ use rustc_hir:: intravisit:: Visitor ;
12
+ use rustc_middle:: ty:: error:: ExpectedFound ;
13
+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
14
+ use rustc_span:: { MultiSpan , Span } ;
10
15
11
16
impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
12
17
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
@@ -36,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
36
41
var_origin. span ( ) ,
37
42
sub_expected_found. expected ,
38
43
sub_expected_found. found ,
39
- self . tcx ( ) . def_span ( * trait_item_def_id) ,
44
+ * trait_item_def_id,
40
45
) ;
41
46
return Some ( ErrorReported ) ;
42
47
}
@@ -47,14 +52,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
47
52
None
48
53
}
49
54
50
- fn emit_err ( & self , sp : Span , expected : Ty < ' tcx > , found : Ty < ' tcx > , impl_sp : Span ) {
55
+ fn emit_err ( & self , sp : Span , expected : Ty < ' tcx > , found : Ty < ' tcx > , trait_def_id : DefId ) {
56
+ let tcx = self . tcx ( ) ;
57
+ let trait_sp = self . tcx ( ) . def_span ( trait_def_id) ;
51
58
let mut err = self
52
59
. tcx ( )
53
60
. sess
54
61
. struct_span_err ( sp, "`impl` item signature doesn't match `trait` item signature" ) ;
55
- err. note ( & format ! ( "expected `{:?}`\n found `{:?}`" , expected, found) ) ;
56
- err. span_label ( sp, & format ! ( "found {:?}" , found) ) ;
57
- err. span_label ( impl_sp, & format ! ( "expected {:?}" , expected) ) ;
62
+ err. span_label ( sp, & format ! ( "found `{:?}`" , found) ) ;
63
+ err. span_label ( trait_sp, & format ! ( "expected `{:?}`" , expected) ) ;
64
+
65
+ // Get the span of all the used type parameters in the method.
66
+ let assoc_item = self . tcx ( ) . associated_item ( trait_def_id) ;
67
+ let mut visitor = TypeParamSpanVisitor { tcx : self . tcx ( ) , types : vec ! [ ] } ;
68
+ match assoc_item. kind {
69
+ ty:: AssocKind :: Fn => {
70
+ let hir = self . tcx ( ) . hir ( ) ;
71
+ if let Some ( hir_id) = assoc_item. def_id . as_local ( ) . map ( |id| hir. as_local_hir_id ( id) )
72
+ {
73
+ if let Some ( decl) = hir. fn_decl_by_hir_id ( hir_id) {
74
+ visitor. visit_fn_decl ( decl) ;
75
+ }
76
+ }
77
+ }
78
+ _ => { }
79
+ }
80
+ let mut type_param_span: MultiSpan =
81
+ visitor. types . iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) . into ( ) ;
82
+ for & span in & visitor. types {
83
+ type_param_span. push_span_label (
84
+ span,
85
+ "consider borrowing this type parameter in the trait" . to_string ( ) ,
86
+ ) ;
87
+ }
88
+
89
+ if let Some ( ( expected, found) ) = tcx
90
+ . infer_ctxt ( )
91
+ . enter ( |infcx| infcx. expected_found_str_ty ( & ExpectedFound { expected, found } ) )
92
+ {
93
+ // Highlighted the differences when showing the "expected/found" note.
94
+ err. note_expected_found ( & "" , expected, & "" , found) ;
95
+ } else {
96
+ // This fallback shouldn't be necessary, but let's keep it in just in case.
97
+ err. note ( & format ! ( "expected `{:?}`\n found `{:?}`" , expected, found) ) ;
98
+ }
99
+ err. span_help (
100
+ type_param_span,
101
+ "the lifetime requirements from the `impl` do not correspond to the requirements in \
102
+ the `trait`",
103
+ ) ;
104
+ if visitor. types . is_empty ( ) {
105
+ err. help (
106
+ "verify the lifetime relationships in the `trait` and `impl` between the `self` \
107
+ argument, the other inputs and its output",
108
+ ) ;
109
+ }
58
110
err. emit ( ) ;
59
111
}
60
112
}
113
+
114
+ struct TypeParamSpanVisitor < ' tcx > {
115
+ tcx : TyCtxt < ' tcx > ,
116
+ types : Vec < Span > ,
117
+ }
118
+
119
+ impl Visitor < ' tcx > for TypeParamSpanVisitor < ' tcx > {
120
+ type Map = rustc_middle:: hir:: map:: Map < ' tcx > ;
121
+
122
+ fn nested_visit_map ( & mut self ) -> hir:: intravisit:: NestedVisitorMap < Self :: Map > {
123
+ hir:: intravisit:: NestedVisitorMap :: OnlyBodies ( self . tcx . hir ( ) )
124
+ }
125
+
126
+ fn visit_ty ( & mut self , arg : & ' tcx hir:: Ty < ' tcx > ) {
127
+ match arg. kind {
128
+ hir:: TyKind :: Rptr ( _, ref mut_ty) => {
129
+ // We don't want to suggest looking into borrowing `&T` or `&Self`.
130
+ hir:: intravisit:: walk_ty ( self , mut_ty. ty ) ;
131
+ return ;
132
+ }
133
+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) => match & path. segments {
134
+ [ segment]
135
+ if segment
136
+ . res
137
+ . map ( |res| match res {
138
+ Res :: SelfTy ( _, _) | Res :: Def ( hir:: def:: DefKind :: TyParam , _) => true ,
139
+ _ => false ,
140
+ } )
141
+ . unwrap_or ( false ) =>
142
+ {
143
+ self . types . push ( path. span ) ;
144
+ }
145
+ _ => { }
146
+ } ,
147
+ _ => { }
148
+ }
149
+ hir:: intravisit:: walk_ty ( self , arg) ;
150
+ }
151
+ }
0 commit comments