Skip to content
Draft
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
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::require_type_outlives`].
#[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, require_type_outlives,
};
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(
require_type_outlives(
&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