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() -> usize +where + [u8; M2 + 1]: Sized, +{ + M2 +} + +fn caller() -> 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; + +struct ConstU64; + +impl Generic +where + ConstU64<{ K - 1 }>: , +{ + fn foo(self) -> u64 { + K + } +} + +impl Generic +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() -> Substs1 +where + [u8; N + 1]: , +{ + Substs1([0; N + 1]) +} +struct Substs1([u8; N + 1]) +where + [(); N + 1]: ; + +fn substs2() -> Substs1<{ M * 2 }> +where + [(); { M * 2 } + 1]: , +{ + zero_init::<{ M * 2 }>() +} + +fn substs3() -> 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() -> Substs1<{ (N) }> +where + [u8; { (N) }]: , +{ + Substs1([0; { (N) }]) +} + +struct Substs1([u8; { (N) }]) +where + [(); { (N) }]: ; + +fn substs2() -> Substs1<{ (M) }> { + zero_init::<{ (M) }>() +} + +fn substs3() -> Substs1<{ (L) }> { + substs2::<{ (L) }>() +} + +fn main() { + assert_eq!(substs3::<2>().0, [0; 2]); +}