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