Keep going if normalized projection has unevaluated consts in QueryNormalizer

This commit is contained in:
Michael Goulet 2022-08-09 09:41:23 +00:00
parent 6f18f0a9d4
commit ca7e3c4a83
7 changed files with 287 additions and 1 deletions

View File

@ -194,7 +194,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
// wait to fold the substs.
// Wrap this in a closure so we don't accidentally return from the outer function
let res = (|| match *ty.kind() {
let mut res = (|| match *ty.kind() {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
@ -317,6 +317,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
_ => ty.try_super_fold_with(self),
})()?;
// `tcx.normalize_projection_ty` may normalize to a type that still has
// unevaluated consts, so keep normalizing here if that's the case.
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
res = res.try_super_fold_with(self)?;
}
self.cache.insert(ty, res);
Ok(res)
}

View File

@ -0,0 +1,42 @@
// build-pass
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
trait TraitOne {
const MY_NUM: usize;
type MyErr: std::fmt::Debug;
fn do_one_stuff(arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr>;
}
trait TraitTwo {
fn do_two_stuff();
}
impl<O: TraitOne> TraitTwo for O
where
[(); Self::MY_NUM]:,
{
fn do_two_stuff() {
O::do_one_stuff([5; Self::MY_NUM]).unwrap()
}
}
struct Blargotron;
#[derive(Debug)]
struct ErrTy<const N: usize>([(); N]);
impl TraitOne for Blargotron {
const MY_NUM: usize = 3;
type MyErr = ErrTy<{ Self::MY_NUM }>;
fn do_one_stuff(_arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr> {
Ok(())
}
}
fn main() {
Blargotron::do_two_stuff();
}

View File

@ -0,0 +1,23 @@
// build-pass
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
use std::convert::AsMut;
use std::default::Default;
trait Foo: Sized {
type Baz: Default + AsMut<[u8]>;
fn bar() {
Self::Baz::default().as_mut();
}
}
impl Foo for () {
type Baz = [u8; 1 * 1];
//type Baz = [u8; 1];
}
fn main() {
<() as Foo>::bar();
}

View File

@ -0,0 +1,73 @@
// build-pass
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
trait Collate<Op> {
type Pass;
type Fail;
fn collate(self) -> (Self::Pass, Self::Fail);
}
impl<Op> Collate<Op> for () {
type Pass = ();
type Fail = ();
fn collate(self) -> ((), ()) {
((), ())
}
}
trait CollateStep<X, Prev> {
type Pass;
type Fail;
fn collate_step(x: X, prev: Prev) -> (Self::Pass, Self::Fail);
}
impl<X, P, F> CollateStep<X, (P, F)> for () {
type Pass = (X, P);
type Fail = F;
fn collate_step(x: X, (p, f): (P, F)) -> ((X, P), F) {
((x, p), f)
}
}
struct CollateOpImpl<const MASK: u32>;
trait CollateOpStep {
type NextOp;
type Apply;
}
impl<const MASK: u32> CollateOpStep for CollateOpImpl<MASK>
where
CollateOpImpl<{ MASK >> 1 }>: Sized,
{
type NextOp = CollateOpImpl<{ MASK >> 1 }>;
type Apply = ();
}
impl<H, T, Op: CollateOpStep> Collate<Op> for (H, T)
where
T: Collate<Op::NextOp>,
Op::Apply: CollateStep<H, (T::Pass, T::Fail)>,
{
type Pass = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Pass;
type Fail = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Fail;
fn collate(self) -> (Self::Pass, Self::Fail) {
<Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::collate_step(self.0, self.1.collate())
}
}
fn collate<X, const MASK: u32>(x: X) -> (X::Pass, X::Fail)
where
X: Collate<CollateOpImpl<MASK>>,
{
x.collate()
}
fn main() {
dbg!(collate::<_, 5>(("Hello", (42, ('!', ())))));
}

View File

@ -0,0 +1,38 @@
// build-pass
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
pub trait Foo {
fn foo(&self);
}
pub struct FooImpl<const N: usize>;
impl<const N: usize> Foo for FooImpl<N> {
fn foo(&self) {}
}
pub trait Bar: 'static {
type Foo: Foo;
fn get() -> &'static Self::Foo;
}
struct BarImpl;
impl Bar for BarImpl {
type Foo = FooImpl<
{
{ 4 }
},
>;
fn get() -> &'static Self::Foo {
&FooImpl
}
}
pub fn boom<B: Bar>() {
B::get().foo();
}
fn main() {
boom::<BarImpl>();
}

View File

@ -0,0 +1,30 @@
// build-pass
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
trait Foo {
type Output;
fn foo() -> Self::Output;
}
impl Foo for [u8; 3] {
type Output = [u8; 1 + 2];
fn foo() -> [u8; 3] {
[1u8; 3]
}
}
fn bug<const N: usize>()
where
[u8; N]: Foo,
<[u8; N] as Foo>::Output: AsRef<[u8]>,
{
<[u8; N]>::foo().as_ref();
}
fn main() {
bug::<3>();
}

View File

@ -0,0 +1,73 @@
// build-pass
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
use std::marker::PhantomData;
fn main() {
let x = FooImpl::<BarImpl<1>> { phantom: PhantomData };
let _ = x.foo::<BarImpl<1>>();
}
trait Foo<T>
where
T: Bar,
{
fn foo<U>(&self)
where
T: Operation<U>,
<T as Operation<U>>::Output: Bar;
}
struct FooImpl<T>
where
T: Bar,
{
phantom: PhantomData<T>,
}
impl<T> Foo<T> for FooImpl<T>
where
T: Bar,
{
fn foo<U>(&self)
where
T: Operation<U>,
<T as Operation<U>>::Output: Bar,
{
<<T as Operation<U>>::Output as Bar>::error_occurs_here();
}
}
trait Bar {
fn error_occurs_here();
}
struct BarImpl<const N: usize>;
impl<const N: usize> Bar for BarImpl<N> {
fn error_occurs_here() {}
}
trait Operation<Rhs> {
type Output;
}
//// Part-A: This causes error.
impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N>
where
BarImpl<{ N + M }>: Sized,
{
type Output = BarImpl<{ N + M }>;
}
//// Part-B: This doesn't cause error.
// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
// type Output = BarImpl<M>;
// }
//// Part-C: This also doesn't cause error.
// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
// type Output = BarImpl<{ M }>;
// }