support Expr
in is_const_evaluatable
and compute
This commit is contained in:
parent
344889e963
commit
c9bab74fb2
@ -25,15 +25,13 @@ use crate::traits::ObligationCtxt;
|
|||||||
#[instrument(skip(infcx), level = "debug")]
|
#[instrument(skip(infcx), level = "debug")]
|
||||||
pub fn is_const_evaluatable<'tcx>(
|
pub fn is_const_evaluatable<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
ct: ty::Const<'tcx>,
|
unexpanded_ct: ty::Const<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<(), NotConstEvaluatable> {
|
) -> Result<(), NotConstEvaluatable> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let uv = match ct.kind() {
|
match unexpanded_ct.kind() {
|
||||||
ty::ConstKind::Unevaluated(uv) => uv,
|
ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (),
|
||||||
// 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:?}"),
|
|
||||||
ty::ConstKind::Param(_)
|
ty::ConstKind::Param(_)
|
||||||
| ty::ConstKind::Bound(_, _)
|
| ty::ConstKind::Bound(_, _)
|
||||||
| ty::ConstKind::Placeholder(_)
|
| ty::ConstKind::Placeholder(_)
|
||||||
@ -43,7 +41,7 @@ pub fn is_const_evaluatable<'tcx>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if tcx.features().generic_const_exprs {
|
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() {
|
let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
|
||||||
tcx.def_kind(uv.def.did) == DefKind::AnonConst
|
tcx.def_kind(uv.def.did) == DefKind::AnonConst
|
||||||
@ -62,18 +60,40 @@ pub fn is_const_evaluatable<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||||
match concrete {
|
match concrete {
|
||||||
Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error(
|
Err(ErrorHandled::TooGeneric) => {
|
||||||
infcx
|
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
|
||||||
.tcx
|
span,
|
||||||
.sess
|
"Missing value for constant, but no error reported?",
|
||||||
.delay_span_bug(span, "Missing value for constant, but no error reported?"),
|
)))
|
||||||
)),
|
}
|
||||||
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
|
||||||
|
}
|
||||||
} else {
|
} 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
|
// 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>()]`.
|
// 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(
|
&& satisfied_from_param_env(
|
||||||
tcx,
|
tcx,
|
||||||
infcx,
|
infcx,
|
||||||
tcx.expand_abstract_consts(ct),
|
tcx.expand_abstract_consts(unexpanded_ct),
|
||||||
param_env,
|
param_env,
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
@ -152,6 +172,7 @@ fn satisfied_from_param_env<'tcx>(
|
|||||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||||
type BreakTy = ();
|
type BreakTy = ();
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::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(|_| {
|
if let Ok(()) = self.infcx.commit_if_ok(|_| {
|
||||||
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
|
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
|
||||||
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
|
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);
|
let result = b_ct.visit_with(&mut v);
|
||||||
|
|
||||||
if let ControlFlow::Break(()) = result {
|
if let ControlFlow::Break(()) = result {
|
||||||
debug!("is_const_evaluatable: abstract_const ~~> ok");
|
debug!("is_const_evaluatable: yes");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,5 +216,6 @@ fn satisfied_from_param_env<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("is_const_evaluatable: no");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -476,9 +476,24 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())),
|
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(_) => {
|
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(_)
|
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