Skip to content

Commit 2a6ff72

Browse files
committed
Auto merge of #107434 - BoxyUwU:nll_const_equate, r=compiler-errors
emit `ConstEquate` in `TypeRelating<D>` emitting `ConstEquate` during mir typeck is useful since it can help catch bugs in hir typeck incase our impl of `ConstEquate` is wrong. doing this did actually catch a bug, when relating `Expr::Call` we `==` the types of all the argument consts which spuriously returns false if the type contains const projections/aliases which causes us to fall through to the `expected_found` error arm. Generally its an ICE if the `Const`'s `Ty`s arent equal but `ConstKind::Expr` is kind of special since they are sort of like const items that are `const CALL<F: const Fn(...), const N: F>` though we dont actually explicitly represent the `F` type param explicitly in `Expr::Call` so I just made us relate the `Const`'s ty field to avoid getting ICEs from the tests I added and the following existing test: ```rust // tests/ui/const-generics/generic_const_exprs/different-fn.rs #![feature(generic_const_exprs)] #![allow(incomplete_features)] use std::mem::size_of; use std::marker::PhantomData; struct Foo<T>(PhantomData<T>); fn test<T>() -> [u8; size_of::<T>()] { [0; size_of::<Foo<T>>()] //~^ ERROR unconstrained generic constant //~| ERROR mismatched types } fn main() { test::<u32>(); } ``` which has us relate two `ConstKind::Value` one for the fn item of `size_of::<Foo<T>>` and one for the fn item of `size_of::<T>()`, these only differ by their `Ty` and if we don't relate the `Ty` we'll end up getting an ICE from the checks that ensure the `ty` fields always match. In theory `Expr::UnOp` has the same problem so I added a call to `relate` for the ty's, although I was unable to create a repro test.
2 parents 50d3ba5 + d85d906 commit 2a6ff72

File tree

6 files changed

+92
-21
lines changed

6 files changed

+92
-21
lines changed

compiler/rustc_infer/src/infer/nll_relate/mod.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -817,12 +817,13 @@ impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
817817
where
818818
D: TypeRelatingDelegate<'tcx>,
819819
{
820-
fn const_equate_obligation(&mut self, _a: ty::Const<'tcx>, _b: ty::Const<'tcx>) {
821-
// We don't have to worry about the equality of consts during borrow checking
822-
// as consts always have a static lifetime.
823-
// FIXME(oli-obk): is this really true? We can at least have HKL and with
824-
// inline consts we may have further lifetimes that may be unsound to treat as
825-
// 'static.
820+
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
821+
self.delegate.register_obligations(vec![Obligation::new(
822+
self.tcx(),
823+
ObligationCause::dummy(),
824+
self.param_env(),
825+
ty::Binder::dummy(ty::PredicateKind::ConstEquate(a, b)),
826+
)]);
826827
}
827828
}
828829

compiler/rustc_middle/src/ty/relate.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,8 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
629629
b = tcx.expand_abstract_consts(b);
630630
}
631631

