about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-05-31 15:02:33 +0200
committerRalf Jung <post@ralfj.de>2020-06-22 09:19:08 +0200
commit93e3552d040edfa67cdedfe2fe4a44fe0c4ead59 (patch)
treeb3a3b7bbc7e42c73a915832e644f14d87359a95d /src
parent50d7deac4de3bfde44a634ff4dabf3115f694c79 (diff)
downloadrust-93e3552d040edfa67cdedfe2fe4a44fe0c4ead59.tar.gz
rust-93e3552d040edfa67cdedfe2fe4a44fe0c4ead59.zip
also normalize constants when comparing types
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/interpret/eval_context.rs1
-rw-r--r--src/librustc_mir/transform/validate.rs68
2 files changed, 36 insertions, 33 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 22f4691c22b..1a6ed41ba47 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -239,6 +239,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
     // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
     //    with their late-bound lifetimes are still around and can lead to type differences.
     // Normalize both of them away.
+    // Also see the related but slightly different pre-monomorphization method in `transform/validate.rs`.
     let normalize = |ty: Ty<'tcx>| {
         ty.fold_with(&mut BottomUpFolder {
             tcx,
diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs
index 051ce9e6b1e..14c67c2372c 100644
--- a/src/librustc_mir/transform/validate.rs
+++ b/src/librustc_mir/transform/validate.rs
@@ -81,40 +81,42 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             self.fail(location, format!("encountered jump to invalid basic block {:?}", bb))
         }
     }
-}
 
-/// Check if src can be assigned into dest.
-/// This is not precise, it will accept some incorrect assignments.
-fn mir_assign_valid_types<'tcx>(tcx: TyCtxt<'tcx>, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
-    if src == dest {
-        // Equal types, all is good.
-        return true;
-    }
+    /// Check if src can be assigned into dest.
+    /// This is not precise, it will accept some incorrect assignments.
+    fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
+        if src == dest {
+            // Equal types, all is good.
+            return true;
+        }
 
-    // Type-changing assignments can happen for (at least) two reasons:
-    // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
-    // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
-    //    with their late-bound lifetimes are still around and can lead to type differences.
-    // Normalize both of them away.
-    // FIXME: Share this code with `interpret/eval_context.rs`.
-    let normalize = |ty: Ty<'tcx>| {
-        ty.fold_with(&mut BottomUpFolder {
-            tcx,
-            // Normalize all references to immutable.
-            ty_op: |ty| match ty.kind {
-                ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee),
-                _ => ty,
-            },
-            // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
-            // lifetimes in invariant positions could matter (e.g. through associated types).
-            // But that just means we miss some potential incompatible types, it will not
-            // lead to wrong errors.
-            lt_op: |_| tcx.lifetimes.re_erased,
-            // Leave consts unchanged.
-            ct_op: |ct| ct,
-        })
-    };
-    normalize(src) == normalize(dest)
+        // Type-changing assignments can happen for (at least) two reasons:
+        // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
+        // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
+        //    with their late-bound lifetimes are still around and can lead to type differences.
+        // Normalize both of them away.
+        // Also see the related but slightly different post-monomorphization method in `interpret/eval_context.rs`.
+        let normalize = |ty: Ty<'tcx>| {
+            ty.fold_with(&mut BottomUpFolder {
+                tcx: self.tcx,
+                // Normalize all references to immutable.
+                ty_op: |ty| match ty.kind {
+                    ty::Ref(_, pointee, _) => {
+                        self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, pointee)
+                    }
+                    _ => ty,
+                },
+                // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
+                // lifetimes in invariant positions could matter (e.g. through associated types).
+                // But that just means we miss some potential incompatible types, it will not
+                // lead to wrong errors.
+                lt_op: |_| self.tcx.lifetimes.re_erased,
+                // Evaluate consts.
+                ct_op: |ct| ct.eval(self.tcx, self.param_env),
+            })
+        };
+        normalize(src) == normalize(dest)
+    }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
@@ -138,7 +140,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 // LHS and RHS of the assignment must have the same type.
                 let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
                 let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
-                if !mir_assign_valid_types(self.tcx, right_ty, left_ty) {
+                if !self.mir_assign_valid_types(right_ty, left_ty) {
                     self.fail(
                         location,
                         format!(