Avoid obligation construction dance with query region constraints
This commit is contained in:
parent
95a2212587
commit
3efd885927
9 changed files with 52 additions and 96 deletions
|
|
@ -742,7 +742,7 @@ fn ty_known_to_outlive<'tcx>(
|
|||
region: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
|
||||
infcx.register_region_obligation(infer::RegionObligation {
|
||||
infcx.type_outlives_predicate(infer::RegionObligation {
|
||||
sub_region: region,
|
||||
sup_type: ty,
|
||||
origin: infer::RelateParamBound(DUMMY_SP, ty, None),
|
||||
|
|
|
|||
|
|
@ -12,23 +12,20 @@ use std::iter;
|
|||
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::arena::ArenaAllocatable;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::infer::canonical::instantiate::{CanonicalExt, instantiate_value};
|
||||
use crate::infer::canonical::{
|
||||
Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
|
||||
QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
|
||||
QueryRegionConstraints, QueryResponse,
|
||||
};
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin};
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{
|
||||
Obligation, ObligationCause, PredicateObligation, PredicateObligations, ScrubbedTraitError,
|
||||
TraitEngine,
|
||||
};
|
||||
use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// This method is meant to be invoked as the final step of a canonical query
|
||||
|
|
@ -169,15 +166,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
where
|
||||
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let InferOk { value: result_args, mut obligations } =
|
||||
let InferOk { value: result_args, obligations } =
|
||||
self.query_response_instantiation(cause, param_env, original_values, query_response)?;
|
||||
|
||||
obligations.extend(self.query_outlives_constraints_into_obligations(
|
||||
cause,
|
||||
param_env,
|
||||
&query_response.value.region_constraints.outlives,
|
||||
&result_args,
|
||||
));
|
||||
for (predicate, _category) in &query_response.value.region_constraints.outlives {
|
||||
let predicate = instantiate_value(self.tcx, &result_args, *predicate);
|
||||
self.outlives_predicate_with_cause(predicate, cause);
|
||||
}
|
||||
|
||||
let user_result: R =
|
||||
query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
|
||||
|
|
@ -525,47 +520,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response)
|
||||
}
|
||||
|
||||
/// Converts the region constraints resulting from a query into an
|
||||
/// iterator of obligations.
|
||||
fn query_outlives_constraints_into_obligations(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
uninstantiated_region_constraints: &[QueryOutlivesConstraint<'tcx>],
|
||||
result_args: &CanonicalVarValues<'tcx>,
|
||||
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
|
||||
uninstantiated_region_constraints.iter().map(move |&constraint| {
|
||||
let predicate = instantiate_value(self.tcx, result_args, constraint);
|
||||
self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn query_outlives_constraint_to_obligation(
|
||||
&self,
|
||||
(predicate, _): QueryOutlivesConstraint<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Obligation<'tcx, ty::Predicate<'tcx>> {
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate;
|
||||
|
||||
let atom = match k1.unpack() {
|
||||
GenericArgKind::Lifetime(r1) => ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
|
||||
),
|
||||
GenericArgKind::Type(t1) => ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
|
||||
ty::OutlivesPredicate(t1, r2),
|
||||
)),
|
||||
GenericArgKind::Const(..) => {
|
||||
// Consts cannot outlive one another, so we don't expect to
|
||||
// encounter this branch.
|
||||
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
|
||||
}
|
||||
};
|
||||
let predicate = ty::Binder::dummy(atom);
|
||||
|
||||
Obligation::new(self.tcx, cause, param_env, predicate)
|
||||
}
|
||||
|
||||
/// Given two sets of values for the same set of canonical variables, unify them.
|
||||
/// The second set is produced lazily by supplying indices from the first set.
|
||||
fn unify_canonical_vars(
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>, span: Span) {
|
||||
self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(span));
|
||||
self.type_outlives_predicate_with_cause(ty, r, &ObligationCause::dummy_with_span(span));
|
||||
}
|
||||
|
||||
type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries;
|
||||
|
|
|
|||
|
|
@ -738,19 +738,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn region_outlives_predicate(
|
||||
&self,
|
||||
cause: &traits::ObligationCause<'tcx>,
|
||||
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
|
||||
) {
|
||||
self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
|
||||
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||
RelateRegionParamBound(cause.span, None)
|
||||
});
|
||||
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
|
||||
})
|
||||
}
|
||||
|
||||
/// Number of type variables created so far.
|
||||
pub fn num_ty_vars(&self) -> usize {
|
||||
self.inner.borrow_mut().type_variables().num_vars()
|
||||
|
|
|
|||
|
|
@ -80,19 +80,47 @@ use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrig
|
|||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
pub fn outlives_predicate_with_cause(
|
||||
&self,
|
||||
ty::OutlivesPredicate(arg, r2): ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
) {
|
||||
match arg.unpack() {
|
||||
ty::GenericArgKind::Lifetime(r1) => {
|
||||
self.region_outlives_predicate(ty::OutlivesPredicate(r1, r2), cause);
|
||||
}
|
||||
ty::GenericArgKind::Type(ty1) => {
|
||||
self.type_outlives_predicate_with_cause(ty1, r2, cause);
|
||||
}
|
||||
ty::GenericArgKind::Const(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn region_outlives_predicate(
|
||||
&self,
|
||||
ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
) {
|
||||
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||
SubregionOrigin::RelateRegionParamBound(cause.span, None)
|
||||
});
|
||||
// `b : a` ==> `a <= b`
|
||||
self.sub_regions(origin, r_b, r_a);
|
||||
}
|
||||
|
||||
/// Registers that the given region obligation must be resolved
|
||||
/// from within the scope of `body_id`. These regions are enqueued
|
||||
/// and later processed by regionck, when full type information is
|
||||
/// available (see `region_obligations` field for more
|
||||
/// information).
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn register_region_obligation(&self, obligation: RegionObligation<'tcx>) {
|
||||
pub fn type_outlives_predicate(&self, obligation: RegionObligation<'tcx>) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.undo_log.push(UndoLog::PushRegionObligation);
|
||||
inner.region_obligations.push(obligation);
|
||||
}
|
||||
|
||||
pub fn register_region_obligation_with_cause(
|
||||
pub fn type_outlives_predicate_with_cause(
|
||||
&self,
|
||||
sup_type: Ty<'tcx>,
|
||||
sub_region: Region<'tcx>,
|
||||
|
|
@ -124,7 +152,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
)
|
||||
});
|
||||
|
||||
self.register_region_obligation(RegionObligation { sup_type, sub_region, origin });
|
||||
self.type_outlives_predicate(RegionObligation { sup_type, sub_region, origin });
|
||||
}
|
||||
|
||||
/// Trait queries just want to pass back type obligations "as is"
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
|||
Some(HasChanged::No)
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
|
||||
self.0.register_region_obligation_with_cause(
|
||||
self.0.type_outlives_predicate_with_cause(
|
||||
outlives.0,
|
||||
outlives.1,
|
||||
&ObligationCause::dummy_with_span(span),
|
||||
|
|
|
|||
|
|
@ -726,7 +726,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => {
|
||||
let binder = bound_predicate.rebind(binder);
|
||||
selcx.infcx.region_outlives_predicate(&dummy_cause, binder)
|
||||
selcx.infcx.enter_forall(binder, |pred| {
|
||||
selcx.infcx.region_outlives_predicate(pred, &dummy_cause);
|
||||
});
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => {
|
||||
let binder = bound_predicate.rebind(binder);
|
||||
|
|
@ -735,14 +737,14 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
binder.map_bound_ref(|pred| pred.0).no_bound_vars(),
|
||||
) {
|
||||
(None, Some(t_a)) => {
|
||||
selcx.infcx.register_region_obligation_with_cause(
|
||||
selcx.infcx.type_outlives_predicate_with_cause(
|
||||
t_a,
|
||||
selcx.infcx.tcx.lifetimes.re_static,
|
||||
&dummy_cause,
|
||||
);
|
||||
}
|
||||
(Some(ty::OutlivesPredicate(t_a, r_b)), _) => {
|
||||
selcx.infcx.register_region_obligation_with_cause(
|
||||
selcx.infcx.type_outlives_predicate_with_cause(
|
||||
t_a,
|
||||
r_b,
|
||||
&dummy_cause,
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
|
||||
if infcx.considering_regions {
|
||||
infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
|
||||
infcx.region_outlives_predicate(data, &obligation.cause);
|
||||
}
|
||||
|
||||
ProcessResult::Changed(Default::default())
|
||||
|
|
@ -439,7 +439,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
r_b,
|
||||
))) => {
|
||||
if infcx.considering_regions {
|
||||
infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
|
||||
infcx.type_outlives_predicate_with_cause(t_a, r_b, &obligation.cause);
|
||||
}
|
||||
ProcessResult::Changed(Default::default())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId;
|
|||
use tracing::instrument;
|
||||
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::{ObligationCause, ObligationCtxt};
|
||||
use crate::traits::ObligationCause;
|
||||
|
||||
/// Implied bounds are region relationships that we deduce
|
||||
/// automatically. The idea is that (e.g.) a caller must check that a
|
||||
|
|
@ -79,24 +79,9 @@ fn implied_outlives_bounds<'a, 'tcx>(
|
|||
|
||||
if !constraints.is_empty() {
|
||||
let QueryRegionConstraints { outlives } = constraints;
|
||||
// Instantiation may have produced new inference variables and constraints on those
|
||||
// variables. Process these constraints.
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
for &constraint in &outlives {
|
||||
ocx.register_obligation(infcx.query_outlives_constraint_to_obligation(
|
||||
constraint,
|
||||
cause.clone(),
|
||||
param_env,
|
||||
));
|
||||
}
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.dcx().span_bug(
|
||||
span,
|
||||
"implied_outlives_bounds failed to solve obligations from instantiation",
|
||||
);
|
||||
for &(predicate, _) in &outlives {
|
||||
infcx.outlives_predicate_with_cause(predicate, &cause);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue