Skip to content
5 changes: 2 additions & 3 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ pub(crate) enum Cause {
///
/// For more information about this translation, see
/// `InferCtxt::process_registered_region_obligations` and
/// `InferCtxt::type_must_outlive` in `rustc_infer::infer::InferCtxt`.
/// [`rustc_infer::infer::outlives::obligations::type_must_outlive`].
#[derive(Clone, Debug)]
pub(crate) struct TypeTest<'tcx> {
/// The type `T` that must outlive the region.
Expand Down Expand Up @@ -837,8 +837,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
lub
}

/// Tests if `test` is true when applied to `lower_bound` at
/// `point`.
/// Tests if `generic_ty: lower_bound` holds by evaluating `verify_bound`
fn eval_verify_bound(
&self,
infcx: &InferCtxt<'tcx>,
Expand Down
22 changes: 12 additions & 10 deletions compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use rustc_hir::def_id::LocalDefId;
use rustc_infer::infer::SubregionOrigin;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc_infer::infer::outlives::obligations::{
OutlivesHandlingDelegate, TypeOutlivesOpCtxt, type_must_outlive,
};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::traits::query::type_op::DeeplyNormalize;
use rustc_middle::bug;
Expand Down Expand Up @@ -191,14 +193,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = SubregionOrigin::RelateParamBound(self.span, t1, None);
TypeOutlives::new(
&mut *self,
tcx,
region_bound_pairs,
Some(implicit_region_bound),
known_type_outlives_obligations,
)
.type_must_outlive(
type_must_outlive(
&mut TypeOutlivesOpCtxt::new(
&mut *self,
tcx,
region_bound_pairs,
Some(implicit_region_bound),
known_type_outlives_obligations,
),
origin,
t1,
r2,
Expand Down Expand Up @@ -302,7 +304,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
}

impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
impl<'a, 'b, 'tcx> OutlivesHandlingDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
fn push_sub_region_constraint(
&mut self,
_origin: SubregionOrigin<'tcx>,
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_hir_analysis/src/outlives/utils.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_middle::ty::outlives::{Component, push_outlives_components};
use rustc_middle::ty::outlives::{Component, compute_outlives_components};
use rustc_middle::ty::{self, GenericArg, GenericArgKind, Region, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::Span;
use smallvec::smallvec;

/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
/// must be added to the struct header.
Expand Down Expand Up @@ -33,8 +32,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
//
// Or if within `struct Foo<U>` you had `T = Vec<U>`, then
// we would want to add `U: 'outlived_region`
let mut components = smallvec![];
push_outlives_components(tcx, ty, &mut components);
let components = compute_outlives_components(tcx, ty);
for component in components {
match component {
Component::Region(r) => {
Expand Down
111 changes: 107 additions & 4 deletions compiler/rustc_infer/src/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::traits::query::{NoSolution, OutlivesBound};
use rustc_middle::ty;
use tracing::instrument;
use rustc_middle::ty::{self, Region, Ty, TypeVisitableExt};
use tracing::{debug, instrument};

use self::env::OutlivesEnvironment;
use super::region_constraints::{RegionConstraintData, UndoLog};
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
use crate::infer::free_regions::RegionRelations;
use crate::infer::lexical_region_resolve;
use crate::infer::region_constraints::ConstraintKind;
use crate::infer::{TypeOutlivesConstraint, lexical_region_resolve};
use crate::traits::{ObligationCause, ObligationCauseCode};

pub mod env;
pub mod for_liveness;
pub mod obligations;
pub mod test_type_match;
pub(crate) mod verify;

#[instrument(level = "debug", skip(param_env), ret)]
pub fn explicit_outlives_bounds<'tcx>(
Expand All @@ -31,6 +31,88 @@ pub fn explicit_outlives_bounds<'tcx>(
}

impl<'tcx> InferCtxt<'tcx> {
pub fn register_outlives_constraint(
&self,
ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>,
cause: &ObligationCause<'tcx>,
) {
match arg.kind() {
ty::GenericArgKind::Lifetime(r1) => {
self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), cause);
}
ty::GenericArgKind::Type(ty1) => {
self.register_type_outlives_constraint(ty1, r2, cause);
}
ty::GenericArgKind::Const(_) => unreachable!(),
}
}

pub fn register_region_outlives_constraint(
&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)
});
// `'a: 'b` ==> `'b <= 'a`
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_type_outlives_constraint_inner(
&self,
obligation: TypeOutlivesConstraint<'tcx>,
) {
let mut inner = self.inner.borrow_mut();
inner.undo_log.push(crate::infer::UndoLog::PushTypeOutlivesConstraint);
inner.region_obligations.push(obligation);
}

pub fn register_type_outlives_constraint(
&self,
sup_type: Ty<'tcx>,
sub_region: Region<'tcx>,
cause: &ObligationCause<'tcx>,
) {
// `is_global` means the type has no params, infer, placeholder, or non-`'static`
// free regions. If the type has none of these things, then we can skip registering
// this outlives obligation since it has no components which affect lifetime
// checking in an interesting way.
if sup_type.is_global() {
return;
}

debug!(?sup_type, ?sub_region, ?cause);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
SubregionOrigin::RelateParamBound(
cause.span,
sup_type,
match cause.code().peel_derives() {
ObligationCauseCode::WhereClause(_, span)
| ObligationCauseCode::WhereClauseInExpr(_, span, ..)
| ObligationCauseCode::OpaqueTypeBound(span, _)
if !span.is_dummy() =>
{
Some(*span)
}
_ => None,
},
)
});

self.register_type_outlives_constraint_inner(TypeOutlivesConstraint {
sup_type,
sub_region,
origin,
});
}

/// Process the region constraints and return any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
Expand Down Expand Up @@ -89,6 +171,27 @@ impl<'tcx> InferCtxt<'tcx> {
errors
}

/// Trait queries just want to pass back type obligations "as is"
pub fn take_registered_region_obligations(&self) -> Vec<TypeOutlivesConstraint<'tcx>> {
assert!(!self.in_snapshot(), "cannot take registered region obligations in a snapshot");
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
}

pub fn clone_registered_region_obligations(&self) -> Vec<TypeOutlivesConstraint<'tcx>> {
self.inner.borrow().region_obligations.clone()
}

pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) {
let mut inner = self.inner.borrow_mut();
inner.undo_log.push(crate::infer::UndoLog::PushRegionAssumption);
inner.region_assumptions.push(assumption);
}

pub fn take_registered_region_assumptions(&self) -> Vec<ty::ArgOutlivesPredicate<'tcx>> {
assert!(!self.in_snapshot(), "cannot take registered region assumptions in a snapshot");
std::mem::take(&mut self.inner.borrow_mut().region_assumptions)
}

/// Obtains (and clears) the current set of region
/// constraints. The inference context is still usable: further
/// unifications will simply add new constraints.
Expand Down
Loading
Loading