Skip to content

Commit 952f90b

Browse files
committed
Auto merge of #67717 - skinny121:canonicalize-const-eval, r=<try>
Turn const eval queries into canonical queries This is ground work for lazy normalization of consts. This enables invoking const eval queries even if the current param env has inference variable within it, which can occur during trait selection. r? @nikomatsakis
2 parents 4f074de + 92b63b8 commit 952f90b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+748
-612
lines changed

src/librustc/arena.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ macro_rules! arena_types {
6565
Vec<rustc::traits::query::outlives_bounds::OutlivesBound<'tcx>>
6666
>
6767
>,
68+
[] resolve_vtables:
69+
rustc::infer::canonical::Canonical<'tcx,
70+
rustc::infer::canonical::QueryResponse<'tcx,
71+
rustc::traits::Vtable<'tcx, ()>
72+
>
73+
>,
6874
[] type_op_subtype:
6975
rustc::infer::canonical::Canonical<'tcx,
7076
rustc::infer::canonical::QueryResponse<'tcx, ()>

src/librustc/dep_graph/dep_node.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@
5252
use crate::hir::map::DefPathHash;
5353
use crate::ich::{Fingerprint, StableHashingContext};
5454
use crate::mir;
55-
use crate::mir::interpret::GlobalId;
55+
use crate::mir::interpret::ConstEvalInput;
5656
use crate::traits;
5757
use crate::traits::query::{
58-
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
58+
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTraitGoal, CanonicalTyGoal,
5959
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
6060
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
6161
};

src/librustc/infer/canonical/canonicalizer.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ use crate::infer::InferCtxt;
1313
use crate::ty::flags::FlagComputation;
1414
use crate::ty::fold::{TypeFoldable, TypeFolder};
1515
use crate::ty::subst::GenericArg;
16-
use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
17-
use std::sync::atomic::Ordering;
16+
use crate::ty::{self, BoundVar, InferConst, Ty, TyCtxt, TypeFlags};
1817

1918
use rustc_data_structures::fx::FxHashMap;
2019
use rustc_index::vec::Idx;
2120
use smallvec::SmallVec;
21+
use std::sync::atomic::Ordering;
2222

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

497497
// Fast path: nothing that needs to be canonicalized.
498498
if !value.has_type_flags(needs_canonical_flags) {
499-
let canon_value = Canonical {
500-
max_universe: ty::UniverseIndex::ROOT,
501-
variables: List::empty(),
502-
value: value.clone(),
503-
};
504-
return canon_value;
499+
return Canonical::empty(value.clone());
505500
}
506501

507502
let mut canonicalizer = Canonicalizer {

src/librustc/infer/canonical/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,19 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
266266
}
267267
}
268268

269+
impl<'tcx, V: TypeFoldable<'tcx>> Canonical<'tcx, V> {
270+
/// Construct a canonical `value` with an empty set of variables
271+
/// in the `ROOT` universe.
272+
pub fn empty(value: V) -> Canonical<'tcx, V> {
273+
assert!(!value.has_local_value() && !value.has_placeholders());
274+
Canonical {
275+
max_universe: ty::UniverseIndex::ROOT,
276+
variables: List::empty(),
277+
value: value.clone(),
278+
}
279+
}
280+
}
281+
269282
impl<'tcx, V> Canonical<'tcx, V> {
270283
/// Allows you to map the `value` of a canonical while keeping the
271284
/// same set of bound variables.

src/librustc/mir/interpret/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ pub use self::allocation::{Allocation, AllocationExtra, Relocations, UndefMask};
115115

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

118+
use crate::infer::canonical::Canonical;
118119
use crate::mir;
120+
use crate::traits::Reveal;
119121
use crate::ty::codec::TyDecoder;
120122
use crate::ty::layout::{self, Size};
121123
use crate::ty::subst::GenericArgKind;
@@ -147,6 +149,23 @@ pub struct GlobalId<'tcx> {
147149
pub promoted: Option<mir::Promoted>,
148150
}
149151

152+
/// The input type for const eval queries. Const eval queries are given both the `ParamEnv` in which
153+
/// the constant is evaluated in and the identifier of the constant.
154+
pub type ConstEvalInput<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>>;
155+
156+
impl ConstEvalInput<'_> {
157+
/// The `DefId` of the constant that is being evaluated.
158+
pub fn def_id(&self) -> DefId {
159+
self.value.value.instance.def_id()
160+
}
161+
162+
pub fn with_reveal_user_facing(&self) -> Self {
163+
let mut new_input = self.clone();
164+
new_input.value.param_env.reveal = Reveal::UserFacing;
165+
new_input
166+
}
167+
}
168+
150169
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
151170
pub struct AllocId(pub u64);
152171

src/librustc/mir/interpret/queries.rs

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::{ConstEvalResult, ErrorHandled, GlobalId};
22

3+
use crate::infer::canonical::{Canonical, OriginalQueryValues};
4+
use crate::infer::InferCtxt;
35
use crate::mir;
46
use crate::ty::subst::{InternalSubsts, SubstsRef};
57
use crate::ty::{self, TyCtxt};
@@ -19,7 +21,7 @@ impl<'tcx> TyCtxt<'tcx> {
1921
let instance = ty::Instance::new(def_id, substs);
2022
let cid = GlobalId { instance, promoted: None };
2123
let param_env = self.param_env(def_id).with_reveal_all();
22-
self.const_eval_validated(param_env.and(cid))
24+
self.const_eval_validated(Canonical::empty(param_env.and(cid)))
2325
}
2426

