about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs24
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs22
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs32
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs32
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs26
5 files changed, 132 insertions, 4 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index ad229e03b0b..272588ad516 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -609,9 +609,27 @@ where
 /// Tries to unify two abstract constants using structural equality.
 pub(super) fn try_unify<'tcx>(
     tcx: TyCtxt<'tcx>,
-    a: AbstractConst<'tcx>,
-    b: AbstractConst<'tcx>,
+    mut a: AbstractConst<'tcx>,
+    mut b: AbstractConst<'tcx>,
 ) -> bool {
+    while let Node::Leaf(a_ct) = a.root() {
+        let a_ct = a_ct.subst(tcx, a.substs);
+        match AbstractConst::from_const(tcx, a_ct) {
+            Ok(Some(a_act)) => a = a_act,
+            Ok(None) => break,
+            Err(_) => return true,
+        }
+    }
+
+    while let Node::Leaf(b_ct) = b.root() {
+        let b_ct = b_ct.subst(tcx, b.substs);
+        match AbstractConst::from_const(tcx, b_ct) {
+            Ok(Some(b_act)) => b = b_act,
+            Ok(None) => break,
+            Err(_) => return true,
+        }
+    }
+
     match (a.root(), b.root()) {
         (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
             let a_ct = a_ct.subst(tcx, a.substs);
@@ -632,8 +650,6 @@ pub(super) fn try_unify<'tcx>(
                 // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
                 // means that we only allow inference variables if they are equal.
                 (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
-                // We may want to instead recurse into unevaluated constants here. That may require some
-                // care to prevent infinite recursion, so let's just ignore this for now.
                 (
                     ty::ConstKind::Unevaluated(a_def, a_substs, None),
                     ty::ConstKind::Unevaluated(b_def, b_substs, None),
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs
new file mode 100644
index 00000000000..124cd317da5
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+fn callee<const M2: usize>() -> usize
+where
+    [u8; M2 + 1]: Sized,
+{
+    M2
+}
+
+fn caller<const N1: usize>() -> usize
+where
+    [u8; N1 + 1]: Sized,
+    [u8; (N1 + 1) + 1]: Sized,
+{
+    callee::<{ N1 + 1 }>()
+}
+
+fn main() {
+    assert_eq!(caller::<4>(), 5);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs
new file mode 100644
index 00000000000..5936662dadb
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs
@@ -0,0 +1,32 @@
+// run-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Generic<const K: u64>;
+
+struct ConstU64<const K: u64>;
+
+impl<const K: u64> Generic<K>
+where
+    ConstU64<{ K - 1 }>: ,
+{
+    fn foo(self) -> u64 {
+        K
+    }
+}
+
+impl<const K: u64> Generic<K>
+where
+    ConstU64<{ K - 1 }>: ,
+    ConstU64<{ K + 1 }>: ,
+    ConstU64<{ K + 1 - 1 }>: ,
+{
+    fn bar(self) -> u64 {
+        let x: Generic<{ K + 1 }> = Generic;
+        x.foo()
+    }
+}
+
+fn main() {
+    assert_eq!((Generic::<10>).bar(), 11);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs
new file mode 100644
index 00000000000..ff0f2efaee9
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs
@@ -0,0 +1,32 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+fn zero_init<const N: usize>() -> Substs1<N>
+where
+    [u8; N + 1]: ,
+{
+    Substs1([0; N + 1])
+}
+struct Substs1<const N: usize>([u8; N + 1])
+where
+    [(); N + 1]: ;
+
+fn substs2<const M: usize>() -> Substs1<{ M * 2 }>
+where
+    [(); { M * 2 } + 1]: ,
+{
+    zero_init::<{ M * 2 }>()
+}
+
+fn substs3<const L: usize>() -> Substs1<{ (L - 1) * 2 }>
+where
+    [(); (L - 1)]: ,
+    [(); (L - 1) * 2 + 1]: ,
+{
+    substs2::<{ L - 1 }>()
+}
+
+fn main() {
+    assert_eq!(substs3::<2>().0, [0; 3]);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs
new file mode 100644
index 00000000000..806f7ba9203
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs
@@ -0,0 +1,26 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features, unused_parens, unused_braces)]
+
+fn zero_init<const N: usize>() -> Substs1<{ (N) }>
+where
+    [u8; { (N) }]: ,
+{
+    Substs1([0; { (N) }])
+}
+
+struct Substs1<const N: usize>([u8; { (N) }])
+where
+    [(); { (N) }]: ;
+
+fn substs2<const M: usize>() -> Substs1<{ (M) }> {
+    zero_init::<{ (M) }>()
+}
+
+fn substs3<const L: usize>() -> Substs1<{ (L) }> {
+    substs2::<{ (L) }>()
+}
+
+fn main() {
+    assert_eq!(substs3::<2>().0, [0; 2]);
+}