Skip to content

Commit aeb5067

Browse files
committed
Auto merge of #100315 - compiler-errors:norm-ct-in-proj, r=lcnr
Keep going if normalized projection has unevaluated consts in `QueryNormalizer` #100312 was the wrong approach, I think this is the right one. When normalizing a type, if we see that it's a projection, we currently defer to `tcx.normalize_projection_ty`, which normalizes the projections away but doesn't touch the unevaluated constants. So now we just continue to fold the type if it has unevaluated constants so we make sure to evaluate those too, if we can. Fixes #100217 Fixes #83972 Fixes #84669 Fixes #86710 Fixes #82268 Fixes #73298
2 parents 1876544 + d2667e4 commit aeb5067

File tree

7 files changed

+299
-3
lines changed

7 files changed

+299
-3
lines changed

compiler/rustc_trait_selection/src/traits/query/normalize.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
266266
debug!("QueryNormalizer: result = {:#?}", result);
267267
debug!("QueryNormalizer: obligations = {:#?}", obligations);
268268
self.obligations.extend(obligations);
269-
Ok(result.normalized_ty)
269+
270+
let res = result.normalized_ty;
271+
// `tcx.normalize_projection_ty` may normalize to a type that still has
272+
// unevaluated consts, so keep normalizing here if that's the case.
273+
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
274+
Ok(res.try_super_fold_with(self)?)
275+
} else {
276+
Ok(res)
277+
}
270278
}
271279

272280
ty::Projection(data) => {
@@ -305,18 +313,27 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
305313
debug!("QueryNormalizer: result = {:#?}", result);
306314
debug!("QueryNormalizer: obligations = {:#?}", obligations);
307315
self.obligations.extend(obligations);
308-
Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
316+
317+
let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
309318
infcx,
310319
mapped_regions,
311320
mapped_types,
312321
mapped_consts,
313322
&self.universes,
314323
result.normalized_ty,
315-
))
324+
);
325+
// `tcx.normalize_projection_ty` may normalize to a type that still has
326+
// unevaluated consts, so keep normalizing here if that's the case.
327+
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
328+
Ok(res.try_super_fold_with(self)?)
329+
} else {
330+
Ok(res)
331+
}
316332
}
317333

