mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #131348 - nnethercote:rustc_infer-more-cleanups, r=lcnr
More `rustc_infer` cleanups A sequel to #131226. r? `@lcnr`
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::undo_log::Rollback;
|
||||
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
|
||||
use rustc_data_structures::unify as ut;
|
||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
@@ -50,6 +50,7 @@
|
||||
use tracing::{debug, instrument};
|
||||
use type_variable::TypeVariableOrigin;
|
||||
|
||||
use crate::infer::region_constraints::UndoLog;
|
||||
use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
|
||||
|
||||
pub mod at;
|
||||
@@ -67,6 +68,13 @@
|
||||
pub(crate) mod snapshot;
|
||||
mod type_variable;
|
||||
|
||||
/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
|
||||
/// around `Vec<PredicateObligation<'tcx>>`, but it has one important property:
|
||||
/// because `InferOk` is marked with `#[must_use]`, if you have a method
|
||||
/// `InferCtxt::f` that returns `InferResult<'tcx, ()>` and you call it with
|
||||
/// `infcx.f()?;` you'll get a warning about the obligations being discarded
|
||||
/// without use, which is probably unintentional and has been a source of bugs
|
||||
/// in the past.
|
||||
#[must_use]
|
||||
#[derive(Debug)]
|
||||
pub struct InferOk<'tcx, T> {
|
||||
@@ -163,12 +171,12 @@ fn new() -> InferCtxtInner<'tcx> {
|
||||
undo_log: InferCtxtUndoLogs::default(),
|
||||
|
||||
projection_cache: Default::default(),
|
||||
type_variable_storage: type_variable::TypeVariableStorage::new(),
|
||||
const_unification_storage: ut::UnificationTableStorage::new(),
|
||||
int_unification_storage: ut::UnificationTableStorage::new(),
|
||||
float_unification_storage: ut::UnificationTableStorage::new(),
|
||||
effect_unification_storage: ut::UnificationTableStorage::new(),
|
||||
region_constraint_storage: Some(RegionConstraintStorage::new()),
|
||||
type_variable_storage: Default::default(),
|
||||
const_unification_storage: Default::default(),
|
||||
int_unification_storage: Default::default(),
|
||||
float_unification_storage: Default::default(),
|
||||
effect_unification_storage: Default::default(),
|
||||
region_constraint_storage: Some(Default::default()),
|
||||
region_obligations: vec![],
|
||||
opaque_type_storage: Default::default(),
|
||||
}
|
||||
@@ -1004,8 +1012,8 @@ pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into()
|
||||
}
|
||||
|
||||
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping each
|
||||
/// type/region parameter to a fresh inference variable.
|
||||
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping
|
||||
/// each type/region parameter to a fresh inference variable.
|
||||
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
|
||||
GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param))
|
||||
}
|
||||
@@ -1036,18 +1044,14 @@ pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin {
|
||||
/// Clone the list of variable regions. This is used only during NLL processing
|
||||
/// to put the set of region variables into the NLL region context.
|
||||
pub fn get_region_var_origins(&self) -> VarInfos {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let (var_infos, data) = inner
|
||||
.region_constraint_storage
|
||||
// We clone instead of taking because borrowck still wants to use
|
||||
// the inference context after calling this for diagnostics
|
||||
// and the new trait solver.
|
||||
.clone()
|
||||
.expect("regions already resolved")
|
||||
.with_log(&mut inner.undo_log)
|
||||
.into_infos_and_data();
|
||||
assert!(data.is_empty());
|
||||
var_infos
|
||||
let inner = self.inner.borrow();
|
||||
assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&inner.undo_log));
|
||||
let storage = inner.region_constraint_storage.as_ref().expect("regions already resolved");
|
||||
assert!(storage.data.is_empty());
|
||||
// We clone instead of taking because borrowck still wants to use the
|
||||
// inference context after calling this for diagnostics and the new
|
||||
// trait solver.
|
||||
storage.var_infos.clone()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
@@ -1383,10 +1387,10 @@ pub fn try_const_eval_resolve(
|
||||
///
|
||||
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
|
||||
/// generic parameters and environment are used to resolve the constant. Alternatively if the
|
||||
/// constant has generic parameters in scope the instantiations are used to evaluate the value of
|
||||
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
|
||||
/// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is still
|
||||
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
|
||||
/// constant has generic parameters in scope the instantiations are used to evaluate the value
|
||||
/// of the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
|
||||
/// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is
|
||||
/// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
|
||||
/// returned.
|
||||
///
|
||||
/// This handles inferences variables within both `param_env` and `args` by
|
||||
|
||||
@@ -148,11 +148,11 @@ pub fn handle_opaque_type(
|
||||
}
|
||||
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
|
||||
// We could accept this, but there are various ways to handle this situation, and we don't
|
||||
// want to make a decision on it right now. Likely this case is so super rare anyway, that
|
||||
// no one encounters it in practice.
|
||||
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
|
||||
// where it is of no concern, so we only check for TAITs.
|
||||
// We could accept this, but there are various ways to handle this situation,
|
||||
// and we don't want to make a decision on it right now. Likely this case is so
|
||||
// super rare anyway, that no one encounters it in practice. It does occur
|
||||
// however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, where
|
||||
// it is of no concern, so we only check for TAITs.
|
||||
if self.can_define_opaque_ty(b_def_id)
|
||||
&& self.tcx.is_type_alias_impl_trait(b_def_id)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self, Region};
|
||||
use tracing::{debug, instrument};
|
||||
use rustc_middle::{bug, ty};
|
||||
use tracing::debug;
|
||||
|
||||
use super::explicit_outlives_bounds;
|
||||
use crate::infer::GenericKind;
|
||||
@@ -54,37 +53,16 @@ pub struct OutlivesEnvironment<'tcx> {
|
||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
}
|
||||
|
||||
/// Builder of OutlivesEnvironment.
|
||||
#[derive(Debug)]
|
||||
struct OutlivesEnvironmentBuilder<'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
region_relation: TransitiveRelationBuilder<Region<'tcx>>,
|
||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
}
|
||||
|
||||
/// "Region-bound pairs" tracks outlives relations that are known to
|
||||
/// be true, either because of explicit where-clauses like `T: 'a` or
|
||||
/// because of implied bounds.
|
||||
pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
|
||||
|
||||
impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||
/// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
|
||||
fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> {
|
||||
let mut builder = OutlivesEnvironmentBuilder {
|
||||
param_env,
|
||||
region_relation: Default::default(),
|
||||
region_bound_pairs: Default::default(),
|
||||
};
|
||||
|
||||
builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Create a new `OutlivesEnvironment` without extra outlives bounds.
|
||||
#[inline]
|
||||
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
Self::builder(param_env).build()
|
||||
Self::with_bounds(param_env, vec![])
|
||||
}
|
||||
|
||||
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
|
||||
@@ -92,9 +70,41 @@ pub fn with_bounds(
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||
) -> Self {
|
||||
let mut builder = Self::builder(param_env);
|
||||
builder.add_outlives_bounds(extra_bounds);
|
||||
builder.build()
|
||||
let mut region_relation = TransitiveRelationBuilder::default();
|
||||
let mut region_bound_pairs = RegionBoundPairs::default();
|
||||
|
||||
// Record relationships such as `T:'x` that don't go into the
|
||||
// free-region-map but which we use here.
|
||||
for outlives_bound in explicit_outlives_bounds(param_env).chain(extra_bounds) {
|
||||
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
|
||||
match outlives_bound {
|
||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||
region_bound_pairs
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
|
||||
}
|
||||
OutlivesBound::RegionSubAlias(r_a, alias_b) => {
|
||||
region_bound_pairs
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
|
||||
}
|
||||
OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
|
||||
(
|
||||
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
|
||||
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
|
||||
) => region_relation.add(r_a, r_b),
|
||||
(ty::ReError(_), _) | (_, ty::ReError(_)) => {}
|
||||
// FIXME(#109628): We shouldn't have existential variables in implied bounds.
|
||||
// Panic here once the linked issue is resolved!
|
||||
(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
|
||||
_ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
OutlivesEnvironment {
|
||||
param_env,
|
||||
free_region_map: FreeRegionMap { relation: region_relation.freeze() },
|
||||
region_bound_pairs,
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrows current value of the `free_region_map`.
|
||||
@@ -107,48 +117,3 @@ pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
|
||||
&self.region_bound_pairs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
|
||||
#[inline]
|
||||
#[instrument(level = "debug")]
|
||||
fn build(self) -> OutlivesEnvironment<'tcx> {
|
||||
OutlivesEnvironment {
|
||||
param_env: self.param_env,
|
||||
free_region_map: FreeRegionMap { relation: self.region_relation.freeze() },
|
||||
region_bound_pairs: self.region_bound_pairs,
|
||||
}
|
||||
}
|
||||
|
||||
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
|
||||
fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
|
||||
where
|
||||
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||
{
|
||||
// Record relationships such as `T:'x` that don't go into the
|
||||
// free-region-map but which we use here.
|
||||
for outlives_bound in outlives_bounds {
|
||||
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
|
||||
match outlives_bound {
|
||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||
self.region_bound_pairs
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a));
|
||||
}
|
||||
OutlivesBound::RegionSubAlias(r_a, alias_b) => {
|
||||
self.region_bound_pairs
|
||||
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
|
||||
}
|
||||
OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
|
||||
(
|
||||
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
|
||||
ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_),
|
||||
) => self.region_relation.add(r_a, r_b),
|
||||
(ty::ReError(_), _) | (_, ty::ReError(_)) => {}
|
||||
// FIXME(#109628): We shouldn't have existential variables in implied bounds.
|
||||
// Panic here once the linked issue is resolved!
|
||||
(ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
|
||||
_ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
//! Various code related to computing outlives relations.
|
||||
|
||||
use rustc_data_structures::undo_log::UndoLogs;
|
||||
use rustc_middle::traits::query::{NoSolution, OutlivesBound};
|
||||
use rustc_middle::ty;
|
||||
use tracing::instrument;
|
||||
|
||||
use self::env::OutlivesEnvironment;
|
||||
use super::region_constraints::RegionConstraintData;
|
||||
use super::region_constraints::{RegionConstraintData, UndoLog};
|
||||
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
|
||||
use crate::infer::free_regions::RegionRelations;
|
||||
use crate::infer::lexical_region_resolve;
|
||||
@@ -63,7 +64,7 @@ pub fn resolve_regions_with_normalize(
|
||||
}
|
||||
};
|
||||
|
||||
let (var_infos, data) = {
|
||||
let storage = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let inner = &mut *inner;
|
||||
assert!(
|
||||
@@ -71,18 +72,14 @@ pub fn resolve_regions_with_normalize(
|
||||
"region_obligations not empty: {:#?}",
|
||||
inner.region_obligations
|
||||
);
|
||||
inner
|
||||
.region_constraint_storage
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
.with_log(&mut inner.undo_log)
|
||||
.into_infos_and_data()
|
||||
assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&inner.undo_log));
|
||||
inner.region_constraint_storage.take().expect("regions already resolved")
|
||||
};
|
||||
|
||||
let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
|
||||
|
||||
let (lexical_region_resolutions, errors) =
|
||||
lexical_region_resolve::resolve(region_rels, var_infos, data);
|
||||
lexical_region_resolve::resolve(region_rels, storage.var_infos, storage.data);
|
||||
|
||||
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
|
||||
assert!(old_value.is_none());
|
||||
|
||||
@@ -396,11 +396,12 @@ fn alias_ty_must_outlive(
|
||||
// 'a` in the environment but `trait Foo<'b> { type Item: 'b
|
||||
// }` in the trait definition.
|
||||
approx_env_bounds.retain(|bound_outlives| {
|
||||
// OK to skip binder because we only manipulate and compare against other
|
||||
// values from the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a`
|
||||
// in `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region.
|
||||
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
|
||||
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
|
||||
// OK to skip binder because we only manipulate and compare against other values from
|
||||
// the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a` in
|
||||
// `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region. If the
|
||||
// declaration is `trait Trait<'b> { type Item: 'b; }`, then
|
||||
// `projection_declared_bounds_from_trait` will be invoked with `['b => ^1]` and so we
|
||||
// will get `^1` returned.
|
||||
let bound = bound_outlives.skip_binder();
|
||||
let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") };
|
||||
self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1)
|
||||
|
||||
@@ -55,8 +55,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||
/// * what placeholder they must outlive transitively
|
||||
/// * if they must also be equal to a placeholder, report an error because `P1: P2`
|
||||
/// * minimum universe U of all SCCs they must outlive
|
||||
/// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
|
||||
/// indicates `P: R` and `R` is in an incompatible universe
|
||||
/// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as
|
||||
/// that indicates `P: R` and `R` is in an incompatible universe
|
||||
///
|
||||
/// To improve performance and for the old trait solver caching to be sound, this takes
|
||||
/// an optional snapshot in which case we only look at region constraints added in that
|
||||
@@ -73,7 +73,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||
/// * R: P1, R: P2, as above
|
||||
#[instrument(level = "debug", skip(self, tcx, only_consider_snapshot), ret)]
|
||||
pub fn leak_check(
|
||||
&mut self,
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outer_universe: ty::UniverseIndex,
|
||||
max_universe: ty::UniverseIndex,
|
||||
@@ -83,7 +83,7 @@ pub fn leak_check(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mini_graph = &MiniGraph::new(tcx, self, only_consider_snapshot);
|
||||
let mini_graph = MiniGraph::new(tcx, &self, only_consider_snapshot);
|
||||
|
||||
let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self);
|
||||
leak_check.assign_placeholder_values()?;
|
||||
@@ -92,11 +92,11 @@ pub fn leak_check(
|
||||
}
|
||||
}
|
||||
|
||||
struct LeakCheck<'a, 'b, 'tcx> {
|
||||
struct LeakCheck<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outer_universe: ty::UniverseIndex,
|
||||
mini_graph: &'a MiniGraph<'tcx>,
|
||||
rcc: &'a mut RegionConstraintCollector<'b, 'tcx>,
|
||||
mini_graph: MiniGraph<'tcx>,
|
||||
rcc: RegionConstraintCollector<'a, 'tcx>,
|
||||
|
||||
// Initially, for each SCC S, stores a placeholder `P` such that `S = P`
|
||||
// must hold.
|
||||
@@ -115,26 +115,27 @@ struct LeakCheck<'a, 'b, 'tcx> {
|
||||
// either the placeholder `P1` or the empty region in that same universe.
|
||||
//
|
||||
// To detect errors, we look for an SCC S where the values in
|
||||
// `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`.
|
||||
// `scc_placeholders[S]` (if any) cannot be stored into `scc_universes[S]`.
|
||||
scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> {
|
||||
impl<'a, 'tcx> LeakCheck<'a, 'tcx> {
|
||||
fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outer_universe: ty::UniverseIndex,
|
||||
max_universe: ty::UniverseIndex,
|
||||
mini_graph: &'a MiniGraph<'tcx>,
|
||||
rcc: &'a mut RegionConstraintCollector<'b, 'tcx>,
|
||||
mini_graph: MiniGraph<'tcx>,
|
||||
rcc: RegionConstraintCollector<'a, 'tcx>,
|
||||
) -> Self {
|
||||
let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
|
||||
let num_sccs = mini_graph.sccs.num_sccs();
|
||||
Self {
|
||||
tcx,
|
||||
outer_universe,
|
||||
mini_graph,
|
||||
rcc,
|
||||
scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()),
|
||||
scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()),
|
||||
scc_placeholders: IndexVec::from_elem_n(None, num_sccs),
|
||||
scc_universes: IndexVec::from_elem_n(dummy_scc_universe, num_sccs),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +157,16 @@ fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
|
||||
// Detect those SCCs that directly contain a placeholder
|
||||
if let ty::RePlaceholder(placeholder) = **region {
|
||||
if self.outer_universe.cannot_name(placeholder.universe) {
|
||||
self.assign_scc_value(scc, placeholder)?;
|
||||
// Update `scc_placeholders` to account for the fact that `P: S` must hold.
|
||||
match self.scc_placeholders[scc] {
|
||||
Some(p) => {
|
||||
assert_ne!(p, placeholder);
|
||||
return Err(self.placeholder_error(p, placeholder));
|
||||
}
|
||||
None => {
|
||||
self.scc_placeholders[scc] = Some(placeholder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,26 +174,6 @@ fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
|
||||
// This may create an error.
|
||||
fn assign_scc_value(
|
||||
&mut self,
|
||||
scc: LeakCheckScc,
|
||||
placeholder: ty::PlaceholderRegion,
|
||||
) -> RelateResult<'tcx, ()> {
|
||||
match self.scc_placeholders[scc] {
|
||||
Some(p) => {
|
||||
assert_ne!(p, placeholder);
|
||||
return Err(self.placeholder_error(p, placeholder));
|
||||
}
|
||||
None => {
|
||||
self.scc_placeholders[scc] = Some(placeholder);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// For each SCC S, iterate over each successor S1 where `S: S1`:
|
||||
///
|
||||
/// * Compute
|
||||
@@ -216,8 +206,8 @@ fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
|
||||
// Walk over each `scc2` such that `scc1: scc2` and compute:
|
||||
//
|
||||
// * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
|
||||
// * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
|
||||
// we pick one arbitrarily)
|
||||
// * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there
|
||||
// are multiple, we pick one arbitrarily)
|
||||
let mut scc1_universe = self.scc_universes[scc1];
|
||||
let mut succ_bound = None;
|
||||
for &scc2 in self.mini_graph.sccs.successors(scc1) {
|
||||
@@ -260,7 +250,8 @@ fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
|
||||
self.scc_placeholders[scc1] = succ_bound;
|
||||
}
|
||||
|
||||
// At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
|
||||
// At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must
|
||||
// outlive (if any).
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#[derive(Clone, Default)]
|
||||
pub struct RegionConstraintStorage<'tcx> {
|
||||
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
|
||||
var_infos: IndexVec<RegionVid, RegionVariableInfo>,
|
||||
pub(super) var_infos: IndexVec<RegionVid, RegionVariableInfo>,
|
||||
|
||||
data: RegionConstraintData<'tcx>,
|
||||
pub(super) data: RegionConstraintData<'tcx>,
|
||||
|
||||
/// For a given pair of regions (R1, R2), maps to a region R3 that
|
||||
/// is designated as their LUB (edges R1 <= R3 and R2 <= R3
|
||||
@@ -61,21 +61,6 @@ pub struct RegionConstraintCollector<'a, 'tcx> {
|
||||
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> std::ops::Deref for RegionConstraintCollector<'_, 'tcx> {
|
||||
type Target = RegionConstraintStorage<'tcx>;
|
||||
#[inline]
|
||||
fn deref(&self) -> &RegionConstraintStorage<'tcx> {
|
||||
self.storage
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> {
|
||||
self.storage
|
||||
}
|
||||
}
|
||||
|
||||
pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>;
|
||||
|
||||
/// The full set of region constraints gathered up by the collector.
|
||||
@@ -309,10 +294,6 @@ pub(crate) struct RegionSnapshot {
|
||||
}
|
||||
|
||||
impl<'tcx> RegionConstraintStorage<'tcx> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn with_log<'a>(
|
||||
&'a mut self,
|
||||
@@ -320,46 +301,15 @@ pub(crate) fn with_log<'a>(
|
||||
) -> RegionConstraintCollector<'a, 'tcx> {
|
||||
RegionConstraintCollector { storage: self, undo_log }
|
||||
}
|
||||
|
||||
fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) {
|
||||
match undo_entry {
|
||||
AddVar(vid) => {
|
||||
self.var_infos.pop().unwrap();
|
||||
assert_eq!(self.var_infos.len(), vid.index());
|
||||
}
|
||||
AddConstraint(index) => {
|
||||
self.data.constraints.pop().unwrap();
|
||||
assert_eq!(self.data.constraints.len(), index);
|
||||
}
|
||||
AddVerify(index) => {
|
||||
self.data.verifys.pop();
|
||||
assert_eq!(self.data.verifys.len(), index);
|
||||
}
|
||||
AddCombination(Glb, ref regions) => {
|
||||
self.glbs.remove(regions);
|
||||
}
|
||||
AddCombination(Lub, ref regions) => {
|
||||
self.lubs.remove(regions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||
pub fn num_region_vars(&self) -> usize {
|
||||
self.var_infos.len()
|
||||
self.storage.var_infos.len()
|
||||
}
|
||||
|
||||
pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> {
|
||||
&self.data
|
||||
}
|
||||
|
||||
/// Once all the constraints have been gathered, extract out the final data.
|
||||
///
|
||||
/// Not legal during a snapshot.
|
||||
pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) {
|
||||
assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&self.undo_log));
|
||||
(mem::take(&mut self.storage.var_infos), mem::take(&mut self.storage.data))
|
||||
&self.storage.data
|
||||
}
|
||||
|
||||
/// Takes (and clears) the current set of constraints. Note that
|
||||
@@ -415,17 +365,17 @@ pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &RegionConstraintData<'tcx> {
|
||||
&self.data
|
||||
&self.storage.data
|
||||
}
|
||||
|
||||
pub(super) fn start_snapshot(&mut self) -> RegionSnapshot {
|
||||
pub(super) fn start_snapshot(&self) -> RegionSnapshot {
|
||||
debug!("RegionConstraintCollector: start_snapshot");
|
||||
RegionSnapshot { any_unifications: self.any_unifications }
|
||||
RegionSnapshot { any_unifications: self.storage.any_unifications }
|
||||
}
|
||||
|
||||
pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) {
|
||||
debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
|
||||
self.any_unifications = snapshot.any_unifications;
|
||||
self.storage.any_unifications = snapshot.any_unifications;
|
||||
}
|
||||
|
||||
pub(super) fn new_region_var(
|
||||
@@ -433,7 +383,7 @@ pub(super) fn new_region_var(
|
||||
universe: ty::UniverseIndex,
|
||||
origin: RegionVariableOrigin,
|
||||
) -> RegionVid {
|
||||
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
|
||||
let vid = self.storage.var_infos.push(RegionVariableInfo { origin, universe });
|
||||
|
||||
let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe });
|
||||
assert_eq!(vid, u_vid.vid);
|
||||
@@ -444,7 +394,7 @@ pub(super) fn new_region_var(
|
||||
|
||||
/// Returns the origin for the given variable.
|
||||
pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
|
||||
self.var_infos[vid].origin
|
||||
self.storage.var_infos[vid].origin
|
||||
}
|
||||
|
||||
fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
|
||||
@@ -467,8 +417,8 @@ fn add_verify(&mut self, verify: Verify<'tcx>) {
|
||||
return;
|
||||
}
|
||||
|
||||
let index = self.data.verifys.len();
|
||||
self.data.verifys.push(verify);
|
||||
let index = self.storage.data.verifys.len();
|
||||
self.storage.data.verifys.push(verify);
|
||||
self.undo_log.push(AddVerify(index));
|
||||
}
|
||||
|
||||
@@ -488,7 +438,7 @@ pub(super) fn make_eqregion(
|
||||
(ty::ReVar(a), ty::ReVar(b)) => {
|
||||
debug!("make_eqregion: unifying {:?} with {:?}", a, b);
|
||||
if self.unification_table_mut().unify_var_var(a, b).is_ok() {
|
||||
self.any_unifications = true;
|
||||
self.storage.any_unifications = true;
|
||||
}
|
||||
}
|
||||
(ty::ReVar(vid), _) => {
|
||||
@@ -498,7 +448,7 @@ pub(super) fn make_eqregion(
|
||||
.unify_var_value(vid, RegionVariableValue::Known { value: b })
|
||||
.is_ok()
|
||||
{
|
||||
self.any_unifications = true;
|
||||
self.storage.any_unifications = true;
|
||||
};
|
||||
}
|
||||
(_, ty::ReVar(vid)) => {
|
||||
@@ -508,7 +458,7 @@ pub(super) fn make_eqregion(
|
||||
.unify_var_value(vid, RegionVariableValue::Known { value: a })
|
||||
.is_ok()
|
||||
{
|
||||
self.any_unifications = true;
|
||||
self.storage.any_unifications = true;
|
||||
};
|
||||
}
|
||||
(_, _) => {}
|
||||
@@ -530,7 +480,7 @@ pub(super) fn member_constraint(
|
||||
return;
|
||||
}
|
||||
|
||||
self.data.member_constraints.push(MemberConstraint {
|
||||
self.storage.data.member_constraints.push(MemberConstraint {
|
||||
key,
|
||||
definition_span,
|
||||
hidden_ty,
|
||||
@@ -646,8 +596,8 @@ pub fn probe_value(
|
||||
|
||||
fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
|
||||
match t {
|
||||
Glb => &mut self.glbs,
|
||||
Lub => &mut self.lubs,
|
||||
Glb => &mut self.storage.glbs,
|
||||
Lub => &mut self.storage.lubs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,11 +650,12 @@ pub fn vars_since_snapshot(
|
||||
&self,
|
||||
value_count: usize,
|
||||
) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
|
||||
let range = RegionVid::from(value_count)..RegionVid::from(self.unification_table.len());
|
||||
let range =
|
||||
RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len());
|
||||
(
|
||||
range.clone(),
|
||||
(range.start.index()..range.end.index())
|
||||
.map(|index| self.var_infos[ty::RegionVid::from(index)].origin)
|
||||
.map(|index| self.storage.var_infos[ty::RegionVid::from(index)].origin)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
@@ -801,6 +752,25 @@ pub fn is_empty(&self) -> bool {
|
||||
|
||||
impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> {
|
||||
fn reverse(&mut self, undo: UndoLog<'tcx>) {
|
||||
self.rollback_undo_entry(undo)
|
||||
match undo {
|
||||
AddVar(vid) => {
|
||||
self.var_infos.pop().unwrap();
|
||||
assert_eq!(self.var_infos.len(), vid.index());
|
||||
}
|
||||
AddConstraint(index) => {
|
||||
self.data.constraints.pop().unwrap();
|
||||
assert_eq!(self.data.constraints.len(), index);
|
||||
}
|
||||
AddVerify(index) => {
|
||||
self.data.verifys.pop();
|
||||
assert_eq!(self.data.verifys.len(), index);
|
||||
}
|
||||
AddCombination(Glb, ref regions) => {
|
||||
self.glbs.remove(regions);
|
||||
}
|
||||
AddCombination(Lub, ref regions) => {
|
||||
self.lubs.remove(regions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
// Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
|
||||
// region/type inference variables.
|
||||
//
|
||||
// We then relate `generalized_ty <: source_ty`,adding constraints like `'x: '?2` and `?1 <: ?3`.
|
||||
// We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
|
||||
// `?1 <: ?3`.
|
||||
let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self
|
||||
.generalize(
|
||||
relation.span(),
|
||||
@@ -104,7 +105,8 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
&ty::Alias(ty::Projection, data) => {
|
||||
// FIXME: This does not handle subtyping correctly, we could
|
||||
// instead create a new inference variable `?normalized_source`, emitting
|
||||
// `Projection(normalized_source, ?ty_normalized)` and `?normalized_source <: generalized_ty`.
|
||||
// `Projection(normalized_source, ?ty_normalized)` and
|
||||
// `?normalized_source <: generalized_ty`.
|
||||
relation.register_predicates([ty::ProjectionPredicate {
|
||||
projection_term: data.into(),
|
||||
term: generalized_ty.into(),
|
||||
|
||||
@@ -38,7 +38,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if !t.has_non_region_infer() {
|
||||
t // micro-optimize -- if there is nothing in this type that this fold affects...
|
||||
} else if let Some(&ty) = self.cache.get(&t) {
|
||||
return ty;
|
||||
ty
|
||||
} else {
|
||||
let shallow = self.infcx.shallow_resolve(t);
|
||||
let res = shallow.super_fold_with(self);
|
||||
|
||||
@@ -19,7 +19,7 @@ fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct TypeVariableStorage<'tcx> {
|
||||
/// The origins of each type variable.
|
||||
values: IndexVec<TyVid, TypeVariableData>,
|
||||
@@ -74,13 +74,6 @@ pub(crate) fn is_unknown(&self) -> bool {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVariableStorage<'tcx> {
|
||||
pub(crate) fn new() -> TypeVariableStorage<'tcx> {
|
||||
TypeVariableStorage {
|
||||
values: Default::default(),
|
||||
eq_relations: ut::UnificationTableStorage::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn with_log<'a>(
|
||||
&'a mut self,
|
||||
|
||||
@@ -92,38 +92,31 @@ pub enum ProjectionCacheEntry<'tcx> {
|
||||
Error,
|
||||
NormalizedTerm {
|
||||
ty: NormalizedTerm<'tcx>,
|
||||
/// If we were able to successfully evaluate the
|
||||
/// corresponding cache entry key during predicate
|
||||
/// evaluation, then this field stores the final
|
||||
/// result obtained from evaluating all of the projection
|
||||
/// sub-obligations. During evaluation, we will skip
|
||||
/// evaluating the cached sub-obligations in `ty`
|
||||
/// if this field is set. Evaluation only
|
||||
/// cares about the final result, so we don't
|
||||
/// care about any region constraint side-effects
|
||||
/// produced by evaluating the sub-obligations.
|
||||
///
|
||||
/// Additionally, we will clear out the sub-obligations
|
||||
/// entirely if we ever evaluate the cache entry (along
|
||||
/// with all its sub obligations) to `EvaluatedToOk`.
|
||||
/// This affects all users of the cache, not just evaluation.
|
||||
/// Since a result of `EvaluatedToOk` means that there were
|
||||
/// no region obligations that need to be tracked, it's
|
||||
/// fine to forget about the sub-obligations - they
|
||||
/// don't provide any additional information. However,
|
||||
/// we do *not* discard any obligations when we see
|
||||
/// `EvaluatedToOkModuloRegions` - we don't know
|
||||
/// which sub-obligations may introduce region constraints,
|
||||
/// so we keep them all to be safe.
|
||||
///
|
||||
/// When we are not performing evaluation
|
||||
/// (e.g. in `FulfillmentContext`), we ignore this field,
|
||||
/// and always re-process the cached sub-obligations
|
||||
/// (which may have been cleared out - see the above
|
||||
/// paragraph).
|
||||
/// This ensures that we do not lose any regions
|
||||
/// constraints that arise from processing the
|
||||
/// If we were able to successfully evaluate the corresponding cache
|
||||
/// entry key during predicate evaluation, then this field stores the
|
||||
/// final result obtained from evaluating all of the projection
|
||||
/// sub-obligations. During evaluation, we will skip evaluating the
|
||||
/// cached sub-obligations in `ty` if this field is set. Evaluation
|
||||
/// only cares about the final result, so we don't care about any
|
||||
/// region constraint side-effects produced by evaluating the
|
||||
/// sub-obligations.
|
||||
///
|
||||
/// Additionally, we will clear out the sub-obligations entirely if we
|
||||
/// ever evaluate the cache entry (along with all its sub obligations)
|
||||
/// to `EvaluatedToOk`. This affects all users of the cache, not just
|
||||
/// evaluation. Since a result of `EvaluatedToOk` means that there were
|
||||
/// no region obligations that need to be tracked, it's fine to forget
|
||||
/// about the sub-obligations - they don't provide any additional
|
||||
/// information. However, we do *not* discard any obligations when we
|
||||
/// see `EvaluatedToOkModuloRegions` - we don't know which
|
||||
/// sub-obligations may introduce region constraints, so we keep them
|
||||
/// all to be safe.
|
||||
///
|
||||
/// When we are not performing evaluation (e.g. in
|
||||
/// `FulfillmentContext`), we ignore this field, and always re-process
|
||||
/// the cached sub-obligations (which may have been cleared out - see
|
||||
/// the above paragraph). This ensures that we do not lose any regions
|
||||
/// constraints that arise from processing the sub-obligations.
|
||||
complete: Option<EvaluationResult>,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user