Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make EvalCtxt's infcx private #109511

Merged
merged 2 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 62 additions & 7 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,42 @@ 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,
};
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>,
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved

pub(super) var_values: CanonicalVarValues<'tcx>,
/// The highest universe index nameable by the caller.
///
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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> {
Expand Down Expand Up @@ -219,15 +216,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
for &(ty::OutlivesPredicate(lhs, rhs), _) in &region_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:?}"),
}
}
Expand Down
25 changes: 8 additions & 17 deletions compiler/rustc_trait_selection/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,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;
Expand Down Expand Up @@ -68,7 +65,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)
}

Expand All @@ -77,10 +74,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)
}

Expand Down Expand Up @@ -146,13 +141,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),
Expand Down
16 changes: 7 additions & 9 deletions compiler/rustc_trait_selection/src/solve/project_goals.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -168,7 +167,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(),
Expand Down Expand Up @@ -199,8 +198,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,
Expand Down Expand Up @@ -500,15 +498,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() {
Expand All @@ -520,7 +518,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");
Expand Down