Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -130,18 +130,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
}
}