about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-08-11 10:47:48 +0000
committerbors <bors@rust-lang.org>2022-08-11 10:47:48 +0000
commitaeb5067967ef58e4a324b19dd0dba2f385d5959f (patch)
tree3169c9fba086a5386eee71fe238953d770da70cf
parent187654481fd828e495919295369d33827f10e1c4 (diff)
parentd2667e4b718e3ded742a095e79eec92beb9bbbd6 (diff)
downloadrust-aeb5067967ef58e4a324b19dd0dba2f385d5959f.tar.gz
rust-aeb5067967ef58e4a324b19dd0dba2f385d5959f.zip
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
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs23
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-100217.rs42
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-73298.rs23
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-82268.rs73
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-83972.rs38
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-84669.rs30
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-86710.rs73
7 files changed, 299 insertions, 3 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 38b3a4b7253..61c556b726d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -266,7 +266,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-                Ok(result.normalized_ty)
+
+                let res = result.normalized_ty;
+                // `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) {
+                    Ok(res.try_super_fold_with(self)?)
+                } else {
+                    Ok(res)
+                }
             }
 
             ty::Projection(data) => {
@@ -305,18 +313,27 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-                Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+
+                let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
                     infcx,
                     mapped_regions,
                     mapped_types,
                     mapped_consts,
                     &self.universes,
                     result.normalized_ty,
-                ))
+                );
+                // `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) {
+                    Ok(res.try_super_fold_with(self)?)
+                } else {
+                    Ok(res)
+                }
             }
 
             _ => ty.try_super_fold_with(self),
         })()?;
+
         self.cache.insert(ty, res);
         Ok(res)
     }
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs b/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs
new file mode 100644
index 00000000000..acdc348a385
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs
@@ -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();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs b/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs
new file mode 100644
index 00000000000..3c59e1b790a
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs
@@ -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();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs b/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs
new file mode 100644
index 00000000000..d08fc5beb75
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs
@@ -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, ('!', ())))));
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs b/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs
new file mode 100644
index 00000000000..0063719b852
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs
@@ -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>();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs b/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs
new file mode 100644
index 00000000000..3933ff20a49
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs
@@ -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>();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs b/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs
new file mode 100644
index 00000000000..bdd8a21b3b9
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs
@@ -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 }>;
+// }