Skip to content

Commit

Permalink
use type folder + normalization for MIR assignment type-checking
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Aug 11, 2020
1 parent 441fd22 commit 31a0251
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 78 deletions.
97 changes: 19 additions & 78 deletions src/librustc_mir/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ use rustc_middle::{
BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind,
},
ty::{
self,
relate::{Relate, RelateResult, TypeRelation},
ParamEnv, Ty, TyCtxt,
},
ty::{self, fold::BottomUpFolder, ParamEnv, Ty, TyCtxt, TypeFoldable},
};

#[derive(Copy, Clone, Debug)]
Expand Down Expand Up @@ -49,79 +45,24 @@ pub fn equal_up_to_regions(
return true;
}

struct LifetimeIgnoreRelation<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}

impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}

fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}

fn tag(&self) -> &'static str {
"librustc_mir::transform::validate"
}

fn a_is_expected(&self) -> bool {
true
}

fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
// Ignore variance, require types to be exactly the same.
self.relate(a, b)
}

fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
if a == b {
// Short-circuit.
return Ok(a);
}
ty::relate::super_relate_tys(self, a, b)
}

fn regions(
&mut self,
a: ty::Region<'tcx>,
_b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
// Ignore regions.
Ok(a)
}

fn consts(
&mut self,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
ty::relate::super_relate_consts(self, a, b)
}

fn binders<T>(
&mut self,
a: ty::Binder<T>,
b: ty::Binder<T>,
) -> RelateResult<'tcx, ty::Binder<T>>
where
T: Relate<'tcx>,
{
self.relate(a.skip_binder(), b.skip_binder())?;
Ok(a)
}
}

// Instantiate and run relation.
let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env };
relator.relate(src, dest).is_ok()
// Normalize lifetimes away on both sides, then compare.
let param_env = param_env.with_reveal_all_normalized(tcx);
let normalize = |ty: Ty<'tcx>| {
tcx.normalize_erasing_regions(
param_env,
ty.fold_with(&mut BottomUpFolder {
tcx,
// 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).
// We rely on the fact that layout was confirmed to be equal above.
lt_op: |_| tcx.lifetimes.re_erased,
// Leave consts and types unchanged.
ct_op: |ct| ct,
ty_op: |ty| ty,
}),
)
};
normalize(src) == normalize(dest)
}

struct TypeChecker<'a, 'tcx> {
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/mir/validation_impl_trait_lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// build-pass
//! This used to fail MIR validation due to the types on both sides of an assignment not being equal.
//! The failure doesn't occur with a check-only build.
fn iter_slice<'a, T>(xs: &'a [T]) -> impl Iterator<Item = &'a T> {
xs.iter()
}

fn main() {
iter_slice::<()> as fn(_) -> _;
}

0 comments on commit 31a0251

Please sign in to comment.