632+
debug!("{}.super_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
633+
632634
// Currently, the values that can be unified are primitive types,
633635
// and those that derive both `PartialEq` and `Eq`, corresponding
634636
// to structural-match types.
@@ -665,30 +667,28 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
665667

666668
// FIXME(generic_const_exprs): is it possible to relate two consts which are not identical
667669
// exprs? Should we care about that?
670+
// FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to
671+
// ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought
672+
// of as being generic over the argument types, however this is implicit so these types don't get
673+
// related when we relate the substs of the item this const arg is for.
668674
let expr = match (ae, be) {
669-
(Expr::Binop(a_op, al, ar), Expr::Binop(b_op, bl, br))
670-
if a_op == b_op && al.ty() == bl.ty() && ar.ty() == br.ty() =>
671-
{
675+
(Expr::Binop(a_op, al, ar), Expr::Binop(b_op, bl, br)) if a_op == b_op => {
676+
r.relate(al.ty(), bl.ty())?;
677+
r.relate(ar.ty(), br.ty())?;
672678
Expr::Binop(a_op, r.consts(al, bl)?, r.consts(ar, br)?)
673679
}
674-
(Expr::UnOp(a_op, av), Expr::UnOp(b_op, bv))
675-
if a_op == b_op && av.ty() == bv.ty() =>
676-
{
680+
(Expr::UnOp(a_op, av), Expr::UnOp(b_op, bv)) if a_op == b_op => {
681+
r.relate(av.ty(), bv.ty())?;
677682
Expr::UnOp(a_op, r.consts(av, bv)?)
678683
}
679-
(Expr::Cast(ak, av, at), Expr::Cast(bk, bv, bt))
680-
if ak == bk && av.ty() == bv.ty() =>
681-
{
684+
(Expr::Cast(ak, av, at), Expr::Cast(bk, bv, bt)) if ak == bk => {
685+
r.relate(av.ty(), bv.ty())?;
682686
Expr::Cast(ak, r.consts(av, bv)?, r.tys(at, bt)?)
683687
}
684688
(Expr::FunctionCall(af, aa), Expr::FunctionCall(bf, ba))
685-
if aa.len() == ba.len()
686-
&& af.ty() == bf.ty()
687-
&& aa
688-
.iter()
689-
.zip(ba.iter())
690-
.all(|(a_arg, b_arg)| a_arg.ty() == b_arg.ty()) =>
689+
if aa.len() == ba.len() =>
691690
{
691+
r.relate(af.ty(), bf.ty())?;
692692
let func = r.consts(af, bf)?;
693693
let mut related_args = Vec::with_capacity(aa.len());
694694
for (a_arg, b_arg) in aa.iter().zip(ba.iter()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// checks that when we relate a `Expr::Binop` we also relate the types of the
2+
// const arguments.
3+
#![feature(generic_const_exprs)]
4+
#![allow(incomplete_features)]
5+
6+
struct Bar<const B: bool>;
7+
8+
const fn make_generic(_: usize, a: bool) -> bool {
9+
a
10+
}
11+
12+
fn foo<const N: usize>() -> Bar<{ make_generic(N, true == false) }> {
13+
Bar::<{ make_generic(N, 1_u8 == 0_u8) }>
14+
//~^ error: mismatched types
15+
//~| error: unconstrained generic constant
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/relate_binop_arg_tys.rs:13:5
3+
|
4+
LL | Bar::<{ make_generic(N, 1_u8 == 0_u8) }>
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ make_generic(N, true == false) }`, found `{ make_generic(N, 1_u8 == 0_u8) }`
6+
|
7+
= note: expected constant `{ make_generic(N, true == false) }`
8+
found constant `{ make_generic(N, 1_u8 == 0_u8) }`
9+
10+
error: unconstrained generic constant
11+
--> $DIR/relate_binop_arg_tys.rs:13:11
12+
|
13+
LL | Bar::<{ make_generic(N, 1_u8 == 0_u8) }>
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
|
16+
= help: try adding a `where` bound using this expression: `where [(); { make_generic(N, 1_u8 == 0_u8) }]:`
17+
18+
error: aborting due to 2 previous errors
19+
20+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// checks that when we relate a `Expr::Cast` we also relate the type of the
2+
// const argument.
3+
#![feature(generic_const_exprs)]
4+
#![allow(incomplete_features)]
5+
6+
fn foo<const N: usize>() -> [(); (true as usize) + N] {
7+
[(); (1_u8 as usize) + N]
8+
//~^ error: mismatched types
9+
//~| error: unconstrained generic constant
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/relate_cast_arg_ty.rs:7:5
3+
|
4+
LL | [(); (1_u8 as usize) + N]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(true as usize) + N`, found `(1_u8 as usize) + N`
6+
|
7+
= note: expected constant `(true as usize) + N`
8+
found constant `(1_u8 as usize) + N`
9+
10+
error: unconstrained generic constant
11+
--> $DIR/relate_cast_arg_ty.rs:7:10
12+
|
13+
LL | [(); (1_u8 as usize) + N]
14+
| ^^^^^^^^^^^^^^^^^^^
15+
|
16+
= help: try adding a `where` bound using this expression: `where [(); (1_u8 as usize) + N]:`
17+
18+
error: aborting due to 2 previous errors
19+
20+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)