Skip to content

Commit 9f28c98

Browse files
authored
Rollup merge of #109511 - compiler-errors:eval-ctxt-infcx-private, r=lcnr
Make `EvalCtxt`'s `infcx` private To better protect against people doing bad things with the inner `InferCtxt` r? `@lcnr`
2 parents 57f1d11 + a61616a commit 9f28c98

File tree

5 files changed

+84
-50
lines changed

5 files changed

+84
-50
lines changed

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+62-7
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,42 @@ use rustc_infer::infer::{
66
DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
77
};
88
use rustc_infer::traits::query::NoSolution;
9-
use rustc_infer::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
109
use rustc_infer::traits::ObligationCause;
1110
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
11+
use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
1212
use rustc_middle::ty::{
1313
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
1414
TypeVisitor,
1515
};
1616
use rustc_span::DUMMY_SP;
1717
use std::ops::ControlFlow;
1818

19+
use crate::traits::specialization_graph;
20+
1921
use super::search_graph::{self, OverflowHandler};
2022
use super::SolverMode;
2123
use super::{search_graph::SearchGraph, Goal};
2224

25+
mod canonical;
26+
2327
pub struct EvalCtxt<'a, 'tcx> {
24-
// FIXME: should be private.
25-
pub(super) infcx: &'a InferCtxt<'tcx>,
28+
/// The inference context that backs (mostly) inference and placeholder terms
29+
/// instantiated while solving goals.
30+
///
31+
/// NOTE: The `InferCtxt` that backs the `EvalCtxt` is intentionally private,
32+
/// because the `InferCtxt` is much more general than `EvalCtxt`. Methods such
33+
/// as `take_registered_region_obligations` can mess up query responses,
34+
/// using `At::normalize` is totally wrong, calling `evaluate_root_goal` can
35+
/// cause coinductive unsoundness, etc.
36+
///
37+
/// Methods that are generally of use for trait solving are *intentionally*
38+
/// re-declared through the `EvalCtxt` below, often with cleaner signatures
39+
/// since we don't care about things like `ObligationCause`s and `Span`s here.
40+
/// If some `InferCtxt` method is missing, please first think defensively about
41+
/// the method's compatibility with this solver, or if an existing one does
42+
/// the job already.
43+
infcx: &'a InferCtxt<'tcx>,
44+
2645
pub(super) var_values: CanonicalVarValues<'tcx>,
2746
/// The highest universe index nameable by the caller.
2847
///
@@ -393,7 +412,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
393412
if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
394413
match self.infcx.probe_ty_var(vid) {
395414
Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
396-
Err(universe) => universe == self.universe(),
415+
Err(universe) => universe == self.infcx.universe(),
397416
}
398417
} else {
399418
false
@@ -403,7 +422,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
403422
if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
404423
match self.infcx.probe_const_var(vid) {
405424
Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
406-
Err(universe) => universe == self.universe(),
425+
Err(universe) => universe == self.infcx.universe(),
407426
}
408427
} else {
409428
false
@@ -545,7 +564,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
545564
self.infcx.fresh_substs_for_item(DUMMY_SP, def_id)
546565
}
547566

548-
pub(super) fn universe(&self) -> ty::UniverseIndex {
549-
self.infcx.universe()
567+
pub(super) fn translate_substs(
568+
&self,
569+
param_env: ty::ParamEnv<'tcx>,
570+
source_impl: DefId,
571+
source_substs: ty::SubstsRef<'tcx>,
572+
target_node: specialization_graph::Node,
573+
) -> ty::SubstsRef<'tcx> {
574+
crate::traits::translate_substs(
575+
self.infcx,
576+
param_env,
577+
source_impl,
578+
source_substs,
579+
target_node,
580+
)
581+
}
582+
583+
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
584+
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
585+
}
586+
587+
pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) {
588+
// `b : a` ==> `a <= b`
589+
// (inlined from `InferCtxt::region_outlives_predicate`)
590+
self.infcx.sub_regions(
591+
rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP),
592+
b,
593+
a,
594+
);
595+
}
596+
597+
/// Computes the list of goals required for `arg` to be well-formed
598+
pub(super) fn well_formed_goals(
599+
&self,
600+
param_env: ty::ParamEnv<'tcx>,
601+
arg: ty::GenericArg<'tcx>,
602+
) -> Option<impl Iterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>> {
603+
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
604+
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
550605
}
551606
}

compiler/rustc_trait_selection/src/solve/canonical/mod.rs renamed to compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs

+7-17
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,19 @@
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};
1211
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal};
13-
use super::{CanonicalResponse, ExternalConstraints, QueryResult, Response};
12+
use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
13+
use crate::solve::{CanonicalResponse, QueryResult, Response};
1414
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
1515
use rustc_infer::infer::canonical::CanonicalVarValues;
1616
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
17-
use rustc_infer::traits::query::NoSolution;
18-
use rustc_infer::traits::solve::ExternalConstraintsData;
19-
use rustc_infer::traits::ObligationCause;
17+
use rustc_middle::traits::query::NoSolution;
18+
use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
2019
use rustc_middle::ty::{self, GenericArgKind};
2120
use rustc_span::DUMMY_SP;
2221
use std::iter;
2322
use std::ops::Deref;
2423

25-
mod canonicalize;
26-
2724
impl<'tcx> EvalCtxt<'_, 'tcx> {
2825
/// Canonicalizes the goal remembering the original values
2926
/// for each bound variable.
@@ -48,7 +45,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
4845
/// - `external_constraints`: additional constraints which aren't expressable
4946
/// using simple unification of inference variables.
5047
#[instrument(level = "debug", skip(self))]
51-
pub(super) fn evaluate_added_goals_and_make_canonical_response(
48+
pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
5249
&mut self,
5350
certainty: Certainty,
5451
) -> QueryResult<'tcx> {
@@ -219,15 +216,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
219216
fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
220217
for &(ty::OutlivesPredicate(lhs, rhs), _) in &region_constraints.outlives {
221218
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-
),
219+
GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
220+
GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
231221
GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"),
232222
}
233223
}

compiler/rustc_trait_selection/src/solve/mod.rs

+8-17
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,15 @@ use rustc_hir::def_id::DefId;
1313
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
1414
use rustc_infer::traits::query::NoSolution;
1515
use rustc_middle::traits::solve::{
16-
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
17-
Goal, QueryResult, Response,
16+
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response,
1817
};
1918
use rustc_middle::ty::{self, Ty, TyCtxt};
2019
use rustc_middle::ty::{
2120
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
2221
};
2322

24-
use crate::traits::ObligationCause;
25-
2623
mod assembly;
27-
mod canonical;
24+
mod canonicalize;
2825
mod eval_ctxt;
2926
mod fulfill;
3027
mod project_goals;
@@ -66,7 +63,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
6663
goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
6764
) -> QueryResult<'tcx> {
6865
let ty::OutlivesPredicate(ty, lt) = goal.predicate;
69-
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
66+
self.register_ty_outlives(ty, lt);
7067
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
7168
}
7269

@@ -75,10 +72,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
7572
&mut self,
7673
goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
7774
) -> QueryResult<'tcx> {
78-
self.infcx.region_outlives_predicate(
79-
&ObligationCause::dummy(),
80-
ty::Binder::dummy(goal.predicate),
81-
);
75+
let ty::OutlivesPredicate(a, b) = goal.predicate;
76+
self.register_region_outlives(a, b);
8277
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
8378
}
8479

@@ -142,13 +137,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
142137
&mut self,
143138
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
144139
) -> QueryResult<'tcx> {
145-
match crate::traits::wf::unnormalized_obligations(
146-
self.infcx,
147-
goal.param_env,
148-
goal.predicate,
149-
) {
150-
Some(obligations) => {
151-
self.add_goals(obligations.into_iter().map(|o| o.into()));
140+
match self.well_formed_goals(goal.param_env, goal.predicate) {
141+
Some(goals) => {
142+
self.add_goals(goals);
152143
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
153144
}
154145
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;
@@ -165,7 +164,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
165164
// return ambiguity this would otherwise be incomplete, resulting in
166165
// unsoundness during coherence (#105782).
167166
let Some(assoc_def) = fetch_eligible_assoc_item_def(
168-
ecx.infcx,
167+
ecx,
169168
goal.param_env,
170169
goal_trait_ref,
171170
goal.predicate.def_id(),
@@ -196,8 +195,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
196195
goal_trait_ref.def_id,
197196
impl_substs,
198197
);
199-
let substs = translate_substs(
200-
ecx.infcx,
198+
let substs = ecx.translate_substs(
201199
goal.param_env,
202200
impl_def_id,
203201
impl_substs_with_gat,
@@ -504,15 +502,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
504502
///
505503
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
506504
/// diverge.
507-
#[instrument(level = "debug", skip(infcx, param_env), ret)]
505+
#[instrument(level = "debug", skip(ecx, param_env), ret)]
508506
fn fetch_eligible_assoc_item_def<'tcx>(
509-
infcx: &InferCtxt<'tcx>,
507+
ecx: &EvalCtxt<'_, 'tcx>,
510508
param_env: ty::ParamEnv<'tcx>,
511509
goal_trait_ref: ty::TraitRef<'tcx>,
512510
trait_assoc_def_id: DefId,
513511
impl_def_id: DefId,
514512
) -> Result<Option<LeafDef>, NoSolution> {
515-
let node_item = specialization_graph::assoc_def(infcx.tcx, impl_def_id, trait_assoc_def_id)
513+
let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id)
516514
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
517515

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

0 commit comments

Comments
 (0)