318334
_ => ty.try_super_fold_with(self),
319335
})()?;
336+
320337
self.cache.insert(ty, res);
321338
Ok(res)
322339
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// build-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
trait TraitOne {
7+
const MY_NUM: usize;
8+
type MyErr: std::fmt::Debug;
9+
10+
fn do_one_stuff(arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr>;
11+
}
12+
13+
trait TraitTwo {
14+
fn do_two_stuff();
15+
}
16+
17+
impl<O: TraitOne> TraitTwo for O
18+
where
19+
[(); Self::MY_NUM]:,
20+
{
21+
fn do_two_stuff() {
22+
O::do_one_stuff([5; Self::MY_NUM]).unwrap()
23+
}
24+
}
25+
26+
struct Blargotron;
27+
28+
#[derive(Debug)]
29+
struct ErrTy<const N: usize>([(); N]);
30+
31+
impl TraitOne for Blargotron {
32+
const MY_NUM: usize = 3;
33+
type MyErr = ErrTy<{ Self::MY_NUM }>;
34+
35+
fn do_one_stuff(_arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr> {
36+
Ok(())
37+
}
38+
}
39+
40+
fn main() {
41+
Blargotron::do_two_stuff();
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// build-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
use std::convert::AsMut;
7+
use std::default::Default;
8+
9+
trait Foo: Sized {
10+
type Baz: Default + AsMut<[u8]>;
11+
fn bar() {
12+
Self::Baz::default().as_mut();
13+
}
14+
}
15+
16+
impl Foo for () {
17+
type Baz = [u8; 1 * 1];
18+
//type Baz = [u8; 1];
19+
}
20+
21+
fn main() {
22+
<() as Foo>::bar();
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// build-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
trait Collate<Op> {
7+
type Pass;
8+
type Fail;
9+
10+
fn collate(self) -> (Self::Pass, Self::Fail);
11+
}
12+
13+
impl<Op> Collate<Op> for () {
14+
type Pass = ();
15+
type Fail = ();
16+
17+
fn collate(self) -> ((), ()) {
18+
((), ())
19+
}
20+
}
21+
22+
trait CollateStep<X, Prev> {
23+
type Pass;
24+
type Fail;
25+
fn collate_step(x: X, prev: Prev) -> (Self::Pass, Self::Fail);
26+
}
27+
28+
impl<X, P, F> CollateStep<X, (P, F)> for () {
29+
type Pass = (X, P);
30+
type Fail = F;
31+
32+
fn collate_step(x: X, (p, f): (P, F)) -> ((X, P), F) {
33+
((x, p), f)
34+
}
35+
}
36+
37+
struct CollateOpImpl<const MASK: u32>;
38+
trait CollateOpStep {
39+
type NextOp;
40+
type Apply;
41+
}
42+
43+
impl<const MASK: u32> CollateOpStep for CollateOpImpl<MASK>
44+
where
45+
CollateOpImpl<{ MASK >> 1 }>: Sized,
46+
{
47+
type NextOp = CollateOpImpl<{ MASK >> 1 }>;
48+
type Apply = ();
49+
}
50+
51+
impl<H, T, Op: CollateOpStep> Collate<Op> for (H, T)
52+
where
53+
T: Collate<Op::NextOp>,
54+
Op::Apply: CollateStep<H, (T::Pass, T::Fail)>,
55+
{
56+
type Pass = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Pass;
57+
type Fail = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Fail;
58+
59+
fn collate(self) -> (Self::Pass, Self::Fail) {
60+
<Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::collate_step(self.0, self.1.collate())
61+
}
62+
}
63+
64+
fn collate<X, const MASK: u32>(x: X) -> (X::Pass, X::Fail)
65+
where
66+
X: Collate<CollateOpImpl<MASK>>,
67+
{
68+
x.collate()
69+
}
70+
71+
fn main() {
72+
dbg!(collate::<_, 5>(("Hello", (42, ('!', ())))));
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// build-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
pub trait Foo {
7+
fn foo(&self);
8+
}
9+
10+
pub struct FooImpl<const N: usize>;
11+
impl<const N: usize> Foo for FooImpl<N> {
12+
fn foo(&self) {}
13+
}
14+
15+
pub trait Bar: 'static {
16+
type Foo: Foo;
17+
fn get() -> &'static Self::Foo;
18+
}
19+
20+
struct BarImpl;
21+
impl Bar for BarImpl {
22+
type Foo = FooImpl<
23+
{
24+
{ 4 }
25+
},
26+
>;
27+
fn get() -> &'static Self::Foo {
28+
&FooImpl
29+
}
30+
}
31+
32+
pub fn boom<B: Bar>() {
33+
B::get().foo();
34+
}
35+
36+
fn main() {
37+
boom::<BarImpl>();
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// build-pass
2+
3+
#![feature(generic_const_exprs)]
4+
#![allow(incomplete_features)]
5+
6+
trait Foo {
7+
type Output;
8+
9+
fn foo() -> Self::Output;
10+
}
11+
12+
impl Foo for [u8; 3] {
13+
type Output = [u8; 1 + 2];
14+
15+
fn foo() -> [u8; 3] {
16+
[1u8; 3]
17+
}
18+
}
19+
20+
fn bug<const N: usize>()
21+
where
22+
[u8; N]: Foo,
23+
<[u8; N] as Foo>::Output: AsRef<[u8]>,
24+
{
25+
<[u8; N]>::foo().as_ref();
26+
}
27+
28+
fn main() {
29+
bug::<3>();
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// build-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
use std::marker::PhantomData;
7+
8+
fn main() {
9+
let x = FooImpl::<BarImpl<1>> { phantom: PhantomData };
10+
let _ = x.foo::<BarImpl<1>>();
11+
}
12+
13+
trait Foo<T>
14+
where
15+
T: Bar,
16+
{
17+
fn foo<U>(&self)
18+
where
19+
T: Operation<U>,
20+
<T as Operation<U>>::Output: Bar;
21+
}
22+
23+
struct FooImpl<T>
24+
where
25+
T: Bar,
26+
{
27+
phantom: PhantomData<T>,
28+
}
29+
30+
impl<T> Foo<T> for FooImpl<T>
31+
where
32+
T: Bar,
33+
{
34+
fn foo<U>(&self)
35+
where
36+
T: Operation<U>,
37+
<T as Operation<U>>::Output: Bar,
38+
{
39+
<<T as Operation<U>>::Output as Bar>::error_occurs_here();
40+
}
41+
}
42+
43+
trait Bar {
44+
fn error_occurs_here();
45+
}
46+
47+
struct BarImpl<const N: usize>;
48+
49+
impl<const N: usize> Bar for BarImpl<N> {
50+
fn error_occurs_here() {}
51+
}
52+
53+
trait Operation<Rhs> {
54+
type Output;
55+
}
56+
57+
//// Part-A: This causes error.
58+
impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N>
59+
where
60+
BarImpl<{ N + M }>: Sized,
61+
{
62+
type Output = BarImpl<{ N + M }>;
63+
}
64+
65+
//// Part-B: This doesn't cause error.
66+
// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
67+
// type Output = BarImpl<M>;
68+
// }
69+
70+
//// Part-C: This also doesn't cause error.
71+
// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
72+
// type Output = BarImpl<{ M }>;
73+
// }

0 commit comments

Comments
 (0)