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`
This commit is contained in:
commit
9f28c98357
5 changed files with 84 additions and 50 deletions
|
@ -6,9 +6,9 @@ use rustc_infer::infer::{
|
|||
DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
TypeVisitor,
|
||||
|
@ -16,13 +16,32 @@ use rustc_middle::ty::{
|
|||
use rustc_span::DUMMY_SP;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::traits::specialization_graph;
|
||||
|
||||
use super::search_graph::{self, OverflowHandler};
|
||||
use super::SolverMode;
|
||||
use super::{search_graph::SearchGraph, Goal};
|
||||
|
||||
mod canonical;
|
||||
|
||||
pub struct EvalCtxt<'a, 'tcx> {
|
||||
// FIXME: should be private.
|
||||
pub(super) infcx: &'a InferCtxt<'tcx>,
|
||||
/// The inference context that backs (mostly) inference and placeholder terms
|
||||
/// instantiated while solving goals.
|
||||
///
|
||||
/// NOTE: The `InferCtxt` that backs the `EvalCtxt` is intentionally private,
|
||||
/// because the `InferCtxt` is much more general than `EvalCtxt`. Methods such
|
||||
/// as `take_registered_region_obligations` can mess up query responses,
|
||||
/// using `At::normalize` is totally wrong, calling `evaluate_root_goal` can
|
||||
/// cause coinductive unsoundness, etc.
|
||||
///
|
||||
/// Methods that are generally of use for trait solving are *intentionally*
|
||||
/// re-declared through the `EvalCtxt` below, often with cleaner signatures
|
||||
/// since we don't care about things like `ObligationCause`s and `Span`s here.
|
||||
/// If some `InferCtxt` method is missing, please first think defensively about
|
||||
/// the method's compatibility with this solver, or if an existing one does
|
||||
/// the job already.
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
|
||||
pub(super) var_values: CanonicalVarValues<'tcx>,
|
||||
/// The highest universe index nameable by the caller.
|
||||
///
|
||||
|
@ -393,7 +412,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
|
||||
match self.infcx.probe_ty_var(vid) {
|
||||
Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
|
||||
Err(universe) => universe == self.universe(),
|
||||
Err(universe) => universe == self.infcx.universe(),
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
@ -403,7 +422,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
|
||||
match self.infcx.probe_const_var(vid) {
|
||||
Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
|
||||
Err(universe) => universe == self.universe(),
|
||||
Err(universe) => universe == self.infcx.universe(),
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
@ -545,7 +564,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
self.infcx.fresh_substs_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
pub(super) fn universe(&self) -> ty::UniverseIndex {
|
||||
self.infcx.universe()
|
||||
pub(super) fn translate_substs(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
source_impl: DefId,
|
||||
source_substs: ty::SubstsRef<'tcx>,
|
||||
target_node: specialization_graph::Node,
|
||||
) -> ty::SubstsRef<'tcx> {
|
||||
crate::traits::translate_substs(
|
||||
self.infcx,
|
||||
param_env,
|
||||
source_impl,
|
||||
source_substs,
|
||||
target_node,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
|
||||
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
|
||||
}
|
||||
|
||||
pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) {
|
||||
// `b : a` ==> `a <= b`
|
||||
// (inlined from `InferCtxt::region_outlives_predicate`)
|
||||
self.infcx.sub_regions(
|
||||
rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP),
|
||||
b,
|
||||
a,
|
||||
);
|
||||
}
|
||||
|
||||
/// Computes the list of goals required for `arg` to be well-formed
|
||||
pub(super) fn well_formed_goals(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
arg: ty::GenericArg<'tcx>,
|
||||
) -> Option<impl Iterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>> {
|
||||
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
|
||||
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,22 +8,19 @@
|
|||
/// section of the [rustc-dev-guide][c].
|
||||
///
|
||||
/// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
|
||||
use self::canonicalize::{CanonicalizeMode, Canonicalizer};
|
||||
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal};
|
||||
use super::{CanonicalResponse, ExternalConstraints, QueryResult, Response};
|
||||
use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
|
||||
use crate::solve::{CanonicalResponse, QueryResult, Response};
|
||||
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
|
||||
use rustc_infer::infer::canonical::CanonicalVarValues;
|
||||
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::ExternalConstraintsData;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
|
||||
use rustc_middle::ty::{self, GenericArgKind};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
|
||||
mod canonicalize;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
/// Canonicalizes the goal remembering the original values
|
||||
/// for each bound variable.
|
||||
|
@ -48,7 +45,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
/// - `external_constraints`: additional constraints which aren't expressable
|
||||
/// using simple unification of inference variables.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn evaluate_added_goals_and_make_canonical_response(
|
||||
pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
|
||||
&mut self,
|
||||
certainty: Certainty,
|
||||
) -> QueryResult<'tcx> {
|
||||
|
@ -219,15 +216,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
|
||||
for &(ty::OutlivesPredicate(lhs, rhs), _) in ®ion_constraints.outlives {
|
||||
match lhs.unpack() {
|
||||
GenericArgKind::Lifetime(lhs) => self.infcx.region_outlives_predicate(
|
||||
&ObligationCause::dummy(),
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(lhs, rhs)),
|
||||
),
|
||||
GenericArgKind::Type(lhs) => self.infcx.register_region_obligation_with_cause(
|
||||
lhs,
|
||||
rhs,
|
||||
&ObligationCause::dummy(),
|
||||
),
|
||||
GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
|
||||
GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
|
||||
GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"),
|
||||
}
|
||||
}
|
|
@ -13,18 +13,15 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{
|
||||
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
|
||||
Goal, QueryResult, Response,
|
||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||
};
|
||||
|
||||
use crate::traits::ObligationCause;
|
||||
|
||||
mod assembly;
|
||||
mod canonical;
|
||||
mod canonicalize;
|
||||
mod eval_ctxt;
|
||||
mod fulfill;
|
||||
mod project_goals;
|
||||
|
@ -66,7 +63,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let ty::OutlivesPredicate(ty, lt) = goal.predicate;
|
||||
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
|
||||
self.register_ty_outlives(ty, lt);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
|
@ -75,10 +72,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
&mut self,
|
||||
goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.infcx.region_outlives_predicate(
|
||||
&ObligationCause::dummy(),
|
||||
ty::Binder::dummy(goal.predicate),
|
||||
);
|
||||
let ty::OutlivesPredicate(a, b) = goal.predicate;
|
||||
self.register_region_outlives(a, b);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
|
@ -142,13 +137,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
&mut self,
|
||||
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
match crate::traits::wf::unnormalized_obligations(
|
||||
self.infcx,
|
||||
goal.param_env,
|
||||
goal.predicate,
|
||||
) {
|
||||
Some(obligations) => {
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
match self.well_formed_goals(goal.param_env, goal.predicate) {
|
||||
Some(goals) => {
|
||||
self.add_goals(goals);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::traits::{specialization_graph, translate_substs};
|
||||
use crate::traits::specialization_graph;
|
||||
|
||||
use super::assembly;
|
||||
use super::trait_goals::structural_traits;
|
||||
|
@ -7,7 +7,6 @@ use rustc_errors::ErrorGuaranteed;
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::specialization_graph::LeafDef;
|
||||
use rustc_infer::traits::Reveal;
|
||||
|
@ -165,7 +164,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
// return ambiguity this would otherwise be incomplete, resulting in
|
||||
// unsoundness during coherence (#105782).
|
||||
let Some(assoc_def) = fetch_eligible_assoc_item_def(
|
||||
ecx.infcx,
|
||||
ecx,
|
||||
goal.param_env,
|
||||
goal_trait_ref,
|
||||
goal.predicate.def_id(),
|
||||
|
@ -196,8 +195,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
goal_trait_ref.def_id,
|
||||
impl_substs,
|
||||
);
|
||||
let substs = translate_substs(
|
||||
ecx.infcx,
|
||||
let substs = ecx.translate_substs(
|
||||
goal.param_env,
|
||||
impl_def_id,
|
||||
impl_substs_with_gat,
|
||||
|
@ -504,15 +502,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
///
|
||||
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
|
||||
/// diverge.
|
||||
#[instrument(level = "debug", skip(infcx, param_env), ret)]
|
||||
#[instrument(level = "debug", skip(ecx, param_env), ret)]
|
||||
fn fetch_eligible_assoc_item_def<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ecx: &EvalCtxt<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
goal_trait_ref: ty::TraitRef<'tcx>,
|
||||
trait_assoc_def_id: DefId,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Option<LeafDef>, NoSolution> {
|
||||
let node_item = specialization_graph::assoc_def(infcx.tcx, impl_def_id, trait_assoc_def_id)
|
||||
let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id)
|
||||
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
|
||||
|
||||
let eligible = if node_item.is_final() {
|
||||
|
@ -524,7 +522,7 @@ fn fetch_eligible_assoc_item_def<'tcx>(
|
|||
// transmute checking and polymorphic MIR optimizations could
|
||||
// get a result which isn't correct for all monomorphizations.
|
||||
if param_env.reveal() == Reveal::All {
|
||||
let poly_trait_ref = infcx.resolve_vars_if_possible(goal_trait_ref);
|
||||
let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
|
||||
!poly_trait_ref.still_further_specializable()
|
||||
} else {
|
||||
debug!(?node_item.item.def_id, "not eligible due to default");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue