Add expand_abstract_const
Adds the ability to directly expand a const to an expr without having to deal with intermediate steps.
This commit is contained in:
parent
f9750c1554
commit
5bb1a9febc
11 changed files with 124 additions and 174 deletions
|
@ -29,8 +29,7 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
let tcx = infcx.tcx;
|
||||
let uv = match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => uv,
|
||||
// should be recursivee fixes.
|
||||
ty::ConstKind::Expr(..) => todo!(),
|
||||
ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"),
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
|
@ -40,10 +39,7 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
};
|
||||
|
||||
if tcx.features().generic_const_exprs {
|
||||
let substs = tcx.erase_regions(uv.substs);
|
||||
if let Some(ct) =
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(uv.def), substs)?
|
||||
{
|
||||
if let Some(ct) = tcx.expand_abstract_consts(ct)? {
|
||||
if satisfied_from_param_env(tcx, infcx, ct, param_env)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -74,17 +70,13 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
//
|
||||
// See #74595 for more details about this.
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||
|
||||
let substs = tcx.erase_regions(uv.substs);
|
||||
match concrete {
|
||||
// If we're evaluating a foreign constant, under a nightly compiler without generic
|
||||
// const exprs, AND it would've passed if that expression had been evaluated with
|
||||
// generic const exprs, then suggest using generic const exprs.
|
||||
// If we're evaluating a generic foreign constant, under a nightly compiler while
|
||||
// the current crate does not enable `feature(generic_const_exprs)`, abort
|
||||
// compilation with a useful error.
|
||||
Err(_) if tcx.sess.is_nightly_build()
|
||||
&& let Ok(Some(ct)) =
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(uv.def), substs)
|
||||
&& let ty::ConstKind::Expr(_expr) = ct.kind()
|
||||
&& satisfied_from_param_env(tcx, infcx, ct, param_env) == Ok(true) => {
|
||||
&& let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
|
||||
&& let ty::ConstKind::Expr(_) = ac.kind() => {
|
||||
tcx.sess
|
||||
.struct_span_fatal(
|
||||
// Slightly better span than just using `span` alone
|
||||
|
@ -126,46 +118,43 @@ fn satisfied_from_param_env<'tcx>(
|
|||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<bool, NotConstEvaluatable> {
|
||||
// Try to unify with each subtree in the AbstractConst to allow for
|
||||
// `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
|
||||
// predicate for `(N + 1) * 2`
|
||||
struct Visitor<'a, 'tcx> {
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
}
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||
type BreakTy = ();
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if c.ty() == self.ct.ty()
|
||||
&& let Ok(_nested_obligations) = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.eq(c, self.ct)
|
||||
{
|
||||
ControlFlow::BREAK
|
||||
} else if let ty::ConstKind::Expr(e) = c.kind() {
|
||||
e.visit_with(self)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for pred in param_env.caller_bounds() {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::ConstEvaluatable(uv) => {
|
||||
let ty::ConstKind::Unevaluated(uv) = uv.kind() else {
|
||||
ty::PredicateKind::ConstEvaluatable(ce) => {
|
||||
let ty::ConstKind::Unevaluated(_) = ce.kind() else {
|
||||
continue
|
||||
};
|
||||
let substs = tcx.erase_regions(uv.substs);
|
||||
let Some(b_ct) =
|
||||
tcx.expand_bound_abstract_const(tcx.bound_abstract_const(uv.def), substs)? else {
|
||||
return Ok(false);
|
||||
let Some(b_ct) = tcx.expand_abstract_consts(ce)? else {
|
||||
continue
|
||||
};
|
||||
|
||||
// Try to unify with each subtree in the AbstractConst to allow for
|
||||
// `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
|
||||
// predicate for `(N + 1) * 2`
|
||||
struct Visitor<'a, 'tcx> {
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
}
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||
type BreakTy = ();
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if c.ty() == self.ct.ty()
|
||||
&& let Ok(_nested_obligations) = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.eq(c, self.ct)
|
||||
{
|
||||
//let obligations = nested_obligations.into_obligations();
|
||||
ControlFlow::BREAK
|
||||
} else if let ty::ConstKind::Expr(e) = c.kind() {
|
||||
e.visit_with(self)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut v = Visitor { ct, infcx, param_env };
|
||||
let result = b_ct.visit_with(&mut v);
|
||||
|
||||
|
|
|
@ -478,14 +478,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(a.def),
|
||||
a.substs,
|
||||
),
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(b.def),
|
||||
b.substs,
|
||||
),
|
||||
tcx.expand_abstract_consts(c1),
|
||||
tcx.expand_abstract_consts(c2),
|
||||
) && a.ty() == b.ty() &&
|
||||
let Ok(new_obligations) = infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
|
@ -534,7 +528,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(c1, c2)
|
||||
{
|
||||
Ok(_) => ProcessResult::Changed(vec![]),
|
||||
Ok(inf_ok) => {
|
||||
ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
|
||||
}
|
||||
Err(err) => ProcessResult::Error(
|
||||
FulfillmentErrorCode::CodeConstEquateError(
|
||||
ExpectedFound::new(true, c1, c2),
|
||||
|
|
|
@ -849,11 +849,8 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
|||
//
|
||||
// This shouldn't really matter though as we can't really use any
|
||||
// constants which are not considered const evaluatable.
|
||||
if let ty::ConstKind::Unevaluated(uv) = ct.kind() &&
|
||||
let Ok(Some(ct)) = self
|
||||
.tcx
|
||||
.expand_bound_abstract_const(self.tcx.bound_abstract_const(uv.def), uv.substs)
|
||||
{
|
||||
if let ty::ConstKind::Unevaluated(_uv) = ct.kind() &&
|
||||
let Ok(Some(ct)) = self.tcx.expand_abstract_consts(ct){
|
||||
self.visit_const(ct)
|
||||
} else {
|
||||
ct.super_visit_with(self)
|
||||
|
|
|
@ -668,19 +668,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// if the constants depend on generic parameters.
|
||||
//
|
||||
// Let's just see where this breaks :shrug:
|
||||
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
|
||||
if let (ty::ConstKind::Unevaluated(_), ty::ConstKind::Unevaluated(_)) =
|
||||
(c1.kind(), c2.kind())
|
||||
{
|
||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(a.def),
|
||||
a.substs,
|
||||
),
|
||||
tcx.expand_bound_abstract_const(
|
||||
tcx.bound_abstract_const(b.def),
|
||||
b.substs,
|
||||
),
|
||||
) && a.ty() == b.ty() && let Ok(new_obligations) =
|
||||
tcx.expand_abstract_consts(c1),
|
||||
tcx.expand_abstract_consts(c2),
|
||||
) && a.ty() == b.ty() && let Ok(new_obligations) =
|
||||
self.infcx.at(&obligation.cause, obligation.param_env).eq(a, b)
|
||||
{
|
||||
let mut obligations = new_obligations.obligations;
|
||||
|
@ -718,7 +712,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(c1, c2)
|
||||
{
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Ok(inf_ok) => self.evaluate_predicates_recursively(
|
||||
previous_stack,
|
||||
inf_ok.into_obligations(),
|
||||
),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue