Auto merge of #86130 - BoxyUwU:abstract_const_as_cast, r=oli-obk
const_eval_checked: Support as casts in abstract consts
This commit is contained in:
commit
d59b80d588
@ -1,6 +1,6 @@
|
||||
//! A subset of a mir body used for const evaluatability checking.
|
||||
use crate::mir;
|
||||
use crate::ty;
|
||||
use crate::mir::{self, CastKind};
|
||||
use crate::ty::{self, Ty};
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// An index into an `AbstractConst`.
|
||||
@ -17,6 +17,7 @@ pub enum Node<'tcx> {
|
||||
Binop(mir::BinOp, NodeId, NodeId),
|
||||
UnaryOp(mir::UnOp, NodeId),
|
||||
FunctionCall(NodeId, &'tcx [NodeId]),
|
||||
Cast(CastKind, NodeId, Ty<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
|
@ -156,6 +156,7 @@ fn visit_abstract_const_expr(
|
||||
let leaf = leaf.subst(tcx, ct.substs);
|
||||
self.visit_const(leaf)
|
||||
}
|
||||
ACNode::Cast(_, _, ty) => self.visit_ty(ty),
|
||||
ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
|
@ -97,6 +97,16 @@ enum FailureKind {
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
Node::Cast(_, _, ty) => {
|
||||
let ty = ty.subst(tcx, ct.substs);
|
||||
if ty.has_infer_types_or_consts() {
|
||||
failure_kind = FailureKind::MentionsInfer;
|
||||
} else if ty.has_param_types_or_consts() {
|
||||
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
|
||||
}
|
||||
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
@ -304,6 +314,9 @@ fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId {
|
||||
self.nodes[func].used = true;
|
||||
nodes.iter().for_each(|&n| self.nodes[n].used = true);
|
||||
}
|
||||
Node::Cast(_, operand, _) => {
|
||||
self.nodes[operand].used = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes start as unused.
|
||||
@ -408,11 +421,19 @@ fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorRe
|
||||
self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
|
||||
Ok(())
|
||||
}
|
||||
Rvalue::Cast(cast_kind, ref operand, ty) => {
|
||||
let operand = self.operand_to_node(span, operand)?;
|
||||
self.locals[local] =
|
||||
self.add_node(Node::Cast(cast_kind, operand, ty), span);
|
||||
Ok(())
|
||||
}
|
||||
_ => self.error(Some(span), "unsupported rvalue")?,
|
||||
}
|
||||
}
|
||||
// These are not actually relevant for us here, so we can ignore them.
|
||||
StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()),
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_) => Ok(()),
|
||||
_ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
|
||||
}
|
||||
}
|
||||
@ -594,6 +615,7 @@ fn recurse<'tcx, R>(
|
||||
recurse(tcx, ct.subtree(func), f)?;
|
||||
args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
|
||||
}
|
||||
Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
|
||||
}
|
||||
}
|
||||
|
||||
@ -676,6 +698,11 @@ pub(super) fn try_unify<'tcx>(
|
||||
&& iter::zip(a_args, b_args)
|
||||
.all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
|
||||
}
|
||||
(Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
|
||||
if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
|
||||
{
|
||||
try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -838,6 +838,7 @@ fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
let leaf = leaf.subst(self.tcx, ct.substs);
|
||||
self.visit_const(leaf)
|
||||
}
|
||||
Node::Cast(_, _, ty) => self.visit_ty(ty),
|
||||
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
@ -859,6 +860,7 @@ fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::Br
|
||||
let leaf = leaf.subst(self.tcx, ct.substs);
|
||||
self.visit_const(leaf)
|
||||
}
|
||||
Node::Cast(_, _, ty) => self.visit_ty(ty),
|
||||
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
#![feature(const_evaluatable_checked, const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Foo<const N: u8>([u8; N as usize])
|
||||
where
|
||||
[(); N as usize]:;
|
||||
|
||||
struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 2) as usize]:;
|
||||
|
||||
// unifying with subtrees
|
||||
struct Evaluatable<const N: u16>;
|
||||
fn foo<const N: u8>() where Evaluatable<{N as usize as u16 }>: {
|
||||
let _ = Foo::<N>([1; N as usize]);
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,20 @@
|
||||
#![feature(const_evaluatable_checked, const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Evaluatable<const N: u128> {}
|
||||
|
||||
struct Foo<const N: u8>([u8; N as usize])
|
||||
//~^ Error: unconstrained generic constant
|
||||
//~| help: try adding a `where` bound using this expression: `where [(); N as usize]:`
|
||||
where
|
||||
Evaluatable<{N as u128}>:;
|
||||
|
||||
struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
|
||||
//~^ Error: unconstrained generic constant
|
||||
//~| help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
|
||||
|
||||
struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
|
||||
//~^ Error: unconstrained generic constant
|
||||
//~| help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,26 @@
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-2.rs:6:25
|
||||
|
|
||||
LL | struct Foo<const N: u8>([u8; N as usize])
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); N as usize]:`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-2.rs:12:26
|
||||
|
|
||||
LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-2.rs:16:25
|
||||
|
|
||||
LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -0,0 +1,47 @@
|
||||
#![feature(const_generics, const_evaluatable_checked)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait {}
|
||||
pub struct EvaluatableU128<const N: u128>;
|
||||
|
||||
struct HasCastInTraitImpl<const N: usize, const M: u128>;
|
||||
impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
|
||||
pub fn use_trait_impl<const N: usize>()
|
||||
where
|
||||
[(); { N + 1}]:,
|
||||
EvaluatableU128<{N as u128}>:, {
|
||||
fn assert_impl<T: Trait>() {}
|
||||
|
||||
// errors are bad but seems to be pre-existing issue #86198
|
||||
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
//~^ Error: mismatched types
|
||||
//~^^ Error: unconstrained generic constant
|
||||
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
//~^ Error: mismatched types
|
||||
//~^^ Error: unconstrained generic constant
|
||||
assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
|
||||
//~^ Error: mismatched types
|
||||
assert_impl::<HasCastInTraitImpl<14, 13>>();
|
||||
//~^ Error: mismatched types
|
||||
}
|
||||
pub fn use_trait_impl_2<const N: usize>()
|
||||
where
|
||||
[(); { N + 1}]:,
|
||||
EvaluatableU128<{N as _}>:, {
|
||||
fn assert_impl<T: Trait>() {}
|
||||
|
||||
// errors are bad but seems to be pre-existing issue #86198
|
||||
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
//~^ Error: mismatched types
|
||||
//~^^ Error: unconstrained generic constant
|
||||
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
//~^ Error: mismatched types
|
||||
//~^^ Error: unconstrained generic constant
|
||||
assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
|
||||
//~^ Error: mismatched types
|
||||
assert_impl::<HasCastInTraitImpl<14, 13>>();
|
||||
//~^ Error: mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,139 @@
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-3.rs:17:5
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ----- required by this bound in `use_trait_impl::assert_impl`
|
||||
...
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
|
||||
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
||||
|
|
||||
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:17:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as u128 }`
|
||||
found type `{ O as u128 }`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-3.rs:20:5
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ----- required by this bound in `use_trait_impl::assert_impl`
|
||||
...
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
|
||||
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
||||
|
|
||||
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:20:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as _ }`
|
||||
found type `{ O as u128 }`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:23:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
|
||||
|
|
||||
= note: expected type `12_u128`
|
||||
found type `13_u128`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:25:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
|
||||
|
|
||||
= note: expected type `13_u128`
|
||||
found type `14_u128`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-3.rs:35:5
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ----- required by this bound in `use_trait_impl_2::assert_impl`
|
||||
...
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
|
||||
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
||||
|
|
||||
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:35:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as u128 }`
|
||||
found type `{ O as u128 }`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/abstract-const-as-cast-3.rs:38:5
|
||||
|
|
||||
LL | fn assert_impl<T: Trait>() {}
|
||||
| ----- required by this bound in `use_trait_impl_2::assert_impl`
|
||||
...
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
|
||||
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
|
||||
--> $DIR/abstract-const-as-cast-3.rs:8:22
|
||||
|
|
||||
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:38:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
|
||||
|
|
||||
= note: expected type `{ N as _ }`
|
||||
found type `{ O as u128 }`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:41:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
|
||||
|
|
||||
= note: expected type `12_u128`
|
||||
found type `13_u128`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/abstract-const-as-cast-3.rs:43:5
|
||||
|
|
||||
LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
|
||||
|
|
||||
= note: expected type `13_u128`
|
||||
found type `14_u128`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -0,0 +1,29 @@
|
||||
// check-pass
|
||||
#![feature(const_evaluatable_checked, const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait {}
|
||||
pub struct EvaluatableU128<const N: u128>;
|
||||
|
||||
struct HasCastInTraitImpl<const N: usize, const M: u128>;
|
||||
impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
|
||||
|
||||
pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, {
|
||||
fn assert_impl<T: Trait>() {}
|
||||
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
|
||||
assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
|
||||
assert_impl::<HasCastInTraitImpl<13, 13>>();
|
||||
}
|
||||
pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, {
|
||||
fn assert_impl<T: Trait>() {}
|
||||
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
|
||||
assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
|
||||
assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
|
||||
assert_impl::<HasCastInTraitImpl<13, 13>>();
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user