Skip to content

Commit

Permalink
Auto merge of rust-lang#97081 - oli-obk:outlives_query_fast_path, r=j…
Browse files Browse the repository at this point in the history
…ackh726

Re-use the type op instead of calling the implied_outlives_bounds query directly

r? `@ghost`
  • Loading branch information
bors committed Jun 7, 2022
2 parents 5435ed6 + e7a1fbc commit b17e9d7
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
/// either the return type of the MIR or one of its arguments. At
/// the same time, compute and add any implied bounds that come
/// from this local.
#[instrument(level = "debug", skip(self))]
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
.param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
Expand Down
43 changes: 26 additions & 17 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,25 +547,34 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
unsubstituted_region_constraints.iter().map(move |&constraint| {
let predicate = substitute_value(self.tcx, result_subst, constraint);
let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
})
}

let atom = match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
}
GenericArgKind::Type(t1) => {
ty::PredicateKind::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 {:?}", constraint);
}
};
let predicate = predicate.rebind(atom).to_predicate(self.tcx);
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();

Obligation::new(cause.clone(), param_env, predicate)
})
let atom = match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
}
GenericArgKind::Type(t1) => {
ty::PredicateKind::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 = predicate.rebind(atom).to_predicate(self.tcx);

Obligation::new(cause, param_env, predicate)
}

/// Given two sets of values for the same set of canonical variables, unify them.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ pub mod verify;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty;

#[instrument(level = "debug", skip(param_env))]
pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
debug!("explicit_outlives_bounds()");
param_env
.caller_bounds()
.into_iter()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
use crate::traits::query::Fallible;
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)]
pub struct ImpliedOutlivesBounds<'tcx> {
Expand All @@ -13,9 +13,16 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {

fn try_fast_path(
_tcx: TyCtxt<'tcx>,
_key: &ParamEnvAnd<'tcx, Self>,
key: &ParamEnvAnd<'tcx, Self>,
) -> 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(
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_typeck/src/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,18 +129,16 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
/// add those assumptions into the outlives-environment.
///
/// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
#[instrument(level = "debug", skip(self, infcx))]
fn add_implied_bounds<'a>(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
fn_sig_tys: FxHashSet<Ty<'tcx>>,
body_id: hir::HirId,
span: Span,
) {
debug!("add_implied_bounds()");

for ty in fn_sig_tys {
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);
self.add_outlives_bounds(Some(infcx), implied_bounds)
}
Expand Down
63 changes: 32 additions & 31 deletions compiler/rustc_typeck/src/outlives/outlives_bounds.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use rustc_hir as hir;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_trait_selection::infer::canonical::OriginalQueryValues;
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::{FulfillmentContext, ObligationCause, TraitEngine};

Expand Down Expand Up @@ -41,18 +40,18 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
/// - `ty`, the type that we are supposed to assume is WF.
/// - `span`, a span to use when normalizing, hopefully not important,
/// might be useful if a `bug!` occurs.
#[instrument(level = "debug", skip(self, param_env, body_id, span))]
fn implied_outlives_bounds(
&self,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
ty: Ty<'tcx>,
span: Span,
) -> Vec<OutlivesBound<'tcx>> {
debug!("implied_outlives_bounds(ty = {:?})", ty);

let mut orig_values = OriginalQueryValues::default();
let key = self.canonicalize_query(param_env.and(ty), &mut orig_values);
let result = match self.tcx.implied_outlives_bounds(key) {
let result = param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
.fully_perform(self);
let result = match result {
Ok(r) => r,
Err(NoSolution) => {
self.tcx.sess.delay_span_bug(
Expand All @@ -62,32 +61,34 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
return vec![];
}
};
assert!(result.value.is_proven());

let result = self.instantiate_query_response_and_region_obligations(
&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![];
};
let TypeOpOutput { output, constraints, .. } = result;

// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new();
fulfill_cx.register_predicate_obligations(self, result.obligations);
let errors = fulfill_cx.select_all_or_error(self);
if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
);
}
if let Some(constraints) = constraints {
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new();
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);
if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
);
}
};

result.value
output
}
}

0 comments on commit b17e9d7

Please sign in to comment.