@@ -81,40 +81,42 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
81
81
self . fail ( location, format ! ( "encountered jump to invalid basic block {:?}" , bb) )
82
82
}
83
83
}
84
- }
85
84
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
+ }
93
92
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
+ }
118
120
}
119
121
120
122
impl < ' a , ' tcx > Visitor < ' tcx > for TypeChecker < ' a , ' tcx > {
@@ -138,7 +140,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
138
140
// LHS and RHS of the assignment must have the same type.
139
141
let left_ty = dest. ty ( & self . body . local_decls , self . tcx ) . ty ;
140
142
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) {
142
144
self . fail (
143
145
location,
144
146
format ! (
0 commit comments