Move some InferCtxt methods to EvalCtxt in new solver
This commit is contained in:
parent
375d5ace70
commit
7596998d1c
7 changed files with 228 additions and 226 deletions
|
@ -1,6 +1,5 @@
|
||||||
//! Code shared by trait and projection goals for candidate assembly.
|
//! Code shared by trait and projection goals for candidate assembly.
|
||||||
|
|
||||||
use super::infcx_ext::InferCtxtExt;
|
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use super::trait_goals::structural_traits::*;
|
use super::trait_goals::structural_traits::*;
|
||||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
||||||
|
@ -206,7 +205,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, G>,
|
goal: Goal<'tcx, G>,
|
||||||
) -> Vec<Candidate<'tcx>> {
|
) -> Vec<Candidate<'tcx>> {
|
||||||
debug_assert_eq!(goal, self.infcx.resolve_vars_if_possible(goal));
|
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
|
||||||
|
|
||||||
// HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
|
// HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
|
||||||
// object bound, alias bound, etc. We are unable to determine this until we can at
|
// object bound, alias bound, etc. We are unable to determine this until we can at
|
||||||
|
@ -250,8 +249,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
|
let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
self.infcx.probe(|_| {
|
self.probe(|this| {
|
||||||
let normalized_ty = self.infcx.next_ty_infer();
|
let normalized_ty = this.next_ty_infer();
|
||||||
let normalizes_to_goal = goal.with(
|
let normalizes_to_goal = goal.with(
|
||||||
tcx,
|
tcx,
|
||||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||||
|
@ -259,16 +258,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
term: normalized_ty.into(),
|
term: normalized_ty.into(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
let normalization_certainty = match self.evaluate_goal(normalizes_to_goal) {
|
let normalization_certainty = match this.evaluate_goal(normalizes_to_goal) {
|
||||||
Ok((_, certainty)) => certainty,
|
Ok((_, certainty)) => certainty,
|
||||||
Err(NoSolution) => return,
|
Err(NoSolution) => return,
|
||||||
};
|
};
|
||||||
let normalized_ty = self.infcx.resolve_vars_if_possible(normalized_ty);
|
let normalized_ty = this.resolve_vars_if_possible(normalized_ty);
|
||||||
|
|
||||||
// NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
|
// NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
|
||||||
// This doesn't work as long as we use `CandidateSource` in winnowing.
|
// This doesn't work as long as we use `CandidateSource` in winnowing.
|
||||||
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
|
let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
|
||||||
let normalized_candidates = self.assemble_and_evaluate_candidates(goal);
|
let normalized_candidates = this.assemble_and_evaluate_candidates(goal);
|
||||||
for mut normalized_candidate in normalized_candidates {
|
for mut normalized_candidate in normalized_candidates {
|
||||||
normalized_candidate.result =
|
normalized_candidate.result =
|
||||||
normalized_candidate.result.unchecked_map(|mut response| {
|
normalized_candidate.result.unchecked_map(|mut response| {
|
||||||
|
|
172
compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
Normal file
172
compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_infer::infer::at::ToTrace;
|
||||||
|
use rustc_infer::infer::canonical::CanonicalVarValues;
|
||||||
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||||
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
use rustc_infer::traits::ObligationCause;
|
||||||
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||||
|
use rustc_middle::ty::{self, ir::TypeVisitor, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable};
|
||||||
|
use rustc_span::DUMMY_SP;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::search_graph::SearchGraph;
|
||||||
|
use super::Goal;
|
||||||
|
|
||||||
|
pub struct EvalCtxt<'a, 'tcx> {
|
||||||
|
// FIXME: should be private.
|
||||||
|
pub(super) infcx: &'a InferCtxt<'tcx>,
|
||||||
|
|
||||||
|
pub(super) var_values: CanonicalVarValues<'tcx>,
|
||||||
|
|
||||||
|
pub(super) search_graph: &'a mut SearchGraph<'tcx>,
|
||||||
|
|
||||||
|
/// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`],
|
||||||
|
/// see the comment in that method for more details.
|
||||||
|
pub in_projection_eq_hack: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
|
||||||
|
self.infcx.probe(|_| f(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
|
self.infcx.tcx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||||
|
self.infcx.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::MiscVariable,
|
||||||
|
span: DUMMY_SP,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
|
||||||
|
self.infcx.next_const_var(
|
||||||
|
ty,
|
||||||
|
ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span: DUMMY_SP },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
|
||||||
|
///
|
||||||
|
/// This is the case if the `term` is an inference variable in the innermost universe
|
||||||
|
/// and does not occur in any other part of the predicate.
|
||||||
|
pub(super) fn term_is_fully_unconstrained(
|
||||||
|
&self,
|
||||||
|
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
|
||||||
|
) -> bool {
|
||||||
|
let term_is_infer = match goal.predicate.term.unpack() {
|
||||||
|
ty::TermKind::Ty(ty) => {
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::TermKind::Const(ct) => {
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Guard against `<T as Trait<?0>>::Assoc = ?0>`.
|
||||||
|
struct ContainsTerm<'tcx> {
|
||||||
|
term: ty::Term<'tcx>,
|
||||||
|
}
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTerm<'tcx> {
|
||||||
|
type BreakTy = ();
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if t.needs_infer() {
|
||||||
|
if ty::Term::from(t) == self.term {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
t.super_visit_with(self)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if c.needs_infer() {
|
||||||
|
if ty::Term::from(c) == self.term {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
c.super_visit_with(self)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visitor = ContainsTerm { term: goal.predicate.term };
|
||||||
|
|
||||||
|
term_is_infer
|
||||||
|
&& goal.predicate.projection_ty.visit_with(&mut visitor).is_continue()
|
||||||
|
&& goal.param_env.visit_with(&mut visitor).is_continue()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self, param_env), ret)]
|
||||||
|
pub(super) fn eq<T: ToTrace<'tcx>>(
|
||||||
|
&self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
lhs: T,
|
||||||
|
rhs: T,
|
||||||
|
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||||
|
self.infcx
|
||||||
|
.at(&ObligationCause::dummy(), param_env)
|
||||||
|
.eq(lhs, rhs)
|
||||||
|
.map(|InferOk { value: (), obligations }| {
|
||||||
|
obligations.into_iter().map(|o| o.into()).collect()
|
||||||
|
})
|
||||||
|
.map_err(|e| {
|
||||||
|
debug!(?e, "failed to equate");
|
||||||
|
NoSolution
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>(
|
||||||
|
&self,
|
||||||
|
value: ty::Binder<'tcx, T>,
|
||||||
|
) -> T {
|
||||||
|
self.infcx.instantiate_binder_with_fresh_vars(
|
||||||
|
DUMMY_SP,
|
||||||
|
LateBoundRegionConversionTime::HigherRankedType,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<'tcx> + Copy>(
|
||||||
|
&self,
|
||||||
|
value: ty::Binder<'tcx, T>,
|
||||||
|
) -> T {
|
||||||
|
self.infcx.instantiate_binder_with_placeholders(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||||
|
where
|
||||||
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
self.infcx.resolve_vars_if_possible(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn fresh_substs_for_item(&self, def_id: DefId) -> ty::SubstsRef<'tcx> {
|
||||||
|
self.infcx.fresh_substs_for_item(DUMMY_SP, def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn universe(&self) -> ty::UniverseIndex {
|
||||||
|
self.infcx.universe()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,77 +0,0 @@
|
||||||
use rustc_infer::infer::at::ToTrace;
|
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
|
||||||
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
|
||||||
use rustc_infer::traits::query::NoSolution;
|
|
||||||
use rustc_infer::traits::ObligationCause;
|
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
|
||||||
use rustc_middle::ty::{self, Ty, TypeFoldable};
|
|
||||||
use rustc_span::DUMMY_SP;
|
|
||||||
|
|
||||||
use super::Goal;
|
|
||||||
|
|
||||||
/// Methods used inside of the canonical queries of the solver.
|
|
||||||
///
|
|
||||||
/// Most notably these do not care about diagnostics information.
|
|
||||||
/// If you find this while looking for methods to use outside of the
|
|
||||||
/// solver, you may look at the implementation of these method for
|
|
||||||
/// help.
|
|
||||||
pub(super) trait InferCtxtExt<'tcx> {
|
|
||||||
fn next_ty_infer(&self) -> Ty<'tcx>;
|
|
||||||
fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx>;
|
|
||||||
|
|
||||||
fn eq<T: ToTrace<'tcx>>(
|
|
||||||
&self,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
lhs: T,
|
|
||||||
rhs: T,
|
|
||||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
|
|
||||||
|
|
||||||
fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>(
|
|
||||||
&self,
|
|
||||||
value: ty::Binder<'tcx, T>,
|
|
||||||
) -> T;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|
||||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
|
||||||
self.next_ty_var(TypeVariableOrigin {
|
|
||||||
kind: TypeVariableOriginKind::MiscVariable,
|
|
||||||
span: DUMMY_SP,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
|
|
||||||
self.next_const_var(
|
|
||||||
ty,
|
|
||||||
ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span: DUMMY_SP },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, param_env), ret)]
|
|
||||||
fn eq<T: ToTrace<'tcx>>(
|
|
||||||
&self,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
lhs: T,
|
|
||||||
rhs: T,
|
|
||||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
|
||||||
self.at(&ObligationCause::dummy(), param_env)
|
|
||||||
.eq(lhs, rhs)
|
|
||||||
.map(|InferOk { value: (), obligations }| {
|
|
||||||
obligations.into_iter().map(|o| o.into()).collect()
|
|
||||||
})
|
|
||||||
.map_err(|e| {
|
|
||||||
debug!(?e, "failed to equate");
|
|
||||||
NoSolution
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>(
|
|
||||||
&self,
|
|
||||||
value: ty::Binder<'tcx, T>,
|
|
||||||
) -> T {
|
|
||||||
self.instantiate_binder_with_fresh_vars(
|
|
||||||
DUMMY_SP,
|
|
||||||
LateBoundRegionConversionTime::HigherRankedType,
|
|
||||||
value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,16 +35,15 @@ use crate::solve::search_graph::OverflowHandler;
|
||||||
use crate::traits::ObligationCause;
|
use crate::traits::ObligationCause;
|
||||||
|
|
||||||
mod assembly;
|
mod assembly;
|
||||||
|
mod eval_ctxt;
|
||||||
mod fulfill;
|
mod fulfill;
|
||||||
mod infcx_ext;
|
|
||||||
mod project_goals;
|
mod project_goals;
|
||||||
mod search_graph;
|
mod search_graph;
|
||||||
mod trait_goals;
|
mod trait_goals;
|
||||||
|
|
||||||
|
pub use eval_ctxt::EvalCtxt;
|
||||||
pub use fulfill::FulfillmentCtxt;
|
pub use fulfill::FulfillmentCtxt;
|
||||||
|
|
||||||
use self::infcx_ext::InferCtxtExt;
|
|
||||||
|
|
||||||
/// A goal is a statement, i.e. `predicate`, we want to prove
|
/// A goal is a statement, i.e. `predicate`, we want to prove
|
||||||
/// given some assumptions, i.e. `param_env`.
|
/// given some assumptions, i.e. `param_env`.
|
||||||
///
|
///
|
||||||
|
@ -180,22 +179,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EvalCtxt<'a, 'tcx> {
|
|
||||||
infcx: &'a InferCtxt<'tcx>,
|
|
||||||
var_values: CanonicalVarValues<'tcx>,
|
|
||||||
|
|
||||||
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
|
|
||||||
|
|
||||||
/// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`],
|
|
||||||
/// see the comment in that method for more details.
|
|
||||||
in_projection_eq_hack: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
|
||||||
self.infcx.tcx
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The entry point of the solver.
|
/// The entry point of the solver.
|
||||||
///
|
///
|
||||||
/// This function deals with (coinductive) cycles, overflow, and caching
|
/// This function deals with (coinductive) cycles, overflow, and caching
|
||||||
|
@ -427,7 +411,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
|
let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
|
||||||
debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
|
debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
|
||||||
let r = ecx.infcx.probe(|_| {
|
let r = ecx.probe(|ecx| {
|
||||||
let (_, certainty) = ecx.evaluate_goal(goal.with(
|
let (_, certainty) = ecx.evaluate_goal(goal.with(
|
||||||
tcx,
|
tcx,
|
||||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||||
|
@ -462,10 +446,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
// Evaluate all 3 potential candidates for the alias' being equal
|
// Evaluate all 3 potential candidates for the alias' being equal
|
||||||
candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
|
candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
|
||||||
candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
|
candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
|
||||||
candidates.push(self.infcx.probe(|_| {
|
candidates.push(self.probe(|this| {
|
||||||
debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
|
debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
|
||||||
let nested_goals = self.infcx.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
let nested_goals = this.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
||||||
self.evaluate_all_and_make_canonical_response(nested_goals)
|
this.evaluate_all_and_make_canonical_response(nested_goals)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
debug!(?candidates);
|
debug!(?candidates);
|
||||||
|
@ -481,7 +465,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
|
goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let (ct, ty) = goal.predicate;
|
let (ct, ty) = goal.predicate;
|
||||||
let nested_goals = self.infcx.eq(goal.param_env, ct.ty(), ty)?;
|
let nested_goals = self.eq(goal.param_env, ct.ty(), ty)?;
|
||||||
self.evaluate_all_and_make_canonical_response(nested_goals)
|
self.evaluate_all_and_make_canonical_response(nested_goals)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::traits::{specialization_graph, translate_substs};
|
use crate::traits::{specialization_graph, translate_substs};
|
||||||
|
|
||||||
use super::assembly;
|
use super::assembly;
|
||||||
use super::infcx_ext::InferCtxtExt;
|
|
||||||
use super::trait_goals::structural_traits;
|
use super::trait_goals::structural_traits;
|
||||||
use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
|
@ -13,12 +12,11 @@ use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_infer::traits::specialization_graph::LeafDef;
|
use rustc_infer::traits::specialization_graph::LeafDef;
|
||||||
use rustc_infer::traits::Reveal;
|
use rustc_infer::traits::Reveal;
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||||
|
use rustc_middle::ty::ProjectionPredicate;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{ir::TypeVisitor, ProjectionPredicate, TypeSuperVisitable};
|
|
||||||
use rustc_middle::ty::{ToPredicate, TypeVisitable};
|
use rustc_middle::ty::{ToPredicate, TypeVisitable};
|
||||||
use rustc_span::{sym, DUMMY_SP};
|
use rustc_span::{sym, DUMMY_SP};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
pub(super) fn compute_projection_goal(
|
pub(super) fn compute_projection_goal(
|
||||||
|
@ -38,8 +36,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
let predicate = goal.predicate;
|
let predicate = goal.predicate;
|
||||||
let unconstrained_rhs = match predicate.term.unpack() {
|
let unconstrained_rhs = match predicate.term.unpack() {
|
||||||
ty::TermKind::Ty(_) => self.infcx.next_ty_infer().into(),
|
ty::TermKind::Ty(_) => self.next_ty_infer().into(),
|
||||||
ty::TermKind::Const(ct) => self.infcx.next_const_infer(ct.ty()).into(),
|
ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(),
|
||||||
};
|
};
|
||||||
let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate {
|
let unconstrained_predicate = ty::Clause::Projection(ProjectionPredicate {
|
||||||
projection_ty: goal.predicate.projection_ty,
|
projection_ty: goal.predicate.projection_ty,
|
||||||
|
@ -49,8 +47,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
this.evaluate_goal(goal.with(this.tcx(), unconstrained_predicate))
|
this.evaluate_goal(goal.with(this.tcx(), unconstrained_predicate))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let nested_eq_goals =
|
let nested_eq_goals = self.eq(goal.param_env, unconstrained_rhs, predicate.term)?;
|
||||||
self.infcx.eq(goal.param_env, unconstrained_rhs, predicate.term)?;
|
|
||||||
let eval_certainty = self.evaluate_all(nested_eq_goals)?;
|
let eval_certainty = self.evaluate_all(nested_eq_goals)?;
|
||||||
self.make_canonical_response(normalize_certainty.unify_and(eval_certainty))
|
self.make_canonical_response(normalize_certainty.unify_and(eval_certainty))
|
||||||
}
|
}
|
||||||
|
@ -65,73 +62,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
|
|
||||||
///
|
|
||||||
/// This is the case if the `term` is an inference variable in the innermost universe
|
|
||||||
/// and does not occur in any other part of the predicate.
|
|
||||||
fn term_is_fully_unconstrained(&self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>) -> bool {
|
|
||||||
let infcx = self.infcx;
|
|
||||||
let term_is_infer = match goal.predicate.term.unpack() {
|
|
||||||
ty::TermKind::Ty(ty) => {
|
|
||||||
if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
|
|
||||||
match infcx.probe_ty_var(vid) {
|
|
||||||
Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
|
|
||||||
Err(universe) => universe == infcx.universe(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::TermKind::Const(ct) => {
|
|
||||||
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 == infcx.universe(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Guard against `<T as Trait<?0>>::Assoc = ?0>`.
|
|
||||||
struct ContainsTerm<'tcx> {
|
|
||||||
term: ty::Term<'tcx>,
|
|
||||||
}
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTerm<'tcx> {
|
|
||||||
type BreakTy = ();
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
if t.needs_infer() {
|
|
||||||
if ty::Term::from(t) == self.term {
|
|
||||||
ControlFlow::Break(())
|
|
||||||
} else {
|
|
||||||
t.super_visit_with(self)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
if c.needs_infer() {
|
|
||||||
if ty::Term::from(c) == self.term {
|
|
||||||
ControlFlow::Break(())
|
|
||||||
} else {
|
|
||||||
c.super_visit_with(self)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visitor = ContainsTerm { term: goal.predicate.term };
|
|
||||||
|
|
||||||
term_is_infer
|
|
||||||
&& goal.predicate.projection_ty.visit_with(&mut visitor).is_continue()
|
|
||||||
&& goal.param_env.visit_with(&mut visitor).is_continue()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// After normalizing the projection to `normalized_alias` with the given
|
/// After normalizing the projection to `normalized_alias` with the given
|
||||||
/// `normalization_certainty`, constrain the inference variable `term` to it
|
/// `normalization_certainty`, constrain the inference variable `term` to it
|
||||||
/// and return a query response.
|
/// and return a query response.
|
||||||
|
@ -145,7 +75,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
//
|
//
|
||||||
// It can however be ambiguous when the `normalized_alias` contains a projection.
|
// It can however be ambiguous when the `normalized_alias` contains a projection.
|
||||||
let nested_goals = self
|
let nested_goals = self
|
||||||
.infcx
|
|
||||||
.eq(goal.param_env, goal.predicate.term, normalized_alias.into())
|
.eq(goal.param_env, goal.predicate.term, normalized_alias.into())
|
||||||
.expect("failed to unify with unconstrained term");
|
.expect("failed to unify with unconstrained term");
|
||||||
let rhs_certainty =
|
let rhs_certainty =
|
||||||
|
@ -177,10 +106,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
|
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
|
||||||
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
|
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
|
||||||
{
|
{
|
||||||
ecx.infcx.probe(|_| {
|
ecx.probe(|ecx| {
|
||||||
let assumption_projection_pred =
|
let assumption_projection_pred =
|
||||||
ecx.infcx.instantiate_binder_with_infer(poly_projection_pred);
|
ecx.instantiate_binder_with_infer(poly_projection_pred);
|
||||||
let mut nested_goals = ecx.infcx.eq(
|
let mut nested_goals = ecx.eq(
|
||||||
goal.param_env,
|
goal.param_env,
|
||||||
goal.predicate.projection_ty,
|
goal.predicate.projection_ty,
|
||||||
assumption_projection_pred.projection_ty,
|
assumption_projection_pred.projection_ty,
|
||||||
|
@ -215,11 +144,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.infcx.probe(|_| {
|
ecx.probe(|ecx| {
|
||||||
let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
|
||||||
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
|
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
|
||||||
|
|
||||||
let mut nested_goals = ecx.infcx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
|
let mut nested_goals = ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
|
||||||
let where_clause_bounds = tcx
|
let where_clause_bounds = tcx
|
||||||
.predicates_of(impl_def_id)
|
.predicates_of(impl_def_id)
|
||||||
.instantiate(tcx, impl_substs)
|
.instantiate(tcx, impl_substs)
|
||||||
|
@ -367,7 +296,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
ecx.infcx.probe(|_| {
|
ecx.probe(|ecx| {
|
||||||
let metadata_ty = match goal.predicate.self_ty().kind() {
|
let metadata_ty = match goal.predicate.self_ty().kind() {
|
||||||
ty::Bool
|
ty::Bool
|
||||||
| ty::Char
|
| ty::Char
|
||||||
|
@ -546,8 +475,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx());
|
let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx());
|
||||||
ecx.infcx
|
ecx.probe(|ecx| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant))
|
||||||
.probe(|_| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use super::assembly;
|
use super::assembly;
|
||||||
use super::infcx_ext::InferCtxtExt;
|
|
||||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::LangItem;
|
use rustc_hir::LangItem;
|
||||||
use rustc_infer::infer::InferCtxt;
|
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_infer::traits::util::supertraits;
|
use rustc_infer::traits::util::supertraits;
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||||
|
@ -45,12 +43,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.infcx.probe(|_| {
|
ecx.probe(|ecx| {
|
||||||
let impl_substs = ecx.infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
|
||||||
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
|
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
|
||||||
|
|
||||||
let mut nested_goals =
|
let mut nested_goals =
|
||||||
ecx.infcx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
|
ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
|
||||||
let where_clause_bounds = tcx
|
let where_clause_bounds = tcx
|
||||||
.predicates_of(impl_def_id)
|
.predicates_of(impl_def_id)
|
||||||
.instantiate(tcx, impl_substs)
|
.instantiate(tcx, impl_substs)
|
||||||
|
@ -72,10 +70,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
&& poly_trait_pred.def_id() == goal.predicate.def_id()
|
&& poly_trait_pred.def_id() == goal.predicate.def_id()
|
||||||
{
|
{
|
||||||
// FIXME: Constness and polarity
|
// FIXME: Constness and polarity
|
||||||
ecx.infcx.probe(|_| {
|
ecx.probe(|ecx| {
|
||||||
let assumption_trait_pred =
|
let assumption_trait_pred =
|
||||||
ecx.infcx.instantiate_binder_with_infer(poly_trait_pred);
|
ecx.instantiate_binder_with_infer(poly_trait_pred);
|
||||||
let mut nested_goals = ecx.infcx.eq(
|
let mut nested_goals = ecx.eq(
|
||||||
goal.param_env,
|
goal.param_env,
|
||||||
goal.predicate.trait_ref,
|
goal.predicate.trait_ref,
|
||||||
assumption_trait_pred.trait_ref,
|
assumption_trait_pred.trait_ref,
|
||||||
|
@ -118,7 +116,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
|
|
||||||
ecx.infcx.probe(|_| {
|
ecx.probe(|ecx| {
|
||||||
let nested_obligations = tcx
|
let nested_obligations = tcx
|
||||||
.predicates_of(goal.predicate.def_id())
|
.predicates_of(goal.predicate.def_id())
|
||||||
.instantiate(tcx, goal.predicate.trait_ref.substs);
|
.instantiate(tcx, goal.predicate.trait_ref.substs);
|
||||||
|
@ -275,7 +273,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
if b_ty.is_ty_var() {
|
if b_ty.is_ty_var() {
|
||||||
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
|
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
|
||||||
}
|
}
|
||||||
ecx.infcx.probe(|_| {
|
ecx.probe(|ecx| {
|
||||||
match (a_ty.kind(), b_ty.kind()) {
|
match (a_ty.kind(), b_ty.kind()) {
|
||||||
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
|
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
|
||||||
(&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
|
(&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
|
||||||
|
@ -318,7 +316,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
// `[T; n]` -> `[T]` unsizing
|
// `[T; n]` -> `[T]` unsizing
|
||||||
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
|
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
|
||||||
// We just require that the element type stays the same
|
// We just require that the element type stays the same
|
||||||
let nested_goals = ecx.infcx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
|
let nested_goals = ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
|
||||||
ecx.evaluate_all_and_make_canonical_response(nested_goals)
|
ecx.evaluate_all_and_make_canonical_response(nested_goals)
|
||||||
}
|
}
|
||||||
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
||||||
|
@ -352,7 +350,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
|
|
||||||
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
|
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
|
||||||
// types.
|
// types.
|
||||||
let mut nested_goals = ecx.infcx.eq(goal.param_env, unsized_a_ty, b_ty)?;
|
let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
|
||||||
nested_goals.push(goal.with(
|
nested_goals.push(goal.with(
|
||||||
tcx,
|
tcx,
|
||||||
ty::Binder::dummy(
|
ty::Binder::dummy(
|
||||||
|
@ -371,7 +369,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
|
|
||||||
// Substitute just the tail field of B., and require that they're equal.
|
// Substitute just the tail field of B., and require that they're equal.
|
||||||
let unsized_a_ty = tcx.mk_tup(a_rest_tys.iter().chain([b_last_ty]).copied());
|
let unsized_a_ty = tcx.mk_tup(a_rest_tys.iter().chain([b_last_ty]).copied());
|
||||||
let mut nested_goals = ecx.infcx.eq(goal.param_env, unsized_a_ty, b_ty)?;
|
let mut nested_goals = ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
|
||||||
|
|
||||||
// Similar to ADTs, require that the rest of the fields are equal.
|
// Similar to ADTs, require that the rest of the fields are equal.
|
||||||
nested_goals.push(goal.with(
|
nested_goals.push(goal.with(
|
||||||
|
@ -411,7 +409,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
|
let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
|
||||||
ecx.infcx.probe(|_| -> Result<_, NoSolution> {
|
ecx.probe(|ecx| -> Result<_, NoSolution> {
|
||||||
// Require that all of the trait predicates from A match B, except for
|
// Require that all of the trait predicates from A match B, except for
|
||||||
// the auto traits. We do this by constructing a new A type with B's
|
// the auto traits. We do this by constructing a new A type with B's
|
||||||
// auto traits, and equating these types.
|
// auto traits, and equating these types.
|
||||||
|
@ -431,7 +429,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn);
|
let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn);
|
||||||
|
|
||||||
// We also require that A's lifetime outlives B's lifetime.
|
// We also require that A's lifetime outlives B's lifetime.
|
||||||
let mut nested_obligations = ecx.infcx.eq(goal.param_env, new_a_ty, b_ty)?;
|
let mut nested_obligations = ecx.eq(goal.param_env, new_a_ty, b_ty)?;
|
||||||
nested_obligations.push(
|
nested_obligations.push(
|
||||||
goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))),
|
goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))),
|
||||||
);
|
);
|
||||||
|
@ -482,16 +480,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
fn probe_and_evaluate_goal_for_constituent_tys(
|
fn probe_and_evaluate_goal_for_constituent_tys(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||||
constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
|
constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
self.infcx.probe(|_| {
|
self.probe(|this| {
|
||||||
self.evaluate_all_and_make_canonical_response(
|
this.evaluate_all_and_make_canonical_response(
|
||||||
constituent_tys(self.infcx, goal.predicate.self_ty())?
|
constituent_tys(this, goal.predicate.self_ty())?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ty| {
|
.map(|ty| {
|
||||||
goal.with(
|
goal.with(
|
||||||
self.tcx(),
|
this.tcx(),
|
||||||
ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
|
ty::Binder::dummy(goal.predicate.with_self_ty(this.tcx(), ty)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
use rustc_hir::{Movability, Mutability};
|
use rustc_hir::{Movability, Mutability};
|
||||||
use rustc_infer::{infer::InferCtxt, traits::query::NoSolution};
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
|
|
||||||
|
use crate::solve::EvalCtxt;
|
||||||
|
|
||||||
// Calculates the constituent types of a type for `auto trait` purposes.
|
// Calculates the constituent types of a type for `auto trait` purposes.
|
||||||
//
|
//
|
||||||
// For types with an "existential" binder, i.e. generator witnesses, we also
|
// For types with an "existential" binder, i.e. generator witnesses, we also
|
||||||
// instantiate the binder with placeholders eagerly.
|
// instantiate the binder with placeholders eagerly.
|
||||||
pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
||||||
let tcx = infcx.tcx;
|
let tcx = ecx.tcx();
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Uint(_)
|
ty::Uint(_)
|
||||||
| ty::Int(_)
|
| ty::Int(_)
|
||||||
|
@ -53,9 +55,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||||
Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
|
Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::GeneratorWitness(types) => {
|
ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()),
|
||||||
Ok(infcx.instantiate_binder_with_placeholders(types).to_vec())
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::GeneratorWitnessMIR(..) => todo!(),
|
ty::GeneratorWitnessMIR(..) => todo!(),
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
|
@ -113,18 +113,18 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
||||||
ty::Tuple(tys) => Ok(tys.to_vec()),
|
ty::Tuple(tys) => Ok(tys.to_vec()),
|
||||||
|
|
||||||
ty::Adt(def, substs) => {
|
ty::Adt(def, substs) => {
|
||||||
let sized_crit = def.sized_constraint(infcx.tcx);
|
let sized_crit = def.sized_constraint(ecx.tcx());
|
||||||
Ok(sized_crit
|
Ok(sized_crit
|
||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
|
.map(|ty| sized_crit.rebind(*ty).subst(ecx.tcx(), substs))
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
ecx: &EvalCtxt<'_, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
|
@ -165,7 +165,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
|
ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
|
||||||
|
|
||||||
ty::Generator(_, substs, Movability::Movable) => {
|
ty::Generator(_, substs, Movability::Movable) => {
|
||||||
if infcx.tcx.features().generator_clone {
|
if ecx.tcx().features().generator_clone {
|
||||||
let generator = substs.as_generator();
|
let generator = substs.as_generator();
|
||||||
Ok(vec![generator.tupled_upvars_ty(), generator.witness()])
|
Ok(vec![generator.tupled_upvars_ty(), generator.witness()])
|
||||||
} else {
|
} else {
|
||||||
|
@ -173,9 +173,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::GeneratorWitness(types) => {
|
ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()),
|
||||||
Ok(infcx.instantiate_binder_with_placeholders(types).to_vec())
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::GeneratorWitnessMIR(..) => todo!(),
|
ty::GeneratorWitnessMIR(..) => todo!(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue