Skip to content
6 changes: 6 additions & 0 deletions src/librustc/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ macro_rules! arena_types {
Vec<rustc::traits::query::outlives_bounds::OutlivesBound<'tcx>>
>
>,
[] resolve_vtables:
rustc::infer::canonical::Canonical<'tcx,
rustc::infer::canonical::QueryResponse<'tcx,
rustc::traits::Vtable<'tcx, ()>
>
>,
[] type_op_subtype:
rustc::infer::canonical::Canonical<'tcx,
rustc::infer::canonical::QueryResponse<'tcx, ()>
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@
use crate::hir::map::DefPathHash;
use crate::ich::{Fingerprint, StableHashingContext};
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::mir::interpret::ConstEvalInput;
use crate::traits;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTraitGoal, CanonicalTyGoal,
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
Expand Down
11 changes: 3 additions & 8 deletions src/librustc/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ use crate::infer::InferCtxt;
use crate::ty::flags::FlagComputation;
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::GenericArg;
use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
use std::sync::atomic::Ordering;
use crate::ty::{self, BoundVar, InferConst, Ty, TyCtxt, TypeFlags};

use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::Idx;
use smallvec::SmallVec;
use std::sync::atomic::Ordering;

impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// Canonicalizes a query value `V`. When we canonicalize a query,
Expand Down Expand Up @@ -496,12 +496,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {

// Fast path: nothing that needs to be canonicalized.
if !value.has_type_flags(needs_canonical_flags) {
let canon_value = Canonical {
max_universe: ty::UniverseIndex::ROOT,
variables: List::empty(),
value: value.clone(),
};
return canon_value;
return Canonical::empty(value.clone());
}

let mut canonicalizer = Canonicalizer {
Expand Down
13 changes: 13 additions & 0 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,19 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
}
}

impl<'tcx, V: TypeFoldable<'tcx>> Canonical<'tcx, V> {
/// Construct a canonical `value` with an empty set of variables
/// in the `ROOT` universe.
pub fn empty(value: V) -> Canonical<'tcx, V> {
assert!(!value.has_local_value() && !value.has_placeholders());
Canonical {
max_universe: ty::UniverseIndex::ROOT,
variables: List::empty(),
value: value.clone(),
}
}
}

impl<'tcx, V> Canonical<'tcx, V> {
/// Allows you to map the `value` of a canonical while keeping the
/// same set of bound variables.
Expand Down
19 changes: 19 additions & 0 deletions src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ pub use self::allocation::{Allocation, AllocationExtra, Relocations, UndefMask};

pub use self::pointer::{CheckInAllocMsg, Pointer, PointerArithmetic};

use crate::infer::canonical::Canonical;
use crate::mir;
use crate::traits::Reveal;
use crate::ty::codec::TyDecoder;
use crate::ty::layout::{self, Size};
use crate::ty::subst::GenericArgKind;
Expand Down Expand Up @@ -147,6 +149,23 @@ pub struct GlobalId<'tcx> {
pub promoted: Option<mir::Promoted>,
}

/// The input type for const eval queries. Const eval queries are given both the `ParamEnv` in which
/// the constant is evaluated in and the identifier of the constant.
pub type ConstEvalInput<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>>;

impl ConstEvalInput<'_> {
/// The `DefId` of the constant that is being evaluated.
pub fn def_id(&self) -> DefId {
self.value.value.instance.def_id()
}

pub fn with_reveal_user_facing(&self) -> Self {
let mut new_input = self.clone();
new_input.value.param_env.reveal = Reveal::UserFacing;
new_input
}
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
pub struct AllocId(pub u64);

Expand Down
69 changes: 59 additions & 10 deletions src/librustc/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use super::{ConstEvalResult, ErrorHandled, GlobalId};

use crate::infer::canonical::{Canonical, OriginalQueryValues};
use crate::infer::InferCtxt;
use crate::mir;
use crate::ty::subst::{InternalSubsts, SubstsRef};
use crate::ty::{self, TyCtxt};
Expand All @@ -19,7 +21,7 @@ impl<'tcx> TyCtxt<'tcx> {
let instance = ty::Instance::new(def_id, substs);
let cid = GlobalId { instance, promoted: None };
let param_env = self.param_env(def_id).with_reveal_all();
self.const_eval_validated(param_env.and(cid))
self.const_eval_validated(Canonical::empty(param_env.and(cid)))
}

