Skip to content

Commit b17e9d7

Browse files
committed
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`
2 parents 5435ed6 + e7a1fbc commit b17e9d7

File tree

6 files changed

+71
-56
lines changed

6 files changed

+71
-56
lines changed

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
334334
/// either the return type of the MIR or one of its arguments. At
335335
/// the same time, compute and add any implied bounds that come
336336
/// from this local.
337+
#[instrument(level = "debug", skip(self))]
337338
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
338-
debug!("add_implied_bounds(ty={:?})", ty);
339339
let TypeOpOutput { output: bounds, constraints, .. } = self
340340
.param_env
341341
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })

compiler/rustc_infer/src/infer/canonical/query_response.rs

+26-17
Original file line numberDiff line numberDiff line change
@@ -547,25 +547,34 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
547547
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
548548
unsubstituted_region_constraints.iter().map(move |&constraint| {
549549
let predicate = substitute_value(self.tcx, result_subst, constraint);
550-
let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
550+
self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
551+
})
552+
}
551553

552-
let atom = match k1.unpack() {
553-
GenericArgKind::Lifetime(r1) => {
554-
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
555-
}
556-
GenericArgKind::Type(t1) => {
557-
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2))
558-
}
559-
GenericArgKind::Const(..) => {
560-
// Consts cannot outlive one another, so we don't expect to
561-
// encounter this branch.
562-
span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
563-
}
564-
};
565-
let predicate = predicate.rebind(atom).to_predicate(self.tcx);
554+
pub fn query_outlives_constraint_to_obligation(
555+
&self,
556+
predicate: QueryOutlivesConstraint<'tcx>,
557+
cause: ObligationCause<'tcx>,
558+
param_env: ty::ParamEnv<'tcx>,
559+
) -> Obligation<'tcx, ty::Predicate<'tcx>> {
560+
let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
566561

567-
Obligation::new(cause.clone(), param_env, predicate)
568-
})
562+
let atom = match k1.unpack() {
563+
GenericArgKind::Lifetime(r1) => {
564+
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
565+
}
566+
GenericArgKind::Type(t1) => {
567+
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2))
568+
}
569+
GenericArgKind::Const(..) => {
570+
// Consts cannot outlive one another, so we don't expect to
571+
// encounter this branch.
572+
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
573+
}
574+
};
575+
let predicate = predicate.rebind(atom).to_predicate(self.tcx);
576+
577+
Obligation::new(cause, param_env, predicate)
569578
}
570579

571580
/// Given two sets of values for the same set of canonical variables, unify them.

compiler/rustc_infer/src/infer/outlives/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ pub mod verify;
88
use rustc_middle::traits::query::OutlivesBound;
99
use rustc_middle::ty;
1010

11+
#[instrument(level = "debug", skip(param_env))]
1112
pub fn explicit_outlives_bounds<'tcx>(
1213
param_env: ty::ParamEnv<'tcx>,
1314
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
14-
debug!("explicit_outlives_bounds()");
1515
param_env
1616
.caller_bounds()
1717
.into_iter()

compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
22
use crate::traits::query::Fallible;
33
use rustc_infer::traits::query::OutlivesBound;
4-
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
4+
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
55

66
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
77
pub struct ImpliedOutlivesBounds<'tcx> {
@@ -13,9 +13,16 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
1313

1414
fn try_fast_path(
1515
_tcx: TyCtxt<'tcx>,
16-
_key: &ParamEnvAnd<'tcx, Self>,
16+
key: &ParamEnvAnd<'tcx, Self>,
1717
) -> Option<Self::QueryResponse> {
18-
None
18+
// Don't go into the query for things that can't possibly have lifetimes.
19+
match key.value.ty.kind() {
20+
ty::Tuple(elems) if elems.is_empty() => Some(vec![]),
21+
ty::Never | ty::Str | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
22+
Some(vec![])
23+
}
24+
_ => None,
25+
}
1926
}
2027

2128
fn perform_query(

compiler/rustc_typeck/src/check/regionck.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,16 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
129129
/// add those assumptions into the outlives-environment.
130130
///
131131
/// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
132+
#[instrument(level = "debug", skip(self, infcx))]
132133
fn add_implied_bounds<'a>(
133134
&mut self,
134135
infcx: &InferCtxt<'a, 'tcx>,
135136
fn_sig_tys: FxHashSet<Ty<'tcx>>,
136137
body_id: hir::HirId,
137138
span: Span,
138139
) {
139-
debug!("add_implied_bounds()");
140-
141140
for ty in fn_sig_tys {
142141
let ty = infcx.resolve_vars_if_possible(ty);
143-
debug!("add_implied_bounds: ty = {}", ty);
144142
let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
145143
self.add_outlives_bounds(Some(infcx), implied_bounds)
146144
}

compiler/rustc_typeck/src/outlives/outlives_bounds.rs

+32-31
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use rustc_hir as hir;
2-
use rustc_infer::traits::TraitEngineExt as _;
32
use rustc_middle::ty::{self, Ty};
43
use rustc_span::source_map::Span;
5-
use rustc_trait_selection::infer::canonical::OriginalQueryValues;
64
use rustc_trait_selection::infer::InferCtxt;
5+
use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
76
use rustc_trait_selection::traits::query::NoSolution;
87
use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
98

@@ -41,18 +40,18 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
4140
/// - `ty`, the type that we are supposed to assume is WF.
4241
/// - `span`, a span to use when normalizing, hopefully not important,
4342
/// might be useful if a `bug!` occurs.
43+
#[instrument(level = "debug", skip(self, param_env, body_id, span))]
4444
fn implied_outlives_bounds(
4545
&self,
4646
param_env: ty::ParamEnv<'tcx>,
4747
body_id: hir::HirId,
4848
ty: Ty<'tcx>,
4949
span: Span,
5050
) -> Vec<OutlivesBound<'tcx>> {
51-
debug!("implied_outlives_bounds(ty = {:?})", ty);
52-
53-
let mut orig_values = OriginalQueryValues::default();
54-
let key = self.canonicalize_query(param_env.and(ty), &mut orig_values);
55-
let result = match self.tcx.implied_outlives_bounds(key) {
51+
let result = param_env
52+
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
53+
.fully_perform(self);
54+
let result = match result {
5655
Ok(r) => r,
5756
Err(NoSolution) => {
5857
self.tcx.sess.delay_span_bug(
@@ -62,32 +61,34 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
6261
return vec![];
6362
}
6463
};
65-
assert!(result.value.is_proven());
6664

67-
let result = self.instantiate_query_response_and_region_obligations(
68-
&ObligationCause::misc(span, body_id),
69-
param_env,
70-
&orig_values,
71-
result,
72-
);
73-
debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
74-
let Ok(result) = result else {
75-
self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate");
76-
return vec![];
77-
};
65+
let TypeOpOutput { output, constraints, .. } = result;
7866

79-
// Instantiation may have produced new inference variables and constraints on those
80-
// variables. Process these constraints.
81-
let mut fulfill_cx = FulfillmentContext::new();
82-
fulfill_cx.register_predicate_obligations(self, result.obligations);
83-
let errors = fulfill_cx.select_all_or_error(self);
84-
if !errors.is_empty() {
85-
self.tcx.sess.delay_span_bug(
86-
span,
87-
"implied_outlives_bounds failed to solve obligations from instantiation",
88-
);
89-
}
67+
if let Some(constraints) = constraints {
68+
// Instantiation may have produced new inference variables and constraints on those
69+
// variables. Process these constraints.
70+
let mut fulfill_cx = FulfillmentContext::new();
71+
let cause = ObligationCause::misc(span, body_id);
72+
for &constraint in &constraints.outlives {
73+
let obligation = self.query_outlives_constraint_to_obligation(
74+
constraint,
75+
cause.clone(),
76+
param_env,
77+
);
78+
fulfill_cx.register_predicate_obligation(self, obligation);
79+
}
80+
if !constraints.member_constraints.is_empty() {
81+
span_bug!(span, "{:#?}", constraints.member_constraints);
82+
}
83+
let errors = fulfill_cx.select_all_or_error(self);
84+
if !errors.is_empty() {
85+
self.tcx.sess.delay_span_bug(
86+
span,
87+
"implied_outlives_bounds failed to solve obligations from instantiation",
88+
);
89+
}
90+
};
9091

91-
result.value
92+
output
9293
}
9394
}

0 commit comments

Comments
 (0)