@@ -81,40 +81,42 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
8181 self . fail ( location, format ! ( "encountered jump to invalid basic block {:?}" , bb) )
8282 }
8383 }
84- }
8584
86- /// Check if src can be assigned into dest.
87- /// This is not precise, it will accept some incorrect assignments.
88- fn mir_assign_valid_types < ' tcx > ( tcx : TyCtxt < ' tcx > , src : Ty < ' tcx > , dest : Ty < ' tcx > ) -> bool {
89- if src == dest {
90- // Equal types, all is good.
91- return true ;
92- }
85+ /// Check if src can be assigned into dest.
86+ /// This is not precise, it will accept some incorrect assignments.
87+ fn mir_assign_valid_types ( & self , src : Ty < ' tcx > , dest : Ty < ' tcx > ) -> bool {
88+ if src == dest {
89+ // Equal types, all is good.
90+ return true ;
91+ }
9392
94- // Type-changing assignments can happen for (at least) two reasons:
95- // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
96- // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
97- // with their late-bound lifetimes are still around and can lead to type differences.
98- // Normalize both of them away.
99- // FIXME: Share this code with `interpret/eval_context.rs`.
100- let normalize = |ty : Ty < ' tcx > | {
101- ty. fold_with ( & mut BottomUpFolder {
102- tcx,
103- // Normalize all references to immutable.
104- ty_op : |ty| match ty. kind {
105- ty:: Ref ( _, pointee, _) => tcx. mk_imm_ref ( tcx. lifetimes . re_erased , pointee) ,
106- _ => ty,
107- } ,
108- // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
109- // lifetimes in invariant positions could matter (e.g. through associated types).
110- // But that just means we miss some potential incompatible types, it will not
111- // lead to wrong errors.
112- lt_op : |_| tcx. lifetimes . re_erased ,
113- // Leave consts unchanged.
114- ct_op : |ct| ct,
115- } )
116- } ;
117- normalize ( src) == normalize ( dest)
93+ // Type-changing assignments can happen for (at least) two reasons:
94+ // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
95+ // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
96+ // with their late-bound lifetimes are still around and can lead to type differences.
97+ // Normalize both of them away.
98+ // Also see the related but slightly different post-monomorphization method in `interpret/eval_context.rs`.
99+ let normalize = |ty : Ty < ' tcx > | {
100+ ty. fold_with ( & mut BottomUpFolder {
101+ tcx : self . tcx ,
102+ // Normalize all references to immutable.
103+ ty_op : |ty| match ty. kind {
104+ ty:: Ref ( _, pointee, _) => {
105+ self . tcx . mk_imm_ref ( self . tcx . lifetimes . re_erased , pointee)
106+ }
107+ _ => ty,
108+ } ,
109+ // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
110+ // lifetimes in invariant positions could matter (e.g. through associated types).
111+ // But that just means we miss some potential incompatible types, it will not
112+ // lead to wrong errors.
113+ lt_op : |_| self . tcx . lifetimes . re_erased ,
114+ // Evaluate consts.
115+ ct_op : |ct| ct. eval ( self . tcx , self . param_env ) ,
116+ } )
117+ } ;
118+ normalize ( src) == normalize ( dest)
119+ }
118120}
119121
120122impl < ' a , ' tcx > Visitor < ' tcx > for TypeChecker < ' a , ' tcx > {
@@ -138,7 +140,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
138140 // LHS and RHS of the assignment must have the same type.
139141 let left_ty = dest. ty ( & self . body . local_decls , self . tcx ) . ty ;
140142 let right_ty = rvalue. ty ( & self . body . local_decls , self . tcx ) ;
141- if !mir_assign_valid_types ( self . tcx , right_ty, left_ty) {
143+ if !self . mir_assign_valid_types ( right_ty, left_ty) {
142144 self . fail (
143145 location,
144146 format ! (
0 commit comments