diff options
| author | Ralf Jung <post@ralfj.de> | 2020-05-31 15:02:33 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2020-06-22 09:19:08 +0200 |
| commit | 93e3552d040edfa67cdedfe2fe4a44fe0c4ead59 (patch) | |
| tree | b3a3b7bbc7e42c73a915832e644f14d87359a95d /src | |
| parent | 50d7deac4de3bfde44a634ff4dabf3115f694c79 (diff) | |
| download | rust-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.rs | 1 | ||||
| -rw-r--r-- | src/librustc_mir/transform/validate.rs | 68 |
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!( |
