@@ -27,65 +27,83 @@ 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 ( ) )
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)
5157 } else {
5258 return false ;
5359 }
5460 } else {
5561 return false ;
56- }
57- } else {
58- return false ; // inapplicable
59- } ;
62+ } ;
6063
61- if let ( Some ( sup_arg) , Some ( sub_arg) ) =
64+ let ( label1 , label2 ) = if let ( Some ( sup_arg) , Some ( sub_arg) ) =
6265 ( self . find_arg_with_anonymous_region ( sup, sup) ,
6366 self . find_arg_with_anonymous_region ( sub, sub) ) {
64- let ( ( anon_arg1, _, _, _) , ( anon_arg2, _, _, _) ) = ( sup_arg, sub_arg) ;
6567
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+ }
7179
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" ) )
7482 } 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+ } ;
7794
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+ }
8597 } else {
8698 return false ;
87- }
99+ } ;
88100
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 ( ) ;
89107 return true ;
90108 }
91109
@@ -94,7 +112,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
94112 /// contains the anonymous type.
95113 ///
96114 /// # Arguments
97- ///
98115 /// region - the anonymous region corresponding to the anon_anon conflict
99116 /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
100117 ///
@@ -105,8 +122,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
105122 /// ```
106123 /// The function returns the nested type corresponding to the anonymous region
107124 /// 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 ) {
110127 let ( def_id, _) = anon_reg;
111128 if let Some ( node_id) = self . tcx . hir . as_local_node_id ( def_id) {
112129 let ret_ty = self . tcx . type_of ( def_id) ;
@@ -117,19 +134,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
117134 . inputs
118135 . iter ( )
119136 . 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+ } )
133164 . next ( ) ;
134165 }
135166 }
@@ -138,6 +169,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
138169 }
139170 None
140171 }
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+ }
141188}
142189
143190// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
@@ -176,8 +223,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
176223 hir:: TyRptr ( ref lifetime, _) => {
177224 match self . infcx . tcx . named_region_map . defs . get ( & lifetime. id ) {
178225 // 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 {
181228 self . found_type = Some ( arg) ;
182229 return ; // we can stop visiting now
183230 }
@@ -191,10 +238,77 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
191238 }
192239 }
193240 }
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+ }
194255 _ => { }
195256 }
196257 // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
197258 // go on to visit `&Foo`
198259 intravisit:: walk_ty ( self , arg) ;
199260 }
200261}
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