mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +00:00
Rollup merge of #81426 - BoxyUwU:boxychangesv2, r=oli-obk
const_evaluatable: expand abstract consts in try_unify See this [zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/260443-project-const-generics/topic/combining.20const.20bounds) for more info cc ```@lcnr``` r? ```@oli-obk```
This commit is contained in:
commit
f183e5f04c
@ -609,9 +609,29 @@ where
|
|||||||
/// Tries to unify two abstract constants using structural equality.
|
/// Tries to unify two abstract constants using structural equality.
|
||||||
pub(super) fn try_unify<'tcx>(
|
pub(super) fn try_unify<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
a: AbstractConst<'tcx>,
|
mut a: AbstractConst<'tcx>,
|
||||||
b: AbstractConst<'tcx>,
|
mut b: AbstractConst<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
// We substitute generics repeatedly to allow AbstractConsts to unify where a
|
||||||
|
// ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
|
||||||
|
// Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
|
||||||
|
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()) {
|
match (a.root(), b.root()) {
|
||||||
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
|
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
|
||||||
let a_ct = a_ct.subst(tcx, a.substs);
|
let a_ct = a_ct.subst(tcx, a.substs);
|
||||||
@ -632,8 +652,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
|
// 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.
|
// 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,
|
(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(a_def, a_substs, None),
|
||||||
ty::ConstKind::Unevaluated(b_def, b_substs, None),
|
ty::ConstKind::Unevaluated(b_def, b_substs, None),
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the ``(N1 + 1) + 1`` bound on ``caller`` satisfies the ``M2 + 1`` bound on ``callee``
|
@ -0,0 +1,35 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the ``ConstU64<{ K + 1 - 1}>`` bound on ``bar``'s impl block satisfies the
|
||||||
|
// ``ConstU64<{K - 1}>`` bound on ``foo``'s impl block
|
@ -0,0 +1,35 @@
|
|||||||
|
// 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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the ``{ (L - 1) * 2 + 1 }`` bound on ``substs3`` satisfies the
|
||||||
|
// ``{ N + 1 }`` bound on ``Substs1``
|
@ -0,0 +1,29 @@
|
|||||||
|
// 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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the implicit ``{ (L) }`` bound on ``substs3`` satisfies the
|
||||||
|
// ``{ (N) }`` bound on ``Substs1``
|
Loading…
Reference in New Issue
Block a user