Auto merge of #85313 - jackh726:region_eq, r=nikomatsakis

Unify Regions with RegionVids in UnificationTable

A few test output changes; might be able to revert those but figured I would open this for perf and comments.

r? `@nikomatsakis`
This commit is contained in:
bors 2021-05-18 12:07:56 +00:00
commit 70b9d1e102
5 changed files with 85 additions and 43 deletions

View File

@ -3,7 +3,6 @@
use self::CombineMapType::*;
use self::UndoLog::*;
use super::unify_key;
use super::{
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
};
@ -12,9 +11,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
use rustc_data_structures::unify::UnifyKey;
use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
use rustc_middle::ty::ReStatic;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReLateBound, ReVar};
@ -54,7 +53,7 @@ pub struct RegionConstraintStorage<'tcx> {
/// code is iterating to a fixed point, because otherwise we sometimes
/// would wind up with a fresh stream of region variables that have been
/// equated but appear distinct.
pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>,
pub(super) unification_table: ut::UnificationTableStorage<RegionVidKey<'tcx>>,
/// a flag set to true when we perform any unifications; this is used
/// to micro-optimize `take_and_reset_data`
@ -407,8 +406,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
// `RegionConstraintData` contains the relationship here.
if *any_unifications {
*any_unifications = false;
self.unification_table()
.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
self.unification_table().reset_unifications(|_| UnifiedRegion(None));
}
data
@ -435,8 +433,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
) -> RegionVid {
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
let u_vid = self.unification_table().new_key(unify_key::RegionVidKey { min_vid: vid });
assert_eq!(vid, u_vid);
let u_vid = self.unification_table().new_key(UnifiedRegion(None));
assert_eq!(vid, u_vid.vid);
self.undo_log.push(AddVar(vid));
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
vid
@ -498,10 +496,18 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
self.make_subregion(origin.clone(), sub, sup);
self.make_subregion(origin, sup, sub);
if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
debug!("make_eqregion: uniying {:?} with {:?}", sub, sup);
self.unification_table().union(sub, sup);
self.any_unifications = true;
match (sub, sup) {
(&ty::ReVar(sub), &ty::ReVar(sup)) => {
debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
self.unification_table().union(sub, sup);
self.any_unifications = true;
}
(&ty::ReVar(vid), value) | (value, &ty::ReVar(vid)) => {
debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
self.unification_table().union_value(vid, UnifiedRegion(Some(value)));
self.any_unifications = true;
}
(_, _) => {}
}
}
}
@ -617,8 +623,29 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
pub fn opportunistic_resolve_var(&mut self, rid: RegionVid) -> ty::RegionVid {
self.unification_table().probe_value(rid).min_vid
/// Resolves the passed RegionVid to the root RegionVid in the unification table
pub fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
self.unification_table().find(rid).vid
}
/// If the Region is a `ReVar`, then resolves it either to the root value in
/// the unification table, if it exists, or to the root `ReVar` in the table.
/// If the Region is not a `ReVar`, just returns the Region itself.
pub fn opportunistic_resolve_region(
&mut self,
tcx: TyCtxt<'tcx>,
region: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
match region {
ty::ReVar(rid) => {
let unified_region = self.unification_table().probe_value(*rid);
unified_region.0.unwrap_or_else(|| {
let root = self.unification_table().find(*rid).vid;
tcx.reuse_or_mk_region(region, ty::ReVar(root))
})
}
_ => region,
}
}
fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
@ -673,8 +700,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
&self,
value_count: usize,
) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
let range = RegionVid::from_index(value_count as u32)
..RegionVid::from_index(self.unification_table.len() as u32);
let range = RegionVid::from(value_count)..RegionVid::from(self.unification_table.len());
(
range.clone(),
(range.start.index()..range.end.index())
@ -696,7 +722,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
#[inline]
fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, ty::RegionVid> {
fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
}
}

View File

@ -3,6 +3,7 @@ use std::marker::PhantomData;
use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut;
use rustc_middle::infer::unify_key::RegionVidKey;
use rustc_middle::ty;
use crate::{
@ -22,7 +23,7 @@ pub(crate) enum UndoLog<'tcx> {
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>),
PushRegionObligation,
}
@ -55,7 +56,7 @@ impl_from! {
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>),
}

View File

@ -16,37 +16,48 @@ pub trait ToType {
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey {
/// The minimum region vid in the unification set. This is needed
/// to have a canonical name for a type to prevent infinite
/// recursion.
pub min_vid: ty::RegionVid,
pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>);
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey<'tcx> {
pub vid: ty::RegionVid,
pub phantom: PhantomData<UnifiedRegion<'tcx>>,
}
impl UnifyValue for RegionVidKey {
impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
fn from(vid: ty::RegionVid) -> Self {
RegionVidKey { vid, phantom: PhantomData }
}
}
impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
type Value = UnifiedRegion<'tcx>;
fn index(&self) -> u32 {
self.vid.as_u32()
}
fn from_index(i: u32) -> Self {
RegionVidKey::from(ty::RegionVid::from_u32(i))
}
fn tag() -> &'static str {
"RegionVidKey"
}
}
impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
type Error = NoError;
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
let min_vid = if value1.min_vid.index() < value2.min_vid.index() {
value1.min_vid
} else {
value2.min_vid
};
Ok(match (value1.0, value2.0) {
// Here we can just pick one value, because the full constraints graph
// will be handled later. Ideally, we might want a `MultipleValues`
// variant or something. For now though, this is fine.
(Some(_), Some(_)) => *value1,
Ok(RegionVidKey { min_vid })
}
}
(Some(_), _) => *value1,
(_, Some(_)) => *value2,
impl UnifyKey for ty::RegionVid {
type Value = RegionVidKey;
fn index(&self) -> u32 {
u32::from(*self)
}
fn from_index(i: u32) -> ty::RegionVid {
ty::RegionVid::from(i)
}
fn tag() -> &'static str {
"RegionVid"
(None, None) => *value1,
})
}
}

View File

@ -26,4 +26,6 @@ fn main() {
// Should only be a few notes.
is_send::<X<C<'static>>>();
//~^ ERROR overflow evaluating
//~| 2 redundant requirements hidden
//~| required because of
}

View File

@ -7,11 +7,13 @@ LL | fn is_send<S: NotAuto>() {}
LL | is_send::<X<C<'static>>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>`
note: required because of the requirements on the impl of `NotAuto` for `X<C<'_>>`
--> $DIR/lifetime.rs:19:12
|
LL | impl<T: Y> NotAuto for X<T> where T::P: NotAuto {}
| ^^^^^^^ ^^^^
= note: 2 redundant requirements hidden
= note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>`
error: aborting due to previous error