Consolidate type system const evaluation under traits::evaluate_const
mew
This commit is contained in:
parent
81eef2d362
commit
bea0148ac6
31 changed files with 434 additions and 569 deletions
|
@ -15,7 +15,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
|
|||
use rustc_type_ir::TypingMode;
|
||||
use rustc_type_ir::solve::{Certainty, NoSolution};
|
||||
|
||||
use crate::traits::specialization_graph;
|
||||
use crate::traits::{EvaluateConstErr, specialization_graph};
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
|
||||
|
@ -77,20 +77,19 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
|
||||
}
|
||||
|
||||
fn try_const_eval_resolve(
|
||||
fn evaluate_const(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
unevaluated: ty::UnevaluatedConst<'tcx>,
|
||||
uv: ty::UnevaluatedConst<'tcx>,
|
||||
) -> Option<ty::Const<'tcx>> {
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
|
||||
Ok(Ok(val)) => Some(ty::Const::new_value(
|
||||
self.tcx,
|
||||
val,
|
||||
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
|
||||
)),
|
||||
Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None,
|
||||
Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())),
|
||||
let ct = ty::Const::new_unevaluated(self.tcx, uv);
|
||||
|
||||
match crate::traits::try_evaluate_const(&self.0, ct, param_env) {
|
||||
Ok(ct) => Some(ct),
|
||||
Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
|
||||
Err(
|
||||
EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
|
||||
) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ use std::iter;
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::{Region, RegionVid};
|
||||
use tracing::debug;
|
||||
use ty::TypingMode;
|
||||
|
@ -761,23 +760,20 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
ty::PredicateKind::ConstEquate(c1, c2) => {
|
||||
let evaluate = |c: ty::Const<'tcx>| {
|
||||
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
|
||||
match selcx.infcx.const_eval_resolve(
|
||||
let ct = super::try_evaluate_const(
|
||||
selcx.infcx,
|
||||
c,
|
||||
obligation.param_env,
|
||||
unevaluated,
|
||||
obligation.cause.span,
|
||||
) {
|
||||
Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))),
|
||||
Ok(Err(_)) => {
|
||||
let tcx = self.tcx;
|
||||
let reported =
|
||||
tcx.dcx().emit_err(UnableToConstructConstantValue {
|
||||
span: tcx.def_span(unevaluated.def),
|
||||
unevaluated,
|
||||
});
|
||||
Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
);
|
||||
|
||||
if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct {
|
||||
self.tcx.dcx().emit_err(UnableToConstructConstantValue {
|
||||
span: self.tcx.def_span(unevaluated.def),
|
||||
unevaluated,
|
||||
});
|
||||
}
|
||||
|
||||
ct
|
||||
} else {
|
||||
Ok(c)
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::EvaluateConstErr;
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
/// Check if a given constant can be evaluated.
|
||||
|
@ -68,16 +68,18 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
// here.
|
||||
tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported");
|
||||
}
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv, span);
|
||||
match concrete {
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
ty::ConstKind::Unevaluated(_) => {
|
||||
match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
|
||||
Err(EvaluateConstErr::HasGenericsOrInfers) => {
|
||||
Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
"Missing value for constant, but no error reported?",
|
||||
)))
|
||||
}
|
||||
Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
|
||||
Err(
|
||||
EvaluateConstErr::EvaluationFailure(e)
|
||||
| EvaluateConstErr::InvalidConstParamTy(e),
|
||||
) => Err(NotConstEvaluatable::Error(e.into())),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
@ -92,16 +94,7 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
_ => 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>()]`.
|
||||
//
|
||||
// We previously did not check this, so we only emit a future compat warning if
|
||||
// const evaluation succeeds and the given constant is still polymorphic for now
|
||||
// and hopefully soon change this to an error.
|
||||
//
|
||||
// See #74595 for more details about this.
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv, span);
|
||||
match concrete {
|
||||
match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
|
||||
// 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.
|
||||
|
@ -130,7 +123,7 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
.emit()
|
||||
}
|
||||
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
Err(EvaluateConstErr::HasGenericsOrInfers) => {
|
||||
let err = if uv.has_non_region_infer() {
|
||||
NotConstEvaluatable::MentionsInfer
|
||||
} else if uv.has_non_region_param() {
|
||||
|
@ -145,7 +138,9 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
|
||||
Err(err)
|
||||
}
|
||||
Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
|
||||
Err(
|
||||
EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e),
|
||||
) => Err(NotConstEvaluatable::Error(e.into())),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ use rustc_infer::traits::{
|
|||
TraitEngine,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
|
||||
|
@ -26,6 +25,7 @@ use super::{
|
|||
};
|
||||
use crate::error_reporting::InferCtxtErrorExt;
|
||||
use crate::infer::{InferCtxt, TyOrConstInferVar};
|
||||
use crate::traits::EvaluateConstErr;
|
||||
use crate::traits::normalize::normalize_with_depth_to;
|
||||
use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
|
@ -664,23 +664,25 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
|
||||
let mut evaluate = |c: Const<'tcx>| {
|
||||
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
|
||||
match self.selcx.infcx.try_const_eval_resolve(
|
||||
match super::try_evaluate_const(
|
||||
self.selcx.infcx,
|
||||
c,
|
||||
obligation.param_env,
|
||||
unevaluated,
|
||||
obligation.cause.span,
|
||||
) {
|
||||
Ok(val) => Ok(val),
|
||||
Err(e) => {
|
||||
match e {
|
||||
ErrorHandled::TooGeneric(..) => {
|
||||
stalled_on.extend(unevaluated.args.iter().filter_map(
|
||||
TyOrConstInferVar::maybe_from_generic_arg,
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Err(e)
|
||||
e @ Err(EvaluateConstErr::HasGenericsOrInfers) => {
|
||||
stalled_on.extend(
|
||||
unevaluated
|
||||
.args
|
||||
.iter()
|
||||
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
|
||||
);
|
||||
e
|
||||
}
|
||||
e @ Err(
|
||||
EvaluateConstErr::EvaluationFailure(_)
|
||||
| EvaluateConstErr::InvalidConstParamTy(_),
|
||||
) => e,
|
||||
}
|
||||
} else {
|
||||
Ok(c)
|
||||
|
@ -707,14 +709,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
(Err(ErrorHandled::Reported(reported, _)), _)
|
||||
| (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error(
|
||||
FulfillmentErrorCode::Select(SelectionError::NotConstEvaluatable(
|
||||
NotConstEvaluatable::Error(reported.into()),
|
||||
)),
|
||||
),
|
||||
(Err(ErrorHandled::TooGeneric(_)), _)
|
||||
| (_, Err(ErrorHandled::TooGeneric(_))) => {
|
||||
(Err(EvaluateConstErr::InvalidConstParamTy(e)), _)
|
||||
| (_, Err(EvaluateConstErr::InvalidConstParamTy(e))) => {
|
||||
ProcessResult::Error(FulfillmentErrorCode::Select(
|
||||
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
|
||||
))
|
||||
}
|
||||
(Err(EvaluateConstErr::EvaluationFailure(e)), _)
|
||||
| (_, Err(EvaluateConstErr::EvaluationFailure(e))) => {
|
||||
ProcessResult::Error(FulfillmentErrorCode::Select(
|
||||
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
|
||||
))
|
||||
}
|
||||
(Err(EvaluateConstErr::HasGenericsOrInfers), _)
|
||||
| (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
|
||||
if c1.has_non_region_infer() || c2.has_non_region_infer() {
|
||||
ProcessResult::Unchanged
|
||||
} else {
|
||||
|
|
|
@ -27,6 +27,7 @@ use std::fmt::Debug;
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
pub use rustc_infer::traits::*;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::span_bug;
|
||||
|
@ -34,11 +35,11 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
|||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode,
|
||||
Upcast,
|
||||
self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
|
||||
TypeSuperVisitable, TypingMode, Upcast,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
pub use self::coherence::{
|
||||
|
@ -366,11 +367,23 @@ pub fn normalize_param_env_or_error<'tcx>(
|
|||
if c.has_escaping_bound_vars() {
|
||||
return ty::Const::new_misc_error(self.0);
|
||||
}
|
||||
|
||||
// While it is pretty sus to be evaluating things with an empty param env, it
|
||||
// should actually be okay since without `feature(generic_const_exprs)` the only
|
||||
// const arguments that have a non-empty param env are array repeat counts. These
|
||||
// do not appear in the type system though.
|
||||
c.normalize_internal(self.0, ty::ParamEnv::empty())
|
||||
if let ty::ConstKind::Unevaluated(uv) = c.kind()
|
||||
&& self.0.def_kind(uv.def) == DefKind::AnonConst
|
||||
{
|
||||
let infcx = self.0.infer_ctxt().build(TypingMode::non_body_analysis());
|
||||
let c = evaluate_const(&infcx, c, ty::ParamEnv::empty());
|
||||
// We should never wind up with any `infcx` local state when normalizing anon consts
|
||||
// under min const generics.
|
||||
assert!(!c.has_infer() && !c.has_placeholders());
|
||||
return c;
|
||||
}
|
||||
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,6 +487,198 @@ pub fn normalize_param_env_or_error<'tcx>(
|
|||
ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EvaluateConstErr {
|
||||
/// The constant being evaluated was either a generic parameter or inference variable, *or*,
|
||||
/// some unevaluated constant with either generic parameters or inference variables in its
|
||||
/// generic arguments.
|
||||
HasGenericsOrInfers,
|
||||
/// The type this constant evalauted to is not valid for use in const generics. This should
|
||||
/// always result in an error when checking the constant is correctly typed for the parameter
|
||||
/// it is an argument to, so a bug is delayed when encountering this.
|
||||
InvalidConstParamTy(ErrorGuaranteed),
|
||||
/// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`).
|
||||
/// This is also used when the constant was already tainted by error.
|
||||
EvaluationFailure(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
|
||||
// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
|
||||
// normalization scheme
|
||||
/// Evaluates a type system constant returning a `ConstKind::Error` in cases where CTFE failed and
|
||||
/// returning the passed in constant if it was not fully concrete (i.e. depended on generic parameters
|
||||
/// or inference variables)
|
||||
///
|
||||
/// You should not call this function unless you are implementing normalization itself. Prefer to use
|
||||
/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
|
||||
pub fn evaluate_const<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> ty::Const<'tcx> {
|
||||
match try_evaluate_const(infcx, ct, param_env) {
|
||||
Ok(ct) => ct,
|
||||
Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => {
|
||||
ty::Const::new_error(infcx.tcx, e)
|
||||
}
|
||||
Err(EvaluateConstErr::HasGenericsOrInfers) => ct,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
|
||||
// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
|
||||
// normalization scheme
|
||||
/// Evaluates a type system constant making sure to not allow constants that depend on generic parameters
|
||||
/// or inference variables to succeed in evaluating.
|
||||
///
|
||||
/// You should not call this function unless you are implementing normalization itself. Prefer to use
|
||||
/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
|
||||
#[instrument(level = "debug", skip(infcx), ret)]
|
||||
pub fn try_evaluate_const<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ct: ty::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<ty::Const<'tcx>, EvaluateConstErr> {
|
||||
let tcx = infcx.tcx;
|
||||
let ct = infcx.resolve_vars_if_possible(ct);
|
||||
debug!(?ct);
|
||||
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Value(..) => Ok(ct),
|
||||
ty::ConstKind::Error(e) => Err(EvaluateConstErr::EvaluationFailure(e)),
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Infer(_)
|
||||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
// Postpone evaluation of constants that depend on generic parameters or inference variables.
|
||||
let (args, param_env) = if tcx.features().generic_const_exprs()
|
||||
&& uv.has_non_region_infer()
|
||||
{
|
||||
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
|
||||
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
|
||||
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
|
||||
match tcx.thir_abstract_const(uv.def) {
|
||||
Ok(Some(ct)) => {
|
||||
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
|
||||
if let Err(e) = ct.error_reported() {
|
||||
return Err(EvaluateConstErr::EvaluationFailure(e));
|
||||
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
|
||||
// If the anon const *does* actually use generic parameters or inference variables from
|
||||
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
|
||||
return Err(EvaluateConstErr::HasGenericsOrInfers);
|
||||
} else {
|
||||
(replace_param_and_infer_args_with_placeholder(tcx, uv.args), param_env)
|
||||
}
|
||||
}
|
||||
Err(_) | Ok(None) => {
|
||||
let args = GenericArgs::identity_for_item(tcx, uv.def);
|
||||
let param_env = tcx.param_env(uv.def);
|
||||
(args, param_env)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// FIXME: We don't check anything on stable as the only way we can wind up with
|
||||
// an unevaluated constant containing generic parameters is through array repeat
|
||||
// expression counts which have a future compat lint for usage of generic parameters
|
||||
// instead of a hard error.
|
||||
//
|
||||
// This codepath is however also reachable by `generic_const_exprs` and some other
|
||||
// feature gates which allow constants in the type system to use generic parameters.
|
||||
// In theory we should be checking for generic parameters here and returning an error
|
||||
// in such cases.
|
||||
(uv.args, param_env)
|
||||
};
|
||||
let uv = ty::UnevaluatedConst::new(uv.def, args);
|
||||
|
||||
// It's not *technically* correct to be revealing opaque types here as we could still be
|
||||
// before borrowchecking. However, CTFE itself uses `Reveal::All` unconditionally even during
|
||||
// typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a result we
|
||||
// always use a revealed env when resolving the instance to evaluate.
|
||||
//
|
||||
// FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
|
||||
// instead of having this logic here
|
||||
let env = tcx.erase_regions(param_env).with_reveal_all_normalized(tcx);
|
||||
let erased_uv = tcx.erase_regions(uv);
|
||||
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
match tcx.const_eval_resolve_for_typeck(env, erased_uv, DUMMY_SP) {
|
||||
Ok(Ok(val)) => Ok(ty::Const::new_value(
|
||||
tcx,
|
||||
val,
|
||||
tcx.type_of(uv.def).instantiate(tcx, uv.args),
|
||||
)),
|
||||
Ok(Err(_)) => {
|
||||
let e = tcx.dcx().delayed_bug(
|
||||
"Type system constant with non valtree'able type evaluated but no error emitted",
|
||||
);
|
||||
Err(EvaluateConstErr::InvalidConstParamTy(e))
|
||||
}
|
||||
Err(ErrorHandled::Reported(info, _)) => {
|
||||
Err(EvaluateConstErr::EvaluationFailure(info.into()))
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric(_)) => Err(EvaluateConstErr::HasGenericsOrInfers),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces args that reference param or infer variables with suitable
|
||||
/// placeholders. This function is meant to remove these param and infer
|
||||
/// args when they're not actually needed to evaluate a constant.
|
||||
fn replace_param_and_infer_args_with_placeholder<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
struct ReplaceParamAndInferWithPlaceholder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
idx: u32,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let ty::Infer(_) = t.kind() {
|
||||
let idx = {
|
||||
let idx = self.idx;
|
||||
self.idx += 1;
|
||||
idx
|
||||
};
|
||||
Ty::new_placeholder(self.tcx, ty::PlaceholderType {
|
||||
universe: ty::UniverseIndex::ROOT,
|
||||
bound: ty::BoundTy {
|
||||
var: ty::BoundVar::from_u32(idx),
|
||||
kind: ty::BoundTyKind::Anon,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
t.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if let ty::ConstKind::Infer(_) = c.kind() {
|
||||
ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst {
|
||||
universe: ty::UniverseIndex::ROOT,
|
||||
bound: ty::BoundVar::from_u32({
|
||||
let idx = self.idx;
|
||||
self.idx += 1;
|
||||
idx
|
||||
}),
|
||||
})
|
||||
} else {
|
||||
c.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
|
||||
}
|
||||
|
||||
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
|
||||
/// returns true, then either normalize encountered an error or one of the predicates did not
|
||||
/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be
|
||||
|
|
|
@ -418,8 +418,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
|||
self.selcx.infcx,
|
||||
&mut self.universes,
|
||||
constant,
|
||||
|constant| constant.normalize_internal(tcx, self.param_env),
|
||||
|constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env),
|
||||
)
|
||||
.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -342,7 +342,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
|
|||
self.infcx,
|
||||
&mut self.universes,
|
||||
constant,
|
||||
|constant| constant.normalize_internal(self.infcx.tcx, self.param_env),
|
||||
|constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
|
||||
);
|
||||
debug!(?constant, ?self.param_env);
|
||||
constant.try_super_fold_with(self)
|
||||
|
|
|
@ -403,7 +403,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let mut assume = predicate.trait_ref.args.const_at(2);
|
||||
// FIXME(min_generic_const_exprs): We should shallowly normalize this.
|
||||
if self.tcx().features().generic_const_exprs() {
|
||||
assume = assume.normalize_internal(self.tcx(), obligation.param_env);
|
||||
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
|
||||
}
|
||||
let Some(assume) =
|
||||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
|
||||
|
|
|
@ -22,7 +22,6 @@ use rustc_infer::infer::relate::TypeRelation;
|
|||
use rustc_infer::traits::{PredicateObligations, TraitObligation};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
pub use rustc_middle::traits::select::*;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::TypeErrorToStringExt;
|
||||
|
@ -50,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
|||
use crate::solve::InferCtxtSelectExt as _;
|
||||
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
|
||||
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
|
||||
use crate::traits::{ProjectionCacheKey, Unimplemented, effects};
|
||||
use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects};
|
||||
|
||||
mod _match;
|
||||
mod candidate_assembly;
|
||||
|
@ -931,11 +930,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
let evaluate = |c: ty::Const<'tcx>| {
|
||||
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
|
||||
match self.infcx.try_const_eval_resolve(
|
||||
if let ty::ConstKind::Unevaluated(_) = c.kind() {
|
||||
match crate::traits::try_evaluate_const(
|
||||
self.infcx,
|
||||
c,
|
||||
obligation.param_env,
|
||||
unevaluated,
|
||||
obligation.cause.span,
|
||||
) {
|
||||
Ok(val) => Ok(val),
|
||||
Err(e) => Err(e),
|
||||
|
@ -961,10 +960,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
(Err(ErrorHandled::Reported(..)), _)
|
||||
| (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr),
|
||||
(Err(ErrorHandled::TooGeneric(..)), _)
|
||||
| (_, Err(ErrorHandled::TooGeneric(..))) => {
|
||||
(Err(EvaluateConstErr::InvalidConstParamTy(..)), _)
|
||||
| (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr),
|
||||
(Err(EvaluateConstErr::EvaluationFailure(..)), _)
|
||||
| (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr),
|
||||
(Err(EvaluateConstErr::HasGenericsOrInfers), _)
|
||||
| (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
|
||||
if c1.has_non_region_infer() || c2.has_non_region_infer() {
|
||||
Ok(EvaluatedToAmbig)
|
||||
} else {
|
||||
|
|
|
@ -83,7 +83,7 @@ impl<'tcx> At<'_, 'tcx> {
|
|||
|
||||
Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
|
||||
} else if self.infcx.tcx.features().generic_const_exprs() {
|
||||
Ok(ct.normalize_internal(self.infcx.tcx, self.param_env))
|
||||
Ok(super::evaluate_const(&self.infcx, ct, self.param_env))
|
||||
} else {
|
||||
Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue