Skip to content

Commit 7f89c7c

Browse files
Make EvalCtxt's infcx private
1 parent f421586 commit 7f89c7c

File tree

4 files changed

+134
-75
lines changed

4 files changed

+134
-75
lines changed

compiler/rustc_trait_selection/src/solve/canonical/mod.rs

+11-46
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@
88
/// section of the [rustc-dev-guide][c].
99
///
1010
/// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
11-
use self::canonicalize::{CanonicalizeMode, Canonicalizer};
11+
pub use self::canonicalize::{CanonicalizeMode, Canonicalizer};
12+
1213
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal};
13-
use super::{CanonicalResponse, ExternalConstraints, QueryResult, Response};
14-
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
14+
use super::{CanonicalResponse, QueryResult, Response};
1515
use rustc_infer::infer::canonical::CanonicalVarValues;
1616
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
1717
use rustc_infer::traits::query::NoSolution;
1818
use rustc_infer::traits::solve::ExternalConstraintsData;
19-
use rustc_infer::traits::ObligationCause;
2019
use rustc_middle::ty::{self, GenericArgKind};
21-
use rustc_span::DUMMY_SP;
2220
use std::iter;
2321
use std::ops::Deref;
2422

@@ -32,12 +30,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3230
goal: Goal<'tcx, ty::Predicate<'tcx>>,
3331
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalGoal<'tcx>) {
3432
let mut orig_values = Default::default();
35-
let canonical_goal = Canonicalizer::canonicalize(
36-
self.infcx,
37-
CanonicalizeMode::Input,
38-
&mut orig_values,
39-
goal,
40-
);
33+
let canonical_goal = self.canonicalize(CanonicalizeMode::Input, &mut orig_values, goal);
4134
(orig_values, canonical_goal)
4235
}
4336

@@ -58,35 +51,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
5851
let external_constraints = self.compute_external_query_constraints()?;
5952

6053
let response = Response { var_values: self.var_values, external_constraints, certainty };
61-
let canonical = Canonicalizer::canonicalize(
62-
self.infcx,
54+
let canonical = self.canonicalize(
6355
CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
6456
&mut Default::default(),
6557
response,
6658
);
6759
Ok(canonical)
6860
}
6961

70-
#[instrument(level = "debug", skip(self), ret)]
71-
fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
72-
// Cannot use `take_registered_region_obligations` as we may compute the response
73-
// inside of a `probe` whenever we have multiple choices inside of the solver.
74-
let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
75-
let region_constraints = self.infcx.with_region_constraints(|region_constraints| {
76-
make_query_region_constraints(
77-
self.tcx(),
78-
region_obligations
79-
.iter()
80-
.map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
81-
region_constraints,
82-
)
83-
});
84-
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
85-
Ok(self
86-
.tcx()
87-
.mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
88-
}
89-
9062
/// After calling a canonical query, we apply the constraints returned
9163
/// by the query using this function.
9264
///
@@ -126,10 +98,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
12698
// FIXME: Longterm canonical queries should deal with all placeholders
12799
// created inside of the query directly instead of returning them to the
128100
// caller.
129-
let prev_universe = self.infcx.universe();
101+
let prev_universe = self.universe();
130102
let universes_created_in_query = response.max_universe.index() + 1;
131103
for _ in 0..universes_created_in_query {
132-
self.infcx.create_next_universe();
104+
self.create_next_universe();
133105
}
134106

135107
let var_values = response.value.var_values;
@@ -172,7 +144,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
172144
// A variable from inside a binder of the query. While ideally these shouldn't
173145
// exist at all (see the FIXME at the start of this method), we have to deal with
174146
// them for now.
175-
self.infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| {
147+
self.instantiate_canonical_var(info, |idx| {
176148
ty::UniverseIndex::from(prev_universe.index() + idx.index())
177149
})
178150
} else if info.is_existential() {
@@ -186,7 +158,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
186158
if let Some(v) = opt_values[index] {
187159
v
188160
} else {
189-
self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe)
161+
self.instantiate_canonical_var(info, |_| prev_universe)
190162
}
191163
} else {
192164
// For placeholders which were already part of the input, we simply map this
@@ -219,15 +191,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
219191
fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
220192
for &(ty::OutlivesPredicate(lhs, rhs), _) in &region_constraints.outlives {
221193
match lhs.unpack() {
222-
GenericArgKind::Lifetime(lhs) => self.infcx.region_outlives_predicate(
223-
&ObligationCause::dummy(),
224-
ty::Binder::dummy(ty::OutlivesPredicate(lhs, rhs)),
225-
),
226-
GenericArgKind::Type(lhs) => self.infcx.register_region_obligation_with_cause(
227-
lhs,
228-
rhs,
229-
&ObligationCause::dummy(),
230-
),
194+
GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
195+
GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
231196
GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"),
232197
}
233198
}

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+108-4
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,49 @@
11
use rustc_hir::def_id::DefId;
22
use rustc_infer::infer::at::ToTrace;
3-
use rustc_infer::infer::canonical::CanonicalVarValues;
3+
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
4+
use rustc_infer::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarValues};
45
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
56
use rustc_infer::infer::{
67
DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
78
};
89
use rustc_infer::traits::query::NoSolution;
9-
use rustc_infer::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
1010
use rustc_infer::traits::ObligationCause;
1111
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
12+
use rustc_middle::traits::solve::{
13+
CanonicalGoal, Certainty, ExternalConstraints, ExternalConstraintsData, MaybeCause, QueryResult,
14+
};
1215
use rustc_middle::ty::{
1316
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
1417
TypeVisitor,
1518
};
1619
use rustc_span::DUMMY_SP;
1720
use std::ops::ControlFlow;
1821

22+
use crate::traits::specialization_graph;
23+
24+
use super::canonical::{CanonicalizeMode, Canonicalizer};
1925
use super::search_graph::{self, OverflowHandler};
2026
use super::SolverMode;
2127
use super::{search_graph::SearchGraph, Goal};
2228

2329
pub struct EvalCtxt<'a, 'tcx> {
24-
// FIXME: should be private.
25-
pub(super) infcx: &'a InferCtxt<'tcx>,
30+
/// The inference context that backs (mostly) inference and placeholder terms
31+
/// instantiated while solving goals.
32+
///
33+
/// NOTE: The `InferCtxt` that backs the `EvalCtxt` is intentionally private,
34+
/// because the `InferCtxt` is much more general than `EvalCtxt`. Methods such
35+
/// as `take_registered_region_obligations` can mess up query responses,
36+
/// using `At::normalize` is totally wrong, calling `evaluate_root_goal` can
37+
/// cause coinductive unsoundness, etc.
38+
///
39+
/// Methods that are generally of use for trait solving are *intentionally*
40+
/// re-declared through the `EvalCtxt` below, often with cleaner signatures
41+
/// since we don't care about things like `ObligationCause`s and `Span`s here.
42+
/// If some `InferCtxt` method is missing, please first think defensively about
43+
/// the method's compatibility with this solver, or if an existing one does
44+
/// the job already.
45+
infcx: &'a InferCtxt<'tcx>,
46+
2647
pub(super) var_values: CanonicalVarValues<'tcx>,
2748
/// The highest universe index nameable by the caller.
2849
///
@@ -548,4 +569,87 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
548569
pub(super) fn universe(&self) -> ty::UniverseIndex {
549570
self.infcx.universe()
550571
}
572+
573+
pub(super) fn create_next_universe(&self) -> ty::UniverseIndex {
574+
self.infcx.create_next_universe()
575+
}
576+
577+
pub(super) fn instantiate_canonical_var(
578+
&self,
579+
cv_info: CanonicalVarInfo<'tcx>,
580+
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
581+
) -> ty::GenericArg<'tcx> {
582+
self.infcx.instantiate_canonical_var(DUMMY_SP, cv_info, universe_map)
583+
}
584+
585+
pub(super) fn translate_substs(
586+
&self,
587+
param_env: ty::ParamEnv<'tcx>,
588+
source_impl: DefId,
589+
source_substs: ty::SubstsRef<'tcx>,
590+
target_node: specialization_graph::Node,
591+
) -> ty::SubstsRef<'tcx> {
592+
crate::traits::translate_substs(
593+
self.infcx,
594+
param_env,
595+
source_impl,
596+
source_substs,
597+
target_node,
598+
)
599+
}
600+
601+
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
602+
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
603+
}
604+
605+
pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) {
606+
// `b : a` ==> `a <= b`
607+
// (inlined from `InferCtxt::region_outlives_predicate`)
608+
self.infcx.sub_regions(
609+
rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP),
610+
b,
611+
a,
612+
);
613+
}
614+
615+
/// Computes the list of goals required for `arg` to be well-formed
616+
pub(super) fn well_formed_goals(
617+
&self,
618+
param_env: ty::ParamEnv<'tcx>,
619+
arg: ty::GenericArg<'tcx>,
620+
) -> Option<impl Iterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>> {
621+
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
622+
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
623+
}
624+
625+
#[instrument(level = "debug", skip(self), ret)]
626+
pub(super) fn compute_external_query_constraints(
627+
&self,
628+
) -> Result<ExternalConstraints<'tcx>, NoSolution> {
629+
// Cannot use `take_registered_region_obligations` as we may compute the response
630+
// inside of a `probe` whenever we have multiple choices inside of the solver.
631+
let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
632+
let region_constraints = self.infcx.with_region_constraints(|region_constraints| {
633+
make_query_region_constraints(
634+
self.tcx(),
635+
region_obligations
636+
.iter()
637+
.map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
638+
region_constraints,
639+
)
640+
});
641+
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
642+
Ok(self
643+
.tcx()
644+
.mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
645+
}
646+
647+
pub(super) fn canonicalize<T: TypeFoldable<TyCtxt<'tcx>>>(
648+
&self,
649+
canonicalize_mode: CanonicalizeMode,
650+
variables: &mut Vec<ty::GenericArg<'tcx>>,
651+
value: T,
652+
) -> Canonical<'tcx, T> {
653+
Canonicalizer::canonicalize(self.infcx, canonicalize_mode, variables, value)
654+
}
551655
}

compiler/rustc_trait_selection/src/solve/mod.rs

+8-16
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,14 @@ use rustc_hir::def_id::DefId;
1515
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
1616
use rustc_infer::traits::query::NoSolution;
1717
use rustc_middle::traits::solve::{
18-
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
19-
Goal, QueryResult, Response,
18+
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult,
19+
Response,
2020
};
2121
use rustc_middle::ty::{self, Ty, TyCtxt};
2222
use rustc_middle::ty::{
2323
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
2424
};
2525

26-
use crate::traits::ObligationCause;
27-
2826
mod assembly;
2927
mod canonical;
3028
mod eval_ctxt;
@@ -68,7 +66,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
6866
goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
6967
) -> QueryResult<'tcx> {
7068
let ty::OutlivesPredicate(ty, lt) = goal.predicate;
71-
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
69+
self.register_ty_outlives(ty, lt);
7270
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
7371
}
7472

@@ -77,10 +75,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
7775
&mut self,
7876
goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
7977
) -> QueryResult<'tcx> {
80-
self.infcx.region_outlives_predicate(
81-
&ObligationCause::dummy(),
82-
ty::Binder::dummy(goal.predicate),
83-
);
78+
let ty::OutlivesPredicate(a, b) = goal.predicate;
79+
self.register_region_outlives(a, b);
8480
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
8581
}
8682

@@ -146,13 +142,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
146142
&mut self,
147143
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
148144
) -> QueryResult<'tcx> {
149-
match crate::traits::wf::unnormalized_obligations(
150-
self.infcx,
151-
goal.param_env,
152-
goal.predicate,
153-
) {
154-
Some(obligations) => {
155-
self.add_goals(obligations.into_iter().map(|o| o.into()));
145+
match self.well_formed_goals(goal.param_env, goal.predicate) {
146+
Some(goals) => {
147+
self.add_goals(goals);
156148
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
157149
}
158150
None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS),

compiler/rustc_trait_selection/src/solve/project_goals.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::traits::{specialization_graph, translate_substs};
1+
use crate::traits::specialization_graph;
22

33
use super::assembly;
44
use super::trait_goals::structural_traits;
@@ -7,7 +7,6 @@ use rustc_errors::ErrorGuaranteed;
77
use rustc_hir::def::DefKind;
88
use rustc_hir::def_id::DefId;
99
use rustc_hir::LangItem;
10-
use rustc_infer::infer::InferCtxt;
1110
use rustc_infer::traits::query::NoSolution;
1211
use rustc_infer::traits::specialization_graph::LeafDef;
1312
use rustc_infer::traits::Reveal;
@@ -168,7 +167,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
168167
// return ambiguity this would otherwise be incomplete, resulting in
169168
// unsoundness during coherence (#105782).
170169
let Some(assoc_def) = fetch_eligible_assoc_item_def(
171-
ecx.infcx,
170+
ecx,
172171
goal.param_env,
173172
goal_trait_ref,
174173
goal.predicate.def_id(),
@@ -199,8 +198,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
199198
goal_trait_ref.def_id,
200199
impl_substs,
201200
);
202-
let substs = translate_substs(
203-
ecx.infcx,
201+
let substs = ecx.translate_substs(
204202
goal.param_env,
205203
impl_def_id,
206204
impl_substs_with_gat,
@@ -500,15 +498,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
500498
///
501499
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
502500
/// diverge.
503-
#[instrument(level = "debug", skip(infcx, param_env), ret)]
501+
#[instrument(level = "debug", skip(ecx, param_env), ret)]
504502
fn fetch_eligible_assoc_item_def<'tcx>(
505-
infcx: &InferCtxt<'tcx>,
503+
ecx: &EvalCtxt<'_, 'tcx>,
506504
param_env: ty::ParamEnv<'tcx>,
507505
goal_trait_ref: ty::TraitRef<'tcx>,
508506
trait_assoc_def_id: DefId,
509507
impl_def_id: DefId,
510508
) -> Result<Option<LeafDef>, NoSolution> {
511-
let node_item = specialization_graph::assoc_def(infcx.tcx, impl_def_id, trait_assoc_def_id)
509+
let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id)
512510
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
513511

514512
let eligible = if node_item.is_final() {
@@ -520,7 +518,7 @@ fn fetch_eligible_assoc_item_def<'tcx>(
520518
// transmute checking and polymorphic MIR optimizations could
521519
// get a result which isn't correct for all monomorphizations.
522520
if param_env.reveal() == Reveal::All {
523-
let poly_trait_ref = infcx.resolve_vars_if_possible(goal_trait_ref);
521+
let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
524522
!poly_trait_ref.still_further_specializable()
525523
} else {
526524
debug!(?node_item.item.def_id, "not eligible due to default");

0 commit comments

Comments
 (0)