Rollup merge of #105339 - BoxyUwU:wf_ct_kind_expr, r=TaKO8Ki
support `ConstKind::Expr` in `is_const_evaluatable` and `WfPredicates::compute` Fixes #105205 Currently we haven't implemented a way to evaluate `ConstKind::Expr(Expr::Binop(Add, 1, 2))` so I just left that with a `FIXME` and a `delay_span_bug` since I have no idea how to do that and it would make this a much larger (and more complicated) PR :P
This commit is contained in:
commit
762d2545f4
@ -25,15 +25,13 @@ use crate::traits::ObligationCtxt;
|
||||
#[instrument(skip(infcx), level = "debug")]
|
||||
pub fn is_const_evaluatable<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ct: ty::Const<'tcx>,
|
||||
unexpanded_ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<(), NotConstEvaluatable> {
|
||||
let tcx = infcx.tcx;
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
// FIXME(generic_const_exprs): this seems wrong but I couldn't find a way to get this to trigger
|
||||
ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"),
|
||||
match unexpanded_ct.kind() {
|
||||
ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (),
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
@ -43,7 +41,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
};
|
||||
|
||||
if tcx.features().generic_const_exprs {
|
||||
let ct = tcx.expand_abstract_consts(ct);
|
||||
let ct = tcx.expand_abstract_consts(unexpanded_ct);
|
||||
|
||||
let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
|
||||
tcx.def_kind(uv.def.did) == DefKind::AnonConst
|
||||
@ -62,18 +60,40 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||
match concrete {
|
||||
Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error(
|
||||
infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(span, "Missing value for constant, but no error reported?"),
|
||||
)),
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||
Ok(_) => Ok(()),
|
||||
match unexpanded_ct.kind() {
|
||||
ty::ConstKind::Expr(_) => {
|
||||
// FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but
|
||||
// currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it
|
||||
// is evaluatable or not. For now we just ICE until this is implemented this.
|
||||
Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug(
|
||||
span,
|
||||
"evaluating `ConstKind::Expr` is not currently supported",
|
||||
)))
|
||||
}
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||
match concrete {
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
|
||||
span,
|
||||
"Missing value for constant, but no error reported?",
|
||||
)))
|
||||
}
|
||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
|
||||
}
|
||||
} else {
|
||||
let uv = match unexpanded_ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
ty::ConstKind::Expr(_) => {
|
||||
bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled")
|
||||
}
|
||||
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
|
||||
};
|
||||
|
||||
// FIXME: We should only try to evaluate a given constant here if it is fully concrete
|
||||
// as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
|
||||
//
|
||||
@ -92,7 +112,7 @@ pub fn is_const_evaluatable<'tcx>(
|
||||
&& satisfied_from_param_env(
|
||||
tcx,
|
||||
infcx,
|
||||
tcx.expand_abstract_consts(ct),
|
||||
tcx.expand_abstract_consts(unexpanded_ct),
|
||||
param_env,
|
||||
) =>
|
||||
{
|
||||
@ -152,6 +172,7 @@ fn satisfied_from_param_env<'tcx>(
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||
type BreakTy = ();
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!("is_const_evaluatable: candidate={:?}", c);
|
||||
if let Ok(()) = self.infcx.commit_if_ok(|_| {
|
||||
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
|
||||
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
|
||||
@ -187,7 +208,7 @@ fn satisfied_from_param_env<'tcx>(
|
||||
let result = b_ct.visit_with(&mut v);
|
||||
|
||||
if let ControlFlow::Break(()) = result {
|
||||
debug!("is_const_evaluatable: abstract_const ~~> ok");
|
||||
debug!("is_const_evaluatable: yes");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -195,5 +216,6 @@ fn satisfied_from_param_env<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
debug!("is_const_evaluatable: no");
|
||||
false
|
||||
}
|
||||
|
@ -476,9 +476,24 @@ impl<'tcx> WfPredicates<'tcx> {
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())),
|
||||
));
|
||||
}
|
||||
// FIXME(generic_const_exprs): This seems wrong but I could not find a way to get this to trigger
|
||||
ty::ConstKind::Expr(_) => {
|
||||
bug!("checking wfness of `ConstKind::Expr` is unsupported")
|
||||
// FIXME(generic_const_exprs): this doesnt verify that given `Expr(N + 1)` the
|
||||
// trait bound `typeof(N): Add<typeof(1)>` holds. This is currently unnecessary
|
||||
// as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated`
|
||||
// which means that the `DefId` would have been typeck'd elsewhere. However in
|
||||
// the future we may allow directly lowering to `ConstKind::Expr` in which case
|
||||
// we would not be proving bounds we should.
|
||||
|
||||
let predicate =
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct));
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
self.tcx(),
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
predicate,
|
||||
));
|
||||
}
|
||||
|
||||
ty::ConstKind::Error(_)
|
||||
|
@ -0,0 +1,22 @@
|
||||
#![feature(generic_const_exprs, generic_arg_infer)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// minimized repro for #105205
|
||||
//
|
||||
// the `foo::<_, L>` call results in a `WellFormed(_)` obligation and a
|
||||
// `ConstEvaluatable(Unevaluated(_ + 1 + L))` obligation. Attempting to fulfill the latter
|
||||
// unifies the `_` with `Expr(L - 1)` from the paramenv which turns the `WellFormed`
|
||||
// obligation into `WellFormed(Expr(L - 1))`
|
||||
|
||||
fn foo<const N: usize, const M: usize>(_: [(); N + 1 + M]) {}
|
||||
|
||||
fn ice<const L: usize>()
|
||||
where
|
||||
[(); (L - 1) + 1 + L]:,
|
||||
{
|
||||
foo::<_, L>([(); L + 1 + L]);
|
||||
//~^ ERROR: mismatched types
|
||||
//~^^ ERROR: unconstrained generic constant
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,20 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/wf_obligation.rs:17:17
|
||||
|
|
||||
LL | foo::<_, L>([(); L + 1 + L]);
|
||||
| ^^^^^^^^^^^^^^^ expected `N + 1 + M`, found `L + 1 + L`
|
||||
|
|
||||
= note: expected constant `N + 1 + M`
|
||||
found constant `L + 1 + L`
|
||||
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/wf_obligation.rs:17:22
|
||||
|
|
||||
LL | foo::<_, L>([(); L + 1 + L]);
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user