@@ -27,66 +27,97 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
27
27
// { x.push(y); }.
28
28
// The example gives
29
29
// fn foo(x: &mut Vec<&u8>, y: &u8) {
30
- // --- --- these references must have the same lifetime
30
+ // --- --- these references are declared with different lifetimes...
31
31
// x.push(y);
32
- // ^ data from `y` flows into `x` here
33
- // It will later be extended to trait objects and structs.
32
+ // ^ ...but data from `y` flows into `x` here
33
+ // It has been extended for the case of structs too.
34
+ // Consider the example
35
+ // struct Ref<'a> { x: &'a u32 }
36
+ // fn foo(mut x: Vec<Ref>, y: Ref) {
37
+ // --- --- these structs are declared with different lifetimes...
38
+ // x.push(y);
39
+ // ^ ...but data from `y` flows into `x` here
40
+ // }
41
+ // It will later be extended to trait objects.
34
42
pub fn try_report_anon_anon_conflict ( & self , error : & RegionResolutionError < ' tcx > ) -> bool {
35
-
36
43
let ( span, sub, sup) = match * error {
37
44
ConcreteFailure ( ref origin, sub, sup) => ( origin. span ( ) , sub, sup) ,
38
45
_ => return false , // inapplicable
39
46
} ;
40
47
41
48
// Determine whether the sub and sup consist of both anonymous (elided) regions.
42
- let ( ty1, ty2) = if self . is_suitable_anonymous_region ( sup) . is_some ( ) &&
43
- self . is_suitable_anonymous_region ( sub) . is_some ( ) {
49
+ let ( ty1, ty2, scope_def_id_1, scope_def_id_2, bregion1, bregion2) = if
50
+ self . is_suitable_anonymous_region ( sup, true ) . is_some ( ) &&
51
+ self . is_suitable_anonymous_region ( sub, true ) . is_some ( ) {
44
52
if let ( Some ( anon_reg1) , Some ( anon_reg2) ) =
45
- ( self . is_suitable_anonymous_region ( sup) , self . is_suitable_anonymous_region ( sub) ) {
46
- let ( ( _, br1) , ( _, br2) ) = ( anon_reg1, anon_reg2) ;
47
- if self . find_anon_type ( sup, & br1) . is_some ( ) &&
48
- self . find_anon_type ( sub, & br2) . is_some ( ) {
49
- ( self . find_anon_type ( sup, & br1) . unwrap ( ) ,
50
- self . find_anon_type ( sub, & br2) . unwrap ( ) )
51
- } else {
52
- return false ;
53
+ ( self . is_suitable_anonymous_region ( sup, true ) ,
54
+ self . is_suitable_anonymous_region ( sub, true ) ) {
55
+ let ( ( def_id1, br1) , ( def_id2, br2) ) = ( anon_reg1, anon_reg2) ;
56
+ let found_arg1 = self . find_anon_type ( sup, & br1) ;
57
+ let found_arg2 = self . find_anon_type ( sub, & br2) ;
58
+ match ( found_arg1, found_arg2) {
59
+ ( Some ( anonarg_1) , Some ( anonarg_2) ) => {
60
+ ( anonarg_1, anonarg_2, def_id1, def_id2, br1, br2)
61
+ }
62
+ _ => {
63
+ return false ;
64
+ }
53
65
}
66
+
54
67
} else {
55
68
return false ;
56
69
}
57
70
} else {
58
- return false ; // inapplicable
71
+ return false ; //inapplicable
59
72
} ;
60
73
61
- if let ( Some ( sup_arg) , Some ( sub_arg) ) =
74
+ let ( label1 , label2 ) = if let ( Some ( sup_arg) , Some ( sub_arg) ) =
62
75
( self . find_arg_with_anonymous_region ( sup, sup) ,
63
76
self . find_arg_with_anonymous_region ( sub, sub) ) {
64
- let ( ( anon_arg1, _, _, _) , ( anon_arg2, _, _, _) ) = ( sup_arg, sub_arg) ;
65
77
66
- let span_label_var1 = if let Some ( simple_name ) = anon_arg1 . pat . simple_name ( ) {
67
- format ! ( " from `{}` " , simple_name )
68
- } else {
69
- format ! ( " " )
70
- } ;
78
+ let ( ( anon_arg1 , _ , _ , is_first1 ) , ( anon_arg2 , _ , _ , is_first2 ) ) = ( sup_arg , sub_arg ) ;
79
+ if self . is_self_anon ( is_first1 , scope_def_id_1 ) ||
80
+ self . is_self_anon ( is_first2 , scope_def_id_2 ) {
81
+ return false ;
82
+ }
71
83
72
- let span_label_var2 = if let Some ( simple_name) = anon_arg2. pat . simple_name ( ) {
73
- format ! ( " into `{}` " , simple_name)
84
+ if self . is_return_type_anon ( scope_def_id_1, bregion1) ||
85
+ self . is_return_type_anon ( scope_def_id_2, bregion2) {
86
+ return false ;
87
+ }
88
+
89
+
90
+
91
+
92
+ if anon_arg1 == anon_arg2 {
93
+ ( format ! ( " with one lifetime" ) , format ! ( " into the other" ) )
74
94
} else {
75
- format ! ( " " )
76
- } ;
77
-
78
- struct_span_err ! ( self . tcx. sess, span, E0623 , "lifetime mismatch" )
79
- . span_label ( ty1. span ,
80
- format ! ( "these references are not declared with the same lifetime..." ) )
81
- . span_label ( ty2. span , format ! ( "" ) )
82
- . span_label ( span,
83
- format ! ( "...but data{}flows{}here" , span_label_var1, span_label_var2) )
84
- . emit ( ) ;
95
+ let span_label_var1 = if let Some ( simple_name) = anon_arg1. pat . simple_name ( ) {
96
+ format ! ( " from `{}`" , simple_name)
97
+ } else {
98
+ format ! ( "" )
99
+ } ;
100
+
101
+ let span_label_var2 = if let Some ( simple_name) = anon_arg2. pat . simple_name ( ) {
102
+ format ! ( " into `{}`" , simple_name)
103
+ } else {
104
+ format ! ( "" )
105
+ } ;
106
+
107
+ ( span_label_var1, span_label_var2)
108
+ }
85
109
} else {
86
110
return false ;
87
- }
111
+ } ;
88
112
113
+ struct_span_err ! ( self . tcx. sess, span, E0623 , "lifetime mismatch" )
114
+ . span_label ( ty1. span ,
115
+ format ! ( "these two types are declared with different lifetimes..." ) )
116
+ . span_label ( ty2. span , format ! ( "" ) )
117
+ . span_label ( span, format ! ( "...but data{} flows{} here" , label1, label2) )
118
+ . emit ( ) ;
89
119
return true ;
120
+
90
121
}
91
122
92
123
/// This function calls the `visit_ty` method for the parameters
@@ -105,8 +136,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
105
136
/// ```
106
137
/// The function returns the nested type corresponding to the anonymous region
107
138
/// for e.g. `&u8` and Vec<`&u8`.
108
- fn find_anon_type ( & self , region : Region < ' tcx > , br : & ty:: BoundRegion ) -> Option < & hir:: Ty > {
109
- if let Some ( anon_reg) = self . is_suitable_anonymous_region ( region) {
139
+ pub fn find_anon_type ( & self , region : Region < ' tcx > , br : & ty:: BoundRegion ) -> Option < ( & hir:: Ty ) > {
140
+ if let Some ( anon_reg) = self . is_suitable_anonymous_region ( region, true ) {
110
141
let ( def_id, _) = anon_reg;
111
142
if let Some ( node_id) = self . tcx . hir . as_local_node_id ( def_id) {
112
143
let ret_ty = self . tcx . type_of ( def_id) ;
@@ -117,19 +148,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
117
148
. inputs
118
149
. iter ( )
119
150
. filter_map ( |arg| {
120
- let mut nested_visitor = FindNestedTypeVisitor {
121
- infcx : & self ,
122
- hir_map : & self . tcx . hir ,
123
- bound_region : * br,
124
- found_type : None ,
125
- } ;
126
- nested_visitor. visit_ty ( & * * arg) ;
127
- if nested_visitor. found_type . is_some ( ) {
128
- nested_visitor. found_type
129
- } else {
130
- None
131
- }
132
- } )
151
+ self . find_visitor_found_type ( & * * arg, br)
152
+ } )
153
+ . next ( ) ;
154
+ }
155
+ } else if let hir_map:: NodeTraitItem ( it) = self . tcx . hir . get ( node_id) {
156
+ if let hir:: TraitItemKind :: Method ( ref fndecl, _) = it. node {
157
+ return fndecl
158
+ . decl
159
+ . inputs
160
+ . iter ( )
161
+ . filter_map ( |arg| {
162
+ self . find_visitor_found_type ( & * * arg, br)
163
+ } )
164
+ . next ( ) ;
165
+ }
166
+ } else if let hir_map:: NodeImplItem ( it) = self . tcx . hir . get ( node_id) {
167
+ if let hir:: ImplItemKind :: Method ( ref fndecl, _) = it. node {
168
+ return fndecl
169
+ . decl
170
+ . inputs
171
+ . iter ( )
172
+ . filter_map ( |arg| {
173
+ self . find_visitor_found_type ( & * * arg, br)
174
+ } )
133
175
. next ( ) ;
134
176
}
135
177
}
@@ -138,6 +180,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
138
180
}
139
181
None
140
182
}
183
+
184
+ fn find_visitor_found_type ( & self ,
185
+ arg : & ' gcx hir:: Ty ,
186
+ br : & ty:: BoundRegion )
187
+ -> Option < ( & ' gcx hir:: Ty ) > {
188
+ let mut nested_visitor = FindNestedTypeVisitor {
189
+ infcx : & self ,
190
+ hir_map : & self . tcx . hir ,
191
+ bound_region : * br,
192
+ found_type : None ,
193
+ } ;
194
+ nested_visitor. visit_ty ( arg) ;
195
+ nested_visitor. found_type
196
+ }
141
197
}
142
198
143
199
// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
@@ -191,10 +247,78 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
191
247
}
192
248
}
193
249
}
250
+ // Checks if it is of type `hir::TyPath` which corresponds to a struct.
251
+ hir:: TyPath ( _) => {
252
+ let subvisitor = & mut TyPathVisitor {
253
+ infcx : self . infcx ,
254
+ found_it : false ,
255
+ bound_region : self . bound_region ,
256
+ hir_map : self . hir_map ,
257
+ } ;
258
+ intravisit:: walk_ty ( subvisitor, arg) ; // call walk_ty; as visit_ty is empty,
259
+ // this will visit only outermost type
260
+ if subvisitor. found_it {
261
+ self . found_type = Some ( arg) ;
262
+ }
263
+ }
194
264
_ => { }
195
265
}
196
266
// walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
197
267
// go on to visit `&Foo`
198
268
intravisit:: walk_ty ( self , arg) ;
199
269
}
200
270
}
271
+
272
+ // The visitor captures the corresponding `hir::Ty` of the anonymous region
273
+ // in the case of structs ie. `hir::TyPath`.
274
+ // This visitor would be invoked for each lifetime corresponding to a struct,
275
+ // and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
276
+ // where that lifetime appears. This allows us to highlight the
277
+ // specific part of the type in the error message.
278
+ struct TyPathVisitor < ' a , ' gcx : ' a + ' tcx , ' tcx : ' a > {
279
+ infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
280
+ hir_map : & ' a hir:: map:: Map < ' gcx > ,
281
+ found_it : bool ,
282
+ bound_region : ty:: BoundRegion ,
283
+ }
284
+
285
+ impl < ' a , ' gcx , ' tcx > Visitor < ' gcx > for TyPathVisitor < ' a , ' gcx , ' tcx > {
286
+ fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' gcx > {
287
+ NestedVisitorMap :: OnlyBodies ( & self . hir_map )
288
+ }
289
+
290
+ fn visit_lifetime ( & mut self , lifetime : & hir:: Lifetime ) {
291
+ let br_index = match self . bound_region {
292
+ ty:: BrAnon ( index) => index,
293
+ _ => return ,
294
+ } ;
295
+
296
+
297
+ match self . infcx . tcx . named_region_map . defs . get ( & lifetime. id ) {
298
+ // the lifetime of the TyPath!
299
+ Some ( & rl:: Region :: LateBoundAnon ( debuijn_index, anon_index) ) => {
300
+ if debuijn_index. depth == 1 && anon_index == br_index {
301
+ self . found_it = true ;
302
+ }
303
+ }
304
+ Some ( & rl:: Region :: Static ) |
305
+ Some ( & rl:: Region :: EarlyBound ( _, _) ) |
306
+ Some ( & rl:: Region :: LateBound ( _, _) ) |
307
+ Some ( & rl:: Region :: Free ( _, _) ) |
308
+ None => {
309
+ debug ! ( "no arg found" ) ;
310
+ }
311
+ }
312
+ }
313
+
314
+ fn visit_ty ( & mut self , arg : & ' gcx hir:: Ty ) {
315
+ // ignore nested types
316
+ //
317
+ // If you have a type like `Foo<'a, &Ty>` we
318
+ // are only interested in the immediate lifetimes ('a).
319
+ //
320
+ // Making `visit_ty` empty will ignore the `&Ty` embedded
321
+ // inside, it will get reached by the outer visitor.
322
+ debug ! ( "`Ty` corresponding to a struct is {:?}" , arg) ;
323
+ }
324
+ }
0 commit comments