Skip to content

Commit 31a0251

Browse files
committed
use type folder + normalization for MIR assignment type-checking
1 parent 441fd22 commit 31a0251

File tree

2 files changed

+29
-78
lines changed

2 files changed

+29
-78
lines changed

src/librustc_mir/transform/validate.rs

+19-78
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ use rustc_middle::{
77
BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
88
TerminatorKind,
99
},
10-
ty::{
11-
self,
12-
relate::{Relate, RelateResult, TypeRelation},
13-
ParamEnv, Ty, TyCtxt,
14-
},
10+
ty::{self, fold::BottomUpFolder, ParamEnv, Ty, TyCtxt, TypeFoldable},
1511
};
1612

1713
#[derive(Copy, Clone, Debug)]
@@ -49,79 +45,24 @@ pub fn equal_up_to_regions(
4945
return true;
5046
}
5147

52-
struct LifetimeIgnoreRelation<'tcx> {
53-
tcx: TyCtxt<'tcx>,
54-
param_env: ty::ParamEnv<'tcx>,
55-
}
56-
57-
impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> {
58-
fn tcx(&self) -> TyCtxt<'tcx> {
59-
self.tcx
60-
}
61-
62-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
63-
self.param_env
64-
}
65-
66-
fn tag(&self) -> &'static str {
67-
"librustc_mir::transform::validate"
68-
}
69-
70-
fn a_is_expected(&self) -> bool {
71-
true
72-
}
73-
74-
fn relate_with_variance<T: Relate<'tcx>>(
75-
&mut self,
76-
_: ty::Variance,
77-
a: T,
78-
b: T,
79-
) -> RelateResult<'tcx, T> {
80-
// Ignore variance, require types to be exactly the same.
81-
self.relate(a, b)
82-
}
83-
84-
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
85-
if a == b {
86-
// Short-circuit.
87-
return Ok(a);
88-
}
89-
ty::relate::super_relate_tys(self, a, b)
90-
}
91-
92-
fn regions(
93-
&mut self,
94-
a: ty::Region<'tcx>,
95-
_b: ty::Region<'tcx>,
96-
) -> RelateResult<'tcx, ty::Region<'tcx>> {
97-
// Ignore regions.
98-
Ok(a)
99-
}
100-
101-
fn consts(
102-
&mut self,
103-
a: &'tcx ty::Const<'tcx>,
104-
b: &'tcx ty::Const<'tcx>,
105-
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
106-
ty::relate::super_relate_consts(self, a, b)
107-
}
108-
109-
fn binders<T>(
110-
&mut self,
111-
a: ty::Binder<T>,
112-
b: ty::Binder<T>,
113-
) -> RelateResult<'tcx, ty::Binder<T>>
114-
where
115-
T: Relate<'tcx>,
116-
{
117-
self.relate(a.skip_binder(), b.skip_binder())?;
118-
Ok(a)
119-
}
120-
}
121-
122-
// Instantiate and run relation.
123-
let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env };
124-
relator.relate(src, dest).is_ok()
48+
// Normalize lifetimes away on both sides, then compare.
49+
let param_env = param_env.with_reveal_all_normalized(tcx);
50+
let normalize = |ty: Ty<'tcx>| {
51+
tcx.normalize_erasing_regions(
52+
param_env,
53+
ty.fold_with(&mut BottomUpFolder {
54+
tcx,
55+
// We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
56+
// lifetimes in invariant positions could matter (e.g. through associated types).
57+
// We rely on the fact that layout was confirmed to be equal above.
58+
lt_op: |_| tcx.lifetimes.re_erased,
59+
// Leave consts and types unchanged.
60+
ct_op: |ct| ct,
61+
ty_op: |ty| ty,
62+
}),
63+
)
64+
};
65+
normalize(src) == normalize(dest)
12566
}
12667

12768
struct TypeChecker<'a, 'tcx> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// build-pass
2+
//! This used to fail MIR validation due to the types on both sides of an assignment not being equal.
3+
//! The failure doesn't occur with a check-only build.
4+
fn iter_slice<'a, T>(xs: &'a [T]) -> impl Iterator<Item = &'a T> {
5+
xs.iter()
6+
}
7+
8+
fn main() {
9+
iter_slice::<()> as fn(_) -> _;
10+
}

0 commit comments

Comments
 (0)