Auto merge of #97081 - oli-obk:outlives_query_fast_path, r=jackh726
Re-use the type op instead of calling the implied_outlives_bounds query directly r? `@ghost`
This commit is contained in:
commit
b17e9d76f2
6 changed files with 72 additions and 57 deletions
|
@ -334,8 +334,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
/// either the return type of the MIR or one of its arguments. At
|
/// either the return type of the MIR or one of its arguments. At
|
||||||
/// the same time, compute and add any implied bounds that come
|
/// the same time, compute and add any implied bounds that come
|
||||||
/// from this local.
|
/// from this local.
|
||||||
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
|
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
|
||||||
debug!("add_implied_bounds(ty={:?})", ty);
|
|
||||||
let TypeOpOutput { output: bounds, constraints, .. } = self
|
let TypeOpOutput { output: bounds, constraints, .. } = self
|
||||||
.param_env
|
.param_env
|
||||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||||
|
|
|
@ -547,6 +547,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
|
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
|
||||||
unsubstituted_region_constraints.iter().map(move |&constraint| {
|
unsubstituted_region_constraints.iter().map(move |&constraint| {
|
||||||
let predicate = substitute_value(self.tcx, result_subst, constraint);
|
let predicate = substitute_value(self.tcx, result_subst, 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.skip_binder();
|
let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
|
||||||
|
|
||||||
let atom = match k1.unpack() {
|
let atom = match k1.unpack() {
|
||||||
|
@ -559,13 +569,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
GenericArgKind::Const(..) => {
|
GenericArgKind::Const(..) => {
|
||||||
// Consts cannot outlive one another, so we don't expect to
|
// Consts cannot outlive one another, so we don't expect to
|
||||||
// encounter this branch.
|
// encounter this branch.
|
||||||
span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
|
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let predicate = predicate.rebind(atom).to_predicate(self.tcx);
|
let predicate = predicate.rebind(atom).to_predicate(self.tcx);
|
||||||
|
|
||||||
Obligation::new(cause.clone(), param_env, predicate)
|
Obligation::new(cause, param_env, predicate)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given two sets of values for the same set of canonical variables, unify them.
|
/// Given two sets of values for the same set of canonical variables, unify them.
|
||||||
|
|
|
@ -8,10 +8,10 @@ pub mod verify;
|
||||||
use rustc_middle::traits::query::OutlivesBound;
|
use rustc_middle::traits::query::OutlivesBound;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(param_env))]
|
||||||
pub fn explicit_outlives_bounds<'tcx>(
|
pub fn explicit_outlives_bounds<'tcx>(
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
|
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
|
||||||
debug!("explicit_outlives_bounds()");
|
|
||||||
param_env
|
param_env
|
||||||
.caller_bounds()
|
.caller_bounds()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
|
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
|
||||||
use crate::traits::query::Fallible;
|
use crate::traits::query::Fallible;
|
||||||
use rustc_infer::traits::query::OutlivesBound;
|
use rustc_infer::traits::query::OutlivesBound;
|
||||||
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
|
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
|
||||||
pub struct ImpliedOutlivesBounds<'tcx> {
|
pub struct ImpliedOutlivesBounds<'tcx> {
|
||||||
|
@ -13,9 +13,16 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
|
||||||
|
|
||||||
fn try_fast_path(
|
fn try_fast_path(
|
||||||
_tcx: TyCtxt<'tcx>,
|
_tcx: TyCtxt<'tcx>,
|
||||||
_key: &ParamEnvAnd<'tcx, Self>,
|
key: &ParamEnvAnd<'tcx, Self>,
|
||||||
) -> Option<Self::QueryResponse> {
|
) -> Option<Self::QueryResponse> {
|
||||||
None
|
// Don't go into the query for things that can't possibly have lifetimes.
|
||||||
|
match key.value.ty.kind() {
|
||||||
|
ty::Tuple(elems) if elems.is_empty() => Some(vec![]),
|
||||||
|
ty::Never | ty::Str | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
||||||
|
Some(vec![])
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_query(
|
fn perform_query(
|
||||||
|
|
|
@ -129,6 +129,7 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
|
||||||
/// add those assumptions into the outlives-environment.
|
/// add those assumptions into the outlives-environment.
|
||||||
///
|
///
|
||||||
/// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
|
/// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
|
||||||
|
#[instrument(level = "debug", skip(self, infcx))]
|
||||||
fn add_implied_bounds<'a>(
|
fn add_implied_bounds<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
infcx: &InferCtxt<'a, 'tcx>,
|
infcx: &InferCtxt<'a, 'tcx>,
|
||||||
|
@ -136,11 +137,8 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
|
||||||
body_id: hir::HirId,
|
body_id: hir::HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
debug!("add_implied_bounds()");
|
|
||||||
|
|
||||||
for ty in fn_sig_tys {
|
for ty in fn_sig_tys {
|
||||||
let ty = infcx.resolve_vars_if_possible(ty);
|
let ty = infcx.resolve_vars_if_possible(ty);
|
||||||
debug!("add_implied_bounds: ty = {}", ty);
|
|
||||||
let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
|
let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
|
||||||
self.add_outlives_bounds(Some(infcx), implied_bounds)
|
self.add_outlives_bounds(Some(infcx), implied_bounds)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::traits::TraitEngineExt as _;
|
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
use rustc_trait_selection::infer::canonical::OriginalQueryValues;
|
|
||||||
use rustc_trait_selection::infer::InferCtxt;
|
use rustc_trait_selection::infer::InferCtxt;
|
||||||
|
use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
|
||||||
use rustc_trait_selection::traits::query::NoSolution;
|
use rustc_trait_selection::traits::query::NoSolution;
|
||||||
use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
|
use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
|
||||||
|
|
||||||
|
@ -41,6 +40,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||||
/// - `ty`, the type that we are supposed to assume is WF.
|
/// - `ty`, the type that we are supposed to assume is WF.
|
||||||
/// - `span`, a span to use when normalizing, hopefully not important,
|
/// - `span`, a span to use when normalizing, hopefully not important,
|
||||||
/// might be useful if a `bug!` occurs.
|
/// might be useful if a `bug!` occurs.
|
||||||
|
#[instrument(level = "debug", skip(self, param_env, body_id, span))]
|
||||||
fn implied_outlives_bounds(
|
fn implied_outlives_bounds(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
@ -48,11 +48,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Vec<OutlivesBound<'tcx>> {
|
) -> Vec<OutlivesBound<'tcx>> {
|
||||||
debug!("implied_outlives_bounds(ty = {:?})", ty);
|
let result = param_env
|
||||||
|
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||||
let mut orig_values = OriginalQueryValues::default();
|
.fully_perform(self);
|
||||||
let key = self.canonicalize_query(param_env.and(ty), &mut orig_values);
|
let result = match result {
|
||||||
let result = match self.tcx.implied_outlives_bounds(key) {
|
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(NoSolution) => {
|
Err(NoSolution) => {
|
||||||
self.tcx.sess.delay_span_bug(
|
self.tcx.sess.delay_span_bug(
|
||||||
|
@ -62,24 +61,25 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert!(result.value.is_proven());
|
|
||||||
|
|
||||||
let result = self.instantiate_query_response_and_region_obligations(
|
let TypeOpOutput { output, constraints, .. } = result;
|
||||||
&ObligationCause::misc(span, body_id),
|
|
||||||
param_env,
|
|
||||||
&orig_values,
|
|
||||||
result,
|
|
||||||
);
|
|
||||||
debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
|
|
||||||
let Ok(result) = result else {
|
|
||||||
self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate");
|
|
||||||
return vec![];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
if let Some(constraints) = constraints {
|
||||||
// Instantiation may have produced new inference variables and constraints on those
|
// Instantiation may have produced new inference variables and constraints on those
|
||||||
// variables. Process these constraints.
|
// variables. Process these constraints.
|
||||||
let mut fulfill_cx = FulfillmentContext::new();
|
let mut fulfill_cx = FulfillmentContext::new();
|
||||||
fulfill_cx.register_predicate_obligations(self, result.obligations);
|
let cause = ObligationCause::misc(span, body_id);
|
||||||
|
for &constraint in &constraints.outlives {
|
||||||
|
let obligation = self.query_outlives_constraint_to_obligation(
|
||||||
|
constraint,
|
||||||
|
cause.clone(),
|
||||||
|
param_env,
|
||||||
|
);
|
||||||
|
fulfill_cx.register_predicate_obligation(self, obligation);
|
||||||
|
}
|
||||||
|
if !constraints.member_constraints.is_empty() {
|
||||||
|
span_bug!(span, "{:#?}", constraints.member_constraints);
|
||||||
|
}
|
||||||
let errors = fulfill_cx.select_all_or_error(self);
|
let errors = fulfill_cx.select_all_or_error(self);
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
self.tcx.sess.delay_span_bug(
|
self.tcx.sess.delay_span_bug(
|
||||||
|
@ -87,7 +87,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||||
"implied_outlives_bounds failed to solve obligations from instantiation",
|
"implied_outlives_bounds failed to solve obligations from instantiation",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
result.value
|
output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue