Prepopulate opaques in canonical input
This commit is contained in:
parent
a2d7ffc635
commit
f3c9c21658
@ -121,6 +121,7 @@ macro_rules! arena_types {
|
|||||||
>,
|
>,
|
||||||
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
|
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
|
||||||
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
|
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
|
||||||
|
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
|
||||||
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
|
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
|
||||||
[] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
|
[] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
|
||||||
[] mod_child: rustc_middle::metadata::ModChild,
|
[] mod_child: rustc_middle::metadata::ModChild,
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
|
use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
|
||||||
use crate::traits::query::NoSolution;
|
use crate::traits::query::NoSolution;
|
||||||
use crate::traits::Canonical;
|
use crate::traits::{Canonical, DefiningAnchor};
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
|
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
|
||||||
TypeVisitor,
|
TypeVisitor,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type EvaluationCache<'tcx> = Cache<CanonicalGoal<'tcx>, QueryResult<'tcx>>;
|
pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>;
|
||||||
|
|
||||||
/// 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`.
|
||||||
@ -96,7 +96,31 @@ pub enum MaybeCause {
|
|||||||
Overflow,
|
Overflow,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>;
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
|
||||||
|
pub struct QueryInput<'tcx, T> {
|
||||||
|
pub goal: Goal<'tcx, T>,
|
||||||
|
pub anchor: DefiningAnchor,
|
||||||
|
pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Additional constraints returned on success.
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
|
||||||
|
pub struct PredefinedOpaquesData<'tcx> {
|
||||||
|
pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
|
||||||
|
pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>);
|
||||||
|
|
||||||
|
impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
|
||||||
|
type Target = PredefinedOpaquesData<'tcx>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CanonicalInput<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, QueryInput<'tcx, T>>;
|
||||||
|
|
||||||
pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
|
pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
|
||||||
|
|
||||||
@ -165,3 +189,40 @@ fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
|
|||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Having to clone `region_constraints` for folding feels bad and
|
||||||
|
// probably isn't great wrt performance.
|
||||||
|
//
|
||||||
|
// Not sure how to fix this, maybe we should also intern `opaque_types` and
|
||||||
|
// `region_constraints` here or something.
|
||||||
|
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
|
||||||
|
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
|
||||||
|
self,
|
||||||
|
folder: &mut F,
|
||||||
|
) -> Result<Self, F::Error> {
|
||||||
|
Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body(
|
||||||
|
PredefinedOpaquesData {
|
||||||
|
opaque_types: self
|
||||||
|
.opaque_types
|
||||||
|
.iter()
|
||||||
|
.map(|opaque| opaque.try_fold_with(folder))
|
||||||
|
.collect::<Result<_, F::Error>>()?,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
|
||||||
|
TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData {
|
||||||
|
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
|
||||||
|
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
|
||||||
|
&self,
|
||||||
|
visitor: &mut V,
|
||||||
|
) -> std::ops::ControlFlow<V::BreakTy> {
|
||||||
|
self.opaque_types.visit_with(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,7 +21,9 @@
|
|||||||
use crate::thir::Thir;
|
use crate::thir::Thir;
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
use crate::traits::solve;
|
use crate::traits::solve;
|
||||||
use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData};
|
use crate::traits::solve::{
|
||||||
|
ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
|
||||||
|
};
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid,
|
self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid,
|
||||||
GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
|
GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
|
||||||
@ -140,6 +142,7 @@ pub struct CtxtInterners<'tcx> {
|
|||||||
layout: InternedSet<'tcx, LayoutS>,
|
layout: InternedSet<'tcx, LayoutS>,
|
||||||
adt_def: InternedSet<'tcx, AdtDefData>,
|
adt_def: InternedSet<'tcx, AdtDefData>,
|
||||||
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
|
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
|
||||||
|
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
|
||||||
fields: InternedSet<'tcx, List<FieldIdx>>,
|
fields: InternedSet<'tcx, List<FieldIdx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +167,7 @@ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
|
|||||||
layout: Default::default(),
|
layout: Default::default(),
|
||||||
adt_def: Default::default(),
|
adt_def: Default::default(),
|
||||||
external_constraints: Default::default(),
|
external_constraints: Default::default(),
|
||||||
|
predefined_opaques_in_body: Default::default(),
|
||||||
fields: Default::default(),
|
fields: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1520,6 +1524,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
|
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
|
||||||
external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>):
|
external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>):
|
||||||
ExternalConstraints -> ExternalConstraints<'tcx>,
|
ExternalConstraints -> ExternalConstraints<'tcx>,
|
||||||
|
predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>):
|
||||||
|
PredefinedOpaques -> PredefinedOpaques<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! slice_interners {
|
macro_rules! slice_interners {
|
||||||
|
@ -333,8 +333,7 @@ fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
|
|||||||
candidates: &mut Vec<Candidate<'tcx>>,
|
candidates: &mut Vec<Candidate<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
// FIXME: We also have to normalize opaque types, not sure where to best fit that in.
|
let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else {
|
||||||
let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
|
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -356,8 +355,11 @@ fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
ecx.add_goal(normalizes_to_goal);
|
ecx.add_goal(normalizes_to_goal);
|
||||||
let _ = ecx.try_evaluate_added_goals()?;
|
let _ = ecx.try_evaluate_added_goals().inspect_err(|_| {
|
||||||
|
debug!("self type normalization failed");
|
||||||
|
})?;
|
||||||
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
|
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
|
||||||
|
debug!(?normalized_ty, "self type normalized");
|
||||||
// NOTE: Alternatively we could call `evaluate_goal` here and only
|
// NOTE: Alternatively we could call `evaluate_goal` here and only
|
||||||
// have a `Normalized` candidate. This doesn't work as long as we
|
// have a `Normalized` candidate. This doesn't work as long as we
|
||||||
// use `CandidateSource` in winnowing.
|
// use `CandidateSource` in winnowing.
|
||||||
|
@ -9,7 +9,10 @@
|
|||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||||
use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
|
use rustc_middle::traits::solve::{
|
||||||
|
CanonicalInput, Certainty, MaybeCause, PredefinedOpaques, PredefinedOpaquesData, QueryResult,
|
||||||
|
};
|
||||||
|
use rustc_middle::traits::DefiningAnchor;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||||
TypeVisitor,
|
TypeVisitor,
|
||||||
@ -44,6 +47,9 @@ pub struct EvalCtxt<'a, 'tcx> {
|
|||||||
infcx: &'a InferCtxt<'tcx>,
|
infcx: &'a InferCtxt<'tcx>,
|
||||||
|
|
||||||
pub(super) var_values: CanonicalVarValues<'tcx>,
|
pub(super) var_values: CanonicalVarValues<'tcx>,
|
||||||
|
|
||||||
|
predefined_opaques_in_body: PredefinedOpaques<'tcx>,
|
||||||
|
|
||||||
/// The highest universe index nameable by the caller.
|
/// The highest universe index nameable by the caller.
|
||||||
///
|
///
|
||||||
/// When we enter a new binder inside of the query we create new universes
|
/// When we enter a new binder inside of the query we create new universes
|
||||||
@ -126,6 +132,11 @@ fn evaluate_root_goal(
|
|||||||
let mut ecx = EvalCtxt {
|
let mut ecx = EvalCtxt {
|
||||||
search_graph: &mut search_graph,
|
search_graph: &mut search_graph,
|
||||||
infcx: self,
|
infcx: self,
|
||||||
|
// Only relevant when canonicalizing the response,
|
||||||
|
// which we don't do within this evaluation context.
|
||||||
|
predefined_opaques_in_body: self
|
||||||
|
.tcx
|
||||||
|
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
|
||||||
// Only relevant when canonicalizing the response.
|
// Only relevant when canonicalizing the response.
|
||||||
max_input_universe: ty::UniverseIndex::ROOT,
|
max_input_universe: ty::UniverseIndex::ROOT,
|
||||||
var_values: CanonicalVarValues::dummy(),
|
var_values: CanonicalVarValues::dummy(),
|
||||||
@ -162,29 +173,59 @@ pub(super) fn solver_mode(&self) -> SolverMode {
|
|||||||
fn evaluate_canonical_goal(
|
fn evaluate_canonical_goal(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
|
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
|
||||||
canonical_goal: CanonicalGoal<'tcx>,
|
canonical_input: CanonicalInput<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
// Deal with overflow, caching, and coinduction.
|
// Deal with overflow, caching, and coinduction.
|
||||||
//
|
//
|
||||||
// The actual solver logic happens in `ecx.compute_goal`.
|
// The actual solver logic happens in `ecx.compute_goal`.
|
||||||
search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
|
search_graph.with_new_goal(tcx, canonical_input, |search_graph| {
|
||||||
let intercrate = match search_graph.solver_mode() {
|
let intercrate = match search_graph.solver_mode() {
|
||||||
SolverMode::Normal => false,
|
SolverMode::Normal => false,
|
||||||
SolverMode::Coherence => true,
|
SolverMode::Coherence => true,
|
||||||
};
|
};
|
||||||
let (ref infcx, goal, var_values) = tcx
|
let (ref infcx, input, var_values) = tcx
|
||||||
.infer_ctxt()
|
.infer_ctxt()
|
||||||
.intercrate(intercrate)
|
.intercrate(intercrate)
|
||||||
.build_with_canonical(DUMMY_SP, &canonical_goal);
|
.with_opaque_type_inference(canonical_input.value.anchor)
|
||||||
|
.build_with_canonical(DUMMY_SP, &canonical_input);
|
||||||
|
|
||||||
|
for &(a, b) in &input.predefined_opaques_in_body.opaque_types {
|
||||||
|
let InferOk { value: (), obligations } = infcx
|
||||||
|
.handle_opaque_type(
|
||||||
|
tcx.mk_opaque(a.def_id.to_def_id(), a.substs),
|
||||||
|
b,
|
||||||
|
true,
|
||||||
|
&ObligationCause::dummy(),
|
||||||
|
input.goal.param_env,
|
||||||
|
)
|
||||||
|
.expect("expected opaque type instantiation to succeed");
|
||||||
|
// We're only registering opaques already defined by the caller,
|
||||||
|
// so we're not responsible for proving that they satisfy their
|
||||||
|
// item bounds, unless we use them in a normalizes-to goal,
|
||||||
|
// which is handled in `EvalCtxt::unify_existing_opaque_tys`.
|
||||||
|
let _ = obligations;
|
||||||
|
}
|
||||||
let mut ecx = EvalCtxt {
|
let mut ecx = EvalCtxt {
|
||||||
infcx,
|
infcx,
|
||||||
var_values,
|
var_values,
|
||||||
max_input_universe: canonical_goal.max_universe,
|
predefined_opaques_in_body: input.predefined_opaques_in_body,
|
||||||
|
max_input_universe: canonical_input.max_universe,
|
||||||
search_graph,
|
search_graph,
|
||||||
nested_goals: NestedGoals::new(),
|
nested_goals: NestedGoals::new(),
|
||||||
tainted: Ok(()),
|
tainted: Ok(()),
|
||||||
};
|
};
|
||||||
ecx.compute_goal(goal)
|
|
||||||
|
let result = ecx.compute_goal(input.goal);
|
||||||
|
|
||||||
|
// When creating a query response we clone the opaque type constraints
|
||||||
|
// instead of taking them. This would cause an ICE here, since we have
|
||||||
|
// assertions against dropping an `InferCtxt` without taking opaques.
|
||||||
|
// FIXME: Once we remove support for the old impl we can remove this.
|
||||||
|
if input.anchor != DefiningAnchor::Error {
|
||||||
|
let _ = infcx.take_opaque_types();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +240,8 @@ fn evaluate_goal(
|
|||||||
let canonical_response =
|
let canonical_response =
|
||||||
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
|
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
|
||||||
|
|
||||||
let has_changed = !canonical_response.value.var_values.is_identity();
|
let has_changed = !canonical_response.value.var_values.is_identity()
|
||||||
|
|| !canonical_response.value.external_constraints.opaque_types.is_empty();
|
||||||
let (certainty, nested_goals) = self.instantiate_and_apply_query_response(
|
let (certainty, nested_goals) = self.instantiate_and_apply_query_response(
|
||||||
goal.param_env,
|
goal.param_env,
|
||||||
orig_values,
|
orig_values,
|
||||||
@ -418,6 +460,7 @@ pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T)
|
|||||||
let mut ecx = EvalCtxt {
|
let mut ecx = EvalCtxt {
|
||||||
infcx: self.infcx,
|
infcx: self.infcx,
|
||||||
var_values: self.var_values,
|
var_values: self.var_values,
|
||||||
|
predefined_opaques_in_body: self.predefined_opaques_in_body,
|
||||||
max_input_universe: self.max_input_universe,
|
max_input_universe: self.max_input_universe,
|
||||||
search_graph: self.search_graph,
|
search_graph: self.search_graph,
|
||||||
nested_goals: self.nested_goals.clone(),
|
nested_goals: self.nested_goals.clone(),
|
||||||
@ -682,4 +725,16 @@ pub(super) fn is_transmutable(
|
|||||||
| rustc_transmute::Answer::IfAny(_) => Err(NoSolution),
|
| rustc_transmute::Answer::IfAny(_) => Err(NoSolution),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn handle_opaque_ty(
|
||||||
|
&mut self,
|
||||||
|
a: Ty<'tcx>,
|
||||||
|
b: Ty<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
) -> Result<(), NoSolution> {
|
||||||
|
let InferOk { value: (), obligations } =
|
||||||
|
self.infcx.handle_opaque_type(a, b, true, &ObligationCause::dummy(), param_env)?;
|
||||||
|
self.add_goals(obligations.into_iter().map(|obligation| obligation.into()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
/// section of the [rustc-dev-guide][c].
|
/// section of the [rustc-dev-guide][c].
|
||||||
///
|
///
|
||||||
/// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
|
/// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
|
||||||
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal};
|
use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
|
||||||
use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
|
use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
|
||||||
use crate::solve::{CanonicalResponse, QueryResult, Response};
|
use crate::solve::{CanonicalResponse, QueryResult, Response};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
@ -16,8 +16,11 @@
|
|||||||
use rustc_infer::infer::canonical::CanonicalVarValues;
|
use rustc_infer::infer::canonical::CanonicalVarValues;
|
||||||
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
|
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
|
||||||
use rustc_middle::traits::query::NoSolution;
|
use rustc_middle::traits::query::NoSolution;
|
||||||
use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData, MaybeCause};
|
use rustc_middle::traits::solve::{
|
||||||
use rustc_middle::ty::{self, BoundVar, GenericArgKind};
|
ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
|
||||||
|
};
|
||||||
|
use rustc_middle::traits::ObligationCause;
|
||||||
|
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@ -28,13 +31,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
pub(super) fn canonicalize_goal(
|
pub(super) fn canonicalize_goal(
|
||||||
&self,
|
&self,
|
||||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||||
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalGoal<'tcx>) {
|
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx>) {
|
||||||
let mut orig_values = Default::default();
|
let mut orig_values = Default::default();
|
||||||
let canonical_goal = Canonicalizer::canonicalize(
|
let canonical_goal = Canonicalizer::canonicalize(
|
||||||
self.infcx,
|
self.infcx,
|
||||||
CanonicalizeMode::Input,
|
CanonicalizeMode::Input,
|
||||||
&mut orig_values,
|
&mut orig_values,
|
||||||
goal,
|
QueryInput {
|
||||||
|
goal,
|
||||||
|
anchor: self.infcx.defining_use_anchor,
|
||||||
|
predefined_opaques_in_body: self.tcx().mk_predefined_opaques_in_body(
|
||||||
|
PredefinedOpaquesData {
|
||||||
|
opaque_types: self.infcx.clone_opaque_types_for_query_response(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
(orig_values, canonical_goal)
|
(orig_values, canonical_goal)
|
||||||
}
|
}
|
||||||
@ -138,7 +149,13 @@ fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>
|
|||||||
region_constraints,
|
region_constraints,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
|
|
||||||
|
let mut opaque_types = self.infcx.clone_opaque_types_for_query_response();
|
||||||
|
// Only return opaque type keys for newly-defined opaques
|
||||||
|
opaque_types.retain(|(a, _)| {
|
||||||
|
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
|
||||||
|
});
|
||||||
|
|
||||||
Ok(self
|
Ok(self
|
||||||
.tcx()
|
.tcx()
|
||||||
.mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
|
.mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
|
||||||
@ -162,12 +179,13 @@ pub(super) fn instantiate_and_apply_query_response(
|
|||||||
let Response { var_values, external_constraints, certainty } =
|
let Response { var_values, external_constraints, certainty } =
|
||||||
response.substitute(self.tcx(), &substitution);
|
response.substitute(self.tcx(), &substitution);
|
||||||
|
|
||||||
let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?;
|
let mut nested_goals =
|
||||||
|
self.unify_query_var_values(param_env, &original_values, var_values)?;
|
||||||
|
|
||||||
// FIXME: implement external constraints.
|
let ExternalConstraintsData { region_constraints, opaque_types } =
|
||||||
let ExternalConstraintsData { region_constraints, opaque_types: _ } =
|
|
||||||
external_constraints.deref();
|
external_constraints.deref();
|
||||||
self.register_region_constraints(region_constraints);
|
self.register_region_constraints(region_constraints);
|
||||||
|
nested_goals.extend(self.register_opaque_types(param_env, opaque_types)?);
|
||||||
|
|
||||||
Ok((certainty, nested_goals))
|
Ok((certainty, nested_goals))
|
||||||
}
|
}
|
||||||
@ -287,4 +305,29 @@ fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstr
|
|||||||
let _ = member_constraint;
|
let _ = member_constraint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_opaque_types(
|
||||||
|
&mut self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
|
||||||
|
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||||
|
let mut nested_goals = vec![];
|
||||||
|
for &(a, b) in opaque_types {
|
||||||
|
nested_goals.extend(
|
||||||
|
self.infcx
|
||||||
|
.handle_opaque_type(
|
||||||
|
self.tcx().mk_opaque(a.def_id.to_def_id(), a.substs),
|
||||||
|
b,
|
||||||
|
true,
|
||||||
|
&ObligationCause::dummy(),
|
||||||
|
param_env,
|
||||||
|
)?
|
||||||
|
.into_obligations()
|
||||||
|
.into_iter()
|
||||||
|
.map(Goal::from),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(nested_goals)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
use rustc_infer::infer::InferOk;
|
|
||||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||||
use rustc_middle::traits::{ObligationCause, Reveal};
|
use rustc_middle::traits::Reveal;
|
||||||
use rustc_middle::ty::ProjectionPredicate;
|
use rustc_middle::ty::{self};
|
||||||
|
|
||||||
use super::{EvalCtxt, SolverMode};
|
use super::{EvalCtxt, SolverMode};
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
pub(super) fn normalize_opaque_type(
|
pub(super) fn normalize_opaque_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let opaque_ty = goal.predicate.projection_ty;
|
let opaque_ty = goal.predicate.projection_ty;
|
||||||
@ -19,15 +18,8 @@ pub(super) fn normalize_opaque_type(
|
|||||||
SolverMode::Normal => self.probe(|ecx| {
|
SolverMode::Normal => self.probe(|ecx| {
|
||||||
// FIXME: Check that the usage is "defining" (all free params), otherwise bail.
|
// FIXME: Check that the usage is "defining" (all free params), otherwise bail.
|
||||||
// FIXME: This should probably just check the anchor directly
|
// FIXME: This should probably just check the anchor directly
|
||||||
let InferOk { value: (), obligations } = self.infcx.handle_opaque_type(
|
let opaque_ty = tcx.mk_opaque(opaque_ty.def_id, opaque_ty.substs);
|
||||||
expected,
|
ecx.handle_opaque_ty(expected, opaque_ty, goal.param_env)?;
|
||||||
tcx.mk_opaque(opaque_ty.def_id, opaque_ty.substs),
|
|
||||||
true,
|
|
||||||
&ObligationCause::dummy(),
|
|
||||||
goal.param_env,
|
|
||||||
)?;
|
|
||||||
// FIXME: Need to fold these to replace the opaque ty with the expected ty.
|
|
||||||
ecx.add_goals(obligations.into_iter().map(Into::into));
|
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
}),
|
}),
|
||||||
SolverMode::Coherence => {
|
SolverMode::Coherence => {
|
||||||
|
@ -22,24 +22,25 @@ pub(super) fn compute_projection_goal(
|
|||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
// To only compute normalization once for each projection we only
|
match goal.predicate.projection_ty.kind(self.tcx()) {
|
||||||
// normalize if the expected term is an unconstrained inference variable.
|
ty::AliasKind::Projection => {
|
||||||
//
|
// To only compute normalization once for each projection we only
|
||||||
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
|
// normalize if the expected term is an unconstrained inference variable.
|
||||||
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
|
//
|
||||||
// `U` and equate it with `u32`. This means that we don't need a separate
|
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
|
||||||
// projection cache in the solver.
|
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
|
||||||
if self.term_is_fully_unconstrained(goal) {
|
// `U` and equate it with `u32`. This means that we don't need a separate
|
||||||
match goal.predicate.projection_ty.kind(self.tcx()) {
|
// projection cache in the solver.
|
||||||
ty::AliasKind::Projection => {
|
if self.term_is_fully_unconstrained(goal) {
|
||||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||||
self.merge_candidates(candidates)
|
self.merge_candidates(candidates)
|
||||||
|
} else {
|
||||||
|
self.set_normalizes_to_hack_goal(goal);
|
||||||
|
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
}
|
}
|
||||||
ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
|
|
||||||
}
|
}
|
||||||
} else {
|
ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
|
||||||
self.set_normalizes_to_hack_goal(goal);
|
ty::AliasKind::Inherent => bug!("IATs not supported here yet"),
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
use super::StackDepth;
|
use super::StackDepth;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::traits::solve::{CanonicalGoal, QueryResult};
|
use rustc_middle::traits::solve::{CanonicalInput, QueryResult};
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
pub struct EntryIndex {}
|
pub struct EntryIndex {}
|
||||||
@ -34,7 +34,7 @@ pub(super) struct ProvisionalEntry<'tcx> {
|
|||||||
|
|
||||||
// The goal for this entry. Should always be equal to the corresponding goal
|
// The goal for this entry. Should always be equal to the corresponding goal
|
||||||
// in the lookup table.
|
// in the lookup table.
|
||||||
pub(super) goal: CanonicalGoal<'tcx>,
|
pub(super) input: CanonicalInput<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct ProvisionalCache<'tcx> {
|
pub(super) struct ProvisionalCache<'tcx> {
|
||||||
@ -42,7 +42,7 @@ pub(super) struct ProvisionalCache<'tcx> {
|
|||||||
// FIXME: This is only used to quickly check whether a given goal
|
// FIXME: This is only used to quickly check whether a given goal
|
||||||
// is in the cache. We should experiment with using something like
|
// is in the cache. We should experiment with using something like
|
||||||
// `SsoHashSet` here because in most cases there are only a few entries.
|
// `SsoHashSet` here because in most cases there are only a few entries.
|
||||||
pub(super) lookup_table: FxHashMap<CanonicalGoal<'tcx>, EntryIndex>,
|
pub(super) lookup_table: FxHashMap<CanonicalInput<'tcx>, EntryIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ProvisionalCache<'tcx> {
|
impl<'tcx> ProvisionalCache<'tcx> {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
use overflow::OverflowData;
|
use overflow::OverflowData;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::dep_graph::DepKind;
|
use rustc_middle::dep_graph::DepKind;
|
||||||
use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
|
use rustc_middle::traits::solve::{CanonicalInput, Certainty, MaybeCause, QueryResult};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use std::{collections::hash_map::Entry, mem};
|
use std::{collections::hash_map::Entry, mem};
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ pub struct StackDepth {}
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct StackElem<'tcx> {
|
struct StackElem<'tcx> {
|
||||||
goal: CanonicalGoal<'tcx>,
|
input: CanonicalInput<'tcx>,
|
||||||
has_been_used: bool,
|
has_been_used: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ pub(super) fn in_cycle(&self) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ...or it depends on a goal with a lower depth.
|
// ...or it depends on a goal with a lower depth.
|
||||||
let current_goal = self.stack[stack_depth].goal;
|
let current_goal = self.stack[stack_depth].input;
|
||||||
let entry_index = self.provisional_cache.lookup_table[¤t_goal];
|
let entry_index = self.provisional_cache.lookup_table[¤t_goal];
|
||||||
self.provisional_cache.entries[entry_index].depth != stack_depth
|
self.provisional_cache.entries[entry_index].depth != stack_depth
|
||||||
} else {
|
} else {
|
||||||
@ -92,20 +92,20 @@ pub(super) fn in_cycle(&self) -> bool {
|
|||||||
fn try_push_stack(
|
fn try_push_stack(
|
||||||
&mut self,
|
&mut self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
goal: CanonicalGoal<'tcx>,
|
input: CanonicalInput<'tcx>,
|
||||||
) -> Result<(), QueryResult<'tcx>> {
|
) -> Result<(), QueryResult<'tcx>> {
|
||||||
// Look at the provisional cache to check for cycles.
|
// Look at the provisional cache to check for cycles.
|
||||||
let cache = &mut self.provisional_cache;
|
let cache = &mut self.provisional_cache;
|
||||||
match cache.lookup_table.entry(goal) {
|
match cache.lookup_table.entry(input) {
|
||||||
// No entry, simply push this goal on the stack after dealing with overflow.
|
// No entry, simply push this goal on the stack after dealing with overflow.
|
||||||
Entry::Vacant(v) => {
|
Entry::Vacant(v) => {
|
||||||
if self.overflow_data.has_overflow(self.stack.len()) {
|
if self.overflow_data.has_overflow(self.stack.len()) {
|
||||||
return Err(self.deal_with_overflow(tcx, goal));
|
return Err(self.deal_with_overflow(tcx, input));
|
||||||
}
|
}
|
||||||
|
|
||||||
let depth = self.stack.push(StackElem { goal, has_been_used: false });
|
let depth = self.stack.push(StackElem { input, has_been_used: false });
|
||||||
let response = super::response_no_constraints(tcx, goal, Certainty::Yes);
|
let response = super::response_no_constraints(tcx, input, Certainty::Yes);
|
||||||
let entry_index = cache.entries.push(ProvisionalEntry { response, depth, goal });
|
let entry_index = cache.entries.push(ProvisionalEntry { response, depth, input });
|
||||||
v.insert(entry_index);
|
v.insert(entry_index);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -135,13 +135,13 @@ fn try_push_stack(
|
|||||||
// the stack is enough.
|
// the stack is enough.
|
||||||
if self.stack.raw[stack_depth.index()..]
|
if self.stack.raw[stack_depth.index()..]
|
||||||
.iter()
|
.iter()
|
||||||
.all(|g| g.goal.value.predicate.is_coinductive(tcx))
|
.all(|g| g.input.value.goal.predicate.is_coinductive(tcx))
|
||||||
{
|
{
|
||||||
Err(cache.provisional_result(entry_index))
|
Err(cache.provisional_result(entry_index))
|
||||||
} else {
|
} else {
|
||||||
Err(super::response_no_constraints(
|
Err(super::response_no_constraints(
|
||||||
tcx,
|
tcx,
|
||||||
goal,
|
input,
|
||||||
Certainty::Maybe(MaybeCause::Overflow),
|
Certainty::Maybe(MaybeCause::Overflow),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -161,18 +161,18 @@ fn try_push_stack(
|
|||||||
/// updated the provisional cache and we have to recompute the current goal.
|
/// updated the provisional cache and we have to recompute the current goal.
|
||||||
///
|
///
|
||||||
/// FIXME: Refer to the rustc-dev-guide entry once it exists.
|
/// FIXME: Refer to the rustc-dev-guide entry once it exists.
|
||||||
#[instrument(level = "debug", skip(self, actual_goal), ret)]
|
#[instrument(level = "debug", skip(self, actual_input), ret)]
|
||||||
fn try_finalize_goal(
|
fn try_finalize_goal(
|
||||||
&mut self,
|
&mut self,
|
||||||
actual_goal: CanonicalGoal<'tcx>,
|
actual_input: CanonicalInput<'tcx>,
|
||||||
response: QueryResult<'tcx>,
|
response: QueryResult<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let stack_elem = self.stack.pop().unwrap();
|
let stack_elem = self.stack.pop().unwrap();
|
||||||
let StackElem { goal, has_been_used } = stack_elem;
|
let StackElem { input, has_been_used } = stack_elem;
|
||||||
assert_eq!(goal, actual_goal);
|
assert_eq!(input, actual_input);
|
||||||
|
|
||||||
let cache = &mut self.provisional_cache;
|
let cache = &mut self.provisional_cache;
|
||||||
let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
|
let provisional_entry_index = *cache.lookup_table.get(&input).unwrap();
|
||||||
let provisional_entry = &mut cache.entries[provisional_entry_index];
|
let provisional_entry = &mut cache.entries[provisional_entry_index];
|
||||||
// We eagerly update the response in the cache here. If we have to reevaluate
|
// We eagerly update the response in the cache here. If we have to reevaluate
|
||||||
// this goal we use the new response when hitting a cycle, and we definitely
|
// this goal we use the new response when hitting a cycle, and we definitely
|
||||||
@ -194,7 +194,7 @@ fn try_finalize_goal(
|
|||||||
cache.entries.truncate(provisional_entry_index.index() + 1);
|
cache.entries.truncate(provisional_entry_index.index() + 1);
|
||||||
|
|
||||||
// ...and finally push our goal back on the stack and reevaluate it.
|
// ...and finally push our goal back on the stack and reevaluate it.
|
||||||
self.stack.push(StackElem { goal, has_been_used: false });
|
self.stack.push(StackElem { input, has_been_used: false });
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
@ -204,17 +204,17 @@ fn try_finalize_goal(
|
|||||||
pub(super) fn with_new_goal(
|
pub(super) fn with_new_goal(
|
||||||
&mut self,
|
&mut self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
canonical_goal: CanonicalGoal<'tcx>,
|
canonical_input: CanonicalInput<'tcx>,
|
||||||
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
|
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
if self.should_use_global_cache() {
|
if self.should_use_global_cache() {
|
||||||
if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) {
|
if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) {
|
||||||
debug!(?canonical_goal, ?result, "cache hit");
|
debug!(?canonical_input, ?result, "cache hit");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.try_push_stack(tcx, canonical_goal) {
|
match self.try_push_stack(tcx, canonical_input) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
// Our goal is already on the stack, eager return.
|
// Our goal is already on the stack, eager return.
|
||||||
Err(response) => return response,
|
Err(response) => return response,
|
||||||
@ -226,19 +226,19 @@ pub(super) fn with_new_goal(
|
|||||||
let (result, dep_node) = tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || {
|
let (result, dep_node) = tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || {
|
||||||
self.repeat_while_none(
|
self.repeat_while_none(
|
||||||
|this| {
|
|this| {
|
||||||
let result = this.deal_with_overflow(tcx, canonical_goal);
|
let result = this.deal_with_overflow(tcx, canonical_input);
|
||||||
let _ = this.stack.pop().unwrap();
|
let _ = this.stack.pop().unwrap();
|
||||||
result
|
result
|
||||||
},
|
},
|
||||||
|this| {
|
|this| {
|
||||||
let result = loop_body(this);
|
let result = loop_body(this);
|
||||||
this.try_finalize_goal(canonical_goal, result).then(|| result)
|
this.try_finalize_goal(canonical_input, result).then(|| result)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let cache = &mut self.provisional_cache;
|
let cache = &mut self.provisional_cache;
|
||||||
let provisional_entry_index = *cache.lookup_table.get(&canonical_goal).unwrap();
|
let provisional_entry_index = *cache.lookup_table.get(&canonical_input).unwrap();
|
||||||
let provisional_entry = &mut cache.entries[provisional_entry_index];
|
let provisional_entry = &mut cache.entries[provisional_entry_index];
|
||||||
let depth = provisional_entry.depth;
|
let depth = provisional_entry.depth;
|
||||||
|
|
||||||
@ -254,13 +254,13 @@ pub(super) fn with_new_goal(
|
|||||||
// cycle participants without moving them to the global cache.
|
// cycle participants without moving them to the global cache.
|
||||||
let other_cycle_participants = provisional_entry_index.index() + 1;
|
let other_cycle_participants = provisional_entry_index.index() + 1;
|
||||||
for (i, entry) in cache.entries.drain_enumerated(other_cycle_participants..) {
|
for (i, entry) in cache.entries.drain_enumerated(other_cycle_participants..) {
|
||||||
let actual_index = cache.lookup_table.remove(&entry.goal);
|
let actual_index = cache.lookup_table.remove(&entry.input);
|
||||||
debug_assert_eq!(Some(i), actual_index);
|
debug_assert_eq!(Some(i), actual_index);
|
||||||
debug_assert!(entry.depth == depth);
|
debug_assert!(entry.depth == depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_goal = cache.entries.pop().unwrap();
|
let current_goal = cache.entries.pop().unwrap();
|
||||||
let actual_index = cache.lookup_table.remove(¤t_goal.goal);
|
let actual_index = cache.lookup_table.remove(¤t_goal.input);
|
||||||
debug_assert_eq!(Some(provisional_entry_index), actual_index);
|
debug_assert_eq!(Some(provisional_entry_index), actual_index);
|
||||||
debug_assert!(current_goal.depth == depth);
|
debug_assert!(current_goal.depth == depth);
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ pub(super) fn with_new_goal(
|
|||||||
let can_cache = !self.overflow_data.did_overflow() || self.stack.is_empty();
|
let can_cache = !self.overflow_data.did_overflow() || self.stack.is_empty();
|
||||||
if self.should_use_global_cache() && can_cache {
|
if self.should_use_global_cache() && can_cache {
|
||||||
tcx.new_solver_evaluation_cache.insert(
|
tcx.new_solver_evaluation_cache.insert(
|
||||||
current_goal.goal,
|
current_goal.input,
|
||||||
dep_node,
|
dep_node,
|
||||||
current_goal.response,
|
current_goal.response,
|
||||||
);
|
);
|
||||||
|
@ -16,6 +16,7 @@ fn evaluate_obligation<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
canonical_goal: CanonicalPredicateGoal<'tcx>,
|
canonical_goal: CanonicalPredicateGoal<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
|
assert!(!tcx.trait_solver_next());
|
||||||
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
|
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
|
||||||
// HACK This bubble is required for this tests to pass:
|
// HACK This bubble is required for this tests to pass:
|
||||||
// impl-trait/issue99642.rs
|
// impl-trait/issue99642.rs
|
||||||
|
Loading…
Reference in New Issue
Block a user