Skip to content

Unify Regions with RegionVids in UnificationTable #85313

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 6 commits into from
May 18, 2021
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
58 changes: 42 additions & 16 deletions compiler/rustc_infer/src/infer/region_constraints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use self::CombineMapType::*;
use self::UndoLog::*;

use super::unify_key;
use super::{
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
};
Expand All @@ -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};
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
(_, _) => {}
}
}
}
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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())
Expand All @@ -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)
}
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_infer/src/infer/undo_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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,
}
Expand Down Expand Up @@ -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>),
}

Expand Down
55 changes: 33 additions & 22 deletions compiler/rustc_middle/src/infer/unify_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

impl UnifyValue for RegionVidKey {
type Error = NoError;
pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>);

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
};
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey<'tcx> {
pub vid: ty::RegionVid,
pub phantom: PhantomData<UnifiedRegion<'tcx>>,
}

Ok(RegionVidKey { min_vid })
impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
fn from(vid: ty::RegionVid) -> Self {
RegionVidKey { vid, phantom: PhantomData }
}
}

impl UnifyKey for ty::RegionVid {
type Value = RegionVidKey;
impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
type Value = UnifiedRegion<'tcx>;
fn index(&self) -> u32 {
u32::from(*self)
self.vid.as_u32()
}
fn from_index(i: u32) -> ty::RegionVid {
ty::RegionVid::from(i)
fn from_index(i: u32) -> Self {
RegionVidKey::from(ty::RegionVid::from_u32(i))
}
fn tag() -> &'static str {
"RegionVid"
"RegionVidKey"
}
}

impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
type Error = NoError;

fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We better put a comment here about why this makes any sense at all...


(Some(_), _) => *value1,
(_, Some(_)) => *value2,

(None, None) => *value1,
})
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/traits/inductive-overflow/lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 3 additions & 1 deletion src/test/ui/traits/inductive-overflow/lifetime.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down