split opaque type handling in new solver
be more explicit in where we only add new hidden types and where we also have to deal with item bounds.
This commit is contained in:
parent
669d609dfd
commit
b62e20d2fd
5 changed files with 121 additions and 85 deletions
|
@ -27,6 +27,7 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
|||
use rustc_middle::mir::AssertKind;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::adjustment::PointerCast;
|
||||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
|
||||
|
@ -1051,15 +1052,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|ocx| {
|
||||
for (key, hidden_ty) in renumbered_opaques {
|
||||
ocx.register_infer_ok_obligations(
|
||||
ocx.infcx.register_hidden_type_in_new_solver(
|
||||
key,
|
||||
let mut obligations = Vec::new();
|
||||
for (opaque_type_key, hidden_ty) in renumbered_opaques {
|
||||
let cause = ObligationCause::dummy();
|
||||
ocx.infcx.insert_hidden_type(
|
||||
opaque_type_key,
|
||||
&cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
)?,
|
||||
true,
|
||||
&mut obligations,
|
||||
)?;
|
||||
|
||||
ocx.infcx.add_item_bounds_for_hidden_type(
|
||||
opaque_type_key,
|
||||
cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
&mut obligations,
|
||||
);
|
||||
}
|
||||
|
||||
ocx.register_obligations(obligations);
|
||||
Ok(())
|
||||
},
|
||||
"register pre-defined opaques",
|
||||
|
|
|
@ -524,36 +524,16 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
hidden_ty: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
) -> InferResult<'tcx, ()> {
|
||||
// Ideally, we'd get the span where *this specific `ty` came
|
||||
// from*, but right now we just use the span from the overall
|
||||
// value being folded. In simple cases like `-> impl Foo`,
|
||||
// these are the same span, but not in cases like `-> (impl
|
||||
// Foo, impl Bar)`.
|
||||
let span = cause.span;
|
||||
let mut obligations = if self.intercrate {
|
||||
// During intercrate we do not define opaque types but instead always
|
||||
// force ambiguity unless the hidden type is known to not implement
|
||||
// our trait.
|
||||
vec![traits::Obligation::new(
|
||||
self.tcx,
|
||||
cause.clone(),
|
||||
let mut obligations = Vec::new();
|
||||
|
||||
self.insert_hidden_type(
|
||||
opaque_type_key,
|
||||
&cause,
|
||||
param_env,
|
||||
ty::PredicateKind::Ambiguous,
|
||||
)]
|
||||
} else {
|
||||
let prev = self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.opaque_types()
|
||||
.register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
|
||||
if let Some(prev) = prev {
|
||||
self.at(&cause, param_env)
|
||||
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
|
||||
.obligations
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
hidden_ty,
|
||||
a_is_expected,
|
||||
&mut obligations,
|
||||
)?;
|
||||
|
||||
self.add_item_bounds_for_hidden_type(
|
||||
opaque_type_key,
|
||||
|
@ -566,23 +546,54 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
Ok(InferOk { value: (), obligations })
|
||||
}
|
||||
|
||||
/// Registers an opaque's hidden type -- only should be used when the opaque
|
||||
/// can be defined. For something more fallible -- checks the anchors, tries
|
||||
/// to unify opaques in both dirs, etc. -- use `InferCtxt::handle_opaque_type`.
|
||||
pub fn register_hidden_type_in_new_solver(
|
||||
/// Insert a hidden type into the opaque type storage, equating it
|
||||
/// with any previous entries if necessary.
|
||||
///
|
||||
/// This **does not** add the item bounds of the opaque as nested
|
||||
/// obligations. That is only necessary when normalizing the opaque
|
||||
/// itself, not when getting the opaque type constraints from
|
||||
/// somewhere else.
|
||||
pub fn insert_hidden_type(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
) -> InferResult<'tcx, ()> {
|
||||
assert!(self.next_trait_solver());
|
||||
self.register_hidden_type(
|
||||
opaque_type_key,
|
||||
ObligationCause::dummy(),
|
||||
a_is_expected: bool,
|
||||
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
// Ideally, we'd get the span where *this specific `ty` came
|
||||
// from*, but right now we just use the span from the overall
|
||||
// value being folded. In simple cases like `-> impl Foo`,
|
||||
// these are the same span, but not in cases like `-> (impl
|
||||
// Foo, impl Bar)`.
|
||||
let span = cause.span;
|
||||
if self.intercrate {
|
||||
// During intercrate we do not define opaque types but instead always
|
||||
// force ambiguity unless the hidden type is known to not implement
|
||||
// our trait.
|
||||
obligations.push(traits::Obligation::new(
|
||||
self.tcx,
|
||||
cause.clone(),
|
||||
param_env,
|
||||
hidden_ty,
|
||||
true,
|
||||
)
|
||||
ty::PredicateKind::Ambiguous,
|
||||
))
|
||||
} else {
|
||||
let prev = self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.opaque_types()
|
||||
.register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
|
||||
if let Some(prev) = prev {
|
||||
obligations.extend(
|
||||
self.at(&cause, param_env)
|
||||
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
|
||||
.obligations,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_item_bounds_for_hidden_type(
|
||||
|
|
|
@ -15,8 +15,8 @@ use rustc_middle::traits::solve::{
|
|||
};
|
||||
use rustc_middle::traits::DefiningAnchor;
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
TypeVisitor,
|
||||
self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use std::ops::ControlFlow;
|
||||
|
@ -191,16 +191,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
.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
|
||||
.register_hidden_type_in_new_solver(a, input.goal.param_env, b)
|
||||
.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 {
|
||||
infcx,
|
||||
var_values,
|
||||
|
@ -211,6 +201,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
tainted: Ok(()),
|
||||
};
|
||||
|
||||
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
|
||||
ecx.insert_hidden_type(key, input.goal.param_env, ty)
|
||||
.expect("failed to prepopulate opaque types");
|
||||
}
|
||||
|
||||
if !ecx.nested_goals.is_empty() {
|
||||
panic!("prepopulating opaque types shouldn't add goals: {:?}", ecx.nested_goals);
|
||||
}
|
||||
|
||||
let result = ecx.compute_goal(input.goal);
|
||||
|
||||
// When creating a query response we clone the opaque type constraints
|
||||
|
@ -729,18 +728,42 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
self.infcx.opaque_type_origin(def_id).is_some()
|
||||
}
|
||||
|
||||
pub(super) fn register_opaque_ty(
|
||||
pub(super) fn insert_hidden_type(
|
||||
&mut self,
|
||||
a: ty::OpaqueTypeKey<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
let InferOk { value: (), obligations } =
|
||||
self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?;
|
||||
self.add_goals(obligations.into_iter().map(|obligation| obligation.into()));
|
||||
let mut obligations = Vec::new();
|
||||
self.infcx.insert_hidden_type(
|
||||
opaque_type_key,
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
hidden_ty,
|
||||
true,
|
||||
&mut obligations,
|
||||
)?;
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn add_item_bounds_for_hidden_type(
|
||||
&mut self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
) {
|
||||
let mut obligations = Vec::new();
|
||||
self.infcx.add_item_bounds_for_hidden_type(
|
||||
opaque_type_key,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
hidden_ty,
|
||||
&mut obligations,
|
||||
);
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
}
|
||||
|
||||
// Do something for each opaque/hidden pair defined with `def_id` in the
|
||||
// current inference context.
|
||||
pub(super) fn unify_existing_opaque_tys(
|
||||
|
@ -762,15 +785,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
ecx.eq(param_env, a, b)?;
|
||||
}
|
||||
ecx.eq(param_env, candidate_ty, ty)?;
|
||||
let mut obl = vec![];
|
||||
ecx.infcx.add_item_bounds_for_hidden_type(
|
||||
candidate_key,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
candidate_ty,
|
||||
&mut obl,
|
||||
);
|
||||
ecx.add_goals(obl.into_iter().map(Into::into));
|
||||
ecx.add_item_bounds_for_hidden_type(candidate_key, param_env, candidate_ty);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ use rustc_index::IndexVec;
|
|||
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
|
||||
use rustc_infer::infer::canonical::CanonicalVarValues;
|
||||
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{
|
||||
ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
|
||||
|
@ -317,12 +316,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
|
||||
) -> Result<(), NoSolution> {
|
||||
for &(a, b) in opaque_types {
|
||||
let InferOk { value: (), obligations } =
|
||||
self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?;
|
||||
// It's sound to drop these obligations, since the normalizes-to goal
|
||||
// is responsible for proving these obligations.
|
||||
let _ = obligations;
|
||||
for &(key, ty) in opaque_types {
|
||||
self.insert_hidden_type(key, param_env, ty)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
// Otherwise, define a new opaque type
|
||||
self.register_opaque_ty(opaque_ty, expected, goal.param_env)?;
|
||||
self.insert_hidden_type(opaque_ty, goal.param_env, expected)?;
|
||||
self.add_item_bounds_for_hidden_type(opaque_ty, goal.param_env, expected);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
(Reveal::UserFacing, SolverMode::Coherence) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue