mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #69464 - Marwes:detach_undo_log, r=nikomatsakis
perf: Unify the undo log of all snapshot types Extracted from #69218 and extended to all the current snapshot types. Since snapshotting is such a frequent action in the compiler and many of the scopes execute so little work, the act of creating the snapshot and rolling back empty/small snapshots end up showing in perf. By unifying all the logs into one the creation of snapshots becomes significantly cheaper at the cost of some complexity when combining the log with the specific data structures that are being mutated. Depends on https://github.com/rust-lang-nursery/ena/pull/29
This commit is contained in:
commit
8da5869fb7
13
Cargo.lock
13
Cargo.lock
@ -993,6 +993,15 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ena"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.17"
|
version = "0.8.17"
|
||||||
@ -3234,7 +3243,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"crossbeam-utils 0.7.2",
|
"crossbeam-utils 0.7.2",
|
||||||
"ena",
|
"ena 0.13.1",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
@ -3683,7 +3692,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"crossbeam-utils 0.7.2",
|
"crossbeam-utils 0.7.2",
|
||||||
"ena",
|
"ena 0.14.0",
|
||||||
"graphviz",
|
"graphviz",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
|
@ -10,7 +10,7 @@ path = "lib.rs"
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ena = "0.13.1"
|
ena = "0.14"
|
||||||
indexmap = "1"
|
indexmap = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
jobserver_crate = { version = "0.1.13", package = "jobserver" }
|
jobserver_crate = { version = "0.1.13", package = "jobserver" }
|
||||||
|
@ -84,6 +84,7 @@ pub mod sync;
|
|||||||
pub mod thin_vec;
|
pub mod thin_vec;
|
||||||
pub mod tiny_list;
|
pub mod tiny_list;
|
||||||
pub mod transitive_relation;
|
pub mod transitive_relation;
|
||||||
|
pub use ena::undo_log;
|
||||||
pub use ena::unify;
|
pub use ena::unify;
|
||||||
mod atomic_ref;
|
mod atomic_ref;
|
||||||
pub mod fingerprint;
|
pub mod fingerprint;
|
||||||
|
@ -1,77 +1,75 @@
|
|||||||
use crate::fx::FxHashMap;
|
use crate::fx::FxHashMap;
|
||||||
|
use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog};
|
||||||
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::mem;
|
use std::marker::PhantomData;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
|
pub use crate::undo_log::Snapshot;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub struct SnapshotMap<K, V>
|
pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>;
|
||||||
where
|
pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>;
|
||||||
K: Clone + Eq,
|
|
||||||
{
|
pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> {
|
||||||
map: FxHashMap<K, V>,
|
map: M,
|
||||||
undo_log: Vec<UndoLog<K, V>>,
|
undo_log: L,
|
||||||
num_open_snapshots: usize,
|
_marker: PhantomData<(K, V)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`.
|
// HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`.
|
||||||
impl<K, V> Default for SnapshotMap<K, V>
|
impl<K, V, M, L> Default for SnapshotMap<K, V, M, L>
|
||||||
where
|
where
|
||||||
K: Hash + Clone + Eq,
|
M: Default,
|
||||||
|
L: Default,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
SnapshotMap { map: Default::default(), undo_log: Default::default(), num_open_snapshots: 0 }
|
SnapshotMap { map: Default::default(), undo_log: Default::default(), _marker: PhantomData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Snapshot {
|
pub enum UndoLog<K, V> {
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum UndoLog<K, V> {
|
|
||||||
Inserted(K),
|
Inserted(K),
|
||||||
Overwrite(K, V),
|
Overwrite(K, V),
|
||||||
Purged,
|
Purged,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V> SnapshotMap<K, V>
|
impl<K, V, M, L> SnapshotMap<K, V, M, L> {
|
||||||
|
pub fn with_log<L2>(&mut self, undo_log: L2) -> SnapshotMap<K, V, &mut M, L2> {
|
||||||
|
SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V, M, L> SnapshotMap<K, V, M, L>
|
||||||
where
|
where
|
||||||
K: Hash + Clone + Eq,
|
K: Hash + Clone + Eq,
|
||||||
|
M: BorrowMut<FxHashMap<K, V>> + Borrow<FxHashMap<K, V>>,
|
||||||
|
L: UndoLogs<UndoLog<K, V>>,
|
||||||
{
|
{
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.map.clear();
|
self.map.borrow_mut().clear();
|
||||||
self.undo_log.clear();
|
self.undo_log.clear();
|
||||||
self.num_open_snapshots = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn in_snapshot(&self) -> bool {
|
|
||||||
self.num_open_snapshots > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, key: K, value: V) -> bool {
|
pub fn insert(&mut self, key: K, value: V) -> bool {
|
||||||
match self.map.insert(key.clone(), value) {
|
match self.map.borrow_mut().insert(key.clone(), value) {
|
||||||
None => {
|
None => {
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(UndoLog::Inserted(key));
|
self.undo_log.push(UndoLog::Inserted(key));
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Some(old_value) => {
|
Some(old_value) => {
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(UndoLog::Overwrite(key, old_value));
|
self.undo_log.push(UndoLog::Overwrite(key, old_value));
|
||||||
}
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, key: K) -> bool {
|
pub fn remove(&mut self, key: K) -> bool {
|
||||||
match self.map.remove(&key) {
|
match self.map.borrow_mut().remove(&key) {
|
||||||
Some(old_value) => {
|
Some(old_value) => {
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(UndoLog::Overwrite(key, old_value));
|
self.undo_log.push(UndoLog::Overwrite(key, old_value));
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
None => false,
|
None => false,
|
||||||
@ -79,83 +77,64 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &K) -> Option<&V> {
|
pub fn get(&self, key: &K) -> Option<&V> {
|
||||||
self.map.get(key)
|
self.map.borrow().get(key)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> SnapshotMap<K, V>
|
||||||
|
where
|
||||||
|
K: Hash + Clone + Eq,
|
||||||
|
{
|
||||||
pub fn snapshot(&mut self) -> Snapshot {
|
pub fn snapshot(&mut self) -> Snapshot {
|
||||||
let len = self.undo_log.len();
|
self.undo_log.start_snapshot()
|
||||||
self.num_open_snapshots += 1;
|
|
||||||
Snapshot { len }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_open_snapshot(&self, snapshot: &Snapshot) {
|
|
||||||
assert!(self.undo_log.len() >= snapshot.len);
|
|
||||||
assert!(self.num_open_snapshots > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit(&mut self, snapshot: Snapshot) {
|
pub fn commit(&mut self, snapshot: Snapshot) {
|
||||||
self.assert_open_snapshot(&snapshot);
|
self.undo_log.commit(snapshot)
|
||||||
if self.num_open_snapshots == 1 {
|
|
||||||
// The root snapshot. It's safe to clear the undo log because
|
|
||||||
// there's no snapshot further out that we might need to roll back
|
|
||||||
// to.
|
|
||||||
assert!(snapshot.len == 0);
|
|
||||||
self.undo_log.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.num_open_snapshots -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn partial_rollback<F>(&mut self, snapshot: &Snapshot, should_revert_key: &F)
|
|
||||||
where
|
|
||||||
F: Fn(&K) -> bool,
|
|
||||||
{
|
|
||||||
self.assert_open_snapshot(snapshot);
|
|
||||||
for i in (snapshot.len..self.undo_log.len()).rev() {
|
|
||||||
let reverse = match self.undo_log[i] {
|
|
||||||
UndoLog::Purged => false,
|
|
||||||
UndoLog::Inserted(ref k) => should_revert_key(k),
|
|
||||||
UndoLog::Overwrite(ref k, _) => should_revert_key(k),
|
|
||||||
};
|
|
||||||
|
|
||||||
if reverse {
|
|
||||||
let entry = mem::replace(&mut self.undo_log[i], UndoLog::Purged);
|
|
||||||
self.reverse(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rollback_to(&mut self, snapshot: Snapshot) {
|
pub fn rollback_to(&mut self, snapshot: Snapshot) {
|
||||||
self.assert_open_snapshot(&snapshot);
|
let map = &mut self.map;
|
||||||
while self.undo_log.len() > snapshot.len {
|
self.undo_log.rollback_to(|| map, snapshot)
|
||||||
let entry = self.undo_log.pop().unwrap();
|
|
||||||
self.reverse(entry);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.num_open_snapshots -= 1;
|
impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap<K, V, M, L>
|
||||||
|
where
|
||||||
|
K: Hash + Clone + Eq,
|
||||||
|
M: Borrow<FxHashMap<K, V>>,
|
||||||
|
{
|
||||||
|
type Output = V;
|
||||||
|
fn index(&self, key: &'k K) -> &V {
|
||||||
|
&self.map.borrow()[key]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn reverse(&mut self, entry: UndoLog<K, V>) {
|
impl<K, V, M, L> Rollback<UndoLog<K, V>> for SnapshotMap<K, V, M, L>
|
||||||
match entry {
|
where
|
||||||
|
K: Eq + Hash,
|
||||||
|
M: Rollback<UndoLog<K, V>>,
|
||||||
|
{
|
||||||
|
fn reverse(&mut self, undo: UndoLog<K, V>) {
|
||||||
|
self.map.reverse(undo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> Rollback<UndoLog<K, V>> for FxHashMap<K, V>
|
||||||
|
where
|
||||||
|
K: Eq + Hash,
|
||||||
|
{
|
||||||
|
fn reverse(&mut self, undo: UndoLog<K, V>) {
|
||||||
|
match undo {
|
||||||
UndoLog::Inserted(key) => {
|
UndoLog::Inserted(key) => {
|
||||||
self.map.remove(&key);
|
self.remove(&key);
|
||||||
}
|
}
|
||||||
|
|
||||||
UndoLog::Overwrite(key, old_value) => {
|
UndoLog::Overwrite(key, old_value) => {
|
||||||
self.map.insert(key, old_value);
|
self.insert(key, old_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
UndoLog::Purged => {}
|
UndoLog::Purged => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'k, K, V> ops::Index<&'k K> for SnapshotMap<K, V>
|
|
||||||
where
|
|
||||||
K: Hash + Clone + Eq,
|
|
||||||
{
|
|
||||||
type Output = V;
|
|
||||||
fn index(&self, key: &'k K) -> &V {
|
|
||||||
&self.map[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -76,7 +76,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
(&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => {
|
(&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => {
|
||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.int_unification_table
|
.int_unification_table()
|
||||||
.unify_var_var(a_id, b_id)
|
.unify_var_var(a_id, b_id)
|
||||||
.map_err(|e| int_unification_error(a_is_expected, e))?;
|
.map_err(|e| int_unification_error(a_is_expected, e))?;
|
||||||
Ok(a)
|
Ok(a)
|
||||||
@ -98,7 +98,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
(&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => {
|
(&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => {
|
||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.float_unification_table
|
.float_unification_table()
|
||||||
.unify_var_var(a_id, b_id)
|
.unify_var_var(a_id, b_id)
|
||||||
.map_err(|e| float_unification_error(relation.a_is_expected(), e))?;
|
.map_err(|e| float_unification_error(relation.a_is_expected(), e))?;
|
||||||
Ok(a)
|
Ok(a)
|
||||||
@ -133,8 +133,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
return Ok(a);
|
return Ok(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, a);
|
let a = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table(), a);
|
||||||
let b = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, b);
|
let b = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table(), b);
|
||||||
|
|
||||||
let a_is_expected = relation.a_is_expected();
|
let a_is_expected = relation.a_is_expected();
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
) => {
|
) => {
|
||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.const_unification_table
|
.const_unification_table()
|
||||||
.unify_var_var(a_vid, b_vid)
|
.unify_var_var(a_vid, b_vid)
|
||||||
.map_err(|e| const_unification_error(a_is_expected, e))?;
|
.map_err(|e| const_unification_error(a_is_expected, e))?;
|
||||||
return Ok(a);
|
return Ok(a);
|
||||||
@ -179,7 +179,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.const_unification_table
|
.const_unification_table()
|
||||||
.unify_var_value(
|
.unify_var_value(
|
||||||
vid,
|
vid,
|
||||||
ConstVarValue {
|
ConstVarValue {
|
||||||
@ -202,7 +202,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
) -> RelateResult<'tcx, Ty<'tcx>> {
|
) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.int_unification_table
|
.int_unification_table()
|
||||||
.unify_var_value(vid, Some(val))
|
.unify_var_value(vid, Some(val))
|
||||||
.map_err(|e| int_unification_error(vid_is_expected, e))?;
|
.map_err(|e| int_unification_error(vid_is_expected, e))?;
|
||||||
match val {
|
match val {
|
||||||
@ -219,7 +219,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||||||
) -> RelateResult<'tcx, Ty<'tcx>> {
|
) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.float_unification_table
|
.float_unification_table()
|
||||||
.unify_var_value(vid, Some(ty::FloatVarValue(val)))
|
.unify_var_value(vid, Some(ty::FloatVarValue(val)))
|
||||||
.map_err(|e| float_unification_error(vid_is_expected, e))?;
|
.map_err(|e| float_unification_error(vid_is_expected, e))?;
|
||||||
Ok(self.tcx.mk_mach_float(val))
|
Ok(self.tcx.mk_mach_float(val))
|
||||||
@ -266,7 +266,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||||||
use self::RelationDir::*;
|
use self::RelationDir::*;
|
||||||
|
|
||||||
// Get the actual variable that b_vid has been inferred to
|
// Get the actual variable that b_vid has been inferred to
|
||||||
debug_assert!(self.infcx.inner.borrow_mut().type_variables.probe(b_vid).is_unknown());
|
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
|
||||||
|
|
||||||
debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
|
debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||||||
"instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
|
"instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
|
||||||
a_ty, dir, b_vid, b_ty
|
a_ty, dir, b_vid, b_ty
|
||||||
);
|
);
|
||||||
self.infcx.inner.borrow_mut().type_variables.instantiate(b_vid, b_ty);
|
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
|
||||||
|
|
||||||
if needs_wf {
|
if needs_wf {
|
||||||
self.obligations.push(Obligation::new(
|
self.obligations.push(Obligation::new(
|
||||||
@ -344,7 +344,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||||||
|
|
||||||
debug!("generalize: ambient_variance = {:?}", ambient_variance);
|
debug!("generalize: ambient_variance = {:?}", ambient_variance);
|
||||||
|
|
||||||
let for_universe = match self.infcx.inner.borrow_mut().type_variables.probe(for_vid) {
|
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
|
||||||
v @ TypeVariableValue::Known { .. } => {
|
v @ TypeVariableValue::Known { .. } => {
|
||||||
panic!("instantiating {:?} which has a known value {:?}", for_vid, v,)
|
panic!("instantiating {:?} which has a known value {:?}", for_vid, v,)
|
||||||
}
|
}
|
||||||
@ -356,7 +356,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||||||
let mut generalize = Generalizer {
|
let mut generalize = Generalizer {
|
||||||
infcx: self.infcx,
|
infcx: self.infcx,
|
||||||
span: self.trace.cause.span,
|
span: self.trace.cause.span,
|
||||||
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid),
|
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
|
||||||
for_universe,
|
for_universe,
|
||||||
ambient_variance,
|
ambient_variance,
|
||||||
needs_wf: false,
|
needs_wf: false,
|
||||||
@ -508,14 +508,14 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||||||
// us from creating infinitely sized types.
|
// us from creating infinitely sized types.
|
||||||
match t.kind {
|
match t.kind {
|
||||||
ty::Infer(ty::TyVar(vid)) => {
|
ty::Infer(ty::TyVar(vid)) => {
|
||||||
let vid = self.infcx.inner.borrow_mut().type_variables.root_var(vid);
|
let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
|
||||||
let sub_vid = self.infcx.inner.borrow_mut().type_variables.sub_root_var(vid);
|
let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid);
|
||||||
if sub_vid == self.for_vid_sub_root {
|
if sub_vid == self.for_vid_sub_root {
|
||||||
// If sub-roots are equal, then `for_vid` and
|
// If sub-roots are equal, then `for_vid` and
|
||||||
// `vid` are related via subtyping.
|
// `vid` are related via subtyping.
|
||||||
Err(TypeError::CyclicTy(self.root_ty))
|
Err(TypeError::CyclicTy(self.root_ty))
|
||||||
} else {
|
} else {
|
||||||
let probe = self.infcx.inner.borrow_mut().type_variables.probe(vid);
|
let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
|
||||||
match probe {
|
match probe {
|
||||||
TypeVariableValue::Known { value: u } => {
|
TypeVariableValue::Known { value: u } => {
|
||||||
debug!("generalize: known value {:?}", u);
|
debug!("generalize: known value {:?}", u);
|
||||||
@ -542,12 +542,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let origin =
|
let origin =
|
||||||
*self.infcx.inner.borrow_mut().type_variables.var_origin(vid);
|
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
|
||||||
let new_var_id = self.infcx.inner.borrow_mut().type_variables.new_var(
|
let new_var_id = self
|
||||||
self.for_universe,
|
.infcx
|
||||||
false,
|
.inner
|
||||||
origin,
|
.borrow_mut()
|
||||||
);
|
.type_variables()
|
||||||
|
.new_var(self.for_universe, false, origin);
|
||||||
let u = self.tcx().mk_ty_var(new_var_id);
|
let u = self.tcx().mk_ty_var(new_var_id);
|
||||||
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
|
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
|
||||||
Ok(u)
|
Ok(u)
|
||||||
@ -618,7 +619,8 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||||||
|
|
||||||
match c.val {
|
match c.val {
|
||||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||||
let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table;
|
let mut inner = self.infcx.inner.borrow_mut();
|
||||||
|
let variable_table = &mut inner.const_unification_table();
|
||||||
let var_value = variable_table.probe_value(vid);
|
let var_value = variable_table.probe_value(vid);
|
||||||
match var_value.val {
|
match var_value.val {
|
||||||
ConstVariableValue::Known { value: u } => self.relate(&u, &u),
|
ConstVariableValue::Known { value: u } => self.relate(&u, &u),
|
||||||
|
@ -72,14 +72,14 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let infcx = self.fields.infcx;
|
let infcx = self.fields.infcx;
|
||||||
let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a);
|
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
|
||||||
let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b);
|
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
|
||||||
|
|
||||||
debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
|
debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b);
|
||||||
|
|
||||||
match (&a.kind, &b.kind) {
|
match (&a.kind, &b.kind) {
|
||||||
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
|
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
|
||||||
infcx.inner.borrow_mut().type_variables.equate(a_id, b_id);
|
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::Infer(TyVar(a_id)), _) => {
|
(&ty::Infer(TyVar(a_id)), _) => {
|
||||||
|
@ -59,7 +59,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
|
|||||||
.infcx
|
.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.type_variables
|
.type_variables()
|
||||||
.sub_unified(a_vid, b_vid),
|
.sub_unified(a_vid, b_vid),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -194,7 +194,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
highlight: Option<ty::print::RegionHighlightMode>,
|
highlight: Option<ty::print::RegionHighlightMode>,
|
||||||
) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
|
) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
|
||||||
if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind {
|
if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind {
|
||||||
let ty_vars = &self.inner.borrow().type_variables;
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
let ty_vars = &inner.type_variables();
|
||||||
let var_origin = ty_vars.var_origin(ty_vid);
|
let var_origin = ty_vars.var_origin(ty_vid);
|
||||||
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind {
|
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind {
|
||||||
let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
|
let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
|
||||||
@ -248,7 +249,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
||||||
let ty_vars = &self.inner.borrow().type_variables;
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
let ty_vars = inner.type_variables();
|
||||||
let getter = move |ty_vid| {
|
let getter = move |ty_vid| {
|
||||||
let var_origin = ty_vars.var_origin(ty_vid);
|
let var_origin = ty_vars.var_origin(ty_vid);
|
||||||
if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
|
if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
|
||||||
|
@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||||||
|
|
||||||
match t.kind {
|
match t.kind {
|
||||||
ty::Infer(ty::TyVar(v)) => {
|
ty::Infer(ty::TyVar(v)) => {
|
||||||
let opt_ty = self.infcx.inner.borrow_mut().type_variables.probe(v).known();
|
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
|
||||||
self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy)
|
self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||||||
self.infcx
|
self.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.int_unification_table
|
.int_unification_table()
|
||||||
.probe_value(v)
|
.probe_value(v)
|
||||||
.map(|v| v.to_type(tcx)),
|
.map(|v| v.to_type(tcx)),
|
||||||
ty::IntVar(v),
|
ty::IntVar(v),
|
||||||
@ -166,7 +166,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||||||
self.infcx
|
self.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.float_unification_table
|
.float_unification_table()
|
||||||
.probe_value(v)
|
.probe_value(v)
|
||||||
.map(|v| v.to_type(tcx)),
|
.map(|v| v.to_type(tcx)),
|
||||||
ty::FloatVar(v),
|
ty::FloatVar(v),
|
||||||
@ -222,7 +222,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||||||
.infcx
|
.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.const_unification_table
|
.const_unification_table()
|
||||||
.probe_value(v)
|
.probe_value(v)
|
||||||
.val
|
.val
|
||||||
.known();
|
.known();
|
||||||
|
@ -3,18 +3,30 @@ use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt,
|
|||||||
|
|
||||||
use super::type_variable::TypeVariableOrigin;
|
use super::type_variable::TypeVariableOrigin;
|
||||||
use super::InferCtxt;
|
use super::InferCtxt;
|
||||||
use super::{ConstVariableOrigin, RegionVariableOrigin};
|
use super::{ConstVariableOrigin, RegionVariableOrigin, UnificationTable};
|
||||||
|
|
||||||
|
use rustc_data_structures::snapshot_vec as sv;
|
||||||
use rustc_data_structures::unify as ut;
|
use rustc_data_structures::unify as ut;
|
||||||
use ut::UnifyKey;
|
use ut::UnifyKey;
|
||||||
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
fn vars_since_snapshot<'tcx, T>(
|
||||||
|
table: &mut UnificationTable<'_, 'tcx, T>,
|
||||||
|
snapshot_var_len: usize,
|
||||||
|
) -> Range<T>
|
||||||
|
where
|
||||||
|
T: UnifyKey,
|
||||||
|
super::UndoLog<'tcx>: From<sv::UndoLog<ut::Delegate<T>>>,
|
||||||
|
{
|
||||||
|
T::from_index(snapshot_var_len as u32)..T::from_index(table.len() as u32)
|
||||||
|
}
|
||||||
|
|
||||||
fn const_vars_since_snapshot<'tcx>(
|
fn const_vars_since_snapshot<'tcx>(
|
||||||
table: &mut ut::UnificationTable<ut::InPlace<ConstVid<'tcx>>>,
|
table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>,
|
||||||
snapshot: &ut::Snapshot<ut::InPlace<ConstVid<'tcx>>>,
|
snapshot_var_len: usize,
|
||||||
) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) {
|
) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) {
|
||||||
let range = table.vars_since_snapshot(snapshot);
|
let range = vars_since_snapshot(table, snapshot_var_len);
|
||||||
(
|
(
|
||||||
range.start..range.end,
|
range.start..range.end,
|
||||||
(range.start.index..range.end.index)
|
(range.start.index..range.end.index)
|
||||||
@ -23,7 +35,26 @@ fn const_vars_since_snapshot<'tcx>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VariableLengths {
|
||||||
|
type_var_len: usize,
|
||||||
|
const_var_len: usize,
|
||||||
|
int_var_len: usize,
|
||||||
|
float_var_len: usize,
|
||||||
|
region_constraints_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
fn variable_lengths(&self) -> VariableLengths {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
VariableLengths {
|
||||||
|
type_var_len: inner.type_variables().num_vars(),
|
||||||
|
const_var_len: inner.const_unification_table().len(),
|
||||||
|
int_var_len: inner.int_unification_table().len(),
|
||||||
|
float_var_len: inner.float_unification_table().len(),
|
||||||
|
region_constraints_len: inner.unwrap_region_constraints().num_region_vars(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This rather funky routine is used while processing expected
|
/// This rather funky routine is used while processing expected
|
||||||
/// types. What happens here is that we want to propagate a
|
/// types. What happens here is that we want to propagate a
|
||||||
/// coercion through the return type of a fn to its
|
/// coercion through the return type of a fn to its
|
||||||
@ -70,7 +101,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
debug!("fudge_inference_if_ok()");
|
debug!("fudge_inference_if_ok()");
|
||||||
|
|
||||||
let (mut fudger, value) = self.probe(|snapshot| {
|
let variable_lengths = self.variable_lengths();
|
||||||
|
let (mut fudger, value) = self.probe(|_| {
|
||||||
match f() {
|
match f() {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
let value = self.resolve_vars_if_possible(&value);
|
let value = self.resolve_vars_if_possible(&value);
|
||||||
@ -83,17 +115,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
let type_vars =
|
let type_vars =
|
||||||
inner.type_variables.vars_since_snapshot(&snapshot.type_snapshot);
|
inner.type_variables().vars_since_snapshot(variable_lengths.type_var_len);
|
||||||
let int_vars =
|
let int_vars = vars_since_snapshot(
|
||||||
inner.int_unification_table.vars_since_snapshot(&snapshot.int_snapshot);
|
&mut inner.int_unification_table(),
|
||||||
let float_vars =
|
variable_lengths.int_var_len,
|
||||||
inner.float_unification_table.vars_since_snapshot(&snapshot.float_snapshot);
|
);
|
||||||
|
let float_vars = vars_since_snapshot(
|
||||||
|
&mut inner.float_unification_table(),
|
||||||
|
variable_lengths.float_var_len,
|
||||||
|
);
|
||||||
let region_vars = inner
|
let region_vars = inner
|
||||||
.unwrap_region_constraints()
|
.unwrap_region_constraints()
|
||||||
.vars_since_snapshot(&snapshot.region_constraints_snapshot);
|
.vars_since_snapshot(variable_lengths.region_constraints_len);
|
||||||
let const_vars = const_vars_since_snapshot(
|
let const_vars = const_vars_since_snapshot(
|
||||||
&mut inner.const_unification_table,
|
&mut inner.const_unification_table(),
|
||||||
&snapshot.const_snapshot,
|
variable_lengths.const_var_len,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fudger = InferenceFudger {
|
let fudger = InferenceFudger {
|
||||||
@ -161,7 +197,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> {
|
|||||||
// that it is unbound, so we can just return
|
// that it is unbound, so we can just return
|
||||||
// it.
|
// it.
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.infcx.inner.borrow_mut().type_variables.probe(vid).is_unknown()
|
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
|
||||||
);
|
);
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let infcx = this.infcx();
|
let infcx = this.infcx();
|
||||||
let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a);
|
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
|
||||||
let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b);
|
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
|
||||||
match (&a.kind, &b.kind) {
|
match (&a.kind, &b.kind) {
|
||||||
// If one side is known to be a variable and one is not,
|
// If one side is known to be a variable and one is not,
|
||||||
// create a variable (`v`) to represent the LUB. Make sure to
|
// create a variable (`v`) to represent the LUB. Make sure to
|
||||||
|
@ -6,11 +6,14 @@ pub use self::RegionVariableOrigin::*;
|
|||||||
pub use self::SubregionOrigin::*;
|
pub use self::SubregionOrigin::*;
|
||||||
pub use self::ValuePairs::*;
|
pub use self::ValuePairs::*;
|
||||||
|
|
||||||
|
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
|
||||||
|
|
||||||
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
|
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_data_structures::undo_log::Rollback;
|
||||||
use rustc_data_structures::unify as ut;
|
use rustc_data_structures::unify as ut;
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
@ -42,7 +45,9 @@ use self::free_regions::RegionRelations;
|
|||||||
use self::lexical_region_resolve::LexicalRegionResolutions;
|
use self::lexical_region_resolve::LexicalRegionResolutions;
|
||||||
use self::outlives::env::OutlivesEnvironment;
|
use self::outlives::env::OutlivesEnvironment;
|
||||||
use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
|
use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
|
||||||
use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
|
use self::region_constraints::{
|
||||||
|
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
|
||||||
|
};
|
||||||
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
|
||||||
pub mod at;
|
pub mod at;
|
||||||
@ -64,6 +69,7 @@ pub mod region_constraints;
|
|||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
mod sub;
|
mod sub;
|
||||||
pub mod type_variable;
|
pub mod type_variable;
|
||||||
|
mod undo_log;
|
||||||
|
|
||||||
use crate::infer::canonical::OriginalQueryValues;
|
use crate::infer::canonical::OriginalQueryValues;
|
||||||
pub use rustc_middle::infer::unify_key;
|
pub use rustc_middle::infer::unify_key;
|
||||||
@ -80,6 +86,10 @@ pub type Bound<T> = Option<T>;
|
|||||||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||||
pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
|
pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
|
||||||
|
|
||||||
|
pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
|
||||||
|
ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
|
||||||
|
>;
|
||||||
|
|
||||||
/// How we should handle region solving.
|
/// How we should handle region solving.
|
||||||
///
|
///
|
||||||
/// This is used so that the region values inferred by HIR region solving are
|
/// This is used so that the region values inferred by HIR region solving are
|
||||||
@ -136,28 +146,28 @@ pub struct InferCtxtInner<'tcx> {
|
|||||||
/// Cache for projections. This cache is snapshotted along with the infcx.
|
/// Cache for projections. This cache is snapshotted along with the infcx.
|
||||||
///
|
///
|
||||||
/// Public so that `traits::project` can use it.
|
/// Public so that `traits::project` can use it.
|
||||||
pub projection_cache: traits::ProjectionCache<'tcx>,
|
pub projection_cache: traits::ProjectionCacheStorage<'tcx>,
|
||||||
|
|
||||||
/// We instantiate `UnificationTable` with `bounds<Ty>` because the types
|
/// We instantiate `UnificationTable` with `bounds<Ty>` because the types
|
||||||
/// that might instantiate a general type variable have an order,
|
/// that might instantiate a general type variable have an order,
|
||||||
/// represented by its upper and lower bounds.
|
/// represented by its upper and lower bounds.
|
||||||
type_variables: type_variable::TypeVariableTable<'tcx>,
|
type_variable_storage: type_variable::TypeVariableStorage<'tcx>,
|
||||||
|
|
||||||
/// Map from const parameter variable to the kind of const it represents.
|
/// Map from const parameter variable to the kind of const it represents.
|
||||||
const_unification_table: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>,
|
const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>,
|
||||||
|
|
||||||
/// Map from integral variable to the kind of integer it represents.
|
/// Map from integral variable to the kind of integer it represents.
|
||||||
int_unification_table: ut::UnificationTable<ut::InPlace<ty::IntVid>>,
|
int_unification_storage: ut::UnificationTableStorage<ty::IntVid>,
|
||||||
|
|
||||||
/// Map from floating variable to the kind of float it represents.
|
/// Map from floating variable to the kind of float it represents.
|
||||||
float_unification_table: ut::UnificationTable<ut::InPlace<ty::FloatVid>>,
|
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
|
||||||
|
|
||||||
/// Tracks the set of region variables and the constraints between them.
|
/// Tracks the set of region variables and the constraints between them.
|
||||||
/// This is initially `Some(_)` but when
|
/// This is initially `Some(_)` but when
|
||||||
/// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
|
/// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
|
||||||
/// -- further attempts to perform unification, etc., may fail if new
|
/// -- further attempts to perform unification, etc., may fail if new
|
||||||
/// region constraints would've been added.
|
/// region constraints would've been added.
|
||||||
region_constraints: Option<RegionConstraintCollector<'tcx>>,
|
region_constraint_storage: Option<RegionConstraintStorage<'tcx>>,
|
||||||
|
|
||||||
/// A set of constraints that regionck must validate. Each
|
/// A set of constraints that regionck must validate. Each
|
||||||
/// constraint has the form `T:'a`, meaning "some type `T` must
|
/// constraint has the form `T:'a`, meaning "some type `T` must
|
||||||
@ -190,24 +200,78 @@ pub struct InferCtxtInner<'tcx> {
|
|||||||
/// for each body-id in this map, which will process the
|
/// for each body-id in this map, which will process the
|
||||||
/// obligations within. This is expected to be done 'late enough'
|
/// obligations within. This is expected to be done 'late enough'
|
||||||
/// that all type inference variables have been bound and so forth.
|
/// that all type inference variables have been bound and so forth.
|
||||||
pub region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
|
region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
|
||||||
|
|
||||||
|
undo_log: InferCtxtUndoLogs<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> InferCtxtInner<'tcx> {
|
impl<'tcx> InferCtxtInner<'tcx> {
|
||||||
fn new() -> InferCtxtInner<'tcx> {
|
fn new() -> InferCtxtInner<'tcx> {
|
||||||
InferCtxtInner {
|
InferCtxtInner {
|
||||||
projection_cache: Default::default(),
|
projection_cache: Default::default(),
|
||||||
type_variables: type_variable::TypeVariableTable::new(),
|
type_variable_storage: type_variable::TypeVariableStorage::new(),
|
||||||
const_unification_table: ut::UnificationTable::new(),
|
undo_log: InferCtxtUndoLogs::default(),
|
||||||
int_unification_table: ut::UnificationTable::new(),
|
const_unification_storage: ut::UnificationTableStorage::new(),
|
||||||
float_unification_table: ut::UnificationTable::new(),
|
int_unification_storage: ut::UnificationTableStorage::new(),
|
||||||
region_constraints: Some(RegionConstraintCollector::new()),
|
float_unification_storage: ut::UnificationTableStorage::new(),
|
||||||
|
region_constraint_storage: Some(RegionConstraintStorage::new()),
|
||||||
region_obligations: vec![],
|
region_obligations: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> {
|
pub fn region_obligations(&self) -> &[(hir::HirId, RegionObligation<'tcx>)] {
|
||||||
self.region_constraints.as_mut().expect("region constraints already solved")
|
&self.region_obligations
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn projection_cache(&mut self) -> traits::ProjectionCache<'_, 'tcx> {
|
||||||
|
self.projection_cache.with_log(&mut self.undo_log)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
|
||||||
|
self.type_variable_storage.with_log(&mut self.undo_log)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_unification_table(
|
||||||
|
&mut self,
|
||||||
|
) -> ut::UnificationTable<
|
||||||
|
ut::InPlace<
|
||||||
|
ty::IntVid,
|
||||||
|
&mut ut::UnificationStorage<ty::IntVid>,
|
||||||
|
&mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
self.int_unification_storage.with_log(&mut self.undo_log)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn float_unification_table(
|
||||||
|
&mut self,
|
||||||
|
) -> ut::UnificationTable<
|
||||||
|
ut::InPlace<
|
||||||
|
ty::FloatVid,
|
||||||
|
&mut ut::UnificationStorage<ty::FloatVid>,
|
||||||
|
&mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
self.float_unification_storage.with_log(&mut self.undo_log)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_unification_table(
|
||||||
|
&mut self,
|
||||||
|
) -> ut::UnificationTable<
|
||||||
|
ut::InPlace<
|
||||||
|
ty::ConstVid<'tcx>,
|
||||||
|
&mut ut::UnificationStorage<ty::ConstVid<'tcx>>,
|
||||||
|
&mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
self.const_unification_storage.with_log(&mut self.undo_log)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
|
||||||
|
self.region_constraint_storage
|
||||||
|
.as_mut()
|
||||||
|
.expect("region constraints already solved")
|
||||||
|
.with_log(&mut self.undo_log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,16 +707,10 @@ impl<'tcx> InferOk<'tcx, ()> {
|
|||||||
|
|
||||||
#[must_use = "once you start a snapshot, you should always consume it"]
|
#[must_use = "once you start a snapshot, you should always consume it"]
|
||||||
pub struct CombinedSnapshot<'a, 'tcx> {
|
pub struct CombinedSnapshot<'a, 'tcx> {
|
||||||
projection_cache_snapshot: traits::ProjectionCacheSnapshot,
|
undo_snapshot: Snapshot<'tcx>,
|
||||||
type_snapshot: type_variable::Snapshot<'tcx>,
|
|
||||||
const_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>,
|
|
||||||
int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
|
|
||||||
float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
|
|
||||||
region_constraints_snapshot: RegionSnapshot,
|
region_constraints_snapshot: RegionSnapshot,
|
||||||
region_obligations_snapshot: usize,
|
|
||||||
universe: ty::UniverseIndex,
|
universe: ty::UniverseIndex,
|
||||||
was_in_snapshot: bool,
|
was_in_snapshot: bool,
|
||||||
was_skip_leak_check: bool,
|
|
||||||
_in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
|
_in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,7 +725,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
|
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
|
||||||
match ty.kind {
|
match ty.kind {
|
||||||
ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid),
|
ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -681,14 +739,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
|
use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
|
||||||
match ty.kind {
|
match ty.kind {
|
||||||
ty::Infer(ty::IntVar(vid)) => {
|
ty::Infer(ty::IntVar(vid)) => {
|
||||||
if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() {
|
if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() {
|
||||||
Neither
|
Neither
|
||||||
} else {
|
} else {
|
||||||
UnconstrainedInt
|
UnconstrainedInt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Infer(ty::FloatVar(vid)) => {
|
ty::Infer(ty::FloatVar(vid)) => {
|
||||||
if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() {
|
if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() {
|
||||||
Neither
|
Neither
|
||||||
} else {
|
} else {
|
||||||
UnconstrainedFloat
|
UnconstrainedFloat
|
||||||
@ -703,21 +761,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
// FIXME(const_generics): should there be an equivalent function for const variables?
|
// FIXME(const_generics): should there be an equivalent function for const variables?
|
||||||
|
|
||||||
let mut vars: Vec<Ty<'_>> = inner
|
let mut vars: Vec<Ty<'_>> = inner
|
||||||
.type_variables
|
.type_variables()
|
||||||
.unsolved_variables()
|
.unsolved_variables()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|t| self.tcx.mk_ty_var(t))
|
.map(|t| self.tcx.mk_ty_var(t))
|
||||||
.collect();
|
.collect();
|
||||||
vars.extend(
|
vars.extend(
|
||||||
(0..inner.int_unification_table.len())
|
(0..inner.int_unification_table().len())
|
||||||
.map(|i| ty::IntVid { index: i as u32 })
|
.map(|i| ty::IntVid { index: i as u32 })
|
||||||
.filter(|&vid| inner.int_unification_table.probe_value(vid).is_none())
|
.filter(|&vid| inner.int_unification_table().probe_value(vid).is_none())
|
||||||
.map(|v| self.tcx.mk_int_var(v)),
|
.map(|v| self.tcx.mk_int_var(v)),
|
||||||
);
|
);
|
||||||
vars.extend(
|
vars.extend(
|
||||||
(0..inner.float_unification_table.len())
|
(0..inner.float_unification_table().len())
|
||||||
.map(|i| ty::FloatVid { index: i as u32 })
|
.map(|i| ty::FloatVid { index: i as u32 })
|
||||||
.filter(|&vid| inner.float_unification_table.probe_value(vid).is_none())
|
.filter(|&vid| inner.float_unification_table().probe_value(vid).is_none())
|
||||||
.map(|v| self.tcx.mk_float_var(v)),
|
.map(|v| self.tcx.mk_float_var(v)),
|
||||||
);
|
);
|
||||||
vars
|
vars
|
||||||
@ -769,17 +827,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
let in_snapshot = self.in_snapshot.replace(true);
|
let in_snapshot = self.in_snapshot.replace(true);
|
||||||
|
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
|
||||||
CombinedSnapshot {
|
CombinedSnapshot {
|
||||||
projection_cache_snapshot: inner.projection_cache.snapshot(),
|
undo_snapshot: inner.undo_log.start_snapshot(),
|
||||||
type_snapshot: inner.type_variables.snapshot(),
|
|
||||||
const_snapshot: inner.const_unification_table.snapshot(),
|
|
||||||
int_snapshot: inner.int_unification_table.snapshot(),
|
|
||||||
float_snapshot: inner.float_unification_table.snapshot(),
|
|
||||||
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
|
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
|
||||||
region_obligations_snapshot: inner.region_obligations.len(),
|
|
||||||
universe: self.universe(),
|
universe: self.universe(),
|
||||||
was_in_snapshot: in_snapshot,
|
was_in_snapshot: in_snapshot,
|
||||||
was_skip_leak_check: self.skip_leak_check.get(),
|
|
||||||
// Borrow tables "in progress" (i.e., during typeck)
|
// Borrow tables "in progress" (i.e., during typeck)
|
||||||
// to ban writes from within a snapshot to them.
|
// to ban writes from within a snapshot to them.
|
||||||
_in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()),
|
_in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()),
|
||||||
@ -789,59 +842,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
|
fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
|
||||||
debug!("rollback_to(cause={})", cause);
|
debug!("rollback_to(cause={})", cause);
|
||||||
let CombinedSnapshot {
|
let CombinedSnapshot {
|
||||||
projection_cache_snapshot,
|
undo_snapshot,
|
||||||
type_snapshot,
|
|
||||||
const_snapshot,
|
|
||||||
int_snapshot,
|
|
||||||
float_snapshot,
|
|
||||||
region_constraints_snapshot,
|
region_constraints_snapshot,
|
||||||
region_obligations_snapshot,
|
|
||||||
universe,
|
universe,
|
||||||
was_in_snapshot,
|
was_in_snapshot,
|
||||||
was_skip_leak_check,
|
|
||||||
_in_progress_tables,
|
_in_progress_tables,
|
||||||
} = snapshot;
|
} = snapshot;
|
||||||
|
|
||||||
self.in_snapshot.set(was_in_snapshot);
|
self.in_snapshot.set(was_in_snapshot);
|
||||||
self.universe.set(universe);
|
self.universe.set(universe);
|
||||||
self.skip_leak_check.set(was_skip_leak_check);
|
|
||||||
|
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
inner.projection_cache.rollback_to(projection_cache_snapshot);
|
inner.rollback_to(undo_snapshot);
|
||||||
inner.type_variables.rollback_to(type_snapshot);
|
|
||||||
inner.const_unification_table.rollback_to(const_snapshot);
|
|
||||||
inner.int_unification_table.rollback_to(int_snapshot);
|
|
||||||
inner.float_unification_table.rollback_to(float_snapshot);
|
|
||||||
inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
|
inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
|
||||||
inner.region_obligations.truncate(region_obligations_snapshot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
|
fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
|
||||||
debug!("commit_from()");
|
debug!("commit_from()");
|
||||||
let CombinedSnapshot {
|
let CombinedSnapshot {
|
||||||
projection_cache_snapshot,
|
undo_snapshot,
|
||||||
type_snapshot,
|
region_constraints_snapshot: _,
|
||||||
const_snapshot,
|
|
||||||
int_snapshot,
|
|
||||||
float_snapshot,
|
|
||||||
region_constraints_snapshot,
|
|
||||||
region_obligations_snapshot: _,
|
|
||||||
universe: _,
|
universe: _,
|
||||||
was_in_snapshot,
|
was_in_snapshot,
|
||||||
was_skip_leak_check,
|
|
||||||
_in_progress_tables,
|
_in_progress_tables,
|
||||||
} = snapshot;
|
} = snapshot;
|
||||||
|
|
||||||
self.in_snapshot.set(was_in_snapshot);
|
self.in_snapshot.set(was_in_snapshot);
|
||||||
self.skip_leak_check.set(was_skip_leak_check);
|
|
||||||
|
|
||||||
let mut inner = self.inner.borrow_mut();
|
self.inner.borrow_mut().commit(undo_snapshot);
|
||||||
inner.projection_cache.commit(projection_cache_snapshot);
|
|
||||||
inner.type_variables.commit(type_snapshot);
|
|
||||||
inner.const_unification_table.commit(const_snapshot);
|
|
||||||
inner.int_unification_table.commit(int_snapshot);
|
|
||||||
inner.float_unification_table.commit(float_snapshot);
|
|
||||||
inner.unwrap_region_constraints().commit(region_constraints_snapshot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes `f` and commit the bindings.
|
/// Executes `f` and commit the bindings.
|
||||||
@ -895,10 +923,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
debug!("probe()");
|
debug!("probe()");
|
||||||
let snapshot = self.start_snapshot();
|
let snapshot = self.start_snapshot();
|
||||||
let skip_leak_check = should_skip || self.skip_leak_check.get();
|
let was_skip_leak_check = self.skip_leak_check.get();
|
||||||
self.skip_leak_check.set(skip_leak_check);
|
if should_skip {
|
||||||
|
self.skip_leak_check.set(true);
|
||||||
|
}
|
||||||
let r = f(&snapshot);
|
let r = f(&snapshot);
|
||||||
self.rollback_to("probe", snapshot);
|
self.rollback_to("probe", snapshot);
|
||||||
|
self.skip_leak_check.set(was_skip_leak_check);
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,7 +945,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
self.inner
|
self.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.unwrap_region_constraints()
|
.unwrap_region_constraints()
|
||||||
.region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot)
|
.region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
|
pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
|
||||||
@ -1032,7 +1063,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
|
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
|
||||||
self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin)
|
self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
|
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
|
||||||
@ -1044,7 +1075,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
origin: TypeVariableOrigin,
|
origin: TypeVariableOrigin,
|
||||||
universe: ty::UniverseIndex,
|
universe: ty::UniverseIndex,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin);
|
let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin);
|
||||||
self.tcx.mk_ty_var(vid)
|
self.tcx.mk_ty_var(vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1069,20 +1100,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
let vid = self
|
let vid = self
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.const_unification_table
|
.const_unification_table()
|
||||||
.new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
|
.new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
|
||||||
self.tcx.mk_const_var(vid, ty)
|
self.tcx.mk_const_var(vid, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
|
pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
|
||||||
self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
|
self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
|
||||||
origin,
|
origin,
|
||||||
val: ConstVariableValue::Unknown { universe: self.universe() },
|
val: ConstVariableValue::Unknown { universe: self.universe() },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_int_var_id(&self) -> IntVid {
|
fn next_int_var_id(&self) -> IntVid {
|
||||||
self.inner.borrow_mut().int_unification_table.new_key(None)
|
self.inner.borrow_mut().int_unification_table().new_key(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_int_var(&self) -> Ty<'tcx> {
|
pub fn next_int_var(&self) -> Ty<'tcx> {
|
||||||
@ -1090,7 +1121,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn next_float_var_id(&self) -> FloatVid {
|
fn next_float_var_id(&self) -> FloatVid {
|
||||||
self.inner.borrow_mut().float_unification_table.new_key(None)
|
self.inner.borrow_mut().float_unification_table().new_key(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_float_var(&self) -> Ty<'tcx> {
|
pub fn next_float_var(&self) -> Ty<'tcx> {
|
||||||
@ -1161,7 +1192,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
// used in a path such as `Foo::<T, U>::new()` will
|
// used in a path such as `Foo::<T, U>::new()` will
|
||||||
// use an inference variable for `C` with `[T, U]`
|
// use an inference variable for `C` with `[T, U]`
|
||||||
// as the substitutions for the default, `(T, U)`.
|
// as the substitutions for the default, `(T, U)`.
|
||||||
let ty_var_id = self.inner.borrow_mut().type_variables.new_var(
|
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
|
||||||
self.universe(),
|
self.universe(),
|
||||||
false,
|
false,
|
||||||
TypeVariableOrigin {
|
TypeVariableOrigin {
|
||||||
@ -1181,7 +1212,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
let const_var_id =
|
let const_var_id =
|
||||||
self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
|
self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
|
||||||
origin,
|
origin,
|
||||||
val: ConstVariableValue::Unknown { universe: self.universe() },
|
val: ConstVariableValue::Unknown { universe: self.universe() },
|
||||||
});
|
});
|
||||||
@ -1234,18 +1265,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||||
mode: RegionckMode,
|
mode: RegionckMode,
|
||||||
) {
|
) {
|
||||||
|
let (var_infos, data) = {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
let inner = &mut *inner;
|
||||||
assert!(
|
assert!(
|
||||||
self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(),
|
self.is_tainted_by_errors() || inner.region_obligations.is_empty(),
|
||||||
"region_obligations not empty: {:#?}",
|
"region_obligations not empty: {:#?}",
|
||||||
self.inner.borrow().region_obligations
|
inner.region_obligations
|
||||||
);
|
);
|
||||||
let (var_infos, data) = self
|
inner
|
||||||
.inner
|
.region_constraint_storage
|
||||||
.borrow_mut()
|
|
||||||
.region_constraints
|
|
||||||
.take()
|
.take()
|
||||||
.expect("regions already resolved")
|
.expect("regions already resolved")
|
||||||
.into_infos_and_data();
|
.with_log(&mut inner.undo_log)
|
||||||
|
.into_infos_and_data()
|
||||||
|
};
|
||||||
|
|
||||||
let region_rels = &RegionRelations::new(
|
let region_rels = &RegionRelations::new(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
@ -1306,12 +1340,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
/// called. This is used only during NLL processing to "hand off" ownership
|
/// called. This is used only during NLL processing to "hand off" ownership
|
||||||
/// of the set of region variables into the NLL region context.
|
/// of the set of region variables into the NLL region context.
|
||||||
pub fn take_region_var_origins(&self) -> VarInfos {
|
pub fn take_region_var_origins(&self) -> VarInfos {
|
||||||
let (var_infos, data) = self
|
let mut inner = self.inner.borrow_mut();
|
||||||
.inner
|
let (var_infos, data) = inner
|
||||||
.borrow_mut()
|
.region_constraint_storage
|
||||||
.region_constraints
|
|
||||||
.take()
|
.take()
|
||||||
.expect("regions already resolved")
|
.expect("regions already resolved")
|
||||||
|
.with_log(&mut inner.undo_log)
|
||||||
.into_infos_and_data();
|
.into_infos_and_data();
|
||||||
assert!(data.is_empty());
|
assert!(data.is_empty());
|
||||||
var_infos
|
var_infos
|
||||||
@ -1335,7 +1369,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> {
|
pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> {
|
||||||
use self::type_variable::TypeVariableValue;
|
use self::type_variable::TypeVariableValue;
|
||||||
|
|
||||||
match self.inner.borrow_mut().type_variables.probe(vid) {
|
match self.inner.borrow_mut().type_variables().probe(vid) {
|
||||||
TypeVariableValue::Known { value } => Ok(value),
|
TypeVariableValue::Known { value } => Ok(value),
|
||||||
TypeVariableValue::Unknown { universe } => Err(universe),
|
TypeVariableValue::Unknown { universe } => Err(universe),
|
||||||
}
|
}
|
||||||
@ -1357,7 +1391,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
|
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||||
self.inner.borrow_mut().type_variables.root_var(var)
|
self.inner.borrow_mut().type_variables().root_var(var)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Where possible, replaces type/const variables in
|
/// Where possible, replaces type/const variables in
|
||||||
@ -1395,7 +1429,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
vid: ty::ConstVid<'tcx>,
|
vid: ty::ConstVid<'tcx>,
|
||||||
) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
|
) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
|
||||||
match self.inner.borrow_mut().const_unification_table.probe_value(vid).val {
|
match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
|
||||||
ConstVariableValue::Known { value } => Ok(value),
|
ConstVariableValue::Known { value } => Ok(value),
|
||||||
ConstVariableValue::Unknown { universe } => Err(universe),
|
ConstVariableValue::Unknown { universe } => Err(universe),
|
||||||
}
|
}
|
||||||
@ -1513,7 +1547,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
pub fn clear_caches(&self) {
|
pub fn clear_caches(&self) {
|
||||||
self.selection_cache.clear();
|
self.selection_cache.clear();
|
||||||
self.evaluation_cache.clear();
|
self.evaluation_cache.clear();
|
||||||
self.inner.borrow_mut().projection_cache.clear();
|
self.inner.borrow_mut().projection_cache().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn universe(&self) -> ty::UniverseIndex {
|
fn universe(&self) -> ty::UniverseIndex {
|
||||||
@ -1576,14 +1610,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
//
|
//
|
||||||
// Note: if these two lines are combined into one we get
|
// Note: if these two lines are combined into one we get
|
||||||
// dynamic borrow errors on `self.inner`.
|
// dynamic borrow errors on `self.inner`.
|
||||||
let known = self.inner.borrow_mut().type_variables.probe(v).known();
|
let known = self.inner.borrow_mut().type_variables().probe(v).known();
|
||||||
known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ)
|
known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Infer(ty::IntVar(v)) => self
|
ty::Infer(ty::IntVar(v)) => self
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.int_unification_table
|
.int_unification_table()
|
||||||
.probe_value(v)
|
.probe_value(v)
|
||||||
.map(|v| v.to_type(self.tcx))
|
.map(|v| v.to_type(self.tcx))
|
||||||
.unwrap_or(typ),
|
.unwrap_or(typ),
|
||||||
@ -1591,7 +1625,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
ty::Infer(ty::FloatVar(v)) => self
|
ty::Infer(ty::FloatVar(v)) => self
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.float_unification_table
|
.float_unification_table()
|
||||||
.probe_value(v)
|
.probe_value(v)
|
||||||
.map(|v| v.to_type(self.tcx))
|
.map(|v| v.to_type(self.tcx))
|
||||||
.unwrap_or(typ),
|
.unwrap_or(typ),
|
||||||
@ -1611,13 +1645,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
/// having to resort to storing full `GenericArg`s in `stalled_on`.
|
/// having to resort to storing full `GenericArg`s in `stalled_on`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
|
pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
match infer_var {
|
match infer_var {
|
||||||
TyOrConstInferVar::Ty(v) => {
|
TyOrConstInferVar::Ty(v) => {
|
||||||
use self::type_variable::TypeVariableValue;
|
use self::type_variable::TypeVariableValue;
|
||||||
|
|
||||||
// If `inlined_probe` returns a `Known` value, it never equals
|
// If `inlined_probe` returns a `Known` value, it never equals
|
||||||
// `ty::Infer(ty::TyVar(v))`.
|
// `ty::Infer(ty::TyVar(v))`.
|
||||||
match self.inner.borrow_mut().type_variables.inlined_probe(v) {
|
match inner.type_variables().inlined_probe(v) {
|
||||||
TypeVariableValue::Unknown { .. } => false,
|
TypeVariableValue::Unknown { .. } => false,
|
||||||
TypeVariableValue::Known { .. } => true,
|
TypeVariableValue::Known { .. } => true,
|
||||||
}
|
}
|
||||||
@ -1627,7 +1662,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
// If `inlined_probe_value` returns a value it's always a
|
// If `inlined_probe_value` returns a value it's always a
|
||||||
// `ty::Int(_)` or `ty::UInt(_)`, which never matches a
|
// `ty::Int(_)` or `ty::UInt(_)`, which never matches a
|
||||||
// `ty::Infer(_)`.
|
// `ty::Infer(_)`.
|
||||||
self.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some()
|
inner.int_unification_table().inlined_probe_value(v).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
TyOrConstInferVar::TyFloat(v) => {
|
TyOrConstInferVar::TyFloat(v) => {
|
||||||
@ -1635,7 +1670,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
// `ty::Float(_)`, which never matches a `ty::Infer(_)`.
|
// `ty::Float(_)`, which never matches a `ty::Infer(_)`.
|
||||||
//
|
//
|
||||||
// Not `inlined_probe_value(v)` because this call site is colder.
|
// Not `inlined_probe_value(v)` because this call site is colder.
|
||||||
self.inner.borrow_mut().float_unification_table.probe_value(v).is_some()
|
inner.float_unification_table().probe_value(v).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
TyOrConstInferVar::Const(v) => {
|
TyOrConstInferVar::Const(v) => {
|
||||||
@ -1643,7 +1678,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
// `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
|
// `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
|
||||||
//
|
//
|
||||||
// Not `inlined_probe_value(v)` because this call site is colder.
|
// Not `inlined_probe_value(v)` because this call site is colder.
|
||||||
match self.inner.borrow_mut().const_unification_table.probe_value(v).val {
|
match inner.const_unification_table().probe_value(v).val {
|
||||||
ConstVariableValue::Unknown { .. } => false,
|
ConstVariableValue::Unknown { .. } => false,
|
||||||
ConstVariableValue::Known { .. } => true,
|
ConstVariableValue::Known { .. } => true,
|
||||||
}
|
}
|
||||||
@ -1718,7 +1753,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
|
|||||||
self.infcx
|
self.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.const_unification_table
|
.const_unification_table()
|
||||||
.probe_value(*vid)
|
.probe_value(*vid)
|
||||||
.val
|
.val
|
||||||
.known()
|
.known()
|
||||||
|
@ -311,7 +311,7 @@ where
|
|||||||
match value_ty.kind {
|
match value_ty.kind {
|
||||||
ty::Infer(ty::TyVar(value_vid)) => {
|
ty::Infer(ty::TyVar(value_vid)) => {
|
||||||
// Two type variables: just equate them.
|
// Two type variables: just equate them.
|
||||||
self.infcx.inner.borrow_mut().type_variables.equate(vid, value_vid);
|
self.infcx.inner.borrow_mut().type_variables().equate(vid, value_vid);
|
||||||
return Ok(value_ty);
|
return Ok(value_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +332,7 @@ where
|
|||||||
assert!(!generalized_ty.has_infer_types_or_consts());
|
assert!(!generalized_ty.has_infer_types_or_consts());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.infcx.inner.borrow_mut().type_variables.instantiate(vid, generalized_ty);
|
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
|
||||||
|
|
||||||
// The generalized values we extract from `canonical_var_values` have
|
// The generalized values we extract from `canonical_var_values` have
|
||||||
// been fully instantiated and hence the set of scopes we have
|
// been fully instantiated and hence the set of scopes we have
|
||||||
@ -362,7 +362,7 @@ where
|
|||||||
delegate: &mut self.delegate,
|
delegate: &mut self.delegate,
|
||||||
first_free_index: ty::INNERMOST,
|
first_free_index: ty::INNERMOST,
|
||||||
ambient_variance: self.ambient_variance,
|
ambient_variance: self.ambient_variance,
|
||||||
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid),
|
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
|
||||||
universe,
|
universe,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -859,7 +859,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::Infer(ty::TyVar(vid)) => {
|
ty::Infer(ty::TyVar(vid)) => {
|
||||||
let variables = &mut self.infcx.inner.borrow_mut().type_variables;
|
let mut inner = self.infcx.inner.borrow_mut();
|
||||||
|
let variables = &mut inner.type_variables();
|
||||||
let vid = variables.root_var(vid);
|
let vid = variables.root_var(vid);
|
||||||
let sub_vid = variables.sub_root_var(vid);
|
let sub_vid = variables.sub_root_var(vid);
|
||||||
if sub_vid == self.for_vid_sub_root {
|
if sub_vid == self.for_vid_sub_root {
|
||||||
@ -961,7 +962,8 @@ where
|
|||||||
bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
|
bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
|
||||||
}
|
}
|
||||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||||
let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table;
|
let mut inner = self.infcx.inner.borrow_mut();
|
||||||
|
let variable_table = &mut inner.const_unification_table();
|
||||||
let var_value = variable_table.probe_value(vid);
|
let var_value = variable_table.probe_value(vid);
|
||||||
match var_value.val.known() {
|
match var_value.val.known() {
|
||||||
Some(u) => self.relate(&u, &u),
|
Some(u) => self.relate(&u, &u),
|
||||||
|
@ -61,13 +61,16 @@
|
|||||||
|
|
||||||
use crate::infer::outlives::env::RegionBoundPairs;
|
use crate::infer::outlives::env::RegionBoundPairs;
|
||||||
use crate::infer::outlives::verify::VerifyBoundCx;
|
use crate::infer::outlives::verify::VerifyBoundCx;
|
||||||
use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
|
use crate::infer::{
|
||||||
|
self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound,
|
||||||
|
};
|
||||||
use crate::traits::ObligationCause;
|
use crate::traits::ObligationCause;
|
||||||
use rustc_middle::ty::outlives::Component;
|
use rustc_middle::ty::outlives::Component;
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_data_structures::undo_log::UndoLogs;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
|
|
||||||
@ -84,7 +87,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||||||
) {
|
) {
|
||||||
debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation);
|
debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation);
|
||||||
|
|
||||||
self.inner.borrow_mut().region_obligations.push((body_id, obligation));
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
inner.undo_log.push(UndoLog::PushRegionObligation);
|
||||||
|
inner.region_obligations.push((body_id, obligation));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_region_obligation_with_cause(
|
pub fn register_region_obligation_with_cause(
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::infer::{CombinedSnapshot, PlaceholderMap};
|
use crate::infer::{CombinedSnapshot, PlaceholderMap};
|
||||||
|
use rustc_data_structures::undo_log::UndoLogs;
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::relate::RelateResult;
|
use rustc_middle::ty::relate::RelateResult;
|
||||||
|
|
||||||
impl<'tcx> RegionConstraintCollector<'tcx> {
|
impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||||
/// Searches region constraints created since `snapshot` that
|
/// Searches region constraints created since `snapshot` that
|
||||||
/// affect one of the placeholders in `placeholder_map`, returning
|
/// affect one of the placeholders in `placeholder_map`, returning
|
||||||
/// an error if any of the placeholders are related to another
|
/// an error if any of the placeholders are related to another
|
||||||
@ -31,7 +32,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
) -> RelateResult<'tcx, ()> {
|
) -> RelateResult<'tcx, ()> {
|
||||||
debug!("leak_check(placeholders={:?})", placeholder_map);
|
debug!("leak_check(placeholders={:?})", placeholder_map);
|
||||||
|
|
||||||
assert!(self.in_snapshot());
|
assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
|
||||||
|
|
||||||
// Go through each placeholder that we created.
|
// Go through each placeholder that we created.
|
||||||
for &placeholder_region in placeholder_map.values() {
|
for &placeholder_region in placeholder_map.values() {
|
||||||
@ -45,7 +46,11 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
// in some way. This means any region that either outlives
|
// in some way. This means any region that either outlives
|
||||||
// or is outlived by a placeholder.
|
// or is outlived by a placeholder.
|
||||||
let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
|
let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
|
||||||
taint_set.fixed_point(tcx, &self.undo_log, &self.data.verifys);
|
taint_set.fixed_point(
|
||||||
|
tcx,
|
||||||
|
self.undo_log.region_constraints(),
|
||||||
|
&self.storage.data.verifys,
|
||||||
|
);
|
||||||
let tainted_regions = taint_set.into_set();
|
let tainted_regions = taint_set.into_set();
|
||||||
|
|
||||||
// Report an error if two placeholders in the same universe
|
// Report an error if two placeholders in the same universe
|
||||||
@ -88,19 +93,21 @@ impl<'tcx> TaintSet<'tcx> {
|
|||||||
TaintSet { directions, regions }
|
TaintSet { directions, regions }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fixed_point(
|
fn fixed_point<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
undo_log: &[UndoLog<'tcx>],
|
undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
|
||||||
verifys: &[Verify<'tcx>],
|
verifys: &[Verify<'tcx>],
|
||||||
) {
|
) where
|
||||||
|
'tcx: 'a,
|
||||||
|
{
|
||||||
let mut prev_len = 0;
|
let mut prev_len = 0;
|
||||||
while prev_len < self.len() {
|
while prev_len < self.len() {
|
||||||
debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
|
debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
|
||||||
|
|
||||||
prev_len = self.len();
|
prev_len = self.len();
|
||||||
|
|
||||||
for undo_entry in undo_log {
|
for undo_entry in undo_log.clone() {
|
||||||
match undo_entry {
|
match undo_entry {
|
||||||
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
||||||
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
|
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
|
||||||
|
@ -4,11 +4,15 @@ use self::CombineMapType::*;
|
|||||||
use self::UndoLog::*;
|
use self::UndoLog::*;
|
||||||
|
|
||||||
use super::unify_key;
|
use super::unify_key;
|
||||||
use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
|
use super::{
|
||||||
|
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
|
||||||
|
};
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync::Lrc;
|
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 as ut;
|
||||||
|
use rustc_data_structures::unify::UnifyKey;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::ty::ReStatic;
|
use rustc_middle::ty::ReStatic;
|
||||||
@ -26,7 +30,7 @@ mod leak_check;
|
|||||||
pub use rustc_middle::infer::MemberConstraint;
|
pub use rustc_middle::infer::MemberConstraint;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RegionConstraintCollector<'tcx> {
|
pub struct RegionConstraintStorage<'tcx> {
|
||||||
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
|
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
|
||||||
var_infos: IndexVec<RegionVid, RegionVariableInfo>,
|
var_infos: IndexVec<RegionVid, RegionVariableInfo>,
|
||||||
|
|
||||||
@ -42,20 +46,6 @@ pub struct RegionConstraintCollector<'tcx> {
|
|||||||
/// exist). This prevents us from making many such regions.
|
/// exist). This prevents us from making many such regions.
|
||||||
glbs: CombineMap<'tcx>,
|
glbs: CombineMap<'tcx>,
|
||||||
|
|
||||||
/// The undo log records actions that might later be undone.
|
|
||||||
///
|
|
||||||
/// Note: `num_open_snapshots` is used to track if we are actively
|
|
||||||
/// snapshotting. When the `start_snapshot()` method is called, we
|
|
||||||
/// increment `num_open_snapshots` to indicate that we are now actively
|
|
||||||
/// snapshotting. The reason for this is that otherwise we end up adding
|
|
||||||
/// entries for things like the lower bound on a variable and so forth,
|
|
||||||
/// which can never be rolled back.
|
|
||||||
undo_log: Vec<UndoLog<'tcx>>,
|
|
||||||
|
|
||||||
/// The number of open snapshots, i.e., those that haven't been committed or
|
|
||||||
/// rolled back.
|
|
||||||
num_open_snapshots: usize,
|
|
||||||
|
|
||||||
/// When we add a R1 == R2 constriant, we currently add (a) edges
|
/// When we add a R1 == R2 constriant, we currently add (a) edges
|
||||||
/// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this
|
/// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this
|
||||||
/// table. You can then call `opportunistic_resolve_var` early
|
/// table. You can then call `opportunistic_resolve_var` early
|
||||||
@ -64,13 +54,31 @@ pub struct RegionConstraintCollector<'tcx> {
|
|||||||
/// is iterating to a fixed point, because otherwise we sometimes
|
/// is iterating to a fixed point, because otherwise we sometimes
|
||||||
/// would wind up with a fresh stream of region variables that
|
/// would wind up with a fresh stream of region variables that
|
||||||
/// have been equated but appear distinct.
|
/// have been equated but appear distinct.
|
||||||
unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>,
|
pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>,
|
||||||
|
|
||||||
/// a flag set to true when we perform any unifications; this is used
|
/// a flag set to true when we perform any unifications; this is used
|
||||||
/// to micro-optimize `take_and_reset_data`
|
/// to micro-optimize `take_and_reset_data`
|
||||||
any_unifications: bool,
|
any_unifications: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RegionConstraintCollector<'a, 'tcx> {
|
||||||
|
storage: &'a mut RegionConstraintStorage<'tcx>,
|
||||||
|
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for RegionConstraintCollector<'_, 'tcx> {
|
||||||
|
type Target = RegionConstraintStorage<'tcx>;
|
||||||
|
fn deref(&self) -> &RegionConstraintStorage<'tcx> {
|
||||||
|
self.storage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> {
|
||||||
|
fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> {
|
||||||
|
self.storage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>;
|
pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>;
|
||||||
|
|
||||||
/// The full set of region constraints gathered up by the collector.
|
/// The full set of region constraints gathered up by the collector.
|
||||||
@ -258,13 +266,13 @@ pub enum VerifyBound<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
struct TwoRegions<'tcx> {
|
pub(crate) struct TwoRegions<'tcx> {
|
||||||
a: Region<'tcx>,
|
a: Region<'tcx>,
|
||||||
b: Region<'tcx>,
|
b: Region<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum UndoLog<'tcx> {
|
pub(crate) enum UndoLog<'tcx> {
|
||||||
/// We added `RegionVid`.
|
/// We added `RegionVid`.
|
||||||
AddVar(RegionVid),
|
AddVar(RegionVid),
|
||||||
|
|
||||||
@ -290,7 +298,7 @@ enum UndoLog<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum CombineMapType {
|
pub(crate) enum CombineMapType {
|
||||||
Lub,
|
Lub,
|
||||||
Glb,
|
Glb,
|
||||||
}
|
}
|
||||||
@ -304,8 +312,6 @@ pub struct RegionVariableInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct RegionSnapshot {
|
pub struct RegionSnapshot {
|
||||||
length: usize,
|
|
||||||
region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>,
|
|
||||||
any_unifications: bool,
|
any_unifications: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,129 +340,16 @@ impl TaintDirections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> RegionConstraintCollector<'tcx> {
|
impl<'tcx> RegionConstraintStorage<'tcx> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_region_vars(&self) -> usize {
|
pub(crate) fn with_log<'a>(
|
||||||
self.var_infos.len()
|
&'a mut self,
|
||||||
}
|
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
) -> RegionConstraintCollector<'a, 'tcx> {
|
||||||
pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> {
|
RegionConstraintCollector { storage: self, undo_log }
|
||||||
&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!(!self.in_snapshot());
|
|
||||||
(self.var_infos, self.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Takes (and clears) the current set of constraints. Note that
|
|
||||||
/// the set of variables remains intact, but all relationships
|
|
||||||
/// between them are reset. This is used during NLL checking to
|
|
||||||
/// grab the set of constraints that arose from a particular
|
|
||||||
/// operation.
|
|
||||||
///
|
|
||||||
/// We don't want to leak relationships between variables between
|
|
||||||
/// points because just because (say) `r1 == r2` was true at some
|
|
||||||
/// point P in the graph doesn't imply that it will be true at
|
|
||||||
/// some other point Q, in NLL.
|
|
||||||
///
|
|
||||||
/// Not legal during a snapshot.
|
|
||||||
pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
|
|
||||||
assert!(!self.in_snapshot());
|
|
||||||
|
|
||||||
// If you add a new field to `RegionConstraintCollector`, you
|
|
||||||
// should think carefully about whether it needs to be cleared
|
|
||||||
// or updated in some way.
|
|
||||||
let RegionConstraintCollector {
|
|
||||||
var_infos: _,
|
|
||||||
data,
|
|
||||||
lubs,
|
|
||||||
glbs,
|
|
||||||
undo_log: _,
|
|
||||||
num_open_snapshots: _,
|
|
||||||
unification_table,
|
|
||||||
any_unifications,
|
|
||||||
} = self;
|
|
||||||
|
|
||||||
// Clear the tables of (lubs, glbs), so that we will create
|
|
||||||
// fresh regions if we do a LUB operation. As it happens,
|
|
||||||
// LUB/GLB are not performed by the MIR type-checker, which is
|
|
||||||
// the one that uses this method, but it's good to be correct.
|
|
||||||
lubs.clear();
|
|
||||||
glbs.clear();
|
|
||||||
|
|
||||||
// Clear all unifications and recreate the variables a "now
|
|
||||||
// un-unified" state. Note that when we unify `a` and `b`, we
|
|
||||||
// also insert `a <= b` and a `b <= a` edges, so the
|
|
||||||
// `RegionConstraintData` contains the relationship here.
|
|
||||||
if *any_unifications {
|
|
||||||
unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
|
|
||||||
*any_unifications = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem::take(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data(&self) -> &RegionConstraintData<'tcx> {
|
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
|
|
||||||
fn in_snapshot(&self) -> bool {
|
|
||||||
self.num_open_snapshots > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start_snapshot(&mut self) -> RegionSnapshot {
|
|
||||||
let length = self.undo_log.len();
|
|
||||||
debug!("RegionConstraintCollector: start_snapshot({})", length);
|
|
||||||
self.num_open_snapshots += 1;
|
|
||||||
RegionSnapshot {
|
|
||||||
length,
|
|
||||||
region_snapshot: self.unification_table.snapshot(),
|
|
||||||
any_unifications: self.any_unifications,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_open_snapshot(&self, snapshot: &RegionSnapshot) {
|
|
||||||
assert!(self.undo_log.len() >= snapshot.length);
|
|
||||||
assert!(self.num_open_snapshots > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit(&mut self, snapshot: RegionSnapshot) {
|
|
||||||
debug!("RegionConstraintCollector: commit({})", snapshot.length);
|
|
||||||
self.assert_open_snapshot(&snapshot);
|
|
||||||
|
|
||||||
if self.num_open_snapshots == 1 {
|
|
||||||
// The root snapshot. It's safe to clear the undo log because
|
|
||||||
// there's no snapshot further out that we might need to roll back
|
|
||||||
// to.
|
|
||||||
assert!(snapshot.length == 0);
|
|
||||||
self.undo_log.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.num_open_snapshots -= 1;
|
|
||||||
|
|
||||||
self.unification_table.commit(snapshot.region_snapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rollback_to(&mut self, snapshot: RegionSnapshot) {
|
|
||||||
debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
|
|
||||||
self.assert_open_snapshot(&snapshot);
|
|
||||||
|
|
||||||
while self.undo_log.len() > snapshot.length {
|
|
||||||
let undo_entry = self.undo_log.pop().unwrap();
|
|
||||||
self.rollback_undo_entry(undo_entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.num_open_snapshots -= 1;
|
|
||||||
|
|
||||||
self.unification_table.rollback_to(snapshot.region_snapshot);
|
|
||||||
self.any_unifications = snapshot.any_unifications;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) {
|
fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) {
|
||||||
@ -486,6 +379,87 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
|
||||||
|
pub fn num_region_vars(&self) -> usize {
|
||||||
|
self.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::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
|
||||||
|
(mem::take(&mut self.storage.var_infos), mem::take(&mut self.storage.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes (and clears) the current set of constraints. Note that
|
||||||
|
/// the set of variables remains intact, but all relationships
|
||||||
|
/// between them are reset. This is used during NLL checking to
|
||||||
|
/// grab the set of constraints that arose from a particular
|
||||||
|
/// operation.
|
||||||
|
///
|
||||||
|
/// We don't want to leak relationships between variables between
|
||||||
|
/// points because just because (say) `r1 == r2` was true at some
|
||||||
|
/// point P in the graph doesn't imply that it will be true at
|
||||||
|
/// some other point Q, in NLL.
|
||||||
|
///
|
||||||
|
/// Not legal during a snapshot.
|
||||||
|
pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
|
||||||
|
assert!(!UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
|
||||||
|
|
||||||
|
// If you add a new field to `RegionConstraintCollector`, you
|
||||||
|
// should think carefully about whether it needs to be cleared
|
||||||
|
// or updated in some way.
|
||||||
|
let RegionConstraintStorage {
|
||||||
|
var_infos: _,
|
||||||
|
data,
|
||||||
|
lubs,
|
||||||
|
glbs,
|
||||||
|
unification_table: _,
|
||||||
|
any_unifications,
|
||||||
|
} = self.storage;
|
||||||
|
|
||||||
|
// Clear the tables of (lubs, glbs), so that we will create
|
||||||
|
// fresh regions if we do a LUB operation. As it happens,
|
||||||
|
// LUB/GLB are not performed by the MIR type-checker, which is
|
||||||
|
// the one that uses this method, but it's good to be correct.
|
||||||
|
lubs.clear();
|
||||||
|
glbs.clear();
|
||||||
|
|
||||||
|
let data = mem::take(data);
|
||||||
|
|
||||||
|
// Clear all unifications and recreate the variables a "now
|
||||||
|
// un-unified" state. Note that when we unify `a` and `b`, we
|
||||||
|
// also insert `a <= b` and a `b <= a` edges, so the
|
||||||
|
// `RegionConstraintData` contains the relationship here.
|
||||||
|
if *any_unifications {
|
||||||
|
*any_unifications = false;
|
||||||
|
self.unification_table()
|
||||||
|
.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
|
||||||
|
}
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data(&self) -> &RegionConstraintData<'tcx> {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_snapshot(&mut self) -> RegionSnapshot {
|
||||||
|
debug!("RegionConstraintCollector: start_snapshot");
|
||||||
|
RegionSnapshot { any_unifications: self.any_unifications }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rollback_to(&mut self, snapshot: RegionSnapshot) {
|
||||||
|
debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
|
||||||
|
self.any_unifications = snapshot.any_unifications;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_region_var(
|
pub fn new_region_var(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -494,11 +468,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
) -> RegionVid {
|
) -> RegionVid {
|
||||||
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
|
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
|
||||||
|
|
||||||
let u_vid = self.unification_table.new_key(unify_key::RegionVidKey { min_vid: vid });
|
let u_vid = self.unification_table().new_key(unify_key::RegionVidKey { min_vid: vid });
|
||||||
assert_eq!(vid, u_vid);
|
assert_eq!(vid, u_vid);
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(AddVar(vid));
|
self.undo_log.push(AddVar(vid));
|
||||||
}
|
|
||||||
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
|
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
|
||||||
vid
|
vid
|
||||||
}
|
}
|
||||||
@ -520,19 +492,29 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) {
|
pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) {
|
||||||
debug!("pop_placeholders(placeholders={:?})", placeholders);
|
debug!("pop_placeholders(placeholders={:?})", placeholders);
|
||||||
|
|
||||||
assert!(self.in_snapshot());
|
assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
|
||||||
|
|
||||||
let constraints_to_kill: Vec<usize> = self
|
let constraints_to_kill: Vec<usize> = self
|
||||||
.undo_log
|
.undo_log
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.rev()
|
.rev()
|
||||||
.filter(|&(_, undo_entry)| kill_constraint(placeholders, undo_entry))
|
.filter(|&(_, undo_entry)| match undo_entry {
|
||||||
|
super::UndoLog::RegionConstraintCollector(undo_entry) => {
|
||||||
|
kill_constraint(placeholders, undo_entry)
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
.map(|(index, _)| index)
|
.map(|(index, _)| index)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for index in constraints_to_kill {
|
for index in constraints_to_kill {
|
||||||
let undo_entry = mem::replace(&mut self.undo_log[index], Purged);
|
let undo_entry = match &mut self.undo_log[index] {
|
||||||
|
super::UndoLog::RegionConstraintCollector(undo_entry) => {
|
||||||
|
mem::replace(undo_entry, Purged)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
self.rollback_undo_entry(undo_entry);
|
self.rollback_undo_entry(undo_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,12 +548,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
// never overwrite an existing (constraint, origin) - only insert one if it isn't
|
// never overwrite an existing (constraint, origin) - only insert one if it isn't
|
||||||
// present in the map yet. This prevents origins from outside the snapshot being
|
// present in the map yet. This prevents origins from outside the snapshot being
|
||||||
// replaced with "less informative" origins e.g., during calls to `can_eq`
|
// replaced with "less informative" origins e.g., during calls to `can_eq`
|
||||||
let in_snapshot = self.in_snapshot();
|
|
||||||
let undo_log = &mut self.undo_log;
|
let undo_log = &mut self.undo_log;
|
||||||
self.data.constraints.entry(constraint).or_insert_with(|| {
|
self.storage.data.constraints.entry(constraint).or_insert_with(|| {
|
||||||
if in_snapshot {
|
|
||||||
undo_log.push(AddConstraint(constraint));
|
undo_log.push(AddConstraint(constraint));
|
||||||
}
|
|
||||||
origin
|
origin
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -589,21 +568,17 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
|
|
||||||
let index = self.data.verifys.len();
|
let index = self.data.verifys.len();
|
||||||
self.data.verifys.push(verify);
|
self.data.verifys.push(verify);
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(AddVerify(index));
|
self.undo_log.push(AddVerify(index));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
|
pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
|
||||||
// cannot add givens once regions are resolved
|
// cannot add givens once regions are resolved
|
||||||
if self.data.givens.insert((sub, sup)) {
|
if self.data.givens.insert((sub, sup)) {
|
||||||
debug!("add_given({:?} <= {:?})", sub, sup);
|
debug!("add_given({:?} <= {:?})", sub, sup);
|
||||||
|
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(AddGiven(sub, sup));
|
self.undo_log.push(AddGiven(sub, sup));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_eqregion(
|
pub fn make_eqregion(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -619,7 +594,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
|
|
||||||
if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
|
if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
|
||||||
debug!("make_eqregion: uniying {:?} with {:?}", sub, sup);
|
debug!("make_eqregion: uniying {:?} with {:?}", sub, sup);
|
||||||
self.unification_table.union(sub, sup);
|
self.unification_table().union(sub, sup);
|
||||||
self.any_unifications = true;
|
self.any_unifications = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -741,7 +716,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
rid: RegionVid,
|
rid: RegionVid,
|
||||||
) -> ty::Region<'tcx> {
|
) -> ty::Region<'tcx> {
|
||||||
let vid = self.unification_table.probe_value(rid).min_vid;
|
let vid = self.unification_table().probe_value(rid).min_vid;
|
||||||
tcx.mk_region(ty::ReVar(vid))
|
tcx.mk_region(ty::ReVar(vid))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,9 +744,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
let c_universe = cmp::max(a_universe, b_universe);
|
let c_universe = cmp::max(a_universe, b_universe);
|
||||||
let c = self.new_region_var(c_universe, MiscVariable(origin.span()));
|
let c = self.new_region_var(c_universe, MiscVariable(origin.span()));
|
||||||
self.combine_map(t).insert(vars, c);
|
self.combine_map(t).insert(vars, c);
|
||||||
if self.in_snapshot() {
|
|
||||||
self.undo_log.push(AddCombination(t, vars));
|
self.undo_log.push(AddCombination(t, vars));
|
||||||
}
|
|
||||||
let new_r = tcx.mk_region(ReVar(c));
|
let new_r = tcx.mk_region(ReVar(c));
|
||||||
for &old_r in &[a, b] {
|
for &old_r in &[a, b] {
|
||||||
match t {
|
match t {
|
||||||
@ -799,9 +772,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
|
|
||||||
pub fn vars_since_snapshot(
|
pub fn vars_since_snapshot(
|
||||||
&self,
|
&self,
|
||||||
mark: &RegionSnapshot,
|
value_count: usize,
|
||||||
) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
|
) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
|
||||||
let range = self.unification_table.vars_since_snapshot(&mark.region_snapshot);
|
let range = RegionVid::from_index(value_count as u32)
|
||||||
|
..RegionVid::from_index(self.unification_table.len() as u32);
|
||||||
(
|
(
|
||||||
range.clone(),
|
range.clone(),
|
||||||
(range.start.index()..range.end.index())
|
(range.start.index()..range.end.index())
|
||||||
@ -810,10 +784,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See `InferCtxt::region_constraints_added_in_snapshot`.
|
/// See [`RegionInference::region_constraints_added_in_snapshot`].
|
||||||
pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option<bool> {
|
pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> Option<bool> {
|
||||||
self.undo_log[mark.length..]
|
self.undo_log
|
||||||
.iter()
|
.region_constraints_in_snapshot(mark)
|
||||||
.map(|&elt| match elt {
|
.map(|&elt| match elt {
|
||||||
AddConstraint(constraint) => Some(constraint.involves_placeholders()),
|
AddConstraint(constraint) => Some(constraint.involves_placeholders()),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -821,11 +795,15 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||||||
.max()
|
.max()
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, ty::RegionVid> {
|
||||||
|
ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for RegionSnapshot {
|
impl fmt::Debug for RegionSnapshot {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "RegionSnapshot(length={})", self.length)
|
write!(f, "RegionSnapshot")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -910,3 +888,9 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||||||
&& givens.is_empty()
|
&& givens.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> {
|
||||||
|
fn reverse(&mut self, undo: UndoLog<'tcx>) {
|
||||||
|
self.rollback_undo_entry(undo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -123,7 +123,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
|
|||||||
// Since we called `shallow_resolve` above, this must
|
// Since we called `shallow_resolve` above, this must
|
||||||
// be an (as yet...) unresolved inference variable.
|
// be an (as yet...) unresolved inference variable.
|
||||||
let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
|
let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
|
||||||
let ty_vars = &self.infcx.inner.borrow().type_variables;
|
let mut inner = self.infcx.inner.borrow_mut();
|
||||||
|
let ty_vars = &inner.type_variables();
|
||||||
if let TypeVariableOrigin {
|
if let TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
|
kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
|
||||||
span,
|
span,
|
||||||
|
@ -80,8 +80,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let infcx = self.fields.infcx;
|
let infcx = self.fields.infcx;
|
||||||
let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a);
|
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
|
||||||
let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b);
|
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
|
||||||
match (&a.kind, &b.kind) {
|
match (&a.kind, &b.kind) {
|
||||||
(&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
|
(&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
|
||||||
// Shouldn't have any LBR here, so we can safely put
|
// Shouldn't have any LBR here, so we can safely put
|
||||||
@ -95,7 +95,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
|
|||||||
// have to record in the `type_variables` tracker that
|
// have to record in the `type_variables` tracker that
|
||||||
// the two variables are equal modulo subtyping, which
|
// the two variables are equal modulo subtyping, which
|
||||||
// is important to the occurs check later on.
|
// is important to the occurs check later on.
|
||||||
infcx.inner.borrow_mut().type_variables.sub(a_vid, b_vid);
|
infcx.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
|
||||||
self.fields.obligations.push(Obligation::new(
|
self.fields.obligations.push(Obligation::new(
|
||||||
self.fields.trace.cause.clone(),
|
self.fields.trace.cause.clone(),
|
||||||
self.fields.param_env,
|
self.fields.param_env,
|
||||||
|
@ -3,19 +3,68 @@ use rustc_middle::ty::{self, Ty, TyVid};
|
|||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use crate::infer::InferCtxtUndoLogs;
|
||||||
|
|
||||||
use rustc_data_structures::snapshot_vec as sv;
|
use rustc_data_structures::snapshot_vec as sv;
|
||||||
use rustc_data_structures::unify as ut;
|
use rustc_data_structures::unify as ut;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
pub struct TypeVariableTable<'tcx> {
|
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
|
||||||
values: sv::SnapshotVec<Delegate>,
|
|
||||||
|
/// Represents a single undo-able action that affects a type inference variable.
|
||||||
|
pub(crate) enum UndoLog<'tcx> {
|
||||||
|
EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>),
|
||||||
|
SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>),
|
||||||
|
Values(sv::UndoLog<Delegate>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert from a specific kind of undo to the more general UndoLog
|
||||||
|
impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
|
||||||
|
fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self {
|
||||||
|
UndoLog::EqRelation(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert from a specific kind of undo to the more general UndoLog
|
||||||
|
impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::TyVid>>> for UndoLog<'tcx> {
|
||||||
|
fn from(l: sv::UndoLog<ut::Delegate<ty::TyVid>>) -> Self {
|
||||||
|
UndoLog::SubRelation(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert from a specific kind of undo to the more general UndoLog
|
||||||
|
impl<'tcx> From<sv::UndoLog<Delegate>> for UndoLog<'tcx> {
|
||||||
|
fn from(l: sv::UndoLog<Delegate>) -> Self {
|
||||||
|
UndoLog::Values(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert from a specific kind of undo to the more general UndoLog
|
||||||
|
impl<'tcx> From<Instantiate> for UndoLog<'tcx> {
|
||||||
|
fn from(l: Instantiate) -> Self {
|
||||||
|
UndoLog::Values(sv::UndoLog::Other(l))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> {
|
||||||
|
fn reverse(&mut self, undo: UndoLog<'tcx>) {
|
||||||
|
match undo {
|
||||||
|
UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo),
|
||||||
|
UndoLog::SubRelation(undo) => self.sub_relations.reverse(undo),
|
||||||
|
UndoLog::Values(undo) => self.values.reverse(undo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeVariableStorage<'tcx> {
|
||||||
|
values: sv::SnapshotVecStorage<Delegate>,
|
||||||
|
|
||||||
/// Two variables are unified in `eq_relations` when we have a
|
/// Two variables are unified in `eq_relations` when we have a
|
||||||
/// constraint `?X == ?Y`. This table also stores, for each key,
|
/// constraint `?X == ?Y`. This table also stores, for each key,
|
||||||
/// the known value.
|
/// the known value.
|
||||||
eq_relations: ut::UnificationTable<ut::InPlace<TyVidEqKey<'tcx>>>,
|
eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>,
|
||||||
|
|
||||||
/// Two variables are unified in `sub_relations` when we have a
|
/// Two variables are unified in `sub_relations` when we have a
|
||||||
/// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
|
/// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
|
||||||
@ -34,7 +83,17 @@ pub struct TypeVariableTable<'tcx> {
|
|||||||
/// This is reasonable because, in Rust, subtypes have the same
|
/// This is reasonable because, in Rust, subtypes have the same
|
||||||
/// "skeleton" and hence there is no possible type such that
|
/// "skeleton" and hence there is no possible type such that
|
||||||
/// (e.g.) `Box<?3> <: ?3` for any `?3`.
|
/// (e.g.) `Box<?3> <: ?3` for any `?3`.
|
||||||
sub_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>,
|
sub_relations: ut::UnificationTableStorage<ty::TyVid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TypeVariableTable<'a, 'tcx> {
|
||||||
|
values: &'a mut sv::SnapshotVecStorage<Delegate>,
|
||||||
|
|
||||||
|
eq_relations: &'a mut ut::UnificationTableStorage<TyVidEqKey<'tcx>>,
|
||||||
|
|
||||||
|
sub_relations: &'a mut ut::UnificationTableStorage<ty::TyVid>,
|
||||||
|
|
||||||
|
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@ -62,7 +121,7 @@ pub enum TypeVariableOriginKind {
|
|||||||
LatticeVariable,
|
LatticeVariable,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypeVariableData {
|
pub(crate) struct TypeVariableData {
|
||||||
origin: TypeVariableOrigin,
|
origin: TypeVariableOrigin,
|
||||||
diverging: bool,
|
diverging: bool,
|
||||||
}
|
}
|
||||||
@ -91,27 +150,31 @@ impl<'tcx> TypeVariableValue<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Snapshot<'tcx> {
|
pub(crate) struct Instantiate {
|
||||||
snapshot: sv::Snapshot,
|
|
||||||
eq_snapshot: ut::Snapshot<ut::InPlace<TyVidEqKey<'tcx>>>,
|
|
||||||
sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Instantiate {
|
|
||||||
vid: ty::TyVid,
|
vid: ty::TyVid,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Delegate;
|
pub(crate) struct Delegate;
|
||||||
|
|
||||||
impl<'tcx> TypeVariableTable<'tcx> {
|
impl<'tcx> TypeVariableStorage<'tcx> {
|
||||||
pub fn new() -> TypeVariableTable<'tcx> {
|
pub fn new() -> TypeVariableStorage<'tcx> {
|
||||||
TypeVariableTable {
|
TypeVariableStorage {
|
||||||
values: sv::SnapshotVec::new(),
|
values: sv::SnapshotVecStorage::new(),
|
||||||
eq_relations: ut::UnificationTable::new(),
|
eq_relations: ut::UnificationTableStorage::new(),
|
||||||
sub_relations: ut::UnificationTable::new(),
|
sub_relations: ut::UnificationTableStorage::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn with_log<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
) -> TypeVariableTable<'a, 'tcx> {
|
||||||
|
let TypeVariableStorage { values, eq_relations, sub_relations } = self;
|
||||||
|
TypeVariableTable { values, eq_relations, sub_relations, undo_log }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
||||||
/// Returns the diverges flag given when `vid` was created.
|
/// Returns the diverges flag given when `vid` was created.
|
||||||
///
|
///
|
||||||
/// Note that this function does not return care whether
|
/// Note that this function does not return care whether
|
||||||
@ -134,8 +197,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
|
pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
|
||||||
debug_assert!(self.probe(a).is_unknown());
|
debug_assert!(self.probe(a).is_unknown());
|
||||||
debug_assert!(self.probe(b).is_unknown());
|
debug_assert!(self.probe(b).is_unknown());
|
||||||
self.eq_relations.union(a, b);
|
self.eq_relations().union(a, b);
|
||||||
self.sub_relations.union(a, b);
|
self.sub_relations().union(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Records that `a <: b`, depending on `dir`.
|
/// Records that `a <: b`, depending on `dir`.
|
||||||
@ -144,7 +207,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
|
pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
|
||||||
debug_assert!(self.probe(a).is_unknown());
|
debug_assert!(self.probe(a).is_unknown());
|
||||||
debug_assert!(self.probe(b).is_unknown());
|
debug_assert!(self.probe(b).is_unknown());
|
||||||
self.sub_relations.union(a, b);
|
self.sub_relations().union(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiates `vid` with the type `ty`.
|
/// Instantiates `vid` with the type `ty`.
|
||||||
@ -154,18 +217,18 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
let vid = self.root_var(vid);
|
let vid = self.root_var(vid);
|
||||||
debug_assert!(self.probe(vid).is_unknown());
|
debug_assert!(self.probe(vid).is_unknown());
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.eq_relations.probe_value(vid).is_unknown(),
|
self.eq_relations().probe_value(vid).is_unknown(),
|
||||||
"instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
|
"instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
|
||||||
vid,
|
vid,
|
||||||
ty,
|
ty,
|
||||||
self.eq_relations.probe_value(vid)
|
self.eq_relations().probe_value(vid)
|
||||||
);
|
);
|
||||||
self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty });
|
self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty });
|
||||||
|
|
||||||
// Hack: we only need this so that `types_escaping_snapshot`
|
// Hack: we only need this so that `types_escaping_snapshot`
|
||||||
// can see what has been unified; see the Delegate impl for
|
// can see what has been unified; see the Delegate impl for
|
||||||
// more details.
|
// more details.
|
||||||
self.values.record(Instantiate { vid });
|
self.undo_log.push(Instantiate { vid });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new type variable.
|
/// Creates a new type variable.
|
||||||
@ -184,12 +247,12 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
diverging: bool,
|
diverging: bool,
|
||||||
origin: TypeVariableOrigin,
|
origin: TypeVariableOrigin,
|
||||||
) -> ty::TyVid {
|
) -> ty::TyVid {
|
||||||
let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown { universe });
|
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
|
||||||
|
|
||||||
let sub_key = self.sub_relations.new_key(());
|
let sub_key = self.sub_relations().new_key(());
|
||||||
assert_eq!(eq_key.vid, sub_key);
|
assert_eq!(eq_key.vid, sub_key);
|
||||||
|
|
||||||
let index = self.values.push(TypeVariableData { origin, diverging });
|
let index = self.values().push(TypeVariableData { origin, diverging });
|
||||||
assert_eq!(eq_key.vid.index, index as u32);
|
assert_eq!(eq_key.vid.index, index as u32);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
@ -211,7 +274,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
/// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
|
/// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
|
||||||
/// b` (transitively).
|
/// b` (transitively).
|
||||||
pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
|
pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
|
||||||
self.eq_relations.find(vid).vid
|
self.eq_relations().find(vid).vid
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the "root" variable of `vid` in the `sub_relations`
|
/// Returns the "root" variable of `vid` in the `sub_relations`
|
||||||
@ -222,7 +285,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
///
|
///
|
||||||
/// exists X. (a <: X || X <: a) && (b <: X || X <: b)
|
/// exists X. (a <: X || X <: a) && (b <: X || X <: b)
|
||||||
pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
|
pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
|
||||||
self.sub_relations.find(vid)
|
self.sub_relations().find(vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if `a` and `b` have same "sub-root" (i.e., exists some
|
/// Returns `true` if `a` and `b` have same "sub-root" (i.e., exists some
|
||||||
@ -240,7 +303,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
/// An always-inlined variant of `probe`, for very hot call sites.
|
/// An always-inlined variant of `probe`, for very hot call sites.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
|
pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
|
||||||
self.eq_relations.inlined_probe_value(vid)
|
self.eq_relations().inlined_probe_value(vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `t` is a type-inference variable, and it has been
|
/// If `t` is a type-inference variable, and it has been
|
||||||
@ -256,56 +319,29 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a snapshot of the type variable state. This snapshot
|
fn values(
|
||||||
/// must later be committed (`commit()`) or rolled back
|
&mut self,
|
||||||
/// (`rollback_to()`). Nested snapshots are permitted, but must
|
) -> sv::SnapshotVec<Delegate, &mut Vec<TypeVariableData>, &mut InferCtxtUndoLogs<'tcx>> {
|
||||||
/// be processed in a stack-like fashion.
|
self.values.with_log(self.undo_log)
|
||||||
pub fn snapshot(&mut self) -> Snapshot<'tcx> {
|
|
||||||
Snapshot {
|
|
||||||
snapshot: self.values.start_snapshot(),
|
|
||||||
eq_snapshot: self.eq_relations.snapshot(),
|
|
||||||
sub_snapshot: self.sub_relations.snapshot(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Undoes all changes since the snapshot was created. Any
|
fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> {
|
||||||
/// snapshots created since that point must already have been
|
self.eq_relations.with_log(self.undo_log)
|
||||||
/// committed or rolled back.
|
|
||||||
pub fn rollback_to(&mut self, s: Snapshot<'tcx>) {
|
|
||||||
debug!("rollback_to{:?}", {
|
|
||||||
for action in self.values.actions_since_snapshot(&s.snapshot) {
|
|
||||||
if let sv::UndoLog::NewElem(index) = *action {
|
|
||||||
debug!("inference variable _#{}t popped", index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
|
|
||||||
self.values.rollback_to(snapshot);
|
|
||||||
self.eq_relations.rollback_to(eq_snapshot);
|
|
||||||
self.sub_relations.rollback_to(sub_snapshot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commits all changes since the snapshot was created, making
|
fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> {
|
||||||
/// them permanent (unless this snapshot was created within
|
self.sub_relations.with_log(self.undo_log)
|
||||||
/// another snapshot). Any snapshots created since that point
|
|
||||||
/// must already have been committed or rolled back.
|
|
||||||
pub fn commit(&mut self, s: Snapshot<'tcx>) {
|
|
||||||
let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
|
|
||||||
self.values.commit(snapshot);
|
|
||||||
self.eq_relations.commit(eq_snapshot);
|
|
||||||
self.sub_relations.commit(sub_snapshot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a range of the type variables created during the snapshot.
|
/// Returns a range of the type variables created during the snapshot.
|
||||||
pub fn vars_since_snapshot(
|
pub fn vars_since_snapshot(
|
||||||
&mut self,
|
&mut self,
|
||||||
s: &Snapshot<'tcx>,
|
value_count: usize,
|
||||||
) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
|
) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
|
||||||
let range = self.eq_relations.vars_since_snapshot(&s.eq_snapshot);
|
let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 };
|
||||||
(
|
(
|
||||||
range.start.vid..range.end.vid,
|
range.start..range.end,
|
||||||
(range.start.vid.index..range.end.vid.index)
|
(range.start.index..range.end.index)
|
||||||
.map(|index| self.values.get(index as usize).origin)
|
.map(|index| self.values.get(index as usize).origin)
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
@ -317,14 +353,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
/// a type variable `V0`, then we started the snapshot, then we
|
/// a type variable `V0`, then we started the snapshot, then we
|
||||||
/// created a type variable `V1`, unified `V0` with `T0`, and
|
/// created a type variable `V1`, unified `V0` with `T0`, and
|
||||||
/// unified `V1` with `T1`, this function would return `{T0}`.
|
/// unified `V1` with `T1`, this function would return `{T0}`.
|
||||||
pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> {
|
pub fn types_escaping_snapshot(&mut self, s: &super::Snapshot<'tcx>) -> Vec<Ty<'tcx>> {
|
||||||
let mut new_elem_threshold = u32::MAX;
|
let mut new_elem_threshold = u32::MAX;
|
||||||
let mut escaping_types = Vec::new();
|
let mut escaping_types = Vec::new();
|
||||||
let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
|
let actions_since_snapshot = self.undo_log.actions_since_snapshot(s);
|
||||||
debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
|
debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
|
||||||
for action in actions_since_snapshot {
|
for i in 0..actions_since_snapshot.len() {
|
||||||
match *action {
|
let actions_since_snapshot = self.undo_log.actions_since_snapshot(s);
|
||||||
sv::UndoLog::NewElem(index) => {
|
match actions_since_snapshot[i] {
|
||||||
|
super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::NewElem(index))) => {
|
||||||
// if any new variables were created during the
|
// if any new variables were created during the
|
||||||
// snapshot, remember the lower index (which will
|
// snapshot, remember the lower index (which will
|
||||||
// always be the first one we see). Note that this
|
// always be the first one we see). Note that this
|
||||||
@ -334,11 +371,17 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||||||
debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
|
debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
sv::UndoLog::Other(Instantiate { vid, .. }) => {
|
super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::Other(
|
||||||
|
Instantiate { vid, .. },
|
||||||
|
))) => {
|
||||||
if vid.index < new_elem_threshold {
|
if vid.index < new_elem_threshold {
|
||||||
// quick check to see if this variable was
|
// quick check to see if this variable was
|
||||||
// created since the snapshot started or not.
|
// created since the snapshot started or not.
|
||||||
let escaping_type = match self.eq_relations.probe_value(vid) {
|
let mut eq_relations = ut::UnificationTable::with_log(
|
||||||
|
&mut *self.eq_relations,
|
||||||
|
&mut *self.undo_log,
|
||||||
|
);
|
||||||
|
let escaping_type = match eq_relations.probe_value(vid) {
|
||||||
TypeVariableValue::Unknown { .. } => bug!(),
|
TypeVariableValue::Unknown { .. } => bug!(),
|
||||||
TypeVariableValue::Known { value } => value,
|
TypeVariableValue::Known { value } => value,
|
||||||
};
|
};
|
||||||
@ -395,7 +438,7 @@ impl sv::SnapshotVecDelegate for Delegate {
|
|||||||
/// for the `eq_relations`; they carry a `TypeVariableValue` along
|
/// for the `eq_relations`; they carry a `TypeVariableValue` along
|
||||||
/// with them.
|
/// with them.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
struct TyVidEqKey<'tcx> {
|
pub(crate) struct TyVidEqKey<'tcx> {
|
||||||
vid: ty::TyVid,
|
vid: ty::TyVid,
|
||||||
|
|
||||||
// in the table, we map each ty-vid to one of these:
|
// in the table, we map each ty-vid to one of these:
|
||||||
|
217
src/librustc_infer/infer/undo_log.rs
Normal file
217
src/librustc_infer/infer/undo_log.rs
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
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::ty;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
infer::{region_constraints, type_variable, InferCtxtInner},
|
||||||
|
traits,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Snapshot<'tcx> {
|
||||||
|
pub(crate) undo_len: usize,
|
||||||
|
_marker: PhantomData<&'tcx ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Records the 'undo' data fora single operation that affects some form of inference variable.
|
||||||
|
pub(crate) enum UndoLog<'tcx> {
|
||||||
|
TypeVariables(type_variable::UndoLog<'tcx>),
|
||||||
|
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'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>>),
|
||||||
|
ProjectionCache(traits::UndoLog<'tcx>),
|
||||||
|
PushRegionObligation,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from {
|
||||||
|
($($ctor: ident ($ty: ty),)*) => {
|
||||||
|
$(
|
||||||
|
impl<'tcx> From<$ty> for UndoLog<'tcx> {
|
||||||
|
fn from(x: $ty) -> Self {
|
||||||
|
UndoLog::$ctor(x.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upcast from a single kind of "undoable action" to the general enum
|
||||||
|
impl_from! {
|
||||||
|
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
|
||||||
|
TypeVariables(type_variable::UndoLog<'tcx>),
|
||||||
|
|
||||||
|
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
|
||||||
|
TypeVariables(sv::UndoLog<ut::Delegate<ty::TyVid>>),
|
||||||
|
TypeVariables(sv::UndoLog<type_variable::Delegate>),
|
||||||
|
TypeVariables(type_variable::Instantiate),
|
||||||
|
|
||||||
|
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||||
|
|
||||||
|
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||||
|
|
||||||
|
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
|
||||||
|
|
||||||
|
RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
|
||||||
|
ProjectionCache(traits::UndoLog<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Rollback trait defines how to rollback a particular action.
|
||||||
|
impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
|
||||||
|
fn reverse(&mut self, undo: UndoLog<'tcx>) {
|
||||||
|
match undo {
|
||||||
|
UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
|
||||||
|
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
|
||||||
|
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
|
||||||
|
UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
|
||||||
|
UndoLog::RegionConstraintCollector(undo) => {
|
||||||
|
self.region_constraint_storage.as_mut().unwrap().reverse(undo)
|
||||||
|
}
|
||||||
|
UndoLog::RegionUnificationTable(undo) => {
|
||||||
|
self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo)
|
||||||
|
}
|
||||||
|
UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo),
|
||||||
|
UndoLog::PushRegionObligation => {
|
||||||
|
self.region_obligations.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The combined undo log for all the various unification tables. For each change to the storage
|
||||||
|
/// for any kind of inference variable, we record an UndoLog entry in the vector here.
|
||||||
|
pub(crate) struct InferCtxtUndoLogs<'tcx> {
|
||||||
|
logs: Vec<UndoLog<'tcx>>,
|
||||||
|
num_open_snapshots: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InferCtxtUndoLogs<'_> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { logs: Default::default(), num_open_snapshots: Default::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
|
||||||
|
/// action that is convertable into a UndoLog (per the From impls above).
|
||||||
|
impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
|
||||||
|
where
|
||||||
|
UndoLog<'tcx>: From<T>,
|
||||||
|
{
|
||||||
|
fn num_open_snapshots(&self) -> usize {
|
||||||
|
self.num_open_snapshots
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, undo: T) {
|
||||||
|
if self.in_snapshot() {
|
||||||
|
self.logs.push(undo.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.logs.clear();
|
||||||
|
self.num_open_snapshots = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend<J>(&mut self, undos: J)
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
J: IntoIterator<Item = T>,
|
||||||
|
{
|
||||||
|
if self.in_snapshot() {
|
||||||
|
self.logs.extend(undos.into_iter().map(UndoLog::from))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> InferCtxtInner<'tcx> {
|
||||||
|
pub fn rollback_to(&mut self, snapshot: Snapshot<'tcx>) {
|
||||||
|
debug!("rollback_to({})", snapshot.undo_len);
|
||||||
|
self.undo_log.assert_open_snapshot(&snapshot);
|
||||||
|
|
||||||
|
while self.undo_log.logs.len() > snapshot.undo_len {
|
||||||
|
let undo = self.undo_log.logs.pop().unwrap();
|
||||||
|
self.reverse(undo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.undo_log.num_open_snapshots == 1 {
|
||||||
|
// The root snapshot. It's safe to clear the undo log because
|
||||||
|
// there's no snapshot further out that we might need to roll back
|
||||||
|
// to.
|
||||||
|
assert!(snapshot.undo_len == 0);
|
||||||
|
self.undo_log.logs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.undo_log.num_open_snapshots -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit(&mut self, snapshot: Snapshot<'tcx>) {
|
||||||
|
debug!("commit({})", snapshot.undo_len);
|
||||||
|
|
||||||
|
if self.undo_log.num_open_snapshots == 1 {
|
||||||
|
// The root snapshot. It's safe to clear the undo log because
|
||||||
|
// there's no snapshot further out that we might need to roll back
|
||||||
|
// to.
|
||||||
|
assert!(snapshot.undo_len == 0);
|
||||||
|
self.undo_log.logs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.undo_log.num_open_snapshots -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> InferCtxtUndoLogs<'tcx> {
|
||||||
|
pub fn actions_since_snapshot(&self, snapshot: &Snapshot<'tcx>) -> &[UndoLog<'tcx>] {
|
||||||
|
&self.logs[snapshot.undo_len..]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_snapshot(&mut self) -> Snapshot<'tcx> {
|
||||||
|
self.num_open_snapshots += 1;
|
||||||
|
Snapshot { undo_len: self.logs.len(), _marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn region_constraints_in_snapshot(
|
||||||
|
&self,
|
||||||
|
s: &Snapshot<'tcx>,
|
||||||
|
) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
|
||||||
|
self.logs[s.undo_len..].iter().filter_map(|log| match log {
|
||||||
|
UndoLog::RegionConstraintCollector(log) => Some(log),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn region_constraints(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
|
||||||
|
self.logs.iter().filter_map(|log| match log {
|
||||||
|
UndoLog::RegionConstraintCollector(log) => Some(log),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
|
||||||
|
// Failures here may indicate a failure to follow a stack discipline.
|
||||||
|
assert!(self.logs.len() >= snapshot.undo_len);
|
||||||
|
assert!(self.num_open_snapshots > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> {
|
||||||
|
self.logs.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> {
|
||||||
|
type Output = UndoLog<'tcx>;
|
||||||
|
|
||||||
|
fn index(&self, key: usize) -> &Self::Output {
|
||||||
|
&self.logs[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> std::ops::IndexMut<usize> for InferCtxtUndoLogs<'tcx> {
|
||||||
|
fn index_mut(&mut self, key: usize) -> &mut Self::Output {
|
||||||
|
&mut self.logs[key]
|
||||||
|
}
|
||||||
|
}
|
@ -20,9 +20,10 @@ pub use self::Vtable::*;
|
|||||||
|
|
||||||
pub use self::engine::{TraitEngine, TraitEngineExt};
|
pub use self::engine::{TraitEngine, TraitEngineExt};
|
||||||
pub use self::project::MismatchedProjectionTypes;
|
pub use self::project::MismatchedProjectionTypes;
|
||||||
|
pub(crate) use self::project::UndoLog;
|
||||||
pub use self::project::{
|
pub use self::project::{
|
||||||
Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
|
Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
|
||||||
ProjectionCacheSnapshot, Reveal,
|
ProjectionCacheStorage, Reveal,
|
||||||
};
|
};
|
||||||
crate use self::util::elaborate_predicates;
|
crate use self::util::elaborate_predicates;
|
||||||
|
|
||||||
|
@ -2,12 +2,19 @@
|
|||||||
|
|
||||||
use super::PredicateObligation;
|
use super::PredicateObligation;
|
||||||
|
|
||||||
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
|
use crate::infer::InferCtxtUndoLogs;
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
|
||||||
|
use rustc_data_structures::{
|
||||||
|
snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage},
|
||||||
|
undo_log::Rollback,
|
||||||
|
};
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
|
||||||
pub use rustc_middle::traits::Reveal;
|
pub use rustc_middle::traits::Reveal;
|
||||||
|
|
||||||
|
pub(crate) type UndoLog<'tcx> =
|
||||||
|
snapshot_map::UndoLog<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MismatchedProjectionTypes<'tcx> {
|
pub struct MismatchedProjectionTypes<'tcx> {
|
||||||
pub err: ty::error::TypeError<'tcx>,
|
pub err: ty::error::TypeError<'tcx>,
|
||||||
@ -58,9 +65,14 @@ impl<'tcx, T> Normalized<'tcx, T> {
|
|||||||
//
|
//
|
||||||
// FIXME: we probably also want some sort of cross-infcx cache here to
|
// FIXME: we probably also want some sort of cross-infcx cache here to
|
||||||
// reduce the amount of duplication. Let's see what we get with the Chalk reforms.
|
// reduce the amount of duplication. Let's see what we get with the Chalk reforms.
|
||||||
|
pub struct ProjectionCache<'a, 'tcx> {
|
||||||
|
map: &'a mut SnapshotMapStorage<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
|
||||||
|
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ProjectionCache<'tcx> {
|
pub struct ProjectionCacheStorage<'tcx> {
|
||||||
map: SnapshotMap<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
|
map: SnapshotMapStorage<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
@ -82,30 +94,29 @@ pub enum ProjectionCacheEntry<'tcx> {
|
|||||||
NormalizedTy(NormalizedTy<'tcx>),
|
NormalizedTy(NormalizedTy<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
// N.B., intentionally not Clone
|
impl<'tcx> ProjectionCacheStorage<'tcx> {
|
||||||
pub struct ProjectionCacheSnapshot {
|
pub(crate) fn with_log<'a>(
|
||||||
snapshot: Snapshot,
|
&'a mut self,
|
||||||
|
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
|
||||||
|
) -> ProjectionCache<'a, 'tcx> {
|
||||||
|
ProjectionCache { map: &mut self.map, undo_log }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ProjectionCache<'tcx> {
|
impl<'tcx> ProjectionCache<'_, 'tcx> {
|
||||||
|
fn map(
|
||||||
|
&mut self,
|
||||||
|
) -> SnapshotMapRef<
|
||||||
|
'_,
|
||||||
|
ProjectionCacheKey<'tcx>,
|
||||||
|
ProjectionCacheEntry<'tcx>,
|
||||||
|
InferCtxtUndoLogs<'tcx>,
|
||||||
|
> {
|
||||||
|
self.map.with_log(self.undo_log)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.map.clear();
|
self.map().clear();
|
||||||
}
|
|
||||||
|
|
||||||
pub fn snapshot(&mut self) -> ProjectionCacheSnapshot {
|
|
||||||
ProjectionCacheSnapshot { snapshot: self.map.snapshot() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) {
|
|
||||||
self.map.rollback_to(snapshot.snapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) {
|
|
||||||
self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) {
|
|
||||||
self.map.commit(snapshot.snapshot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to start normalize `key`; returns an error if
|
/// Try to start normalize `key`; returns an error if
|
||||||
@ -115,11 +126,12 @@ impl<'tcx> ProjectionCache<'tcx> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
key: ProjectionCacheKey<'tcx>,
|
key: ProjectionCacheKey<'tcx>,
|
||||||
) -> Result<(), ProjectionCacheEntry<'tcx>> {
|
) -> Result<(), ProjectionCacheEntry<'tcx>> {
|
||||||
if let Some(entry) = self.map.get(&key) {
|
let mut map = self.map();
|
||||||
|
if let Some(entry) = map.get(&key) {
|
||||||
return Err(entry.clone());
|
return Err(entry.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.map.insert(key, ProjectionCacheEntry::InProgress);
|
map.insert(key, ProjectionCacheEntry::InProgress);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +141,7 @@ impl<'tcx> ProjectionCache<'tcx> {
|
|||||||
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
|
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
|
||||||
key, value
|
key, value
|
||||||
);
|
);
|
||||||
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
|
let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value));
|
||||||
assert!(!fresh_key, "never started projecting `{:?}`", key);
|
assert!(!fresh_key, "never started projecting `{:?}`", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +150,8 @@ impl<'tcx> ProjectionCache<'tcx> {
|
|||||||
/// snapshot - if the snapshot is rolled back, the obligations will be
|
/// snapshot - if the snapshot is rolled back, the obligations will be
|
||||||
/// marked as incomplete again).
|
/// marked as incomplete again).
|
||||||
pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) {
|
pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) {
|
||||||
let ty = match self.map.get(&key) {
|
let mut map = self.map();
|
||||||
|
let ty = match map.get(&key) {
|
||||||
Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => {
|
Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => {
|
||||||
debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
|
debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
|
||||||
ty.value
|
ty.value
|
||||||
@ -151,7 +164,7 @@ impl<'tcx> ProjectionCache<'tcx> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.map.insert(
|
map.insert(
|
||||||
key,
|
key,
|
||||||
ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }),
|
ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }),
|
||||||
);
|
);
|
||||||
@ -163,7 +176,7 @@ impl<'tcx> ProjectionCache<'tcx> {
|
|||||||
// We want to insert `ty` with no obligations. If the existing value
|
// We want to insert `ty` with no obligations. If the existing value
|
||||||
// already has no obligations (as is common) we don't insert anything.
|
// already has no obligations (as is common) we don't insert anything.
|
||||||
if !ty.obligations.is_empty() {
|
if !ty.obligations.is_empty() {
|
||||||
self.map.insert(
|
self.map().insert(
|
||||||
key,
|
key,
|
||||||
ProjectionCacheEntry::NormalizedTy(Normalized {
|
ProjectionCacheEntry::NormalizedTy(Normalized {
|
||||||
value: ty.value,
|
value: ty.value,
|
||||||
@ -178,14 +191,20 @@ impl<'tcx> ProjectionCache<'tcx> {
|
|||||||
/// type information (in which case, the "fully resolved" key will
|
/// type information (in which case, the "fully resolved" key will
|
||||||
/// be different).
|
/// be different).
|
||||||
pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) {
|
pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) {
|
||||||
let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous);
|
let fresh = self.map().insert(key, ProjectionCacheEntry::Ambiguous);
|
||||||
assert!(!fresh, "never started projecting `{:?}`", key);
|
assert!(!fresh, "never started projecting `{:?}`", key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates that trying to normalize `key` resulted in
|
/// Indicates that trying to normalize `key` resulted in
|
||||||
/// error.
|
/// error.
|
||||||
pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
|
pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
|
||||||
let fresh = self.map.insert(key, ProjectionCacheEntry::Error);
|
let fresh = self.map().insert(key, ProjectionCacheEntry::Error);
|
||||||
assert!(!fresh, "never started projecting `{:?}`", key);
|
assert!(!fresh, "never started projecting `{:?}`", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Rollback<UndoLog<'tcx>> for ProjectionCacheStorage<'tcx> {
|
||||||
|
fn reverse(&mut self, undo: UndoLog<'tcx>) {
|
||||||
|
self.map.reverse(undo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use crate::ty::{self, FloatVarValue, InferConst, IntVarValue, Ty, TyCtxt};
|
use crate::ty::{self, FloatVarValue, InferConst, IntVarValue, Ty, TyCtxt};
|
||||||
use rustc_data_structures::unify::InPlace;
|
use rustc_data_structures::snapshot_vec;
|
||||||
use rustc_data_structures::unify::{EqUnifyValue, NoError, UnificationTable, UnifyKey, UnifyValue};
|
use rustc_data_structures::undo_log::UndoLogs;
|
||||||
|
use rustc_data_structures::unify::{
|
||||||
|
self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue,
|
||||||
|
};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
@ -212,10 +215,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}
|
impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}
|
||||||
|
|
||||||
pub fn replace_if_possible(
|
pub fn replace_if_possible<V, L>(
|
||||||
table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>>>,
|
table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>, V, L>>,
|
||||||
c: &'tcx ty::Const<'tcx>,
|
c: &'tcx ty::Const<'tcx>,
|
||||||
) -> &'tcx ty::Const<'tcx> {
|
) -> &'tcx ty::Const<'tcx>
|
||||||
|
where
|
||||||
|
V: snapshot_vec::VecLike<unify::Delegate<ty::ConstVid<'tcx>>>,
|
||||||
|
L: UndoLogs<snapshot_vec::UndoLog<unify::Delegate<ty::ConstVid<'tcx>>>>,
|
||||||
|
{
|
||||||
if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c {
|
if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c {
|
||||||
match table.probe_value(*vid).val.known() {
|
match table.probe_value(*vid).val.known() {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
|
@ -195,7 +195,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||||||
let body_id_map: FxHashMap<_, _> = infcx
|
let body_id_map: FxHashMap<_, _> = infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow()
|
.borrow()
|
||||||
.region_obligations
|
.region_obligations()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(id, _)| (id, vec![]))
|
.map(|&(id, _)| (id, vec![]))
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -240,9 +240,15 @@ struct FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
register_region_obligations: bool,
|
register_region_obligations: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_pending(os: Vec<PredicateObligation<'tcx>>) -> Vec<PendingPredicateObligation<'tcx>> {
|
fn mk_pending(
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
os: Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> Vec<PendingPredicateObligation<'tcx>> {
|
||||||
os.into_iter()
|
os.into_iter()
|
||||||
.map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] })
|
.map(|mut o| {
|
||||||
|
o.predicate = infcx.resolve_vars_if_possible(&o.predicate);
|
||||||
|
PendingPredicateObligation { obligation: o, stalled_on: vec![] }
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,6 +318,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
|
debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
|
||||||
|
|
||||||
|
let infcx = self.selcx.infcx();
|
||||||
|
|
||||||
match obligation.predicate {
|
match obligation.predicate {
|
||||||
ty::Predicate::Trait(ref data, _) => {
|
ty::Predicate::Trait(ref data, _) => {
|
||||||
let trait_obligation = obligation.with(*data);
|
let trait_obligation = obligation.with(*data);
|
||||||
@ -319,7 +327,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
if data.is_global() {
|
if data.is_global() {
|
||||||
// no type variables present, can use evaluation for better caching.
|
// no type variables present, can use evaluation for better caching.
|
||||||
// FIXME: consider caching errors too.
|
// FIXME: consider caching errors too.
|
||||||
if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) {
|
if infcx.predicate_must_hold_considering_regions(&obligation) {
|
||||||
debug!(
|
debug!(
|
||||||
"selecting trait `{:?}` at depth {} evaluated to holds",
|
"selecting trait `{:?}` at depth {} evaluated to holds",
|
||||||
data, obligation.recursion_depth
|
data, obligation.recursion_depth
|
||||||
@ -334,7 +342,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
"selecting trait `{:?}` at depth {} yielded Ok(Some)",
|
"selecting trait `{:?}` at depth {} yielded Ok(Some)",
|
||||||
data, obligation.recursion_depth
|
data, obligation.recursion_depth
|
||||||
);
|
);
|
||||||
ProcessResult::Changed(mk_pending(vtable.nested_obligations()))
|
ProcessResult::Changed(mk_pending(infcx, vtable.nested_obligations()))
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
debug!(
|
debug!(
|
||||||
@ -351,7 +359,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"process_predicate: pending obligation {:?} now stalled on {:?}",
|
"process_predicate: pending obligation {:?} now stalled on {:?}",
|
||||||
self.selcx.infcx().resolve_vars_if_possible(obligation),
|
infcx.resolve_vars_if_possible(obligation),
|
||||||
pending_obligation.stalled_on
|
pending_obligation.stalled_on
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -369,7 +377,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::Predicate::RegionOutlives(ref binder) => {
|
ty::Predicate::RegionOutlives(ref binder) => {
|
||||||
match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
|
match infcx.region_outlives_predicate(&obligation.cause, binder) {
|
||||||
Ok(()) => ProcessResult::Changed(vec![]),
|
Ok(()) => ProcessResult::Changed(vec![]),
|
||||||
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
|
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
|
||||||
}
|
}
|
||||||
@ -428,7 +436,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx));
|
trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx));
|
||||||
ProcessResult::Unchanged
|
ProcessResult::Unchanged
|
||||||
}
|
}
|
||||||
Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)),
|
Ok(Some(os)) => ProcessResult::Changed(mk_pending(infcx, os)),
|
||||||
Err(e) => ProcessResult::Error(CodeProjectionError(e)),
|
Err(e) => ProcessResult::Error(CodeProjectionError(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -467,7 +475,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()];
|
vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()];
|
||||||
ProcessResult::Unchanged
|
ProcessResult::Unchanged
|
||||||
}
|
}
|
||||||
Some(os) => ProcessResult::Changed(mk_pending(os)),
|
Some(os) => ProcessResult::Changed(mk_pending(infcx, os)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +493,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
];
|
];
|
||||||
ProcessResult::Unchanged
|
ProcessResult::Unchanged
|
||||||
}
|
}
|
||||||
Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
|
Some(Ok(ok)) => ProcessResult::Changed(mk_pending(infcx, ok.obligations)),
|
||||||
Some(Err(err)) => {
|
Some(Err(err)) => {
|
||||||
let expected_found = ExpectedFound::new(
|
let expected_found = ExpectedFound::new(
|
||||||
subtype.skip_binder().a_is_expected,
|
subtype.skip_binder().a_is_expected,
|
||||||
|
@ -471,7 +471,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
// bounds. It might be the case that we want two distinct caches,
|
// bounds. It might be the case that we want two distinct caches,
|
||||||
// or else another kind of cache entry.
|
// or else another kind of cache entry.
|
||||||
|
|
||||||
let cache_result = infcx.inner.borrow_mut().projection_cache.try_start(cache_key);
|
let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key);
|
||||||
match cache_result {
|
match cache_result {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(ProjectionCacheEntry::Ambiguous) => {
|
Err(ProjectionCacheEntry::Ambiguous) => {
|
||||||
@ -537,7 +537,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
// Once we have inferred everything we need to know, we
|
// Once we have inferred everything we need to know, we
|
||||||
// can ignore the `obligations` from that point on.
|
// can ignore the `obligations` from that point on.
|
||||||
if infcx.unresolved_type_vars(&ty.value).is_none() {
|
if infcx.unresolved_type_vars(&ty.value).is_none() {
|
||||||
infcx.inner.borrow_mut().projection_cache.complete_normalized(cache_key, &ty);
|
infcx.inner.borrow_mut().projection_cache().complete_normalized(cache_key, &ty);
|
||||||
// No need to extend `obligations`.
|
// No need to extend `obligations`.
|
||||||
} else {
|
} else {
|
||||||
obligations.extend(ty.obligations);
|
obligations.extend(ty.obligations);
|
||||||
@ -604,7 +604,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let cache_value = prune_cache_value_obligations(infcx, &result);
|
let cache_value = prune_cache_value_obligations(infcx, &result);
|
||||||
infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, cache_value);
|
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, cache_value);
|
||||||
obligations.extend(result.obligations);
|
obligations.extend(result.obligations);
|
||||||
Some(result.value)
|
Some(result.value)
|
||||||
}
|
}
|
||||||
@ -615,7 +615,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
projected_ty
|
projected_ty
|
||||||
);
|
);
|
||||||
let result = Normalized { value: projected_ty, obligations: vec![] };
|
let result = Normalized { value: projected_ty, obligations: vec![] };
|
||||||
infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, result.clone());
|
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
|
||||||
// No need to extend `obligations`.
|
// No need to extend `obligations`.
|
||||||
Some(result.value)
|
Some(result.value)
|
||||||
}
|
}
|
||||||
@ -624,7 +624,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
"opt_normalize_projection_type: \
|
"opt_normalize_projection_type: \
|
||||||
too many candidates"
|
too many candidates"
|
||||||
);
|
);
|
||||||
infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key);
|
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(ProjectionTyError::TraitSelectionError(_)) => {
|
Err(ProjectionTyError::TraitSelectionError(_)) => {
|
||||||
@ -634,7 +634,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
// Trait`, which when processed will cause the error to be
|
// Trait`, which when processed will cause the error to be
|
||||||
// reported later
|
// reported later
|
||||||
|
|
||||||
infcx.inner.borrow_mut().projection_cache.error(cache_key);
|
infcx.inner.borrow_mut().projection_cache().error(cache_key);
|
||||||
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
|
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
|
||||||
obligations.extend(result.obligations);
|
obligations.extend(result.obligations);
|
||||||
Some(result.value)
|
Some(result.value)
|
||||||
|
@ -471,7 +471,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
if let Some(key) =
|
if let Some(key) =
|
||||||
ProjectionCacheKey::from_poly_projection_predicate(self, data)
|
ProjectionCacheKey::from_poly_projection_predicate(self, data)
|
||||||
{
|
{
|
||||||
self.infcx.inner.borrow_mut().projection_cache.complete(key);
|
self.infcx.inner.borrow_mut().projection_cache().complete(key);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user