Canonicalize inputs to const eval where needed.

This commit is contained in:
Ben Lewis 2020-01-24 20:05:07 +13:00
parent a2fb0c28be
commit f77f07c55b
3 changed files with 50 additions and 35 deletions

View File

@ -15,6 +15,8 @@ use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToTy
use rustc::middle::free_region::RegionRelations;
use rustc::middle::lang_items;
use rustc::middle::region;
use rustc::mir;
use rustc::mir::interpret::ConstEvalResult;
use rustc::session::config::BorrowckMode;
use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use rustc::ty::fold::{TypeFoldable, TypeFolder};
@ -63,6 +65,7 @@ pub mod resolve;
mod sub;
pub mod type_variable;
use crate::infer::canonical::OriginalQueryValues;
pub use rustc::infer::unify_key;
#[must_use]
@ -1565,6 +1568,35 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.universe.set(u);
u
}
/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
/// substitutions and environment are used to resolve the constant. Alternatively if the
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
/// returned.
///
/// This handles inferences variables within both `param_env` and `substs` by
/// performing the operation on their respective canonical forms.
pub fn const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
substs: SubstsRef<'tcx>,
promoted: Option<mir::Promoted>,
span: Option<Span>,
) -> ConstEvalResult<'tcx> {
let mut original_values = OriginalQueryValues::default();
let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values);
let (param_env, substs) = canonical.value;
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, span)
}
}
pub struct ShallowResolver<'a, 'tcx> {

View File

@ -510,27 +510,15 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
}
ty::Predicate::ConstEvaluatable(def_id, substs) => {
if obligation.param_env.has_local_value() {
ProcessResult::Unchanged
} else {
if !substs.has_local_value() {
match self.selcx.tcx().const_eval_resolve(
obligation.param_env,
def_id,
substs,
None,
Some(obligation.cause.span),
) {
Ok(_) => ProcessResult::Changed(vec![]),
Err(err) => {
ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err)))
}
}
} else {
pending_obligation.stalled_on =
substs.types().map(|ty| infer_ty(ty)).collect();
ProcessResult::Unchanged
}
match self.selcx.infcx().const_eval_resolve(
obligation.param_env,
def_id,
substs,
None,
Some(obligation.cause.span),
) {
Ok(_) => ProcessResult::Changed(vec![]),
Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
}
}
}

View File

@ -532,20 +532,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::Predicate::ConstEvaluatable(def_id, substs) => {
if !(obligation.param_env, substs).has_local_value() {
match self.tcx().const_eval_resolve(
obligation.param_env,
def_id,
substs,
None,
None,
) {
Ok(_) => Ok(EvaluatedToOk),
Err(_) => Ok(EvaluatedToErr),
}
} else {
// Inference variables still left in param_env or substs.
Ok(EvaluatedToAmbig)
match self.tcx().const_eval_resolve(
obligation.param_env,
def_id,
substs,
None,
None,
) {
Ok(_) => Ok(EvaluatedToOk),
Err(_) => Ok(EvaluatedToErr),
}
}
}