@@ -27,65 +27,84 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2727 // { x.push(y); }.
2828 // The example gives
2929 // fn foo(x: &mut Vec<&u8>, y: &u8) {
30- // --- --- these references must have the same lifetime
30+ // --- --- these references are declared with different lifetimes...
3131 // 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.
3442 pub fn try_report_anon_anon_conflict ( & self , error : & RegionResolutionError < ' tcx > ) -> bool {
35-
3643 let ( span, sub, sup) = match * error {
3744 ConcreteFailure ( ref origin, sub, sup) => ( origin. span ( ) , sub, sup) ,
3845 _ => return false , // inapplicable
3946 } ;
4047
4148 // 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) ) ;
6050
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) ) =
6262 ( self . find_arg_with_anonymous_region ( sup, sup) ,
6363 self . find_arg_with_anonymous_region ( sub, sub) ) {
64- let ( ( anon_arg1, _, _, _) , ( anon_arg2, _, _, _) ) = ( sup_arg, sub_arg) ;
6564
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+ }
7171
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" ) )
7481 } 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+ }
8599 } else {
86100 return false ;
87- }
101+ } ;
88102
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 ( ) ;
89108 return true ;
90109 }
91110
@@ -94,7 +113,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
94113 /// contains the anonymous type.
95114 ///
96115 /// # Arguments
97- ///
98116 /// region - the anonymous region corresponding to the anon_anon conflict
99117 /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
100118 ///
@@ -105,39 +123,56 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
105123 /// ```
106124 /// The function returns the nested type corresponding to the anonymous region
107125 /// 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 > {
109127 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 ;
111129 if let Some ( node_id) = self . tcx . hir . as_local_node_id ( def_id) {
112130 let ret_ty = self . tcx . type_of ( def_id) ;
113131 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 ( ) ;
136155 }
137156 }
138157 }
139158 None
140159 }
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+ }
141176}
142177
143178// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
@@ -176,8 +211,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
176211 hir:: TyRptr ( ref lifetime, _) => {
177212 match self . infcx . tcx . named_region_map . defs . get ( & lifetime. id ) {
178213 // 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 {
181216 self . found_type = Some ( arg) ;
182217 return ; // we can stop visiting now
183218 }
@@ -191,10 +226,77 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
191226 }
192227 }
193228 }
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+ }
194243 _ => { }
195244 }
196245 // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
197246 // go on to visit `&Foo`
198247 intravisit:: walk_ty ( self , arg) ;
199248 }
200249}
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