/// Resolves and evaluates a constant.
Expand All @@ -38,25 +40,23 @@ impl<'tcx> TyCtxt<'tcx> {
substs: SubstsRef<'tcx>,
span: Option<Span>,
) -> ConstEvalResult<'tcx> {
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
if let Some(instance) = instance {
self.const_eval_instance(param_env, instance, span)
} else {
Err(ErrorHandled::TooGeneric)
}
self.infer_ctxt()
.enter(|ref infcx| infcx.const_eval_resolve(param_env, def_id, substs, span))
}

/// Evaluates the constant represented by the instance.
pub fn const_eval_instance(
self,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
span: Option<Span>,
) -> ConstEvalResult<'tcx> {
let cid = GlobalId { instance, promoted: None };
let canonical = Canonical::empty(param_env.and(cid));
if let Some(span) = span {
self.at(span).const_eval_validated(param_env.and(cid))
self.at(span).const_eval_validated(canonical)
} else {
self.const_eval_validated(param_env.and(cid))
self.const_eval_validated(canonical)
}
}

Expand All @@ -68,6 +68,55 @@ impl<'tcx> TyCtxt<'tcx> {
) -> ConstEvalResult<'tcx> {
let cid = GlobalId { instance, promoted: Some(promoted) };
let param_env = ty::ParamEnv::reveal_all();
self.const_eval_validated(param_env.and(cid))
self.const_eval_validated(Canonical::empty(param_env.and(cid)))
}
}

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Evaluates the constant represented by the instance.
///
/// The given `ParamEnv` and `Instance` can contain inference variables from this inference
/// context.
pub fn const_eval_instance(
&self,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
span: Option<Span>,
) -> ConstEvalResult<'tcx> {
let cid = GlobalId { instance, promoted: None };
let mut orig_values = OriginalQueryValues::default();
let canonical = self.canonicalize_query(&param_env.and(cid), &mut orig_values);
if let Some(span) = span {
self.tcx.at(span).const_eval_validated(canonical)
} else {
self.tcx.const_eval_validated(canonical)
}
}

/// 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.
///
/// The given `ParamEnv` and `substs` can contain inference variables from this inference
/// context.
pub fn const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
substs: SubstsRef<'tcx>,
span: Option<Span>,
) -> ConstEvalResult<'tcx> {
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
if let Some(instance) = instance {
self.const_eval_instance(param_env, instance, span)
} else {
Err(ErrorHandled::TooGeneric)
}
}
}
26 changes: 12 additions & 14 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::dep_graph::{DepKind, DepNode, RecoverKey, SerializedDepNodeIndex};
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::mir::interpret::ConstEvalInput;
use crate::traits;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTraitGoal, CanonicalTyGoal,
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
Expand Down Expand Up @@ -467,12 +467,12 @@ rustc_queries! {
/// during validation. Please add a comment to every use site explaining why using
/// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable
/// form to be used outside of const eval.
query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
query const_eval_raw(key: ConstEvalInput<'tcx>)
-> ConstEvalRawResult<'tcx> {
no_force
desc { |tcx|
"const-evaluating `{}`",
tcx.def_path_str(key.value.instance.def.def_id())
tcx.def_path_str(key.def_id())
}
}

Expand All @@ -484,12 +484,12 @@ rustc_queries! {
///
/// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
/// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`.
query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
query const_eval_validated(key: ConstEvalInput<'tcx>)
-> ConstEvalResult<'tcx> {
no_force
desc { |tcx|
"const-evaluating + checking `{}`",
tcx.def_path_str(key.value.instance.def.def_id())
tcx.def_path_str(key.def_id())
}
cache_on_disk_if(_, opt_result) {
// Only store results without errors
Expand Down Expand Up @@ -592,17 +592,15 @@ rustc_queries! {
no_force
desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
}
}

Codegen {
query codegen_fulfill_obligation(
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
) -> Vtable<'tcx, ()> {
/// Do not call this query directly: invoke `infcx.resolve_vtable()` instead.
query resolve_vtable(
goal: CanonicalTraitGoal<'tcx>
) -> Result<&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vtable<'tcx, ()>>>, NoSolution> {
no_force
cache_on_disk_if { true }
desc { |tcx|
"checking if `{}` fulfills its obligations",
tcx.def_path_str(key.1.def_id())
"resolving vtable for `{}`",
tcx.def_path_str(goal.value.value.def_id())
}
}
}
Expand Down
Loading