2527
/// Resolves and evaluates a constant.
@@ -38,25 +40,23 @@ impl<'tcx> TyCtxt<'tcx> {
3840
substs: SubstsRef<'tcx>,
3941
span: Option<Span>,
4042
) -> ConstEvalResult<'tcx> {
41-
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
42-
if let Some(instance) = instance {
43-
self.const_eval_instance(param_env, instance, span)
44-
} else {
45-
Err(ErrorHandled::TooGeneric)
46-
}
43+
self.infer_ctxt()
44+
.enter(|ref infcx| infcx.const_eval_resolve(param_env, def_id, substs, span))
4745
}
4846

47+
/// Evaluates the constant represented by the instance.
4948
pub fn const_eval_instance(
5049
self,
5150
param_env: ty::ParamEnv<'tcx>,
5251
instance: ty::Instance<'tcx>,
5352
span: Option<Span>,
5453
) -> ConstEvalResult<'tcx> {
5554
let cid = GlobalId { instance, promoted: None };
55+
let canonical = Canonical::empty(param_env.and(cid));
5656
if let Some(span) = span {
57-
self.at(span).const_eval_validated(param_env.and(cid))
57+
self.at(span).const_eval_validated(canonical)
5858
} else {
59-
self.const_eval_validated(param_env.and(cid))
59+
self.const_eval_validated(canonical)
6060
}
6161
}
6262

@@ -68,6 +68,55 @@ impl<'tcx> TyCtxt<'tcx> {
6868
) -> ConstEvalResult<'tcx> {
6969
let cid = GlobalId { instance, promoted: Some(promoted) };
7070
let param_env = ty::ParamEnv::reveal_all();
71-
self.const_eval_validated(param_env.and(cid))
71+
self.const_eval_validated(Canonical::empty(param_env.and(cid)))
72+
}
73+
}
74+
75+
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
76+
/// Evaluates the constant represented by the instance.
77+
///
78+
/// The given `ParamEnv` and `Instance` can contain inference variables from this inference
79+
/// context.
80+
pub fn const_eval_instance(
81+
&self,
82+
param_env: ty::ParamEnv<'tcx>,
83+
instance: ty::Instance<'tcx>,
84+
span: Option<Span>,
85+
) -> ConstEvalResult<'tcx> {
86+
let cid = GlobalId { instance, promoted: None };
87+
let mut orig_values = OriginalQueryValues::default();
88+
let canonical = self.canonicalize_query(&param_env.and(cid), &mut orig_values);
89+
if let Some(span) = span {
90+
self.tcx.at(span).const_eval_validated(canonical)
91+
} else {
92+
self.tcx.const_eval_validated(canonical)
93+
}
94+
}
95+
96+
/// Resolves and evaluates a constant.
97+
///
98+
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
99+
/// substitutions and environment are used to resolve the constant. Alternatively if the
100+
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
101+
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
102+
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
103+
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
104+
/// returned.
105+
///
106+
/// The given `ParamEnv` and `substs` can contain inference variables from this inference
107+
/// context.
108+
pub fn const_eval_resolve(
109+
&self,
110+
param_env: ty::ParamEnv<'tcx>,
111+
def_id: DefId,
112+
substs: SubstsRef<'tcx>,
113+
span: Option<Span>,
114+
) -> ConstEvalResult<'tcx> {
115+
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
116+
if let Some(instance) = instance {
117+
self.const_eval_instance(param_env, instance, span)
118+
} else {
119+
Err(ErrorHandled::TooGeneric)
120+
}
72121
}
73122
}

src/librustc/query/mod.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::dep_graph::{DepKind, DepNode, RecoverKey, SerializedDepNodeIndex};
22
use crate::mir;
3-
use crate::mir::interpret::GlobalId;
3+
use crate::mir::interpret::ConstEvalInput;
44
use crate::traits;
55
use crate::traits::query::{
6-
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
6+
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTraitGoal, CanonicalTyGoal,
77
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
88
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
99
};
@@ -467,12 +467,12 @@ rustc_queries! {
467467
/// during validation. Please add a comment to every use site explaining why using
468468
/// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable
469469
/// form to be used outside of const eval.
470-
query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
470+
query const_eval_raw(key: ConstEvalInput<'tcx>)
471471
-> ConstEvalRawResult<'tcx> {
472472
no_force
473473
desc { |tcx|
474474
"const-evaluating `{}`",
475-
tcx.def_path_str(key.value.instance.def.def_id())
475+
tcx.def_path_str(key.def_id())
476476
}
477477
}
478478

@@ -484,12 +484,12 @@ rustc_queries! {
484484
///
485485
/// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
486486
/// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`.
487-
query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
487+
query const_eval_validated(key: ConstEvalInput<'tcx>)
488488
-> ConstEvalResult<'tcx> {
489489
no_force
490490
desc { |tcx|
491491
"const-evaluating + checking `{}`",
492-
tcx.def_path_str(key.value.instance.def.def_id())
492+
tcx.def_path_str(key.def_id())
493493
}
494494
cache_on_disk_if(_, opt_result) {
495495
// Only store results without errors
@@ -592,17 +592,15 @@ rustc_queries! {
592592
no_force
593593
desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
594594
}
595-
}
596595

597-
Codegen {
598-
query codegen_fulfill_obligation(
599-
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
600-
) -> Vtable<'tcx, ()> {
596+
/// Do not call this query directly: invoke `infcx.resolve_vtable()` instead.
597+
query resolve_vtable(
598+
goal: CanonicalTraitGoal<'tcx>
599+
) -> Result<&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vtable<'tcx, ()>>>, NoSolution> {
601600
no_force
602-
cache_on_disk_if { true }
603601
desc { |tcx|
604-
"checking if `{}` fulfills its obligations",
605-
tcx.def_path_str(key.1.def_id())
602+
"resolving vtable for `{}`",
603+
tcx.def_path_str(goal.value.value.def_id())
606604
}
607605
}
608606
}

0 commit comments

Comments
 (0)