@@ -27,65 +27,84 @@ 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 ( ) {
44
- 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
- }
54
- } else {
55
- return false ;
56
- }
57
- } else {
58
- return false ; // inapplicable
59
- } ;
49
+ let anon_reg_sup = or_false ! ( self . is_suitable_anonymous_region( sup) ) ;
60
50
61
- if let ( Some ( sup_arg) , Some ( sub_arg) ) =
51
+ let anon_reg_sub = or_false ! ( self . is_suitable_anonymous_region( sub) ) ;
52
+ let scope_def_id_sup = anon_reg_sup. def_id ;
53
+ let bregion_sup = anon_reg_sup. boundregion ;
54
+ let scope_def_id_sub = anon_reg_sub. def_id ;
55
+ let bregion_sub = anon_reg_sub. boundregion ;
56
+
57
+ let ty_sup = or_false ! ( self . find_anon_type( sup, & bregion_sup) ) ;
58
+
59
+ let ty_sub = or_false ! ( self . find_anon_type( sub, & bregion_sub) ) ;
60
+
61
+ let ( main_label, label1, label2) = if let ( Some ( sup_arg) , Some ( sub_arg) ) =
62
62
( self . find_arg_with_anonymous_region ( sup, sup) ,
63
63
self . find_arg_with_anonymous_region ( sub, sub) ) {
64
- let ( ( anon_arg1, _, _, _) , ( anon_arg2, _, _, _) ) = ( sup_arg, sub_arg) ;
65
64
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
- } ;
65
+ let ( anon_arg_sup, is_first_sup, anon_arg_sub, is_first_sub) =
66
+ ( sup_arg. arg , sup_arg. is_first , sub_arg. arg , sub_arg. is_first ) ;
67
+ if self . is_self_anon ( is_first_sup, scope_def_id_sup) ||
68
+ self . is_self_anon ( is_first_sub, scope_def_id_sub) {
69
+ return false ;
70
+ }
71
71
72
- let span_label_var2 = if let Some ( simple_name) = anon_arg2. pat . simple_name ( ) {
73
- format ! ( " into `{}` " , simple_name)
72
+ if self . is_return_type_anon ( scope_def_id_sup, bregion_sup) ||
73
+ self . is_return_type_anon ( scope_def_id_sub, bregion_sub) {
74
+ return false ;
75
+ }
76
+
77
+ if anon_arg_sup == anon_arg_sub {
78
+ ( format ! ( "this type was declared with multiple lifetimes..." ) ,
79
+ format ! ( " with one lifetime" ) ,
80
+ format ! ( " into the other" ) )
74
81
} 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 ( ) ;
82
+ let span_label_var1 = if let Some ( simple_name) = anon_arg_sup. pat . simple_name ( ) {
83
+ format ! ( " from `{}`" , simple_name)
84
+ } else {
85
+ format ! ( "" )
86
+ } ;
87
+
88
+ let span_label_var2 = if let Some ( simple_name) = anon_arg_sub. pat . simple_name ( ) {
89
+ format ! ( " into `{}`" , simple_name)
90
+ } else {
91
+ format ! ( "" )
92
+ } ;
93
+
94
+ let span_label =
95
+ format ! ( "these two types are declared with different lifetimes..." , ) ;
96
+
97
+ ( span_label, span_label_var1, span_label_var2)
98
+ }
85
99
} else {
86
100
return false ;
87
- }
101
+ } ;
88
102
103
+ struct_span_err ! ( self . tcx. sess, span, E0623 , "lifetime mismatch" )
104
+ . span_label ( ty_sup. span , main_label)
105
+ . span_label ( ty_sub. span , format ! ( "" ) )
106
+ . span_label ( span, format ! ( "...but data{} flows{} here" , label1, label2) )
107
+ . emit ( ) ;
89
108
return true ;
90
109
}
91
110
@@ -94,7 +113,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
94
113
/// contains the anonymous type.
95
114
///
96
115
/// # Arguments
97
- ///
98
116
/// region - the anonymous region corresponding to the anon_anon conflict
99
117
/// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
100
118
///
@@ -105,39 +123,56 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
105
123
/// ```
106
124
/// The function returns the nested type corresponding to the anonymous region
107
125
/// for e.g. `&u8` and Vec<`&u8`.
108
- fn find_anon_type ( & self , region : Region < ' tcx > , br : & ty:: BoundRegion ) -> Option < & hir:: Ty > {
126
+ pub fn find_anon_type ( & self , region : Region < ' tcx > , br : & ty:: BoundRegion ) -> Option < & hir:: Ty > {
109
127
if let Some ( anon_reg) = self . is_suitable_anonymous_region ( region) {
110
- let ( def_id, _ ) = anon_reg;
128
+ let def_id = anon_reg. def_id ;
111
129
if let Some ( node_id) = self . tcx . hir . as_local_node_id ( def_id) {
112
130
let ret_ty = self . tcx . type_of ( def_id) ;
113
131
if let ty:: TyFnDef ( _, _) = ret_ty. sty {
114
- if let hir_map:: NodeItem ( it) = self . tcx . hir . get ( node_id) {
115
- if let hir:: ItemFn ( ref fndecl, _, _, _, _, _) = it. node {
116
- return fndecl
117
- . inputs
118
- . iter ( )
119
- . 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
- } )
133
- . next ( ) ;
134
- }
135
- }
132
+ let inputs: & [ _ ] =
133
+ match self . tcx . hir . get ( node_id) {
134
+ hir_map:: NodeItem ( & hir:: Item {
135
+ node : hir:: ItemFn ( ref fndecl, ..) , ..
136
+ } ) => & fndecl. inputs ,
137
+ hir_map:: NodeTraitItem ( & hir:: TraitItem {
138
+ node : hir:: TraitItemKind :: Method ( ref fndecl, ..) ,
139
+ ..
140
+ } ) => & fndecl. decl . inputs ,
141
+ hir_map:: NodeImplItem ( & hir:: ImplItem {
142
+ node : hir:: ImplItemKind :: Method ( ref fndecl, ..) ,
143
+ ..
144
+ } ) => & fndecl. decl . inputs ,
145
+
146
+ _ => & [ ] ,
147
+ } ;
148
+
149
+ return inputs
150
+ . iter ( )
151
+ . filter_map ( |arg| {
152
+ self . find_component_for_bound_region ( & * * arg, br)
153
+ } )
154
+ . next ( ) ;
136
155
}
137
156
}
138
157
}
139
158
None
140
159
}
160
+
161
+ // This method creates a FindNestedTypeVisitor which returns the type corresponding
162
+ // to the anonymous region.
163
+ fn find_component_for_bound_region ( & self ,
164
+ arg : & ' gcx hir:: Ty ,
165
+ br : & ty:: BoundRegion )
166
+ -> Option < ( & ' gcx hir:: Ty ) > {
167
+ let mut nested_visitor = FindNestedTypeVisitor {
168
+ infcx : & self ,
169
+ hir_map : & self . tcx . hir ,
170
+ bound_region : * br,
171
+ found_type : None ,
172
+ } ;
173
+ nested_visitor. visit_ty ( arg) ;
174
+ nested_visitor. found_type
175
+ }
141
176
}
142
177
143
178
// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
@@ -176,8 +211,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
176
211
hir:: TyRptr ( ref lifetime, _) => {
177
212
match self . infcx . tcx . named_region_map . defs . get ( & lifetime. id ) {
178
213
// the lifetime of the TyRptr
179
- Some ( & rl:: Region :: LateBoundAnon ( debuijn_index , anon_index) ) => {
180
- if debuijn_index . depth == 1 && anon_index == br_index {
214
+ Some ( & rl:: Region :: LateBoundAnon ( debruijn_index , anon_index) ) => {
215
+ if debruijn_index . depth == 1 && anon_index == br_index {
181
216
self . found_type = Some ( arg) ;
182
217
return ; // we can stop visiting now
183
218
}
@@ -191,10 +226,77 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
191
226
}
192
227
}
193
228
}
229
+ // Checks if it is of type `hir::TyPath` which corresponds to a struct.
230
+ hir:: TyPath ( _) => {
231
+ let subvisitor = & mut TyPathVisitor {
232
+ infcx : self . infcx ,
233
+ found_it : false ,
234
+ bound_region : self . bound_region ,
235
+ hir_map : self . hir_map ,
236
+ } ;
237
+ intravisit:: walk_ty ( subvisitor, arg) ; // call walk_ty; as visit_ty is empty,
238
+ // this will visit only outermost type
239
+ if subvisitor. found_it {
240
+ self . found_type = Some ( arg) ;
241
+ }
242
+ }
194
243
_ => { }
195
244
}
196
245
// walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
197
246
// go on to visit `&Foo`
198
247
intravisit:: walk_ty ( self , arg) ;
199
248
}
200
249
}
250
+
251
+ // The visitor captures the corresponding `hir::Ty` of the anonymous region
252
+ // in the case of structs ie. `hir::TyPath`.
253
+ // This visitor would be invoked for each lifetime corresponding to a struct,
254
+ // and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
255
+ // where that lifetime appears. This allows us to highlight the
256
+ // specific part of the type in the error message.
257
+ struct TyPathVisitor < ' a , ' gcx : ' a + ' tcx , ' tcx : ' a > {
258
+ infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
259
+ hir_map : & ' a hir:: map:: Map < ' gcx > ,
260
+ found_it : bool ,
261
+ bound_region : ty:: BoundRegion ,
262
+ }
263
+
264
+ impl < ' a , ' gcx , ' tcx > Visitor < ' gcx > for TyPathVisitor < ' a , ' gcx , ' tcx > {
265
+ fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' gcx > {
266
+ NestedVisitorMap :: OnlyBodies ( & self . hir_map )
267
+ }
268
+
269
+ fn visit_lifetime ( & mut self , lifetime : & hir:: Lifetime ) {
270
+ let br_index = match self . bound_region {
271
+ ty:: BrAnon ( index) => index,
272
+ _ => return ,
273
+ } ;
274
+
275
+ match self . infcx . tcx . named_region_map . defs . get ( & lifetime. id ) {
276
+ // the lifetime of the TyPath!
277
+ Some ( & rl:: Region :: LateBoundAnon ( debruijn_index, anon_index) ) => {
278
+ if debruijn_index. depth == 1 && anon_index == br_index {
279
+ self . found_it = true ;
280
+ }
281
+ }
282
+ Some ( & rl:: Region :: Static ) |
283
+ Some ( & rl:: Region :: EarlyBound ( _, _) ) |
284
+ Some ( & rl:: Region :: LateBound ( _, _) ) |
285
+ Some ( & rl:: Region :: Free ( _, _) ) |
286
+ None => {
287
+ debug ! ( "no arg found" ) ;
288
+ }
289
+ }
290
+ }
291
+
292
+ fn visit_ty ( & mut self , arg : & ' gcx hir:: Ty ) {
293
+ // ignore nested types
294
+ //
295
+ // If you have a type like `Foo<'a, &Ty>` we
296
+ // are only interested in the immediate lifetimes ('a).
297
+ //
298
+ // Making `visit_ty` empty will ignore the `&Ty` embedded
299
+ // inside, it will get reached by the outer visitor.
300
+ debug ! ( "`Ty` corresponding to a struct is {:?}" , arg) ;
301
+ }
302
+ }
0 commit comments