mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Move some solver stuff to middle
This commit is contained in:
parent
ff4b772f80
commit
67698aa6ad
@ -53,6 +53,12 @@ pub struct Obligation<'tcx, T> {
|
||||
pub recursion_depth: usize,
|
||||
}
|
||||
|
||||
impl<'tcx, P> From<Obligation<'tcx, P>> for solve::Goal<'tcx, P> {
|
||||
fn from(value: Obligation<'tcx, P>) -> Self {
|
||||
solve::Goal { param_env: value.param_env, predicate: value.predicate }
|
||||
}
|
||||
}
|
||||
|
||||
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
||||
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
||||
|
||||
|
@ -1,12 +1,104 @@
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_query_system::cache::Cache;
|
||||
|
||||
use crate::infer::canonical::QueryRegionConstraints;
|
||||
use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::Canonical;
|
||||
use crate::ty::{
|
||||
FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
|
||||
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
|
||||
TypeVisitor,
|
||||
};
|
||||
|
||||
pub type EvaluationCache<'tcx> = Cache<CanonicalGoal<'tcx>, QueryResult<'tcx>>;
|
||||
|
||||
/// A goal is a statement, i.e. `predicate`, we want to prove
|
||||
/// given some assumptions, i.e. `param_env`.
|
||||
///
|
||||
/// Most of the time the `param_env` contains the `where`-bounds of the function
|
||||
/// we're currently typechecking while the `predicate` is some trait bound.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub struct Goal<'tcx, P> {
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
pub predicate: P,
|
||||
}
|
||||
|
||||
impl<'tcx, P> Goal<'tcx, P> {
|
||||
pub fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
predicate: impl ToPredicate<'tcx, P>,
|
||||
) -> Goal<'tcx, P> {
|
||||
Goal { param_env, predicate: predicate.to_predicate(tcx) }
|
||||
}
|
||||
|
||||
/// Updates the goal to one with a different `predicate` but the same `param_env`.
|
||||
pub fn with<Q>(self, tcx: TyCtxt<'tcx>, predicate: impl ToPredicate<'tcx, Q>) -> Goal<'tcx, Q> {
|
||||
Goal { param_env: self.param_env, predicate: predicate.to_predicate(tcx) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub struct Response<'tcx> {
|
||||
pub var_values: CanonicalVarValues<'tcx>,
|
||||
/// Additional constraints returned by this query.
|
||||
pub external_constraints: ExternalConstraints<'tcx>,
|
||||
pub certainty: Certainty,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub enum Certainty {
|
||||
Yes,
|
||||
Maybe(MaybeCause),
|
||||
}
|
||||
|
||||
impl Certainty {
|
||||
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
|
||||
|
||||
/// When proving multiple goals using **AND**, e.g. nested obligations for an impl,
|
||||
/// use this function to unify the certainty of these goals
|
||||
pub fn unify_and(self, other: Certainty) -> Certainty {
|
||||
match (self, other) {
|
||||
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
|
||||
(Certainty::Yes, Certainty::Maybe(_)) => other,
|
||||
(Certainty::Maybe(_), Certainty::Yes) => self,
|
||||
(Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
|
||||
Certainty::Maybe(MaybeCause::Overflow)
|
||||
}
|
||||
// If at least one of the goals is ambiguous, hide the overflow as the ambiguous goal
|
||||
// may still result in failure.
|
||||
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(_))
|
||||
| (Certainty::Maybe(_), Certainty::Maybe(MaybeCause::Ambiguity)) => {
|
||||
Certainty::Maybe(MaybeCause::Ambiguity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Why we failed to evaluate a goal.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub enum MaybeCause {
|
||||
/// We failed due to ambiguity. This ambiguity can either
|
||||
/// be a true ambiguity, i.e. there are multiple different answers,
|
||||
/// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
|
||||
Ambiguity,
|
||||
/// We gave up due to an overflow, most often by hitting the recursion limit.
|
||||
Overflow,
|
||||
}
|
||||
|
||||
pub type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>;
|
||||
|
||||
pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
|
||||
|
||||
/// The result of evaluating a canonical query.
|
||||
///
|
||||
/// FIXME: We use a different type than the existing canonical queries. This is because
|
||||
/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
|
||||
/// having to worry about changes to currently used code. Once we've made progress on this
|
||||
/// solver, merge the two responses again.
|
||||
pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
|
||||
pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>);
|
||||
|
||||
|
@ -2,11 +2,12 @@
|
||||
|
||||
#[cfg(doc)]
|
||||
use super::trait_goals::structural_traits::*;
|
||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
||||
use super::EvalCtxt;
|
||||
use itertools::Itertools;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::elaborate_predicates;
|
||||
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use std::fmt::Debug;
|
||||
|
@ -21,11 +21,13 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
|
||||
use rustc_middle::traits::solve::{
|
||||
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
|
||||
Goal, MaybeCause, QueryResult, Response,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate,
|
||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
@ -43,45 +45,6 @@ mod trait_goals;
|
||||
pub use eval_ctxt::EvalCtxt;
|
||||
pub use fulfill::FulfillmentCtxt;
|
||||
|
||||
/// A goal is a statement, i.e. `predicate`, we want to prove
|
||||
/// given some assumptions, i.e. `param_env`.
|
||||
///
|
||||
/// Most of the time the `param_env` contains the `where`-bounds of the function
|
||||
/// we're currently typechecking while the `predicate` is some trait bound.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub struct Goal<'tcx, P> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
predicate: P,
|
||||
}
|
||||
|
||||
impl<'tcx, P> Goal<'tcx, P> {
|
||||
pub fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
predicate: impl ToPredicate<'tcx, P>,
|
||||
) -> Goal<'tcx, P> {
|
||||
Goal { param_env, predicate: predicate.to_predicate(tcx) }
|
||||
}
|
||||
|
||||
/// Updates the goal to one with a different `predicate` but the same `param_env`.
|
||||
fn with<Q>(self, tcx: TyCtxt<'tcx>, predicate: impl ToPredicate<'tcx, Q>) -> Goal<'tcx, Q> {
|
||||
Goal { param_env: self.param_env, predicate: predicate.to_predicate(tcx) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, P> From<Obligation<'tcx, P>> for Goal<'tcx, P> {
|
||||
fn from(obligation: Obligation<'tcx, P>) -> Goal<'tcx, P> {
|
||||
Goal { param_env: obligation.param_env, predicate: obligation.predicate }
|
||||
}
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub struct Response<'tcx> {
|
||||
pub var_values: CanonicalVarValues<'tcx>,
|
||||
/// Additional constraints returned by this query.
|
||||
pub external_constraints: ExternalConstraints<'tcx>,
|
||||
pub certainty: Certainty,
|
||||
}
|
||||
|
||||
trait CanonicalResponseExt {
|
||||
fn has_no_inference_or_external_constraints(&self) -> bool;
|
||||
}
|
||||
@ -94,56 +57,6 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub enum Certainty {
|
||||
Yes,
|
||||
Maybe(MaybeCause),
|
||||
}
|
||||
|
||||
impl Certainty {
|
||||
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
|
||||
|
||||
/// When proving multiple goals using **AND**, e.g. nested obligations for an impl,
|
||||
/// use this function to unify the certainty of these goals
|
||||
pub fn unify_and(self, other: Certainty) -> Certainty {
|
||||
match (self, other) {
|
||||
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
|
||||
(Certainty::Yes, Certainty::Maybe(_)) => other,
|
||||
(Certainty::Maybe(_), Certainty::Yes) => self,
|
||||
(Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
|
||||
Certainty::Maybe(MaybeCause::Overflow)
|
||||
}
|
||||
// If at least one of the goals is ambiguous, hide the overflow as the ambiguous goal
|
||||
// may still result in failure.
|
||||
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(_))
|
||||
| (Certainty::Maybe(_), Certainty::Maybe(MaybeCause::Ambiguity)) => {
|
||||
Certainty::Maybe(MaybeCause::Ambiguity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Why we failed to evaluate a goal.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub enum MaybeCause {
|
||||
/// We failed due to ambiguity. This ambiguity can either
|
||||
/// be a true ambiguity, i.e. there are multiple different answers,
|
||||
/// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
|
||||
Ambiguity,
|
||||
/// We gave up due to an overflow, most often by hitting the recursion limit.
|
||||
Overflow,
|
||||
}
|
||||
|
||||
type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>;
|
||||
type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
|
||||
/// The result of evaluating a canonical query.
|
||||
///
|
||||
/// FIXME: We use a different type than the existing canonical queries. This is because
|
||||
/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
|
||||
/// having to worry about changes to currently used code. Once we've made progress on this
|
||||
/// solver, merge the two responses again.
|
||||
pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>;
|
||||
|
||||
pub trait InferCtxtEvalExt<'tcx> {
|
||||
/// Evaluates a goal from **outside** of the trait solver.
|
||||
///
|
||||
|
@ -2,7 +2,7 @@ use crate::traits::{specialization_graph, translate_substs};
|
||||
|
||||
use super::assembly;
|
||||
use super::trait_goals::structural_traits;
|
||||
use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
use super::EvalCtxt;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -11,6 +11,7 @@ use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::specialization_graph::LeafDef;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::ProjectionPredicate;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
@ -512,7 +513,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||
fn consider_builtin_dyn_upcast_candidates(
|
||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Vec<super::CanonicalResponse<'tcx>> {
|
||||
) -> Vec<CanonicalResponse<'tcx>> {
|
||||
bug!("`Unsize` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,9 @@
|
||||
//! before then or if I still haven't done that before January 2023.
|
||||
use super::overflow::OverflowData;
|
||||
use super::StackDepth;
|
||||
use crate::solve::{CanonicalGoal, QueryResult};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::traits::solve::{CanonicalGoal, QueryResult};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
|
@ -2,11 +2,11 @@ mod cache;
|
||||
mod overflow;
|
||||
|
||||
use self::cache::ProvisionalEntry;
|
||||
use super::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
|
||||
pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
|
||||
use cache::ProvisionalCache;
|
||||
use overflow::OverflowData;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use std::{collections::hash_map::Entry, mem};
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{Certainty, MaybeCause, QueryResult};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Limit;
|
||||
|
||||
use super::SearchGraph;
|
||||
use crate::solve::{response_no_constraints, Certainty, EvalCtxt, MaybeCause, QueryResult};
|
||||
use crate::solve::{response_no_constraints, EvalCtxt};
|
||||
|
||||
/// When detecting a solver overflow, we return ambiguity. Overflow can be
|
||||
/// *hidden* by either a fatal error in an **AND** or a trivial success in an **OR**.
|
||||
|
@ -2,12 +2,12 @@
|
||||
|
||||
use std::iter;
|
||||
|
||||
use super::assembly;
|
||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
||||
use super::{assembly, EvalCtxt};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
|
||||
|
@ -1,9 +1,10 @@
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::config::TraitSolver;
|
||||
|
||||
use crate::infer::canonical::OriginalQueryValues;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause};
|
||||
use crate::solve::InferCtxtEvalExt;
|
||||
use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
|
Loading…
Reference in New Issue
Block a user