diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index c9e58c2aa734..93d48184b42a 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -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 `::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() { let _ = [0; bar::()]; }` the repeat count + /// constant `bar::()` 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, + span: Option, + ) -> 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> { diff --git a/src/librustc_infer/traits/fulfill.rs b/src/librustc_infer/traits/fulfill.rs index 6055b0e74df5..28d3f2691801 100644 --- a/src/librustc_infer/traits/fulfill.rs +++ b/src/librustc_infer/traits/fulfill.rs @@ -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))), } } } diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_infer/traits/select.rs index 371268b5ee47..4572b3c026e8 100644 --- a/src/librustc_infer/traits/select.rs +++ b/src/librustc_infer/traits/select.rs @@ -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), } } }