From 61621e2667869a9c6cc153d10f84b8850fd64494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 16 Mar 2020 19:17:40 +0100 Subject: [PATCH 01/22] Allow `hir().find` to return `None` --- src/librustc_middle/hir/map/mod.rs | 24 +++++++++++++----------- src/librustc_middle/hir/mod.rs | 6 +++--- src/librustc_middle/query/mod.rs | 4 ++-- src/test/ui/issues/issue-70041.rs | 2 -- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index 1c71fc57bea5a..971bfd0281eb5 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -311,19 +311,16 @@ impl<'hir> Map<'hir> { } fn find_entry(&self, id: HirId) -> Option> { - if id.local_id == ItemLocalId::from_u32(0) { - let owner = self.tcx.hir_owner(id.owner); + if id.local_id == ItemLocalId::from_u32_const(0) { + let owner = self.tcx.hir_owner(id.owner_def_id()); owner.map(|owner| Entry { parent: owner.parent, node: owner.node }) } else { - let owner = self.tcx.hir_owner_nodes(id.owner); + let owner = self.tcx.hir_owner_items(id.owner_def_id()); owner.and_then(|owner| { - let node = owner.nodes[id.local_id].as_ref(); - // FIXME(eddyb) use a single generic type insted of having both - // `Entry` and `ParentedNode`, which are effectively the same. - // Alternatively, rewrite code using `Entry` to use `ParentedNode`. - node.map(|node| Entry { - parent: HirId { owner: id.owner, local_id: node.parent }, - node: node.node, + let item = owner.items[id.local_id].as_ref(); + item.map(|item| Entry { + parent: HirId { owner: id.owner, local_id: item.parent }, + node: item.node, }) }) } @@ -355,7 +352,12 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap() + self.tcx + .hir_owner_items(DefId::local(id.hir_id.owner)) + .unwrap() + .bodies + .get(&id.hir_id.local_id) + .unwrap() } pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { diff --git a/src/librustc_middle/hir/mod.rs b/src/librustc_middle/hir/mod.rs index 7ab66411b2109..3d84bbd7062f0 100644 --- a/src/librustc_middle/hir/mod.rs +++ b/src/librustc_middle/hir/mod.rs @@ -77,8 +77,8 @@ pub fn provide(providers: &mut Providers<'_>) { let module = hir.as_local_hir_id(id); &tcx.untracked_crate.modules[&module] }; - providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature; - providers.hir_owner_nodes = - |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_ref().map(|nodes| &**nodes); + providers.hir_owner = |tcx, id| tcx.index_hir(id.krate).map[id.index].signature; + providers.hir_owner_items = + |tcx, id| tcx.index_hir(id.krate).map[id.index].with_bodies.as_ref().map(|items| &**items); map::provide(providers); } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index b0c442381484c..8c437ca690770 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -75,7 +75,7 @@ rustc_queries! { // // This can be conveniently accessed by methods on `tcx.hir()`. // Avoid calling this query directly. - query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { + query hir_owner(key: DefId) -> Option<&'tcx HirOwner<'tcx>> { eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -84,7 +84,7 @@ rustc_queries! { // // This can be conveniently accessed by methods on `tcx.hir()`. // Avoid calling this query directly. - query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { + query hir_owner_items(key: DefId) -> Option<&'tcx HirOwnerItems<'tcx>> { eval_always desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } } diff --git a/src/test/ui/issues/issue-70041.rs b/src/test/ui/issues/issue-70041.rs index 22e42295eedf3..e45e16418e144 100644 --- a/src/test/ui/issues/issue-70041.rs +++ b/src/test/ui/issues/issue-70041.rs @@ -2,12 +2,10 @@ // run-pass macro_rules! regex { - //~^ WARN unused macro definition () => {}; } #[allow(dead_code)] use regex; -//~^ WARN unused import fn main() {} From 1506b1fc6a42dda3e56789f43587448cc5bf4a36 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Mon, 24 Feb 2020 10:40:36 +0100 Subject: [PATCH 02/22] perf: Reduce snapshot/rollback overhead By merging the undo_log of all structures part of the snapshot the cost of creating a snapshot becomes much cheaper. Since snapshots with no or few changes are so frequent this ends up mattering more than the slight overhead of dispatching on the variants that map to each field. --- Cargo.lock | 3 +- Cargo.toml | 2 + src/librustc_data_structures/lib.rs | 1 + src/librustc_infer/infer/combine.rs | 46 +-- src/librustc_infer/infer/equate.rs | 6 +- .../infer/error_reporting/need_type_info.rs | 8 +- src/librustc_infer/infer/freshen.rs | 8 +- src/librustc_infer/infer/fudge.rs | 40 ++- src/librustc_infer/infer/lattice.rs | 4 +- src/librustc_infer/infer/mod.rs | 335 +++++++++++++++--- src/librustc_infer/infer/nll_relate/mod.rs | 12 +- src/librustc_infer/infer/resolve.rs | 3 +- src/librustc_infer/infer/sub.rs | 6 +- src/librustc_infer/infer/type_variable.rs | 219 ++++++++---- src/librustc_middle/infer/unify_key.rs | 17 +- 15 files changed, 519 insertions(+), 191 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74578084a72c8..6f442e8d2b9ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -987,8 +987,7 @@ dependencies = [ [[package]] name = "ena" version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36" +source = "git+https://github.com/Marwes/ena?branch=detach_undo_log#9b977ea7f209a35f46d65d33cdd74b8f4931fb8a" dependencies = [ "log", ] diff --git a/Cargo.toml b/Cargo.toml index 7b5e0fa1c2817..9b143dcc8d89a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,5 +65,7 @@ rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' } rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' } rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' } +ena = { version = "0.13.1", git = "https://github.com/Marwes/ena", branch = "detach_undo_log" } + [patch."https://github.com/rust-lang/rust-clippy"] clippy_lints = { path = "src/tools/clippy/clippy_lints" } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index bc2da535fd372..a7bee8a067c29 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -84,6 +84,7 @@ pub mod sync; pub mod thin_vec; pub mod tiny_list; pub mod transitive_relation; +pub use ena::undo_log; pub use ena::unify; mod atomic_ref; pub mod fingerprint; diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index b03044b72da40..d4af470499670 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -76,7 +76,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { self.inner .borrow_mut() - .int_unification_table + .int_unification_table() .unify_var_var(a_id, b_id) .map_err(|e| int_unification_error(a_is_expected, e))?; Ok(a) @@ -98,7 +98,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { (&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => { self.inner .borrow_mut() - .float_unification_table + .float_unification_table() .unify_var_var(a_id, b_id) .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; Ok(a) @@ -133,8 +133,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { return Ok(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 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 a_is_expected = relation.a_is_expected(); @@ -145,7 +145,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) => { self.inner .borrow_mut() - .const_unification_table + .const_unification_table() .unify_var_var(a_vid, b_vid) .map_err(|e| const_unification_error(a_is_expected, e))?; return Ok(a); @@ -179,7 +179,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { self.inner .borrow_mut() - .const_unification_table + .const_unification_table() .unify_var_value( vid, ConstVarValue { @@ -202,7 +202,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) -> RelateResult<'tcx, Ty<'tcx>> { self.inner .borrow_mut() - .int_unification_table + .int_unification_table() .unify_var_value(vid, Some(val)) .map_err(|e| int_unification_error(vid_is_expected, e))?; match val { @@ -219,7 +219,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) -> RelateResult<'tcx, Ty<'tcx>> { self.inner .borrow_mut() - .float_unification_table + .float_unification_table() .unify_var_value(vid, Some(ty::FloatVarValue(val))) .map_err(|e| float_unification_error(vid_is_expected, e))?; Ok(self.tcx.mk_mach_float(val)) @@ -266,7 +266,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { use self::RelationDir::*; // 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); @@ -286,7 +286,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized 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 { self.obligations.push(Obligation::new( @@ -344,7 +344,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { 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 { .. } => { panic!("instantiating {:?} which has a known value {:?}", for_vid, v,) } @@ -356,7 +356,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { let mut generalize = Generalizer { infcx: self.infcx, 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, ambient_variance, needs_wf: false, @@ -508,14 +508,14 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // us from creating infinitely sized types. match t.kind { ty::Infer(ty::TyVar(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 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); if sub_vid == self.for_vid_sub_root { // If sub-roots are equal, then `for_vid` and // `vid` are related via subtyping. Err(TypeError::CyclicTy(self.root_ty)) } 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 { TypeVariableValue::Known { value: u } => { debug!("generalize: known value {:?}", u); @@ -542,12 +542,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } let origin = - *self.infcx.inner.borrow_mut().type_variables.var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables.new_var( - self.for_universe, - false, - origin, - ); + *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); + let new_var_id = self + .infcx + .inner + .borrow_mut() + .type_variables() + .new_var(self.for_universe, false, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); Ok(u) @@ -618,7 +619,8 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { match c.val { 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); match var_value.val { ConstVariableValue::Known { value: u } => self.relate(&u, &u), diff --git a/src/librustc_infer/infer/equate.rs b/src/librustc_infer/infer/equate.rs index e05094cda2762..d054070e292fa 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/src/librustc_infer/infer/equate.rs @@ -72,14 +72,14 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { } let infcx = self.fields.infcx; - 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 a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); match (&a.kind, &b.kind) { (&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)), _) => { diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 93c8e505697b4..d8133c58df7eb 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { .infcx .inner .borrow_mut() - .type_variables + .type_variables() .sub_unified(a_vid, b_vid), _ => false, } @@ -194,7 +194,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { highlight: Option, ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { 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); 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)); @@ -248,7 +249,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); 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 var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind { diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs index 636cf42198b0d..47346c3a85665 100644 --- a/src/librustc_infer/infer/freshen.rs +++ b/src/librustc_infer/infer/freshen.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { match t.kind { 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) } @@ -155,7 +155,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { self.infcx .inner .borrow_mut() - .int_unification_table + .int_unification_table() .probe_value(v) .map(|v| v.to_type(tcx)), ty::IntVar(v), @@ -166,7 +166,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { self.infcx .inner .borrow_mut() - .float_unification_table + .float_unification_table() .probe_value(v) .map(|v| v.to_type(tcx)), ty::FloatVar(v), @@ -222,7 +222,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { .infcx .inner .borrow_mut() - .const_unification_table + .const_unification_table() .probe_value(v) .val .known(); diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index 1a58e100fb3f4..0046dba0b0467 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -3,18 +3,30 @@ use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, use super::type_variable::TypeVariableOrigin; 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 ut::UnifyKey; use std::ops::Range; +fn vars_since_snapshot<'tcx, T>( + table: &mut UnificationTable<'_, 'tcx, T>, + snapshot: usize, +) -> Range +where + T: UnifyKey, + super::UndoLog<'tcx>: From>>, +{ + T::from_index(snapshot as u32)..T::from_index(table.len() as u32) +} + fn const_vars_since_snapshot<'tcx>( - table: &mut ut::UnificationTable>>, - snapshot: &ut::Snapshot>>, + table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>, + snapshot: usize, ) -> (Range>, Vec) { - let range = table.vars_since_snapshot(snapshot); + let range = vars_since_snapshot(table, snapshot); ( range.start..range.end, (range.start.index..range.end.index) @@ -83,17 +95,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut inner = self.inner.borrow_mut(); let type_vars = - inner.type_variables.vars_since_snapshot(&snapshot.type_snapshot); - let int_vars = - inner.int_unification_table.vars_since_snapshot(&snapshot.int_snapshot); - let float_vars = - inner.float_unification_table.vars_since_snapshot(&snapshot.float_snapshot); + inner.type_variables().vars_since_snapshot(&snapshot.type_snapshot); + let int_vars = vars_since_snapshot( + &mut inner.int_unification_table(), + snapshot.int_snapshot, + ); + let float_vars = vars_since_snapshot( + &mut inner.float_unification_table(), + snapshot.float_snapshot, + ); let region_vars = inner .unwrap_region_constraints() .vars_since_snapshot(&snapshot.region_constraints_snapshot); let const_vars = const_vars_since_snapshot( - &mut inner.const_unification_table, - &snapshot.const_snapshot, + &mut inner.const_unification_table(), + snapshot.const_snapshot, ); let fudger = InferenceFudger { @@ -161,7 +177,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { // that it is unbound, so we can just return // it. 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 } diff --git a/src/librustc_infer/infer/lattice.rs b/src/librustc_infer/infer/lattice.rs index c29614b855667..1bf43e74dcd84 100644 --- a/src/librustc_infer/infer/lattice.rs +++ b/src/librustc_infer/infer/lattice.rs @@ -56,8 +56,8 @@ where } let infcx = this.infcx(); - 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 a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); match (&a.kind, &b.kind) { // If one side is known to be a variable and one is not, // create a variable (`v`) to represent the LUB. Make sure to diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 54f80e8f38812..6d76f15998ae8 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -10,7 +10,9 @@ use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs}; use rustc_data_structures::unify as ut; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; @@ -36,6 +38,7 @@ use rustc_span::Span; use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeMap; use std::fmt; +use std::marker::PhantomData; use self::combine::CombineFields; use self::free_regions::RegionRelations; @@ -141,16 +144,17 @@ pub struct InferCtxtInner<'tcx> { /// We instantiate `UnificationTable` with `bounds` because the types /// that might instantiate a general type variable have an order, /// represented by its upper and lower bounds. - type_variables: type_variable::TypeVariableTable<'tcx>, + type_variables: type_variable::TypeVariableStorage<'tcx>, + undo_log: Logs<'tcx>, /// Map from const parameter variable to the kind of const it represents. - const_unification_table: ut::UnificationTable>>, + const_unification_table: ut::UnificationStorage>, /// Map from integral variable to the kind of integer it represents. - int_unification_table: ut::UnificationTable>, + int_unification_table: ut::UnificationStorage, /// Map from floating variable to the kind of float it represents. - float_unification_table: ut::UnificationTable>, + float_unification_table: ut::UnificationStorage, /// Tracks the set of region variables and the constraints between them. /// This is initially `Some(_)` but when @@ -197,20 +201,220 @@ impl<'tcx> InferCtxtInner<'tcx> { fn new() -> InferCtxtInner<'tcx> { InferCtxtInner { projection_cache: Default::default(), - type_variables: type_variable::TypeVariableTable::new(), - const_unification_table: ut::UnificationTable::new(), - int_unification_table: ut::UnificationTable::new(), - float_unification_table: ut::UnificationTable::new(), + type_variables: type_variable::TypeVariableStorage::new(), + undo_log: Logs::default(), + const_unification_table: ut::UnificationStorage::new(), + int_unification_table: ut::UnificationStorage::new(), + float_unification_table: ut::UnificationStorage::new(), region_constraints: Some(RegionConstraintCollector::new()), region_obligations: vec![], } } + fn type_variables(&mut self) -> type_variable::TypeVariableTable<'tcx, '_> { + self.type_variables.with_log(&mut self.undo_log) + } + + fn int_unification_table( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace, &mut Logs<'tcx>>, + > { + ut::UnificationTable::with_log(&mut self.int_unification_table, &mut self.undo_log) + } + + fn float_unification_table( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace, &mut Logs<'tcx>>, + > { + ut::UnificationTable::with_log(&mut self.float_unification_table, &mut self.undo_log) + } + + fn const_unification_table( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace< + ty::ConstVid<'tcx>, + &mut ut::UnificationStorage>, + &mut Logs<'tcx>, + >, + > { + ut::UnificationTable::with_log(&mut self.const_unification_table, &mut self.undo_log) + } + pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> { self.region_constraints.as_mut().expect("region constraints already solved") } } +pub struct Snapshot<'tcx> { + undo_len: usize, + _marker: PhantomData<&'tcx ()>, +} + +pub(crate) enum UndoLog<'tcx> { + TypeVariables(type_variable::UndoLog<'tcx>), + ConstUnificationTable(sv::UndoLog>>), + IntUnificationTable(sv::UndoLog>), + FloatUnificationTable(sv::UndoLog>), +} + +impl<'tcx> From>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>>) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::EqRelation(l)) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::SubRelation(l)) + } +} + +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: sv::UndoLog) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::Values(l)) + } +} + +impl<'tcx> From for UndoLog<'tcx> { + fn from(l: type_variable::Instantiate) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::from(l)) + } +} + +impl From> for UndoLog<'tcx> { + fn from(t: type_variable::UndoLog<'tcx>) -> Self { + Self::TypeVariables(t) + } +} + +impl<'tcx> From>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>>) -> Self { + Self::ConstUnificationTable(l) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + Self::IntUnificationTable(l) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + Self::FloatUnificationTable(l) + } +} + +pub(crate) type UnificationTable<'a, 'tcx, T> = + ut::UnificationTable, &'a mut Logs<'tcx>>>; + +struct RollbackView<'tcx, 'a> { + type_variables: type_variable::RollbackView<'tcx, 'a>, + const_unification_table: &'a mut ut::UnificationStorage>, + int_unification_table: &'a mut ut::UnificationStorage, + float_unification_table: &'a mut ut::UnificationStorage, +} + +impl<'tcx> Rollback> for RollbackView<'tcx, '_> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + match undo { + UndoLog::TypeVariables(undo) => self.type_variables.reverse(undo), + UndoLog::ConstUnificationTable(undo) => self.const_unification_table.reverse(undo), + UndoLog::IntUnificationTable(undo) => self.int_unification_table.reverse(undo), + UndoLog::FloatUnificationTable(undo) => self.float_unification_table.reverse(undo), + } + } +} + +pub(crate) struct Logs<'tcx> { + logs: Vec>, + num_open_snapshots: usize, +} + +impl Default for Logs<'_> { + fn default() -> Self { + Self { logs: Default::default(), num_open_snapshots: Default::default() } + } +} + +impl<'tcx, T> UndoLogs for Logs<'tcx> +where + UndoLog<'tcx>: From, +{ + 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 extend(&mut self, undos: J) + where + Self: Sized, + J: IntoIterator, + { + if self.in_snapshot() { + self.logs.extend(undos.into_iter().map(UndoLog::from)) + } + } +} + +impl<'tcx> Snapshots> for Logs<'tcx> { + type Snapshot = Snapshot<'tcx>; + fn actions_since_snapshot(&self, snapshot: &Self::Snapshot) -> &[UndoLog<'tcx>] { + &self.logs[snapshot.undo_len..] + } + + fn start_snapshot(&mut self) -> Self::Snapshot { + unreachable!() + } + + fn rollback_to(&mut self, values: &mut impl Rollback>, snapshot: Self::Snapshot) { + debug!("rollback_to({})", snapshot.undo_len); + self.assert_open_snapshot(&snapshot); + + while self.logs.len() > snapshot.undo_len { + values.reverse(self.logs.pop().unwrap()); + } + + 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.undo_len == 0); + self.logs.clear(); + } + + self.num_open_snapshots -= 1; + } + + fn commit(&mut self, snapshot: Self::Snapshot) { + debug!("commit({})", snapshot.undo_len); + + 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.undo_len == 0); + self.logs.clear(); + } + + self.num_open_snapshots -= 1; + } +} + +impl<'tcx> Logs<'tcx> { + 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 struct InferCtxt<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, @@ -644,10 +848,11 @@ impl<'tcx> InferOk<'tcx, ()> { #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, + undo_snapshot: Snapshot<'tcx>, type_snapshot: type_variable::Snapshot<'tcx>, - const_snapshot: ut::Snapshot>>, - int_snapshot: ut::Snapshot>, - float_snapshot: ut::Snapshot>, + const_snapshot: usize, + int_snapshot: usize, + float_snapshot: usize, region_constraints_snapshot: RegionSnapshot, region_obligations_snapshot: usize, universe: ty::UniverseIndex, @@ -667,7 +872,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { 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, } } @@ -681,14 +886,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; match ty.kind { 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 } else { UnconstrainedInt } } 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 } else { UnconstrainedFloat @@ -703,21 +908,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // FIXME(const_generics): should there be an equivalent function for const variables? let mut vars: Vec> = inner - .type_variables + .type_variables() .unsolved_variables() .into_iter() .map(|t| self.tcx.mk_ty_var(t)) .collect(); vars.extend( - (0..inner.int_unification_table.len()) + (0..inner.int_unification_table().len()) .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)), ); vars.extend( - (0..inner.float_unification_table.len()) + (0..inner.float_unification_table().len()) .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)), ); vars @@ -769,12 +974,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let in_snapshot = self.in_snapshot.replace(true); let mut inner = self.inner.borrow_mut(); + + inner.undo_log.num_open_snapshots += 1; + let undo_snapshot = Snapshot { undo_len: inner.undo_log.logs.len(), _marker: PhantomData }; CombinedSnapshot { projection_cache_snapshot: inner.projection_cache.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(), + undo_snapshot, + type_snapshot: inner.type_variables().snapshot(), + const_snapshot: inner.const_unification_table().len(), + int_snapshot: inner.int_unification_table().len(), + float_snapshot: inner.float_unification_table().len(), region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), region_obligations_snapshot: inner.region_obligations.len(), universe: self.universe(), @@ -790,10 +999,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("rollback_to(cause={})", cause); let CombinedSnapshot { projection_cache_snapshot, - type_snapshot, - const_snapshot, - int_snapshot, - float_snapshot, + undo_snapshot, + type_snapshot: _, + const_snapshot: _, + int_snapshot: _, + float_snapshot: _, region_constraints_snapshot, region_obligations_snapshot, universe, @@ -807,11 +1017,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.skip_leak_check.set(was_skip_leak_check); let mut inner = self.inner.borrow_mut(); + let inner = &mut *inner; + let InferCtxtInner { + type_variables, + const_unification_table, + int_unification_table, + float_unification_table, + .. + } = inner; + inner.undo_log.rollback_to( + &mut RollbackView { + type_variables: type_variable::RollbackView::from(type_variables), + const_unification_table, + int_unification_table, + float_unification_table, + }, + undo_snapshot, + ); inner.projection_cache.rollback_to(projection_cache_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.region_obligations.truncate(region_obligations_snapshot); } @@ -820,10 +1043,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("commit_from()"); let CombinedSnapshot { projection_cache_snapshot, - type_snapshot, - const_snapshot, - int_snapshot, - float_snapshot, + undo_snapshot, + type_snapshot: _, + const_snapshot: _, + int_snapshot: _, + float_snapshot: _, region_constraints_snapshot, region_obligations_snapshot: _, universe: _, @@ -836,11 +1060,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.skip_leak_check.set(was_skip_leak_check); let mut inner = self.inner.borrow_mut(); + inner.undo_log.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); } @@ -1032,7 +1253,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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> { @@ -1044,7 +1265,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> 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) } @@ -1069,20 +1290,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let vid = self .inner .borrow_mut() - .const_unification_table + .const_unification_table() .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); self.tcx.mk_const_var(vid, ty) } 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, val: ConstVariableValue::Unknown { universe: self.universe() }, }) } 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> { @@ -1090,7 +1311,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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> { @@ -1161,7 +1382,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // used in a path such as `Foo::::new()` will // use an inference variable for `C` with `[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(), false, TypeVariableOrigin { @@ -1181,7 +1402,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span, }; 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, val: ConstVariableValue::Unknown { universe: self.universe() }, }); @@ -1335,7 +1556,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn probe_ty_var(&self, vid: TyVid) -> Result, ty::UniverseIndex> { 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::Unknown { universe } => Err(universe), } @@ -1357,7 +1578,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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 @@ -1395,7 +1616,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, vid: ty::ConstVid<'tcx>, ) -> 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::Unknown { universe } => Err(universe), } @@ -1576,14 +1797,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // // Note: if these two lines are combined into one we get // 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) } ty::Infer(ty::IntVar(v)) => self .inner .borrow_mut() - .int_unification_table + .int_unification_table() .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ), @@ -1591,7 +1812,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Infer(ty::FloatVar(v)) => self .inner .borrow_mut() - .float_unification_table + .float_unification_table() .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ), @@ -1617,7 +1838,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // If `inlined_probe` returns a `Known` value, it never equals // `ty::Infer(ty::TyVar(v))`. - match self.inner.borrow_mut().type_variables.inlined_probe(v) { + match self.inner.borrow_mut().type_variables().inlined_probe(v) { TypeVariableValue::Unknown { .. } => false, TypeVariableValue::Known { .. } => true, } @@ -1627,7 +1848,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // If `inlined_probe_value` returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which never matches a // `ty::Infer(_)`. - self.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some() + self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_some() } TyOrConstInferVar::TyFloat(v) => { @@ -1635,7 +1856,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `ty::Float(_)`, which never matches a `ty::Infer(_)`. // // Not `inlined_probe_value(v)` because this call site is colder. - self.inner.borrow_mut().float_unification_table.probe_value(v).is_some() + self.inner.borrow_mut().float_unification_table().probe_value(v).is_some() } TyOrConstInferVar::Const(v) => { @@ -1718,7 +1939,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { self.infcx .inner .borrow_mut() - .const_unification_table + .const_unification_table() .probe_value(*vid) .val .known() diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index a2907e6e373b8..7aea26987a29f 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -311,7 +311,7 @@ where match value_ty.kind { ty::Infer(ty::TyVar(value_vid)) => { // 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); } @@ -332,7 +332,7 @@ where 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 // been fully instantiated and hence the set of scopes we have @@ -362,7 +362,7 @@ where delegate: &mut self.delegate, first_free_index: ty::INNERMOST, 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, }; @@ -859,7 +859,8 @@ where } 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 sub_vid = variables.sub_root_var(vid); if sub_vid == self.for_vid_sub_root { @@ -961,7 +962,8 @@ where bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); } 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); match var_value.val.known() { Some(u) => self.relate(&u, &u), diff --git a/src/librustc_infer/infer/resolve.rs b/src/librustc_infer/infer/resolve.rs index bd9d108cfe871..e28cf49c7f253 100644 --- a/src/librustc_infer/infer/resolve.rs +++ b/src/librustc_infer/infer/resolve.rs @@ -123,7 +123,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { // Since we called `shallow_resolve` above, this must // be an (as yet...) unresolved inference variable. 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 { kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), span, diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 080af37492d89..0abcc15d6fcd8 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -80,8 +80,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { } let infcx = self.fields.infcx; - 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 a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); match (&a.kind, &b.kind) { (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { // 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 // the two variables are equal modulo subtyping, which // 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.trace.cause.clone(), self.fields.param_env, diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 1de820cdb6209..47f7d76413693 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -3,19 +3,76 @@ use rustc_middle::ty::{self, Ty, TyVid}; use rustc_span::symbol::Symbol; use rustc_span::Span; +use crate::infer::Logs; + use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; use std::cmp; use std::marker::PhantomData; use std::ops::Range; -pub struct TypeVariableTable<'tcx> { - values: sv::SnapshotVec, +use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs}; + +pub(crate) enum UndoLog<'tcx> { + EqRelation(sv::UndoLog>>), + SubRelation(sv::UndoLog>), + Values(sv::UndoLog), +} + +impl<'tcx> From>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>>) -> Self { + UndoLog::EqRelation(l) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + UndoLog::SubRelation(l) + } +} + +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: sv::UndoLog) -> Self { + UndoLog::Values(l) + } +} + +impl<'tcx> From for UndoLog<'tcx> { + fn from(l: Instantiate) -> Self { + UndoLog::Values(sv::UndoLog::Other(l)) + } +} + +pub(crate) struct RollbackView<'tcx, 'a> { + pub(crate) eq_relations: &'a mut ut::UnificationStorage>, + pub(crate) sub_relations: &'a mut ut::UnificationStorage, + pub(crate) values: &'a mut Vec, +} + +impl<'tcx, 'a> From<&'a mut TypeVariableStorage<'tcx>> for RollbackView<'tcx, 'a> { + fn from(l: &'a mut TypeVariableStorage<'tcx>) -> Self { + let TypeVariableStorage { eq_relations, sub_relations, values } = l; + Self { eq_relations, sub_relations, values } + } +} + +impl<'tcx> Rollback> for RollbackView<'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: Vec, /// Two variables are unified in `eq_relations` when we have a /// constraint `?X == ?Y`. This table also stores, for each key, /// the known value. - eq_relations: ut::UnificationTable>>, + eq_relations: ut::UnificationStorage>, /// Two variables are unified in `sub_relations` when we have a /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second @@ -34,7 +91,17 @@ pub struct TypeVariableTable<'tcx> { /// This is reasonable because, in Rust, subtypes have the same /// "skeleton" and hence there is no possible type such that /// (e.g.) `Box <: ?3` for any `?3`. - sub_relations: ut::UnificationTable>, + sub_relations: ut::UnificationStorage, +} + +pub struct TypeVariableTable<'tcx, 'a> { + values: &'a mut Vec, + + eq_relations: &'a mut ut::UnificationStorage>, + + sub_relations: &'a mut ut::UnificationStorage, + + undo_log: &'a mut Logs<'tcx>, } #[derive(Copy, Clone, Debug)] @@ -62,7 +129,7 @@ pub enum TypeVariableOriginKind { LatticeVariable, } -struct TypeVariableData { +pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, diverging: bool, } @@ -92,32 +159,41 @@ impl<'tcx> TypeVariableValue<'tcx> { } pub struct Snapshot<'tcx> { - snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot>>, - sub_snapshot: ut::Snapshot>, + value_count: u32, + _marker: PhantomData<&'tcx ()>, } -struct Instantiate { +pub(crate) struct Instantiate { vid: ty::TyVid, } -struct Delegate; +pub(crate) struct Delegate; -impl<'tcx> TypeVariableTable<'tcx> { - pub fn new() -> TypeVariableTable<'tcx> { - TypeVariableTable { - values: sv::SnapshotVec::new(), - eq_relations: ut::UnificationTable::new(), - sub_relations: ut::UnificationTable::new(), +impl<'tcx> TypeVariableStorage<'tcx> { + pub fn new() -> TypeVariableStorage<'tcx> { + TypeVariableStorage { + values: Vec::new(), + eq_relations: ut::UnificationStorage::new(), + sub_relations: ut::UnificationStorage::new(), } } + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut Logs<'tcx>, + ) -> TypeVariableTable<'tcx, 'a> { + 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. /// /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_diverges(&self, vid: ty::TyVid) -> bool { - self.values.get(vid.index as usize).diverging + self.values.get(vid.index as usize).unwrap().diverging } /// Returns the origin that was given when `vid` was created. @@ -125,7 +201,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.values.get(vid.index as usize).origin + &self.values.get(vid.index as usize).unwrap().origin } /// Records that `a == b`, depending on `dir`. @@ -134,8 +210,8 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); - self.eq_relations.union(a, b); - self.sub_relations.union(a, b); + self.eq_relations().union(a, b); + self.sub_relations().union(a, b); } /// Records that `a <: b`, depending on `dir`. @@ -144,7 +220,7 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { debug_assert!(self.probe(a).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`. @@ -154,18 +230,18 @@ impl<'tcx> TypeVariableTable<'tcx> { let vid = self.root_var(vid); debug_assert!(self.probe(vid).is_unknown()); 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={:?}", vid, 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` // can see what has been unified; see the Delegate impl for // more details. - self.values.record(Instantiate { vid }); + self.undo_log.push(Instantiate { vid }); } /// Creates a new type variable. @@ -184,12 +260,12 @@ impl<'tcx> TypeVariableTable<'tcx> { diverging: bool, origin: TypeVariableOrigin, ) -> 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); - 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); debug!( @@ -211,7 +287,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// algorithm), so `root_var(a) == root_var(b)` implies that `a == /// b` (transitively). 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` @@ -222,7 +298,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// exists X. (a <: X || X <: a) && (b <: X || X <: b) 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 @@ -240,7 +316,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// An always-inlined variant of `probe`, for very hot call sites. #[inline(always)] 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 @@ -261,40 +337,31 @@ impl<'tcx> TypeVariableTable<'tcx> { /// (`rollback_to()`). Nested snapshots are permitted, but must /// be processed in a stack-like fashion. 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(), - } + Snapshot { value_count: self.eq_relations().len() as u32, _marker: PhantomData } } - /// Undoes all changes since the snapshot was created. Any - /// snapshots created since that point must already have been - /// 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) - } - } - }); + fn values(&mut self) -> sv::SnapshotVec, &mut Logs<'tcx>> { + sv::SnapshotVec::with_log(self.values, self.undo_log) + } - 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); + fn eq_relations( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace< + TyVidEqKey<'tcx>, + &mut ut::UnificationStorage>, + &mut Logs<'tcx>, + >, + > { + ut::UnificationTable::with_log(self.eq_relations, self.undo_log) } - /// Commits all changes since the snapshot was created, making - /// them permanent (unless this snapshot was created within - /// 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); + fn sub_relations( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace, &mut Logs<'tcx>>, + > { + ut::UnificationTable::with_log(self.sub_relations, self.undo_log) } /// Returns a range of the type variables created during the snapshot. @@ -302,11 +369,12 @@ impl<'tcx> TypeVariableTable<'tcx> { &mut self, s: &Snapshot<'tcx>, ) -> (Range, Vec) { - let range = self.eq_relations.vars_since_snapshot(&s.eq_snapshot); + let range = + TyVid { index: s.value_count }..TyVid { index: self.eq_relations().len() as u32 }; ( - range.start.vid..range.end.vid, - (range.start.vid.index..range.end.vid.index) - .map(|index| self.values.get(index as usize).origin) + range.start..range.end, + (range.start.index..range.end.index) + .map(|index| self.values.get(index as usize).unwrap().origin) .collect(), ) } @@ -317,14 +385,15 @@ impl<'tcx> TypeVariableTable<'tcx> { /// a type variable `V0`, then we started the snapshot, then we /// created a type variable `V1`, unified `V0` with `T0`, and /// unified `V1` with `T1`, this function would return `{T0}`. - pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec> { + pub fn types_escaping_snapshot(&mut self, s: &super::Snapshot<'tcx>) -> Vec> { let mut new_elem_threshold = u32::MAX; 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()); - for action in actions_since_snapshot { - match *action { - sv::UndoLog::NewElem(index) => { + for i in 0..actions_since_snapshot.len() { + let actions_since_snapshot = self.undo_log.actions_since_snapshot(s); + match actions_since_snapshot[i] { + super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::NewElem(index))) => { // if any new variables were created during the // snapshot, remember the lower index (which will // always be the first one we see). Note that this @@ -334,11 +403,17 @@ impl<'tcx> TypeVariableTable<'tcx> { 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 { // quick check to see if this variable was // 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::Known { value } => value, }; @@ -395,7 +470,7 @@ impl sv::SnapshotVecDelegate for Delegate { /// for the `eq_relations`; they carry a `TypeVariableValue` along /// with them. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -struct TyVidEqKey<'tcx> { +pub(crate) struct TyVidEqKey<'tcx> { vid: ty::TyVid, // in the table, we map each ty-vid to one of these: diff --git a/src/librustc_middle/infer/unify_key.rs b/src/librustc_middle/infer/unify_key.rs index e205453a48c53..2580ac6bebd86 100644 --- a/src/librustc_middle/infer/unify_key.rs +++ b/src/librustc_middle/infer/unify_key.rs @@ -1,6 +1,9 @@ use crate::ty::{self, FloatVarValue, InferConst, IntVarValue, Ty, TyCtxt}; -use rustc_data_structures::unify::InPlace; -use rustc_data_structures::unify::{EqUnifyValue, NoError, UnificationTable, UnifyKey, UnifyValue}; +use rustc_data_structures::snapshot_vec; +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::{Span, DUMMY_SP}; @@ -212,10 +215,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {} -pub fn replace_if_possible( - table: &mut UnificationTable>>, +pub fn replace_if_possible( + table: &mut UnificationTable, V, L>>, c: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { +) -> &'tcx ty::Const<'tcx> +where + V: snapshot_vec::VecLike>>, + L: UndoLogs>>>, +{ if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c { match table.probe_value(*vid).val.known() { Some(c) => c, From caacdd2024cc428f95e4177e63fb66fd3e6f6c20 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 09:47:07 +0100 Subject: [PATCH 03/22] Move region_constraint to the unified undo log --- Cargo.lock | 16 +- Cargo.toml | 2 - src/librustc_data_structures/Cargo.toml | 2 +- src/librustc_infer/infer/mod.rs | 61 ++++- .../infer/region_constraints/leak_check.rs | 21 +- .../infer/region_constraints/mod.rs | 249 +++++++++--------- src/librustc_infer/infer/type_variable.rs | 16 +- 7 files changed, 196 insertions(+), 171 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f442e8d2b9ce..45c298ea8bfcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -987,7 +987,17 @@ dependencies = [ [[package]] name = "ena" version = "0.13.1" -source = "git+https://github.com/Marwes/ena?branch=detach_undo_log#9b977ea7f209a35f46d65d33cdd74b8f4931fb8a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36" +dependencies = [ + "log", +] + +[[package]] +name = "ena" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" dependencies = [ "log", ] @@ -3234,7 +3244,7 @@ dependencies = [ "bitflags", "cfg-if", "crossbeam-utils 0.7.2", - "ena", + "ena 0.13.1", "indexmap", "jobserver", "lazy_static 1.4.0", @@ -3680,7 +3690,7 @@ dependencies = [ "bitflags", "cfg-if", "crossbeam-utils 0.7.2", - "ena", + "ena 0.14.0", "graphviz", "indexmap", "jobserver", diff --git a/Cargo.toml b/Cargo.toml index 9b143dcc8d89a..7b5e0fa1c2817 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,5 @@ rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' } rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' } rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' } -ena = { version = "0.13.1", git = "https://github.com/Marwes/ena", branch = "detach_undo_log" } - [patch."https://github.com/rust-lang/rust-clippy"] clippy_lints = { path = "src/tools/clippy/clippy_lints" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 6d7022acc7863..e257ada0629b2 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -ena = "0.13.1" +ena = "0.14" indexmap = "1" log = "0.4" jobserver_crate = { version = "0.1.13", package = "jobserver" } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 6d76f15998ae8..ed99b47f80c7c 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -45,7 +45,9 @@ use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; 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}; pub mod at; @@ -161,7 +163,7 @@ pub struct InferCtxtInner<'tcx> { /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` /// -- further attempts to perform unification, etc., may fail if new /// region constraints would've been added. - region_constraints: Option>, + region_constraints: Option>, /// A set of constraints that regionck must validate. Each /// constraint has the form `T:'a`, meaning "some type `T` must @@ -206,7 +208,7 @@ impl<'tcx> InferCtxtInner<'tcx> { const_unification_table: ut::UnificationStorage::new(), int_unification_table: ut::UnificationStorage::new(), float_unification_table: ut::UnificationStorage::new(), - region_constraints: Some(RegionConstraintCollector::new()), + region_constraints: Some(RegionConstraintStorage::new()), region_obligations: vec![], } } @@ -243,8 +245,11 @@ impl<'tcx> InferCtxtInner<'tcx> { ut::UnificationTable::with_log(&mut self.const_unification_table, &mut self.undo_log) } - pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> { - self.region_constraints.as_mut().expect("region constraints already solved") + pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> { + self.region_constraints + .as_mut() + .expect("region constraints already solved") + .with_log(&mut self.undo_log) } } @@ -258,6 +263,14 @@ pub(crate) enum UndoLog<'tcx> { ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), FloatUnificationTable(sv::UndoLog>), + RegionConstraintCollector(region_constraints::UndoLog<'tcx>), + RegionUnificationTable(sv::UndoLog>), +} + +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: region_constraints::UndoLog<'tcx>) -> Self { + UndoLog::RegionConstraintCollector(l) + } } impl<'tcx> From>>> for UndoLog<'tcx> { @@ -308,6 +321,12 @@ impl<'tcx> From>> for UndoLog<'tcx> { } } +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + Self::RegionUnificationTable(l) + } +} + pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable, &'a mut Logs<'tcx>>>; @@ -316,6 +335,7 @@ struct RollbackView<'tcx, 'a> { const_unification_table: &'a mut ut::UnificationStorage>, int_unification_table: &'a mut ut::UnificationStorage, float_unification_table: &'a mut ut::UnificationStorage, + region_constraints: &'a mut RegionConstraintStorage<'tcx>, } impl<'tcx> Rollback> for RollbackView<'tcx, '_> { @@ -325,6 +345,10 @@ impl<'tcx> Rollback> for RollbackView<'tcx, '_> { UndoLog::ConstUnificationTable(undo) => self.const_unification_table.reverse(undo), UndoLog::IntUnificationTable(undo) => self.int_unification_table.reverse(undo), UndoLog::FloatUnificationTable(undo) => self.float_unification_table.reverse(undo), + UndoLog::RegionConstraintCollector(undo) => self.region_constraints.reverse(undo), + UndoLog::RegionUnificationTable(undo) => { + self.region_constraints.unification_table.reverse(undo) + } } } } @@ -408,6 +432,16 @@ impl<'tcx> Snapshots> for Logs<'tcx> { } impl<'tcx> Logs<'tcx> { + pub(crate) fn region_constraints( + &self, + after: usize, + ) -> impl Iterator> + Clone { + self.logs[after..].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); @@ -1004,7 +1038,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { const_snapshot: _, int_snapshot: _, float_snapshot: _, - region_constraints_snapshot, + region_constraints_snapshot: _, region_obligations_snapshot, universe, was_in_snapshot, @@ -1023,6 +1057,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { const_unification_table, int_unification_table, float_unification_table, + region_constraints, .. } = inner; inner.undo_log.rollback_to( @@ -1031,11 +1066,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { const_unification_table, int_unification_table, float_unification_table, + region_constraints: region_constraints.as_mut().unwrap(), }, undo_snapshot, ); inner.projection_cache.rollback_to(projection_cache_snapshot); - inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); inner.region_obligations.truncate(region_obligations_snapshot); } @@ -1048,7 +1083,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { const_snapshot: _, int_snapshot: _, float_snapshot: _, - region_constraints_snapshot, + region_constraints_snapshot: _, region_obligations_snapshot: _, universe: _, was_in_snapshot, @@ -1062,7 +1097,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut inner = self.inner.borrow_mut(); inner.undo_log.commit(undo_snapshot); inner.projection_cache.commit(projection_cache_snapshot); - inner.unwrap_region_constraints().commit(region_constraints_snapshot); } /// Executes `f` and commit the bindings. @@ -1135,7 +1169,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.inner .borrow_mut() .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) { @@ -1466,6 +1500,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .region_constraints .take() .expect("regions already resolved") + .with_log(&mut inner.undo_log) .into_infos_and_data(); let region_rels = &RegionRelations::new( @@ -1527,12 +1562,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// called. This is used only during NLL processing to "hand off" ownership /// of the set of region variables into the NLL region context. pub fn take_region_var_origins(&self) -> VarInfos { - let (var_infos, data) = self - .inner - .borrow_mut() + let mut inner = self.inner.borrow_mut(); + let (var_infos, data) = inner .region_constraints .take() .expect("regions already resolved") + .with_log(&mut inner.undo_log) .into_infos_and_data(); assert!(data.is_empty()); var_infos diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 18e86162eb5e4..0178fa2eae6ee 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -1,9 +1,10 @@ use super::*; use crate::infer::{CombinedSnapshot, PlaceholderMap}; +use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; -impl<'tcx> RegionConstraintCollector<'tcx> { +impl<'tcx> RegionConstraintCollector<'tcx, '_> { /// Searches region constraints created since `snapshot` that /// affect one of the placeholders in `placeholder_map`, returning /// an error if any of the placeholders are related to another @@ -31,7 +32,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ) -> RelateResult<'tcx, ()> { debug!("leak_check(placeholders={:?})", placeholder_map); - assert!(self.in_snapshot()); + assert!(UndoLogs::>::in_snapshot(&self.undo_log)); // Go through each placeholder that we created. 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 // or is outlived by a placeholder. 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(0), + &self.storage.data.verifys, + ); let tainted_regions = taint_set.into_set(); // Report an error if two placeholders in the same universe @@ -88,19 +93,21 @@ impl<'tcx> TaintSet<'tcx> { TaintSet { directions, regions } } - fn fixed_point( + fn fixed_point<'a>( &mut self, tcx: TyCtxt<'tcx>, - undo_log: &[UndoLog<'tcx>], + undo_log: impl IntoIterator> + Clone, verifys: &[Verify<'tcx>], - ) { + ) where + 'tcx: 'a, + { let mut prev_len = 0; while prev_len < self.len() { debug!("tainted: prev_len = {:?} new_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 { &AddConstraint(Constraint::VarSubVar(a, b)) => { self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b))); diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 2be6ec4481c6b..7b660ce436559 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -4,11 +4,13 @@ use self::CombineMapType::*; use self::UndoLog::*; use super::unify_key; -use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin}; +use super::{Logs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; +use rustc_data_structures::unify::UnifyKey; use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_middle::ty::ReStatic; @@ -26,7 +28,7 @@ mod leak_check; pub use rustc_middle::infer::MemberConstraint; #[derive(Default)] -pub struct RegionConstraintCollector<'tcx> { +pub struct RegionConstraintStorage<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. var_infos: IndexVec, @@ -42,20 +44,6 @@ pub struct RegionConstraintCollector<'tcx> { /// exist). This prevents us from making many such regions. 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>, - - /// 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 /// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this /// table. You can then call `opportunistic_resolve_var` early @@ -64,13 +52,31 @@ pub struct RegionConstraintCollector<'tcx> { /// is iterating to a fixed point, because otherwise we sometimes /// would wind up with a fresh stream of region variables that /// have been equated but appear distinct. - unification_table: ut::UnificationTable>, + pub(super) unification_table: ut::UnificationStorage, /// a flag set to true when we perform any unifications; this is used /// to micro-optimize `take_and_reset_data` any_unifications: bool, } +pub struct RegionConstraintCollector<'tcx, 'a> { + storage: &'a mut RegionConstraintStorage<'tcx>, + undo_log: &'a mut Logs<'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; /// The full set of region constraints gathered up by the collector. @@ -258,13 +264,13 @@ pub enum VerifyBound<'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct TwoRegions<'tcx> { +pub(crate) struct TwoRegions<'tcx> { a: Region<'tcx>, b: Region<'tcx>, } #[derive(Copy, Clone, PartialEq)] -enum UndoLog<'tcx> { +pub(crate) enum UndoLog<'tcx> { /// We added `RegionVid`. AddVar(RegionVid), @@ -290,7 +296,7 @@ enum UndoLog<'tcx> { } #[derive(Copy, Clone, PartialEq)] -enum CombineMapType { +pub(crate) enum CombineMapType { Lub, Glb, } @@ -304,8 +310,7 @@ pub struct RegionVariableInfo { } pub struct RegionSnapshot { - length: usize, - region_snapshot: ut::Snapshot>, + value_count: usize, any_unifications: bool, } @@ -334,11 +339,48 @@ impl TaintDirections { } } -impl<'tcx> RegionConstraintCollector<'tcx> { +impl<'tcx> RegionConstraintStorage<'tcx> { pub fn new() -> Self { Self::default() } + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut Logs<'tcx>, + ) -> RegionConstraintCollector<'tcx, 'a> { + RegionConstraintCollector { storage: self, undo_log } + } + + fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { + match undo_entry { + Purged => { + // nothing to do here + } + AddVar(vid) => { + self.var_infos.pop().unwrap(); + assert_eq!(self.var_infos.len(), vid.index() as usize); + } + AddConstraint(ref constraint) => { + self.data.constraints.remove(constraint); + } + AddVerify(index) => { + self.data.verifys.pop(); + assert_eq!(self.data.verifys.len(), index); + } + AddGiven(sub, sup) => { + self.data.givens.remove(&(sub, sup)); + } + AddCombination(Glb, ref regions) => { + self.glbs.remove(regions); + } + AddCombination(Lub, ref regions) => { + self.lubs.remove(regions); + } + } + } +} + +impl<'tcx> RegionConstraintCollector<'tcx, '_> { pub fn num_region_vars(&self) -> usize { self.var_infos.len() } @@ -351,8 +393,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> { /// /// Not legal during a snapshot. pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) { - assert!(!self.in_snapshot()); - (self.var_infos, self.data) + assert!(!UndoLogs::>::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 @@ -368,21 +410,19 @@ impl<'tcx> RegionConstraintCollector<'tcx> { /// /// Not legal during a snapshot. pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> { - assert!(!self.in_snapshot()); + assert!(!UndoLogs::>::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 RegionConstraintCollector { + let RegionConstraintStorage { var_infos: _, data, lubs, glbs, - undo_log: _, - num_open_snapshots: _, - unification_table, + unification_table: _, any_unifications, - } = self; + } = self.storage; // Clear the tables of (lubs, glbs), so that we will create // fresh regions if we do a LUB operation. As it happens, @@ -391,102 +431,38 @@ impl<'tcx> RegionConstraintCollector<'tcx> { 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 { - unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); *any_unifications = false; + self.unification_table() + .reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); } - mem::take(data) + 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; + debug!("RegionConstraintCollector: start_snapshot"); RegionSnapshot { - length, - region_snapshot: self.unification_table.snapshot(), + value_count: self.unification_table.len(), 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>) { - match undo_entry { - Purged => { - // nothing to do here - } - AddVar(vid) => { - self.var_infos.pop().unwrap(); - assert_eq!(self.var_infos.len(), vid.index() as usize); - } - AddConstraint(ref constraint) => { - self.data.constraints.remove(constraint); - } - AddVerify(index) => { - self.data.verifys.pop(); - assert_eq!(self.data.verifys.len(), index); - } - AddGiven(sub, sup) => { - self.data.givens.remove(&(sub, sup)); - } - AddCombination(Glb, ref regions) => { - self.glbs.remove(regions); - } - AddCombination(Lub, ref regions) => { - self.lubs.remove(regions); - } - } - } - pub fn new_region_var( &mut self, universe: ty::UniverseIndex, @@ -494,11 +470,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ) -> RegionVid { let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); - let u_vid = self.unification_table.new_key(unify_key::RegionVidKey { min_vid: vid }); + let u_vid = self.unification_table().new_key(unify_key::RegionVidKey { min_vid: 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); vid } @@ -520,19 +494,30 @@ impl<'tcx> RegionConstraintCollector<'tcx> { pub fn pop_placeholders(&mut self, placeholders: &FxHashSet>) { debug!("pop_placeholders(placeholders={:?})", placeholders); - assert!(self.in_snapshot()); + assert!(UndoLogs::>::in_snapshot(&self.undo_log)); let constraints_to_kill: Vec = self .undo_log + .logs .iter() .enumerate() .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) .collect(); 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.logs[index] { + super::UndoLog::RegionConstraintCollector(undo_entry) => { + mem::replace(undo_entry, Purged) + } + _ => unreachable!(), + }; self.rollback_undo_entry(undo_entry); } @@ -566,12 +551,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // 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 // 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; - self.data.constraints.entry(constraint).or_insert_with(|| { - if in_snapshot { - undo_log.push(AddConstraint(constraint)); - } + self.storage.data.constraints.entry(constraint).or_insert_with(|| { + undo_log.push(AddConstraint(constraint)); origin }); } @@ -589,9 +571,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { let index = self.data.verifys.len(); 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) { @@ -599,9 +579,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { if self.data.givens.insert((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)); } } @@ -619,7 +597,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { if let (ty::ReVar(sub), ty::ReVar(sup)) = (*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; } } @@ -741,7 +719,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { tcx: TyCtxt<'tcx>, rid: RegionVid, ) -> 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)) } @@ -769,9 +747,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { let c_universe = cmp::max(a_universe, b_universe); let c = self.new_region_var(c_universe, MiscVariable(origin.span())); 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)); for &old_r in &[a, b] { match t { @@ -801,7 +777,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> { &self, mark: &RegionSnapshot, ) -> (Range, Vec) { - let range = self.unification_table.vars_since_snapshot(&mark.region_snapshot); + let range = RegionVid::from_index(mark.value_count as u32) + ..RegionVid::from_index(self.unification_table.len() as u32); ( range.clone(), (range.start.index()..range.end.index()) @@ -810,10 +787,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ) } - /// See `InferCtxt::region_constraints_added_in_snapshot`. - pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option { - self.undo_log[mark.length..] - .iter() + /// See [`RegionInference::region_constraints_added_in_snapshot`]. + pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'_>) -> Option { + self.undo_log + .region_constraints(mark.undo_len) .map(|&elt| match elt { AddConstraint(constraint) => Some(constraint.involves_placeholders()), _ => None, @@ -821,11 +798,15 @@ impl<'tcx> RegionConstraintCollector<'tcx> { .max() .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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RegionSnapshot(length={})", self.length) + write!(f, "RegionSnapshot") } } @@ -910,3 +891,9 @@ impl<'tcx> RegionConstraintData<'tcx> { && givens.is_empty() } } + +impl<'tcx> Rollback> for RegionConstraintStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + self.rollback_undo_entry(undo) + } +} diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 47f7d76413693..3858c50b92c6a 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -344,23 +344,11 @@ impl<'tcx> TypeVariableTable<'tcx, '_> { sv::SnapshotVec::with_log(self.values, self.undo_log) } - fn eq_relations( - &mut self, - ) -> ut::UnificationTable< - ut::InPlace< - TyVidEqKey<'tcx>, - &mut ut::UnificationStorage>, - &mut Logs<'tcx>, - >, - > { + fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> { ut::UnificationTable::with_log(self.eq_relations, self.undo_log) } - fn sub_relations( - &mut self, - ) -> ut::UnificationTable< - ut::InPlace, &mut Logs<'tcx>>, - > { + fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> { ut::UnificationTable::with_log(self.sub_relations, self.undo_log) } From c50fc6e113ee3905992521e1bd2431f6b2cd5c20 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 10:29:47 +0100 Subject: [PATCH 04/22] Allow SnapshotMap to have a separate undo_log --- .../snapshot_map/mod.rs | 150 +++++++----------- src/librustc_infer/infer/mod.rs | 4 + src/librustc_infer/traits/project.rs | 4 - 3 files changed, 62 insertions(+), 96 deletions(-) diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index b71163a8f9433..81b4c35aa1ab7 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -1,77 +1,73 @@ use crate::fx::FxHashMap; +use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; use std::hash::Hash; -use std::mem; +use std::marker::PhantomData; use std::ops; +pub use crate::undo_log::Snapshot; + #[cfg(test)] mod tests; -pub struct SnapshotMap -where - K: Clone + Eq, -{ - map: FxHashMap, - undo_log: Vec>, - num_open_snapshots: usize, +pub type SnapshotMapStorage = SnapshotMap, ()>; + +pub struct SnapshotMap, L = VecLog>> { + map: M, + undo_log: L, + _marker: PhantomData<(K, V)>, } // HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`. -impl Default for SnapshotMap +impl Default for SnapshotMap where - K: Hash + Clone + Eq, + M: Default, + L: Default, { 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 { - len: usize, -} - -enum UndoLog { +pub enum UndoLog { Inserted(K), Overwrite(K, V), Purged, } -impl SnapshotMap +impl SnapshotMap { + pub fn with_log(&mut self, undo_log: L2) -> SnapshotMap { + SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData } + } +} + +impl SnapshotMap where K: Hash + Clone + Eq, + M: AsMut> + AsRef>, + L: UndoLogs>, { pub fn clear(&mut self) { - self.map.clear(); + self.map.as_mut().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 { - match self.map.insert(key.clone(), value) { + match self.map.as_mut().insert(key.clone(), value) { None => { - if self.in_snapshot() { - self.undo_log.push(UndoLog::Inserted(key)); - } + self.undo_log.push(UndoLog::Inserted(key)); true } 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 } } } pub fn remove(&mut self, key: K) -> bool { - match self.map.remove(&key) { + match self.map.as_mut().remove(&key) { 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 } None => false, @@ -79,83 +75,53 @@ where } pub fn get(&self, key: &K) -> Option<&V> { - self.map.get(key) + self.map.as_ref().get(key) } +} +impl SnapshotMap +where + K: Hash + Clone + Eq, +{ pub fn snapshot(&mut self) -> Snapshot { - let len = self.undo_log.len(); - 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); + self.undo_log.start_snapshot() } pub fn commit(&mut self, snapshot: Snapshot) { - 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.len == 0); - self.undo_log.clear(); - } - - self.num_open_snapshots -= 1; - } - - pub fn partial_rollback(&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); - } - } + self.undo_log.commit(snapshot) } pub fn rollback_to(&mut self, snapshot: Snapshot) { - self.assert_open_snapshot(&snapshot); - while self.undo_log.len() > snapshot.len { - let entry = self.undo_log.pop().unwrap(); - self.reverse(entry); - } + self.undo_log.rollback_to(&mut self.map, snapshot) + } +} - self.num_open_snapshots -= 1; +impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap +where + K: Hash + Clone + Eq, + M: AsRef>, +{ + type Output = V; + fn index(&self, key: &'k K) -> &V { + &self.map.as_ref()[key] } +} - fn reverse(&mut self, entry: UndoLog) { - match entry { +impl Rollback> for FxHashMap +where + K: Eq + Hash, +{ + fn reverse(&mut self, undo: UndoLog) { + match undo { UndoLog::Inserted(key) => { - self.map.remove(&key); + self.remove(&key); } UndoLog::Overwrite(key, old_value) => { - self.map.insert(key, old_value); + self.insert(key, old_value); } UndoLog::Purged => {} } } } - -impl<'k, K, V> ops::Index<&'k K> for SnapshotMap -where - K: Hash + Clone + Eq, -{ - type Output = V; - fn index(&self, key: &'k K) -> &V { - &self.map[key] - } -} diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index ed99b47f80c7c..eabb513d2d3a6 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -376,6 +376,10 @@ where self.logs.push(undo.into()) } } + fn clear(&mut self) { + self.logs.clear(); + self.num_open_snapshots = 0; + } fn extend(&mut self, undos: J) where Self: Sized, diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 48375a9ddf418..17105f99ac0fa 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -100,10 +100,6 @@ impl<'tcx> ProjectionCache<'tcx> { 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); } From 0c5d8338120ebf85e68d2f63670fac05fda97de6 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 13:08:38 +0100 Subject: [PATCH 05/22] Move projection_cache into the combined undo log --- Cargo.lock | 12 +--- .../snapshot_map/mod.rs | 26 ++++++-- src/librustc_infer/infer/mod.rs | 25 ++++--- src/librustc_infer/traits/mod.rs | 1 + src/librustc_infer/traits/project.rs | 66 +++++++++++-------- src/librustc_trait_selection/traits/select.rs | 2 +- 6 files changed, 79 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45c298ea8bfcd..c5e25b0a2c722 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -485,7 +485,7 @@ version = "0.0.212" dependencies = [ "cargo_metadata 0.9.1", "if_chain", - "itertools 0.9.0", + "itertools 0.8.0", "lazy_static 1.4.0", "pulldown-cmark 0.7.1", "quine-mc_cluskey", @@ -1629,15 +1629,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "0.4.4" @@ -2188,7 +2179,6 @@ dependencies = [ "rustc-workspace-hack", "rustc_version", "serde", - "serde_json", "shell-escape", "vergen", ] diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index 81b4c35aa1ab7..fe3c5a8afc90e 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -1,5 +1,6 @@ use crate::fx::FxHashMap; use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; +use std::borrow::{Borrow, BorrowMut}; use std::hash::Hash; use std::marker::PhantomData; use std::ops; @@ -10,6 +11,7 @@ pub use crate::undo_log::Snapshot; mod tests; pub type SnapshotMapStorage = SnapshotMap, ()>; +pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap, &'a mut L>; pub struct SnapshotMap, L = VecLog>> { map: M, @@ -43,16 +45,16 @@ impl SnapshotMap { impl SnapshotMap where K: Hash + Clone + Eq, - M: AsMut> + AsRef>, + M: BorrowMut> + Borrow>, L: UndoLogs>, { pub fn clear(&mut self) { - self.map.as_mut().clear(); + self.map.borrow_mut().clear(); self.undo_log.clear(); } pub fn insert(&mut self, key: K, value: V) -> bool { - match self.map.as_mut().insert(key.clone(), value) { + match self.map.borrow_mut().insert(key.clone(), value) { None => { self.undo_log.push(UndoLog::Inserted(key)); true @@ -65,7 +67,7 @@ where } pub fn remove(&mut self, key: K) -> bool { - match self.map.as_mut().remove(&key) { + match self.map.borrow_mut().remove(&key) { Some(old_value) => { self.undo_log.push(UndoLog::Overwrite(key, old_value)); true @@ -75,7 +77,7 @@ where } pub fn get(&self, key: &K) -> Option<&V> { - self.map.as_ref().get(key) + self.map.borrow().get(key) } } @@ -99,11 +101,21 @@ where impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap where K: Hash + Clone + Eq, - M: AsRef>, + M: Borrow>, { type Output = V; fn index(&self, key: &'k K) -> &V { - &self.map.as_ref()[key] + &self.map.borrow()[key] + } +} + +impl Rollback> for SnapshotMap +where + K: Eq + Hash, + M: Rollback>, +{ + fn reverse(&mut self, undo: UndoLog) { + self.map.reverse(undo) } } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index eabb513d2d3a6..685dc1ab8a4ea 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -141,7 +141,7 @@ pub struct InferCtxtInner<'tcx> { /// Cache for projections. This cache is snapshotted along with the infcx. /// /// 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` because the types /// that might instantiate a general type variable have an order, @@ -213,6 +213,10 @@ impl<'tcx> InferCtxtInner<'tcx> { } } + pub(crate) 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_variables.with_log(&mut self.undo_log) } @@ -265,6 +269,7 @@ pub(crate) enum UndoLog<'tcx> { FloatUnificationTable(sv::UndoLog>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog>), + ProjectionCache(traits::UndoLog<'tcx>), } impl<'tcx> From> for UndoLog<'tcx> { @@ -327,6 +332,12 @@ impl<'tcx> From>> for UndoLog<'tcx> { } } +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: traits::UndoLog<'tcx>) -> Self { + Self::ProjectionCache(l) + } +} + pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable, &'a mut Logs<'tcx>>>; @@ -336,6 +347,7 @@ struct RollbackView<'tcx, 'a> { int_unification_table: &'a mut ut::UnificationStorage, float_unification_table: &'a mut ut::UnificationStorage, region_constraints: &'a mut RegionConstraintStorage<'tcx>, + projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>, } impl<'tcx> Rollback> for RollbackView<'tcx, '_> { @@ -349,6 +361,7 @@ impl<'tcx> Rollback> for RollbackView<'tcx, '_> { UndoLog::RegionUnificationTable(undo) => { self.region_constraints.unification_table.reverse(undo) } + UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), } } } @@ -885,7 +898,6 @@ impl<'tcx> InferOk<'tcx, ()> { #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx> { - projection_cache_snapshot: traits::ProjectionCacheSnapshot, undo_snapshot: Snapshot<'tcx>, type_snapshot: type_variable::Snapshot<'tcx>, const_snapshot: usize, @@ -1016,7 +1028,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { inner.undo_log.num_open_snapshots += 1; let undo_snapshot = Snapshot { undo_len: inner.undo_log.logs.len(), _marker: PhantomData }; CombinedSnapshot { - projection_cache_snapshot: inner.projection_cache.snapshot(), undo_snapshot, type_snapshot: inner.type_variables().snapshot(), const_snapshot: inner.const_unification_table().len(), @@ -1036,7 +1047,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("rollback_to(cause={})", cause); let CombinedSnapshot { - projection_cache_snapshot, undo_snapshot, type_snapshot: _, const_snapshot: _, @@ -1062,6 +1072,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { int_unification_table, float_unification_table, region_constraints, + projection_cache, .. } = inner; inner.undo_log.rollback_to( @@ -1071,17 +1082,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { int_unification_table, float_unification_table, region_constraints: region_constraints.as_mut().unwrap(), + projection_cache, }, undo_snapshot, ); - inner.projection_cache.rollback_to(projection_cache_snapshot); inner.region_obligations.truncate(region_obligations_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("commit_from()"); let CombinedSnapshot { - projection_cache_snapshot, undo_snapshot, type_snapshot: _, const_snapshot: _, @@ -1100,7 +1110,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut inner = self.inner.borrow_mut(); inner.undo_log.commit(undo_snapshot); - inner.projection_cache.commit(projection_cache_snapshot); } /// Executes `f` and commit the bindings. @@ -1773,7 +1782,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn clear_caches(&self) { self.selection_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 { diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 2210c663d1469..640ea7774cd33 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -20,6 +20,7 @@ pub use self::Vtable::*; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; +pub(crate) use self::project::UndoLog; pub use self::project::{ Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheSnapshot, Reveal, diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 17105f99ac0fa..0c51dafef6fb6 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -8,6 +8,9 @@ use rustc_middle::ty::{self, Ty}; pub use rustc_middle::traits::Reveal; +pub(crate) type UndoLog<'tcx> = + snapshot_map::UndoLog, ProjectionCacheEntry<'tcx>>; + #[derive(Clone)] pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx>, @@ -58,9 +61,14 @@ impl<'tcx, T> Normalized<'tcx, T> { // // 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. +pub struct ProjectionCache<'tcx, 'a> { + map: &'a mut SnapshotMapStorage, ProjectionCacheEntry<'tcx>>, + undo_log: &'a mut Logs<'tcx>, +} + #[derive(Default)] -pub struct ProjectionCache<'tcx> { - map: SnapshotMap, ProjectionCacheEntry<'tcx>>, +pub struct ProjectionCacheStorage<'tcx> { + map: SnapshotMapStorage, ProjectionCacheEntry<'tcx>>, } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -82,26 +90,24 @@ pub enum ProjectionCacheEntry<'tcx> { NormalizedTy(NormalizedTy<'tcx>), } -// N.B., intentionally not Clone -pub struct ProjectionCacheSnapshot { - snapshot: Snapshot, -} - -impl<'tcx> ProjectionCache<'tcx> { - pub fn clear(&mut self) { - self.map.clear(); - } - - pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { - ProjectionCacheSnapshot { snapshot: self.map.snapshot() } +impl<'tcx> ProjectionCacheStorage<'tcx> { + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut Logs<'tcx>, + ) -> ProjectionCache<'tcx, 'a> { + ProjectionCache { map: &mut self.map, undo_log } } +} - pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.rollback_to(snapshot.snapshot); +impl<'tcx> ProjectionCache<'tcx, '_> { + fn map( + &mut self, + ) -> SnapshotMapRef<'_, ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>, Logs<'tcx>> { + self.map.with_log(self.undo_log) } - pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.commit(snapshot.snapshot); + pub fn clear(&mut self) { + self.map().clear(); } /// Try to start normalize `key`; returns an error if @@ -111,11 +117,12 @@ impl<'tcx> ProjectionCache<'tcx> { &mut self, key: ProjectionCacheKey<'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()); } - self.map.insert(key, ProjectionCacheEntry::InProgress); + map.insert(key, ProjectionCacheEntry::InProgress); Ok(()) } @@ -125,7 +132,7 @@ impl<'tcx> ProjectionCache<'tcx> { "ProjectionCacheEntry::insert_ty: adding cache entry: 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); } @@ -134,7 +141,8 @@ impl<'tcx> ProjectionCache<'tcx> { /// snapshot - if the snapshot is rolled back, the obligations will be /// marked as incomplete again). 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)) => { debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); ty.value @@ -147,7 +155,7 @@ impl<'tcx> ProjectionCache<'tcx> { } }; - self.map.insert( + map.insert( key, ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), ); @@ -159,7 +167,7 @@ impl<'tcx> ProjectionCache<'tcx> { // We want to insert `ty` with no obligations. If the existing value // already has no obligations (as is common) we don't insert anything. if !ty.obligations.is_empty() { - self.map.insert( + self.map().insert( key, ProjectionCacheEntry::NormalizedTy(Normalized { value: ty.value, @@ -174,14 +182,20 @@ impl<'tcx> ProjectionCache<'tcx> { /// type information (in which case, the "fully resolved" key will /// be different). 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); } /// Indicates that trying to normalize `key` resulted in /// error. 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); } } + +impl<'tcx> Rollback> for ProjectionCacheStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + self.map.reverse(undo); + } +} diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index dfbb07424487d..38590abf1f706 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -471,7 +471,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(key) = 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 } From a457566154994c4f75347cbf697382e261700bd7 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 13:32:58 +0100 Subject: [PATCH 06/22] perf: Separate CombinedSnapshot into a FullSnapshot for probing --- src/librustc_infer/infer/fudge.rs | 2 +- src/librustc_infer/infer/mod.rs | 50 ++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index 0046dba0b0467..a105a7704fab8 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -82,7 +82,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("fudge_inference_if_ok()"); - let (mut fudger, value) = self.probe(|snapshot| { + let (mut fudger, value) = self.probe_full(|snapshot| { match f() { Ok(value) => { let value = self.resolve_vars_if_possible(&value); diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 685dc1ab8a4ea..5c899e34850a9 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -897,13 +897,18 @@ impl<'tcx> InferOk<'tcx, ()> { } #[must_use = "once you start a snapshot, you should always consume it"] -pub struct CombinedSnapshot<'a, 'tcx> { - undo_snapshot: Snapshot<'tcx>, +pub struct FullSnapshot<'a, 'tcx> { + snapshot: CombinedSnapshot<'a, 'tcx>, + region_constraints_snapshot: RegionSnapshot, type_snapshot: type_variable::Snapshot<'tcx>, const_snapshot: usize, int_snapshot: usize, float_snapshot: usize, - region_constraints_snapshot: RegionSnapshot, +} + +#[must_use = "once you start a snapshot, you should always consume it"] +pub struct CombinedSnapshot<'a, 'tcx> { + undo_snapshot: Snapshot<'tcx>, region_obligations_snapshot: usize, universe: ty::UniverseIndex, was_in_snapshot: bool, @@ -1018,6 +1023,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { result } + fn start_full_snapshot(&self) -> FullSnapshot<'a, 'tcx> { + let snapshot = self.start_snapshot(); + let mut inner = self.inner.borrow_mut(); + FullSnapshot { + snapshot, + type_snapshot: inner.type_variables().snapshot(), + const_snapshot: inner.const_unification_table().len(), + int_snapshot: inner.int_unification_table().len(), + float_snapshot: inner.float_unification_table().len(), + region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), + } + } + fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> { debug!("start_snapshot()"); @@ -1029,11 +1047,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let undo_snapshot = Snapshot { undo_len: inner.undo_log.logs.len(), _marker: PhantomData }; CombinedSnapshot { undo_snapshot, - type_snapshot: inner.type_variables().snapshot(), - const_snapshot: inner.const_unification_table().len(), - int_snapshot: inner.int_unification_table().len(), - float_snapshot: inner.float_unification_table().len(), - region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), region_obligations_snapshot: inner.region_obligations.len(), universe: self.universe(), was_in_snapshot: in_snapshot, @@ -1048,11 +1061,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("rollback_to(cause={})", cause); let CombinedSnapshot { undo_snapshot, - type_snapshot: _, - const_snapshot: _, - int_snapshot: _, - float_snapshot: _, - region_constraints_snapshot: _, region_obligations_snapshot, universe, was_in_snapshot, @@ -1093,11 +1101,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("commit_from()"); let CombinedSnapshot { undo_snapshot, - type_snapshot: _, - const_snapshot: _, - int_snapshot: _, - float_snapshot: _, - region_constraints_snapshot: _, region_obligations_snapshot: _, universe: _, was_in_snapshot, @@ -1156,6 +1159,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } + pub fn probe_full(&self, f: F) -> R + where + F: FnOnce(&FullSnapshot<'a, 'tcx>) -> R, + { + debug!("probe()"); + let snapshot = self.start_full_snapshot(); + let r = f(&snapshot); + self.rollback_to("probe", snapshot.snapshot); + r + } + /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R where From eb7ed0c917310592a05c5e2257986c6ba13d18b6 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 14:08:34 +0100 Subject: [PATCH 07/22] perf: Lazily recive the Rollback argument in rollback_to --- .../snapshot_map/mod.rs | 3 ++- src/librustc_infer/infer/mod.rs | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index fe3c5a8afc90e..52865f55f786b 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -94,7 +94,8 @@ where } pub fn rollback_to(&mut self, snapshot: Snapshot) { - self.undo_log.rollback_to(&mut self.map, snapshot) + let map = &mut self.map; + self.undo_log.rollback_to(|| map, snapshot) } } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 5c899e34850a9..fbba96fbe99cf 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -414,12 +414,18 @@ impl<'tcx> Snapshots> for Logs<'tcx> { unreachable!() } - fn rollback_to(&mut self, values: &mut impl Rollback>, snapshot: Self::Snapshot) { + fn rollback_to(&mut self, values: impl FnOnce() -> R, snapshot: Self::Snapshot) + where + R: Rollback>, + { debug!("rollback_to({})", snapshot.undo_len); self.assert_open_snapshot(&snapshot); - while self.logs.len() > snapshot.undo_len { - values.reverse(self.logs.pop().unwrap()); + if self.logs.len() > snapshot.undo_len { + let mut values = values(); + while self.logs.len() > snapshot.undo_len { + values.reverse(self.logs.pop().unwrap()); + } } if self.num_open_snapshots == 1 { @@ -1072,8 +1078,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.universe.set(universe); self.skip_leak_check.set(was_skip_leak_check); - let mut inner = self.inner.borrow_mut(); - let inner = &mut *inner; let InferCtxtInner { type_variables, const_unification_table, @@ -1081,10 +1085,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { float_unification_table, region_constraints, projection_cache, + region_obligations, + undo_log, .. - } = inner; - inner.undo_log.rollback_to( - &mut RollbackView { + } = &mut *self.inner.borrow_mut(); + undo_log.rollback_to( + || RollbackView { type_variables: type_variable::RollbackView::from(type_variables), const_unification_table, int_unification_table, @@ -1094,7 +1100,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, undo_snapshot, ); - inner.region_obligations.truncate(region_obligations_snapshot); + region_obligations.truncate(region_obligations_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { From 04f5d54d132d8469acf888e5ad6e39748ab53a1f Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 14:31:07 +0100 Subject: [PATCH 08/22] perf: Limit leak check snapshotting to probe_maybe_skip_leak_check --- src/librustc_infer/infer/mod.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index fbba96fbe99cf..df8119bfa54e3 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -918,7 +918,6 @@ pub struct CombinedSnapshot<'a, 'tcx> { region_obligations_snapshot: usize, universe: ty::UniverseIndex, was_in_snapshot: bool, - was_skip_leak_check: bool, _in_progress_tables: Option>>, } @@ -1056,7 +1055,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { region_obligations_snapshot: inner.region_obligations.len(), universe: self.universe(), was_in_snapshot: in_snapshot, - was_skip_leak_check: self.skip_leak_check.get(), // Borrow tables "in progress" (i.e., during typeck) // to ban writes from within a snapshot to them. _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()), @@ -1070,13 +1068,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { region_obligations_snapshot, universe, was_in_snapshot, - was_skip_leak_check, _in_progress_tables, } = snapshot; self.in_snapshot.set(was_in_snapshot); self.universe.set(universe); - self.skip_leak_check.set(was_skip_leak_check); let InferCtxtInner { type_variables, @@ -1110,12 +1106,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { region_obligations_snapshot: _, universe: _, was_in_snapshot, - was_skip_leak_check, _in_progress_tables, } = snapshot; self.in_snapshot.set(was_in_snapshot); - self.skip_leak_check.set(was_skip_leak_check); let mut inner = self.inner.borrow_mut(); inner.undo_log.commit(undo_snapshot); @@ -1183,10 +1177,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("probe()"); let snapshot = self.start_snapshot(); - let skip_leak_check = should_skip || self.skip_leak_check.get(); - self.skip_leak_check.set(skip_leak_check); + let was_skip_leak_check = self.skip_leak_check.get(); + if should_skip { + self.skip_leak_check.set(true); + } let r = f(&snapshot); self.rollback_to("probe", snapshot); + self.skip_leak_check.set(was_skip_leak_check); r } From f45d852dcc399991a3bcd2cf58921735e560b22c Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 14:45:07 +0100 Subject: [PATCH 09/22] perf: Merge region_obligations snapshotting into the undo log --- src/librustc_infer/infer/mod.rs | 33 +++++++++---------- .../infer/outlives/obligations.rs | 9 +++-- .../traits/auto_trait.rs | 2 +- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index df8119bfa54e3..e594bf450ddef 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -196,7 +196,7 @@ pub struct InferCtxtInner<'tcx> { /// for each body-id in this map, which will process the /// obligations within. This is expected to be done 'late enough' /// 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>)>, } impl<'tcx> InferCtxtInner<'tcx> { @@ -213,6 +213,10 @@ impl<'tcx> InferCtxtInner<'tcx> { } } + pub fn region_obligations(&self) -> &[(hir::HirId, RegionObligation<'tcx>)] { + &self.region_obligations + } + pub(crate) fn projection_cache(&mut self) -> traits::ProjectionCache<'tcx, '_> { self.projection_cache.with_log(&mut self.undo_log) } @@ -270,6 +274,7 @@ pub(crate) enum UndoLog<'tcx> { RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog>), ProjectionCache(traits::UndoLog<'tcx>), + PushRegionObligation, } impl<'tcx> From> for UndoLog<'tcx> { @@ -348,6 +353,7 @@ struct RollbackView<'tcx, 'a> { float_unification_table: &'a mut ut::UnificationStorage, region_constraints: &'a mut RegionConstraintStorage<'tcx>, projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>, + region_obligations: &'a mut Vec<(hir::HirId, RegionObligation<'tcx>)>, } impl<'tcx> Rollback> for RollbackView<'tcx, '_> { @@ -362,6 +368,9 @@ impl<'tcx> Rollback> for RollbackView<'tcx, '_> { self.region_constraints.unification_table.reverse(undo) } UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), + UndoLog::PushRegionObligation => { + self.region_obligations.pop(); + } } } } @@ -915,7 +924,6 @@ pub struct FullSnapshot<'a, 'tcx> { #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx> { undo_snapshot: Snapshot<'tcx>, - region_obligations_snapshot: usize, universe: ty::UniverseIndex, was_in_snapshot: bool, _in_progress_tables: Option>>, @@ -1052,7 +1060,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let undo_snapshot = Snapshot { undo_len: inner.undo_log.logs.len(), _marker: PhantomData }; CombinedSnapshot { undo_snapshot, - region_obligations_snapshot: inner.region_obligations.len(), universe: self.universe(), was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e., during typeck) @@ -1063,13 +1070,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("rollback_to(cause={})", cause); - let CombinedSnapshot { - undo_snapshot, - region_obligations_snapshot, - universe, - was_in_snapshot, - _in_progress_tables, - } = snapshot; + let CombinedSnapshot { undo_snapshot, universe, was_in_snapshot, _in_progress_tables } = + snapshot; self.in_snapshot.set(was_in_snapshot); self.universe.set(universe); @@ -1093,21 +1095,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { float_unification_table, region_constraints: region_constraints.as_mut().unwrap(), projection_cache, + region_obligations, }, undo_snapshot, ); - region_obligations.truncate(region_obligations_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("commit_from()"); - let CombinedSnapshot { - undo_snapshot, - region_obligations_snapshot: _, - universe: _, - was_in_snapshot, - _in_progress_tables, - } = snapshot; + let CombinedSnapshot { undo_snapshot, universe: _, was_in_snapshot, _in_progress_tables } = + snapshot; self.in_snapshot.set(was_in_snapshot); diff --git a/src/librustc_infer/infer/outlives/obligations.rs b/src/librustc_infer/infer/outlives/obligations.rs index c904926e9d93c..f068afc8dff14 100644 --- a/src/librustc_infer/infer/outlives/obligations.rs +++ b/src/librustc_infer/infer/outlives/obligations.rs @@ -61,7 +61,10 @@ use crate::infer::outlives::env::RegionBoundPairs; 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::rustc_data_structures::undo_log::UndoLogs; use crate::traits::ObligationCause; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::subst::GenericArgKind; @@ -84,7 +87,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) { 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( diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index 6326a87c5edc3..e19ddcd9e5e98 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -195,7 +195,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let body_id_map: FxHashMap<_, _> = infcx .inner .borrow() - .region_obligations + .region_obligations() .iter() .map(|&(id, _)| (id, vec![])) .collect(); From e6d7f1584d3107ae1de210619d05f3be0d023ae3 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 15:39:01 +0100 Subject: [PATCH 10/22] simplify --- src/librustc_infer/infer/mod.rs | 11 +++++------ src/librustc_infer/infer/type_variable.rs | 15 +-------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index e594bf450ddef..a2cf772e86ec1 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -347,7 +347,7 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable, &'a mut Logs<'tcx>>>; struct RollbackView<'tcx, 'a> { - type_variables: type_variable::RollbackView<'tcx, 'a>, + type_variables: &'a mut type_variable::TypeVariableStorage<'tcx>, const_unification_table: &'a mut ut::UnificationStorage>, int_unification_table: &'a mut ut::UnificationStorage, float_unification_table: &'a mut ut::UnificationStorage, @@ -420,7 +420,8 @@ impl<'tcx> Snapshots> for Logs<'tcx> { } fn start_snapshot(&mut self) -> Self::Snapshot { - unreachable!() + self.num_open_snapshots += 1; + Snapshot { undo_len: self.logs.len(), _marker: PhantomData } } fn rollback_to(&mut self, values: impl FnOnce() -> R, snapshot: Self::Snapshot) @@ -1056,10 +1057,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut inner = self.inner.borrow_mut(); - inner.undo_log.num_open_snapshots += 1; - let undo_snapshot = Snapshot { undo_len: inner.undo_log.logs.len(), _marker: PhantomData }; CombinedSnapshot { - undo_snapshot, + undo_snapshot: inner.undo_log.start_snapshot(), universe: self.universe(), was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e., during typeck) @@ -1089,7 +1088,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } = &mut *self.inner.borrow_mut(); undo_log.rollback_to( || RollbackView { - type_variables: type_variable::RollbackView::from(type_variables), + type_variables, const_unification_table, int_unification_table, float_unification_table, diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 3858c50b92c6a..26673cff1e8f6 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -43,20 +43,7 @@ impl<'tcx> From for UndoLog<'tcx> { } } -pub(crate) struct RollbackView<'tcx, 'a> { - pub(crate) eq_relations: &'a mut ut::UnificationStorage>, - pub(crate) sub_relations: &'a mut ut::UnificationStorage, - pub(crate) values: &'a mut Vec, -} - -impl<'tcx, 'a> From<&'a mut TypeVariableStorage<'tcx>> for RollbackView<'tcx, 'a> { - fn from(l: &'a mut TypeVariableStorage<'tcx>) -> Self { - let TypeVariableStorage { eq_relations, sub_relations, values } = l; - Self { eq_relations, sub_relations, values } - } -} - -impl<'tcx> Rollback> for RollbackView<'tcx, '_> { +impl<'tcx> Rollback> for TypeVariableStorage<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { match undo { UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo), From bc7f7b2d4d2ae25e6ce234ac4b03715b6979548b Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 16:41:29 +0100 Subject: [PATCH 11/22] refactor: Rename Logs to InferCtxtUndoLogs --- Cargo.lock | 12 ++++++- src/librustc_infer/infer/mod.rs | 34 ++++++++++++------- .../infer/region_constraints/mod.rs | 8 +++-- src/librustc_infer/infer/type_variable.rs | 10 +++--- src/librustc_infer/traits/project.rs | 13 ++++--- 5 files changed, 53 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5e25b0a2c722..45c298ea8bfcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -485,7 +485,7 @@ version = "0.0.212" dependencies = [ "cargo_metadata 0.9.1", "if_chain", - "itertools 0.8.0", + "itertools 0.9.0", "lazy_static 1.4.0", "pulldown-cmark 0.7.1", "quine-mc_cluskey", @@ -1629,6 +1629,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.4" @@ -2179,6 +2188,7 @@ dependencies = [ "rustc-workspace-hack", "rustc_version", "serde", + "serde_json", "shell-escape", "vergen", ] diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index a2cf772e86ec1..90bc1ddc3eb63 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -147,7 +147,6 @@ pub struct InferCtxtInner<'tcx> { /// that might instantiate a general type variable have an order, /// represented by its upper and lower bounds. type_variables: type_variable::TypeVariableStorage<'tcx>, - undo_log: Logs<'tcx>, /// Map from const parameter variable to the kind of const it represents. const_unification_table: ut::UnificationStorage>, @@ -197,6 +196,8 @@ pub struct InferCtxtInner<'tcx> { /// obligations within. This is expected to be done 'late enough' /// that all type inference variables have been bound and so forth. region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, + + undo_log: InferCtxtUndoLogs<'tcx>, } impl<'tcx> InferCtxtInner<'tcx> { @@ -204,7 +205,7 @@ impl<'tcx> InferCtxtInner<'tcx> { InferCtxtInner { projection_cache: Default::default(), type_variables: type_variable::TypeVariableStorage::new(), - undo_log: Logs::default(), + undo_log: InferCtxtUndoLogs::default(), const_unification_table: ut::UnificationStorage::new(), int_unification_table: ut::UnificationStorage::new(), float_unification_table: ut::UnificationStorage::new(), @@ -228,7 +229,11 @@ impl<'tcx> InferCtxtInner<'tcx> { fn int_unification_table( &mut self, ) -> ut::UnificationTable< - ut::InPlace, &mut Logs<'tcx>>, + ut::InPlace< + ty::IntVid, + &mut ut::UnificationStorage, + &mut InferCtxtUndoLogs<'tcx>, + >, > { ut::UnificationTable::with_log(&mut self.int_unification_table, &mut self.undo_log) } @@ -236,7 +241,11 @@ impl<'tcx> InferCtxtInner<'tcx> { fn float_unification_table( &mut self, ) -> ut::UnificationTable< - ut::InPlace, &mut Logs<'tcx>>, + ut::InPlace< + ty::FloatVid, + &mut ut::UnificationStorage, + &mut InferCtxtUndoLogs<'tcx>, + >, > { ut::UnificationTable::with_log(&mut self.float_unification_table, &mut self.undo_log) } @@ -247,7 +256,7 @@ impl<'tcx> InferCtxtInner<'tcx> { ut::InPlace< ty::ConstVid<'tcx>, &mut ut::UnificationStorage>, - &mut Logs<'tcx>, + &mut InferCtxtUndoLogs<'tcx>, >, > { ut::UnificationTable::with_log(&mut self.const_unification_table, &mut self.undo_log) @@ -343,8 +352,9 @@ impl<'tcx> From> for UndoLog<'tcx> { } } -pub(crate) type UnificationTable<'a, 'tcx, T> = - ut::UnificationTable, &'a mut Logs<'tcx>>>; +pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< + ut::InPlace, &'a mut InferCtxtUndoLogs<'tcx>>, +>; struct RollbackView<'tcx, 'a> { type_variables: &'a mut type_variable::TypeVariableStorage<'tcx>, @@ -375,18 +385,18 @@ impl<'tcx> Rollback> for RollbackView<'tcx, '_> { } } -pub(crate) struct Logs<'tcx> { +pub(crate) struct InferCtxtUndoLogs<'tcx> { logs: Vec>, num_open_snapshots: usize, } -impl Default for Logs<'_> { +impl Default for InferCtxtUndoLogs<'_> { fn default() -> Self { Self { logs: Default::default(), num_open_snapshots: Default::default() } } } -impl<'tcx, T> UndoLogs for Logs<'tcx> +impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> where UndoLog<'tcx>: From, { @@ -413,7 +423,7 @@ where } } -impl<'tcx> Snapshots> for Logs<'tcx> { +impl<'tcx> Snapshots> for InferCtxtUndoLogs<'tcx> { type Snapshot = Snapshot<'tcx>; fn actions_since_snapshot(&self, snapshot: &Self::Snapshot) -> &[UndoLog<'tcx>] { &self.logs[snapshot.undo_len..] @@ -464,7 +474,7 @@ impl<'tcx> Snapshots> for Logs<'tcx> { } } -impl<'tcx> Logs<'tcx> { +impl<'tcx> InferCtxtUndoLogs<'tcx> { pub(crate) fn region_constraints( &self, after: usize, diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 7b660ce436559..5f6f82ddaf980 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -4,7 +4,9 @@ use self::CombineMapType::*; use self::UndoLog::*; use super::unify_key; -use super::{Logs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin}; +use super::{ + InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; @@ -61,7 +63,7 @@ pub struct RegionConstraintStorage<'tcx> { pub struct RegionConstraintCollector<'tcx, 'a> { storage: &'a mut RegionConstraintStorage<'tcx>, - undo_log: &'a mut Logs<'tcx>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } impl std::ops::Deref for RegionConstraintCollector<'tcx, '_> { @@ -346,7 +348,7 @@ impl<'tcx> RegionConstraintStorage<'tcx> { pub(crate) fn with_log<'a>( &'a mut self, - undo_log: &'a mut Logs<'tcx>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, ) -> RegionConstraintCollector<'tcx, 'a> { RegionConstraintCollector { storage: self, undo_log } } diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 26673cff1e8f6..69afb605b344f 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::{self, Ty, TyVid}; use rustc_span::symbol::Symbol; use rustc_span::Span; -use crate::infer::Logs; +use crate::infer::InferCtxtUndoLogs; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; @@ -88,7 +88,7 @@ pub struct TypeVariableTable<'tcx, 'a> { sub_relations: &'a mut ut::UnificationStorage, - undo_log: &'a mut Logs<'tcx>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } #[derive(Copy, Clone, Debug)] @@ -167,7 +167,7 @@ impl<'tcx> TypeVariableStorage<'tcx> { pub(crate) fn with_log<'a>( &'a mut self, - undo_log: &'a mut Logs<'tcx>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, ) -> TypeVariableTable<'tcx, 'a> { let TypeVariableStorage { values, eq_relations, sub_relations } = self; TypeVariableTable { values, eq_relations, sub_relations, undo_log } @@ -327,7 +327,9 @@ impl<'tcx> TypeVariableTable<'tcx, '_> { Snapshot { value_count: self.eq_relations().len() as u32, _marker: PhantomData } } - fn values(&mut self) -> sv::SnapshotVec, &mut Logs<'tcx>> { + fn values( + &mut self, + ) -> sv::SnapshotVec, &mut InferCtxtUndoLogs<'tcx>> { sv::SnapshotVec::with_log(self.values, self.undo_log) } diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 0c51dafef6fb6..8cf3987b902ee 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -2,7 +2,7 @@ use super::PredicateObligation; -use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; +use rustc_data_structures::snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty}; @@ -63,7 +63,7 @@ impl<'tcx, T> Normalized<'tcx, T> { // reduce the amount of duplication. Let's see what we get with the Chalk reforms. pub struct ProjectionCache<'tcx, 'a> { map: &'a mut SnapshotMapStorage, ProjectionCacheEntry<'tcx>>, - undo_log: &'a mut Logs<'tcx>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } #[derive(Default)] @@ -93,7 +93,7 @@ pub enum ProjectionCacheEntry<'tcx> { impl<'tcx> ProjectionCacheStorage<'tcx> { pub(crate) fn with_log<'a>( &'a mut self, - undo_log: &'a mut Logs<'tcx>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, ) -> ProjectionCache<'tcx, 'a> { ProjectionCache { map: &mut self.map, undo_log } } @@ -102,7 +102,12 @@ impl<'tcx> ProjectionCacheStorage<'tcx> { impl<'tcx> ProjectionCache<'tcx, '_> { fn map( &mut self, - ) -> SnapshotMapRef<'_, ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>, Logs<'tcx>> { + ) -> SnapshotMapRef< + '_, + ProjectionCacheKey<'tcx>, + ProjectionCacheEntry<'tcx>, + InferCtxtUndoLogs<'tcx>, + > { self.map.with_log(self.undo_log) } From 204c9154e2ac43832cd12828216eff64810c50a7 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 17:09:01 +0100 Subject: [PATCH 12/22] refactor: Extract the undo log to its own modules --- src/librustc_infer/infer/mod.rs | 234 +--------------- .../infer/region_constraints/leak_check.rs | 2 +- .../infer/region_constraints/mod.rs | 7 +- src/librustc_infer/infer/undo_log.rs | 259 ++++++++++++++++++ 4 files changed, 272 insertions(+), 230 deletions(-) create mode 100644 src/librustc_infer/infer/undo_log.rs diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 90bc1ddc3eb63..7bf13c90bf736 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -6,13 +6,14 @@ pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; +pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; + use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs}; +use rustc_data_structures::undo_log::{Rollback, Snapshots}; use rustc_data_structures::unify as ut; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; @@ -69,6 +70,7 @@ pub mod region_constraints; pub mod resolve; mod sub; pub mod type_variable; +mod undo_log; use crate::infer::canonical::OriginalQueryValues; pub use rustc_middle::infer::unify_key; @@ -85,6 +87,10 @@ pub type Bound = Option; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type FixupResult<'tcx, T> = Result>; // "fixup result" +pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< + ut::InPlace, &'a mut InferCtxtUndoLogs<'tcx>>, +>; + /// How we should handle region solving. /// /// This is used so that the region values inferred by HIR region solving are @@ -270,228 +276,6 @@ impl<'tcx> InferCtxtInner<'tcx> { } } -pub struct Snapshot<'tcx> { - undo_len: usize, - _marker: PhantomData<&'tcx ()>, -} - -pub(crate) enum UndoLog<'tcx> { - TypeVariables(type_variable::UndoLog<'tcx>), - ConstUnificationTable(sv::UndoLog>>), - IntUnificationTable(sv::UndoLog>), - FloatUnificationTable(sv::UndoLog>), - RegionConstraintCollector(region_constraints::UndoLog<'tcx>), - RegionUnificationTable(sv::UndoLog>), - ProjectionCache(traits::UndoLog<'tcx>), - PushRegionObligation, -} - -impl<'tcx> From> for UndoLog<'tcx> { - fn from(l: region_constraints::UndoLog<'tcx>) -> Self { - UndoLog::RegionConstraintCollector(l) - } -} - -impl<'tcx> From>>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>>) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::EqRelation(l)) - } -} - -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::SubRelation(l)) - } -} - -impl<'tcx> From> for UndoLog<'tcx> { - fn from(l: sv::UndoLog) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::Values(l)) - } -} - -impl<'tcx> From for UndoLog<'tcx> { - fn from(l: type_variable::Instantiate) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::from(l)) - } -} - -impl From> for UndoLog<'tcx> { - fn from(t: type_variable::UndoLog<'tcx>) -> Self { - Self::TypeVariables(t) - } -} - -impl<'tcx> From>>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>>) -> Self { - Self::ConstUnificationTable(l) - } -} - -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - Self::IntUnificationTable(l) - } -} - -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - Self::FloatUnificationTable(l) - } -} - -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - Self::RegionUnificationTable(l) - } -} - -impl<'tcx> From> for UndoLog<'tcx> { - fn from(l: traits::UndoLog<'tcx>) -> Self { - Self::ProjectionCache(l) - } -} - -pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< - ut::InPlace, &'a mut InferCtxtUndoLogs<'tcx>>, ->; - -struct RollbackView<'tcx, 'a> { - type_variables: &'a mut type_variable::TypeVariableStorage<'tcx>, - const_unification_table: &'a mut ut::UnificationStorage>, - int_unification_table: &'a mut ut::UnificationStorage, - float_unification_table: &'a mut ut::UnificationStorage, - region_constraints: &'a mut RegionConstraintStorage<'tcx>, - projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>, - region_obligations: &'a mut Vec<(hir::HirId, RegionObligation<'tcx>)>, -} - -impl<'tcx> Rollback> for RollbackView<'tcx, '_> { - fn reverse(&mut self, undo: UndoLog<'tcx>) { - match undo { - UndoLog::TypeVariables(undo) => self.type_variables.reverse(undo), - UndoLog::ConstUnificationTable(undo) => self.const_unification_table.reverse(undo), - UndoLog::IntUnificationTable(undo) => self.int_unification_table.reverse(undo), - UndoLog::FloatUnificationTable(undo) => self.float_unification_table.reverse(undo), - UndoLog::RegionConstraintCollector(undo) => self.region_constraints.reverse(undo), - UndoLog::RegionUnificationTable(undo) => { - self.region_constraints.unification_table.reverse(undo) - } - UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), - UndoLog::PushRegionObligation => { - self.region_obligations.pop(); - } - } - } -} - -pub(crate) struct InferCtxtUndoLogs<'tcx> { - logs: Vec>, - num_open_snapshots: usize, -} - -impl Default for InferCtxtUndoLogs<'_> { - fn default() -> Self { - Self { logs: Default::default(), num_open_snapshots: Default::default() } - } -} - -impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> -where - UndoLog<'tcx>: From, -{ - 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(&mut self, undos: J) - where - Self: Sized, - J: IntoIterator, - { - if self.in_snapshot() { - self.logs.extend(undos.into_iter().map(UndoLog::from)) - } - } -} - -impl<'tcx> Snapshots> for InferCtxtUndoLogs<'tcx> { - type Snapshot = Snapshot<'tcx>; - fn actions_since_snapshot(&self, snapshot: &Self::Snapshot) -> &[UndoLog<'tcx>] { - &self.logs[snapshot.undo_len..] - } - - fn start_snapshot(&mut self) -> Self::Snapshot { - self.num_open_snapshots += 1; - Snapshot { undo_len: self.logs.len(), _marker: PhantomData } - } - - fn rollback_to(&mut self, values: impl FnOnce() -> R, snapshot: Self::Snapshot) - where - R: Rollback>, - { - debug!("rollback_to({})", snapshot.undo_len); - self.assert_open_snapshot(&snapshot); - - if self.logs.len() > snapshot.undo_len { - let mut values = values(); - while self.logs.len() > snapshot.undo_len { - values.reverse(self.logs.pop().unwrap()); - } - } - - 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.undo_len == 0); - self.logs.clear(); - } - - self.num_open_snapshots -= 1; - } - - fn commit(&mut self, snapshot: Self::Snapshot) { - debug!("commit({})", snapshot.undo_len); - - 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.undo_len == 0); - self.logs.clear(); - } - - self.num_open_snapshots -= 1; - } -} - -impl<'tcx> InferCtxtUndoLogs<'tcx> { - pub(crate) fn region_constraints( - &self, - after: usize, - ) -> impl Iterator> + Clone { - self.logs[after..].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 struct InferCtxt<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, @@ -1097,7 +881,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .. } = &mut *self.inner.borrow_mut(); undo_log.rollback_to( - || RollbackView { + || undo_log::RollbackView { type_variables, const_unification_table, int_unification_table, diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 0178fa2eae6ee..480a5cb4dccee 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -48,7 +48,7 @@ impl<'tcx> RegionConstraintCollector<'tcx, '_> { let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region); taint_set.fixed_point( tcx, - self.undo_log.region_constraints(0), + self.undo_log.region_constraints(), &self.storage.data.verifys, ); let tainted_regions = taint_set.into_set(); diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 5f6f82ddaf980..ead2494756ce2 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -500,7 +500,6 @@ impl<'tcx> RegionConstraintCollector<'tcx, '_> { let constraints_to_kill: Vec = self .undo_log - .logs .iter() .enumerate() .rev() @@ -514,7 +513,7 @@ impl<'tcx> RegionConstraintCollector<'tcx, '_> { .collect(); for index in constraints_to_kill { - let undo_entry = match &mut self.undo_log.logs[index] { + let undo_entry = match &mut self.undo_log[index] { super::UndoLog::RegionConstraintCollector(undo_entry) => { mem::replace(undo_entry, Purged) } @@ -790,9 +789,9 @@ impl<'tcx> RegionConstraintCollector<'tcx, '_> { } /// See [`RegionInference::region_constraints_added_in_snapshot`]. - pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'_>) -> Option { + pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> Option { self.undo_log - .region_constraints(mark.undo_len) + .region_constraints_in_snapshot(mark) .map(|&elt| match elt { AddConstraint(constraint) => Some(constraint.involves_placeholders()), _ => None, diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs new file mode 100644 index 0000000000000..beb71e9e2e865 --- /dev/null +++ b/src/librustc_infer/infer/undo_log.rs @@ -0,0 +1,259 @@ +use std::marker::PhantomData; + +use rustc::ty; +use rustc_data_structures::snapshot_vec as sv; +use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs}; +use rustc_data_structures::unify as ut; +use rustc_hir as hir; + +use crate::{ + infer::{ + region_constraints::{self, RegionConstraintStorage}, + type_variable, RegionObligation, + }, + traits, +}; + +pub struct Snapshot<'tcx> { + pub(crate) undo_len: usize, + _marker: PhantomData<&'tcx ()>, +} + +pub(crate) enum UndoLog<'tcx> { + TypeVariables(type_variable::UndoLog<'tcx>), + ConstUnificationTable(sv::UndoLog>>), + IntUnificationTable(sv::UndoLog>), + FloatUnificationTable(sv::UndoLog>), + RegionConstraintCollector(region_constraints::UndoLog<'tcx>), + RegionUnificationTable(sv::UndoLog>), + ProjectionCache(traits::UndoLog<'tcx>), + PushRegionObligation, +} + +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: region_constraints::UndoLog<'tcx>) -> Self { + UndoLog::RegionConstraintCollector(l) + } +} + +impl<'tcx> From>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>>) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::EqRelation(l)) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::SubRelation(l)) + } +} + +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: sv::UndoLog) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::Values(l)) + } +} + +impl<'tcx> From for UndoLog<'tcx> { + fn from(l: type_variable::Instantiate) -> Self { + UndoLog::TypeVariables(type_variable::UndoLog::from(l)) + } +} + +impl From> for UndoLog<'tcx> { + fn from(t: type_variable::UndoLog<'tcx>) -> Self { + Self::TypeVariables(t) + } +} + +impl<'tcx> From>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>>) -> Self { + Self::ConstUnificationTable(l) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + Self::IntUnificationTable(l) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + Self::FloatUnificationTable(l) + } +} + +impl<'tcx> From>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog>) -> Self { + Self::RegionUnificationTable(l) + } +} + +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: traits::UndoLog<'tcx>) -> Self { + Self::ProjectionCache(l) + } +} + +pub(super) struct RollbackView<'tcx, 'a> { + pub(super) type_variables: &'a mut type_variable::TypeVariableStorage<'tcx>, + pub(super) const_unification_table: &'a mut ut::UnificationStorage>, + pub(super) int_unification_table: &'a mut ut::UnificationStorage, + pub(super) float_unification_table: &'a mut ut::UnificationStorage, + pub(super) region_constraints: &'a mut RegionConstraintStorage<'tcx>, + pub(super) projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>, + pub(super) region_obligations: &'a mut Vec<(hir::HirId, RegionObligation<'tcx>)>, +} + +impl<'tcx> Rollback> for RollbackView<'tcx, '_> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + match undo { + UndoLog::TypeVariables(undo) => self.type_variables.reverse(undo), + UndoLog::ConstUnificationTable(undo) => self.const_unification_table.reverse(undo), + UndoLog::IntUnificationTable(undo) => self.int_unification_table.reverse(undo), + UndoLog::FloatUnificationTable(undo) => self.float_unification_table.reverse(undo), + UndoLog::RegionConstraintCollector(undo) => self.region_constraints.reverse(undo), + UndoLog::RegionUnificationTable(undo) => { + self.region_constraints.unification_table.reverse(undo) + } + UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), + UndoLog::PushRegionObligation => { + self.region_obligations.pop(); + } + } + } +} + +pub(crate) struct InferCtxtUndoLogs<'tcx> { + logs: Vec>, + num_open_snapshots: usize, +} + +impl Default for InferCtxtUndoLogs<'_> { + fn default() -> Self { + Self { logs: Default::default(), num_open_snapshots: Default::default() } + } +} + +impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> +where + UndoLog<'tcx>: From, +{ + 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(&mut self, undos: J) + where + Self: Sized, + J: IntoIterator, + { + if self.in_snapshot() { + self.logs.extend(undos.into_iter().map(UndoLog::from)) + } + } +} + +impl<'tcx> Snapshots> for InferCtxtUndoLogs<'tcx> { + type Snapshot = Snapshot<'tcx>; + fn actions_since_snapshot(&self, snapshot: &Self::Snapshot) -> &[UndoLog<'tcx>] { + &self.logs[snapshot.undo_len..] + } + + fn start_snapshot(&mut self) -> Self::Snapshot { + self.num_open_snapshots += 1; + Snapshot { undo_len: self.logs.len(), _marker: PhantomData } + } + + fn rollback_to(&mut self, values: impl FnOnce() -> R, snapshot: Self::Snapshot) + where + R: Rollback>, + { + debug!("rollback_to({})", snapshot.undo_len); + self.assert_open_snapshot(&snapshot); + + if self.logs.len() > snapshot.undo_len { + let mut values = values(); + while self.logs.len() > snapshot.undo_len { + values.reverse(self.logs.pop().unwrap()); + } + } + + 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.undo_len == 0); + self.logs.clear(); + } + + self.num_open_snapshots -= 1; + } + + fn commit(&mut self, snapshot: Self::Snapshot) { + debug!("commit({})", snapshot.undo_len); + + 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.undo_len == 0); + self.logs.clear(); + } + + self.num_open_snapshots -= 1; + } +} + +impl<'tcx> InferCtxtUndoLogs<'tcx> { + pub(crate) fn region_constraints_in_snapshot( + &self, + s: &Snapshot<'tcx>, + ) -> impl Iterator> + 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> + 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 for InferCtxtUndoLogs<'tcx> { + type Output = UndoLog<'tcx>; + fn index(&self, key: usize) -> &Self::Output { + &self.logs[key] + } +} + +impl<'tcx> std::ops::IndexMut for InferCtxtUndoLogs<'tcx> { + fn index_mut(&mut self, key: usize) -> &mut Self::Output { + &mut self.logs[key] + } +} From 6e06535468932c2dd9e5731d40fe94fe913bf2e4 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 25 Feb 2020 23:08:29 +0100 Subject: [PATCH 13/22] Fix import --- src/librustc_infer/infer/outlives/obligations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_infer/infer/outlives/obligations.rs b/src/librustc_infer/infer/outlives/obligations.rs index f068afc8dff14..48f6d937f2f7a 100644 --- a/src/librustc_infer/infer/outlives/obligations.rs +++ b/src/librustc_infer/infer/outlives/obligations.rs @@ -64,13 +64,13 @@ use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::{ self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, }; -use crate::rustc_data_structures::undo_log::UndoLogs; use crate::traits::ObligationCause; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::undo_log::UndoLogs; use rustc_hir as hir; use smallvec::smallvec; From 729d16f0104887a0b37b8e5bb9f0f495e4efdd10 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Wed, 26 Feb 2020 10:43:24 +0100 Subject: [PATCH 14/22] Prevent modifications without an undo log --- src/librustc_infer/infer/mod.rs | 12 ++++---- .../infer/region_constraints/mod.rs | 2 +- src/librustc_infer/infer/type_variable.rs | 30 +++++++++---------- src/librustc_infer/infer/undo_log.rs | 6 ++-- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 7bf13c90bf736..93b6a0220bf06 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -155,13 +155,13 @@ pub struct InferCtxtInner<'tcx> { type_variables: type_variable::TypeVariableStorage<'tcx>, /// Map from const parameter variable to the kind of const it represents. - const_unification_table: ut::UnificationStorage>, + const_unification_table: ut::UnificationTableStorage>, /// Map from integral variable to the kind of integer it represents. - int_unification_table: ut::UnificationStorage, + int_unification_table: ut::UnificationTableStorage, /// Map from floating variable to the kind of float it represents. - float_unification_table: ut::UnificationStorage, + float_unification_table: ut::UnificationTableStorage, /// Tracks the set of region variables and the constraints between them. /// This is initially `Some(_)` but when @@ -212,9 +212,9 @@ impl<'tcx> InferCtxtInner<'tcx> { projection_cache: Default::default(), type_variables: type_variable::TypeVariableStorage::new(), undo_log: InferCtxtUndoLogs::default(), - const_unification_table: ut::UnificationStorage::new(), - int_unification_table: ut::UnificationStorage::new(), - float_unification_table: ut::UnificationStorage::new(), + const_unification_table: ut::UnificationTableStorage::new(), + int_unification_table: ut::UnificationTableStorage::new(), + float_unification_table: ut::UnificationTableStorage::new(), region_constraints: Some(RegionConstraintStorage::new()), region_obligations: vec![], } diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index ead2494756ce2..74d31e744fc18 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -54,7 +54,7 @@ pub struct RegionConstraintStorage<'tcx> { /// is iterating to a fixed point, because otherwise we sometimes /// would wind up with a fresh stream of region variables that /// have been equated but appear distinct. - pub(super) unification_table: ut::UnificationStorage, + pub(super) unification_table: ut::UnificationTableStorage, /// a flag set to true when we perform any unifications; this is used /// to micro-optimize `take_and_reset_data` diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 69afb605b344f..78803eea3bc68 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -54,12 +54,12 @@ impl<'tcx> Rollback> for TypeVariableStorage<'tcx> { } pub struct TypeVariableStorage<'tcx> { - values: Vec, + values: sv::SnapshotVecStorage, /// Two variables are unified in `eq_relations` when we have a /// constraint `?X == ?Y`. This table also stores, for each key, /// the known value. - eq_relations: ut::UnificationStorage>, + eq_relations: ut::UnificationTableStorage>, /// Two variables are unified in `sub_relations` when we have a /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second @@ -78,15 +78,15 @@ pub struct TypeVariableStorage<'tcx> { /// This is reasonable because, in Rust, subtypes have the same /// "skeleton" and hence there is no possible type such that /// (e.g.) `Box <: ?3` for any `?3`. - sub_relations: ut::UnificationStorage, + sub_relations: ut::UnificationTableStorage, } pub struct TypeVariableTable<'tcx, 'a> { - values: &'a mut Vec, + values: &'a mut sv::SnapshotVecStorage, - eq_relations: &'a mut ut::UnificationStorage>, + eq_relations: &'a mut ut::UnificationTableStorage>, - sub_relations: &'a mut ut::UnificationStorage, + sub_relations: &'a mut ut::UnificationTableStorage, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } @@ -159,9 +159,9 @@ pub(crate) struct Delegate; impl<'tcx> TypeVariableStorage<'tcx> { pub fn new() -> TypeVariableStorage<'tcx> { TypeVariableStorage { - values: Vec::new(), - eq_relations: ut::UnificationStorage::new(), - sub_relations: ut::UnificationStorage::new(), + values: sv::SnapshotVecStorage::new(), + eq_relations: ut::UnificationTableStorage::new(), + sub_relations: ut::UnificationTableStorage::new(), } } @@ -180,7 +180,7 @@ impl<'tcx> TypeVariableTable<'tcx, '_> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_diverges(&self, vid: ty::TyVid) -> bool { - self.values.get(vid.index as usize).unwrap().diverging + self.values.get(vid.index as usize).diverging } /// Returns the origin that was given when `vid` was created. @@ -188,7 +188,7 @@ impl<'tcx> TypeVariableTable<'tcx, '_> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.values.get(vid.index as usize).unwrap().origin + &self.values.get(vid.index as usize).origin } /// Records that `a == b`, depending on `dir`. @@ -330,15 +330,15 @@ impl<'tcx> TypeVariableTable<'tcx, '_> { fn values( &mut self, ) -> sv::SnapshotVec, &mut InferCtxtUndoLogs<'tcx>> { - sv::SnapshotVec::with_log(self.values, self.undo_log) + self.values.with_log(self.undo_log) } fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> { - ut::UnificationTable::with_log(self.eq_relations, self.undo_log) + self.eq_relations.with_log(self.undo_log) } fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> { - ut::UnificationTable::with_log(self.sub_relations, self.undo_log) + self.sub_relations.with_log(self.undo_log) } /// Returns a range of the type variables created during the snapshot. @@ -351,7 +351,7 @@ impl<'tcx> TypeVariableTable<'tcx, '_> { ( range.start..range.end, (range.start.index..range.end.index) - .map(|index| self.values.get(index as usize).unwrap().origin) + .map(|index| self.values.get(index as usize).origin) .collect(), ) } diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index beb71e9e2e865..a63f1b030bb7e 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -98,9 +98,9 @@ impl<'tcx> From> for UndoLog<'tcx> { pub(super) struct RollbackView<'tcx, 'a> { pub(super) type_variables: &'a mut type_variable::TypeVariableStorage<'tcx>, - pub(super) const_unification_table: &'a mut ut::UnificationStorage>, - pub(super) int_unification_table: &'a mut ut::UnificationStorage, - pub(super) float_unification_table: &'a mut ut::UnificationStorage, + pub(super) const_unification_table: &'a mut ut::UnificationTableStorage>, + pub(super) int_unification_table: &'a mut ut::UnificationTableStorage, + pub(super) float_unification_table: &'a mut ut::UnificationTableStorage, pub(super) region_constraints: &'a mut RegionConstraintStorage<'tcx>, pub(super) projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>, pub(super) region_obligations: &'a mut Vec<(hir::HirId, RegionObligation<'tcx>)>, From fba241fc6690527a3aad4bee98aca00a7c0907ad Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 3 Mar 2020 10:23:04 +0100 Subject: [PATCH 15/22] refactor: simplify --- src/librustc_infer/infer/fudge.rs | 10 +++++----- src/librustc_infer/infer/mod.rs | 19 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index a105a7704fab8..ccc4a73d40f67 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -24,9 +24,9 @@ where fn const_vars_since_snapshot<'tcx>( table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>, - snapshot: usize, + snapshot_var_len: usize, ) -> (Range>, Vec) { - let range = vars_since_snapshot(table, snapshot); + let range = vars_since_snapshot(table, snapshot_var_len); ( range.start..range.end, (range.start.index..range.end.index) @@ -98,18 +98,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { inner.type_variables().vars_since_snapshot(&snapshot.type_snapshot); let int_vars = vars_since_snapshot( &mut inner.int_unification_table(), - snapshot.int_snapshot, + snapshot.int_var_len, ); let float_vars = vars_since_snapshot( &mut inner.float_unification_table(), - snapshot.float_snapshot, + snapshot.float_var_len, ); let region_vars = inner .unwrap_region_constraints() .vars_since_snapshot(&snapshot.region_constraints_snapshot); let const_vars = const_vars_since_snapshot( &mut inner.const_unification_table(), - snapshot.const_snapshot, + snapshot.const_var_len, ); let fudger = InferenceFudger { diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 93b6a0220bf06..1210d56131162 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -39,7 +39,6 @@ use rustc_span::Span; use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeMap; use std::fmt; -use std::marker::PhantomData; use self::combine::CombineFields; use self::free_regions::RegionRelations; @@ -241,7 +240,7 @@ impl<'tcx> InferCtxtInner<'tcx> { &mut InferCtxtUndoLogs<'tcx>, >, > { - ut::UnificationTable::with_log(&mut self.int_unification_table, &mut self.undo_log) + self.int_unification_table.with_log(&mut self.undo_log) } fn float_unification_table( @@ -253,7 +252,7 @@ impl<'tcx> InferCtxtInner<'tcx> { &mut InferCtxtUndoLogs<'tcx>, >, > { - ut::UnificationTable::with_log(&mut self.float_unification_table, &mut self.undo_log) + self.float_unification_table.with_log(&mut self.undo_log) } fn const_unification_table( @@ -265,7 +264,7 @@ impl<'tcx> InferCtxtInner<'tcx> { &mut InferCtxtUndoLogs<'tcx>, >, > { - ut::UnificationTable::with_log(&mut self.const_unification_table, &mut self.undo_log) + self.const_unification_table.with_log(&mut self.undo_log) } pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> { @@ -711,9 +710,9 @@ pub struct FullSnapshot<'a, 'tcx> { snapshot: CombinedSnapshot<'a, 'tcx>, region_constraints_snapshot: RegionSnapshot, type_snapshot: type_variable::Snapshot<'tcx>, - const_snapshot: usize, - int_snapshot: usize, - float_snapshot: usize, + const_var_len: usize, + int_var_len: usize, + float_var_len: usize, } #[must_use = "once you start a snapshot, you should always consume it"] @@ -837,9 +836,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { FullSnapshot { snapshot, type_snapshot: inner.type_variables().snapshot(), - const_snapshot: inner.const_unification_table().len(), - int_snapshot: inner.int_unification_table().len(), - float_snapshot: inner.float_unification_table().len(), + 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_snapshot: inner.unwrap_region_constraints().start_snapshot(), } } From b61a28b2a1db297ed3bd15a3c5ac5c8c40feb586 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Mon, 16 Mar 2020 16:43:03 +0100 Subject: [PATCH 16/22] Rebase and use ena 0.14 --- src/librustc_infer/infer/mod.rs | 39 ++++++++++--------- src/librustc_infer/infer/undo_log.rs | 2 +- src/librustc_infer/traits/mod.rs | 2 +- src/librustc_infer/traits/project.rs | 8 +++- src/librustc_middle/hir/map/mod.rs | 24 ++++++------ src/librustc_middle/hir/mod.rs | 6 +-- src/librustc_middle/query/mod.rs | 4 +- .../traits/fulfill.rs | 26 ++++++++----- .../traits/project.rs | 12 +++--- src/test/ui/issues/issue-70041.rs | 2 + 10 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 1210d56131162..0e0ab8550c6e5 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -223,7 +223,7 @@ impl<'tcx> InferCtxtInner<'tcx> { &self.region_obligations } - pub(crate) fn projection_cache(&mut self) -> traits::ProjectionCache<'tcx, '_> { + pub fn projection_cache(&mut self) -> traits::ProjectionCache<'tcx, '_> { self.projection_cache.with_log(&mut self.undo_log) } @@ -1308,19 +1308,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { outlives_env: &OutlivesEnvironment<'tcx>, mode: RegionckMode, ) { - assert!( - self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(), - "region_obligations not empty: {:#?}", - self.inner.borrow().region_obligations - ); - let (var_infos, data) = self - .inner - .borrow_mut() - .region_constraints - .take() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data(); + let (var_infos, data) = { + let mut inner = self.inner.borrow_mut(); + let inner = &mut *inner; + assert!( + self.is_tainted_by_errors() || inner.region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + inner.region_obligations + ); + inner + .region_constraints + .take() + .expect("regions already resolved") + .with_log(&mut inner.undo_log) + .into_infos_and_data() + }; let region_rels = &RegionRelations::new( self.tcx, @@ -1686,13 +1688,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// having to resort to storing full `GenericArg`s in `stalled_on`. #[inline(always)] pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool { + let mut inner = self.inner.borrow_mut(); match infer_var { TyOrConstInferVar::Ty(v) => { use self::type_variable::TypeVariableValue; // If `inlined_probe` returns a `Known` value, it never equals // `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::Known { .. } => true, } @@ -1702,7 +1705,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // If `inlined_probe_value` returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which never matches a // `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) => { @@ -1710,7 +1713,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `ty::Float(_)`, which never matches a `ty::Infer(_)`. // // 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) => { @@ -1718,7 +1721,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `ty::ConstKind::Infer(ty::InferConst::Var(v))`. // // 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::Known { .. } => true, } diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index a63f1b030bb7e..0d94e32754ac8 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -1,10 +1,10 @@ use std::marker::PhantomData; -use rustc::ty; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs}; use rustc_data_structures::unify as ut; use rustc_hir as hir; +use rustc_middle::ty; use crate::{ infer::{ diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 640ea7774cd33..a8585fd293518 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -23,7 +23,7 @@ pub use self::project::MismatchedProjectionTypes; pub(crate) use self::project::UndoLog; pub use self::project::{ Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, - ProjectionCacheSnapshot, Reveal, + ProjectionCacheStorage, Reveal, }; crate use self::util::elaborate_predicates; diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 8cf3987b902ee..17bc54eed40df 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -2,8 +2,12 @@ use super::PredicateObligation; -use rustc_data_structures::snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage}; -use rustc_middle::ty::fold::TypeFoldable; +use crate::infer::InferCtxtUndoLogs; + +use rustc_data_structures::{ + snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage}, + undo_log::Rollback, +}; use rustc_middle::ty::{self, Ty}; pub use rustc_middle::traits::Reveal; diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index 971bfd0281eb5..1c71fc57bea5a 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -311,16 +311,19 @@ impl<'hir> Map<'hir> { } fn find_entry(&self, id: HirId) -> Option> { - if id.local_id == ItemLocalId::from_u32_const(0) { - let owner = self.tcx.hir_owner(id.owner_def_id()); + if id.local_id == ItemLocalId::from_u32(0) { + let owner = self.tcx.hir_owner(id.owner); owner.map(|owner| Entry { parent: owner.parent, node: owner.node }) } else { - let owner = self.tcx.hir_owner_items(id.owner_def_id()); + let owner = self.tcx.hir_owner_nodes(id.owner); owner.and_then(|owner| { - let item = owner.items[id.local_id].as_ref(); - item.map(|item| Entry { - parent: HirId { owner: id.owner, local_id: item.parent }, - node: item.node, + let node = owner.nodes[id.local_id].as_ref(); + // FIXME(eddyb) use a single generic type insted of having both + // `Entry` and `ParentedNode`, which are effectively the same. + // Alternatively, rewrite code using `Entry` to use `ParentedNode`. + node.map(|node| Entry { + parent: HirId { owner: id.owner, local_id: node.parent }, + node: node.node, }) }) } @@ -352,12 +355,7 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body<'hir> { - self.tcx - .hir_owner_items(DefId::local(id.hir_id.owner)) - .unwrap() - .bodies - .get(&id.hir_id.local_id) - .unwrap() + self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap() } pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { diff --git a/src/librustc_middle/hir/mod.rs b/src/librustc_middle/hir/mod.rs index 3d84bbd7062f0..7ab66411b2109 100644 --- a/src/librustc_middle/hir/mod.rs +++ b/src/librustc_middle/hir/mod.rs @@ -77,8 +77,8 @@ pub fn provide(providers: &mut Providers<'_>) { let module = hir.as_local_hir_id(id); &tcx.untracked_crate.modules[&module] }; - providers.hir_owner = |tcx, id| tcx.index_hir(id.krate).map[id.index].signature; - providers.hir_owner_items = - |tcx, id| tcx.index_hir(id.krate).map[id.index].with_bodies.as_ref().map(|items| &**items); + providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature; + providers.hir_owner_nodes = + |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_ref().map(|nodes| &**nodes); map::provide(providers); } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 8c437ca690770..b0c442381484c 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -75,7 +75,7 @@ rustc_queries! { // // This can be conveniently accessed by methods on `tcx.hir()`. // Avoid calling this query directly. - query hir_owner(key: DefId) -> Option<&'tcx HirOwner<'tcx>> { + query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -84,7 +84,7 @@ rustc_queries! { // // This can be conveniently accessed by methods on `tcx.hir()`. // Avoid calling this query directly. - query hir_owner_items(key: DefId) -> Option<&'tcx HirOwnerItems<'tcx>> { + query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { eval_always desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } } diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 300acf95c9973..1e056c96acd38 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -240,9 +240,15 @@ struct FulfillProcessor<'a, 'b, 'tcx> { register_region_obligations: bool, } -fn mk_pending(os: Vec>) -> Vec> { +fn mk_pending( + infcx: &InferCtxt<'_, 'tcx>, + os: Vec>, +) -> Vec> { 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() } @@ -312,6 +318,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); + let infcx = self.selcx.infcx(); + match obligation.predicate { ty::Predicate::Trait(ref 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() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) { + if infcx.predicate_must_hold_considering_regions(&obligation) { debug!( "selecting trait `{:?}` at depth {} evaluated to holds", 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)", data, obligation.recursion_depth ); - ProcessResult::Changed(mk_pending(vtable.nested_obligations())) + ProcessResult::Changed(mk_pending(infcx, vtable.nested_obligations())) } Ok(None) => { debug!( @@ -351,7 +359,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { debug!( "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 ); @@ -369,7 +377,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } 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![]), 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)); 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)), } } @@ -467,7 +475,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()]; 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 } - Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Some(Ok(ok)) => ProcessResult::Changed(mk_pending(infcx, ok.obligations)), Some(Err(err)) => { let expected_found = ExpectedFound::new( subtype.skip_binder().a_is_expected, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 2b4a0409fd1e2..7536b444351f2 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -471,7 +471,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // bounds. It might be the case that we want two distinct caches, // 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 { Ok(()) => {} 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 // can ignore the `obligations` from that point on. 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`. } else { 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); - 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); Some(result.value) } @@ -615,7 +615,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( projected_ty ); 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`. Some(result.value) } @@ -624,7 +624,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( "opt_normalize_projection_type: \ too many candidates" ); - infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key); + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); None } 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 // 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); obligations.extend(result.obligations); Some(result.value) diff --git a/src/test/ui/issues/issue-70041.rs b/src/test/ui/issues/issue-70041.rs index e45e16418e144..22e42295eedf3 100644 --- a/src/test/ui/issues/issue-70041.rs +++ b/src/test/ui/issues/issue-70041.rs @@ -2,10 +2,12 @@ // run-pass macro_rules! regex { + //~^ WARN unused macro definition () => {}; } #[allow(dead_code)] use regex; +//~^ WARN unused import fn main() {} From bc2fc7fb80d6f55a018e24de07d1ebdbc79d9136 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Fri, 17 Apr 2020 08:54:28 +0200 Subject: [PATCH 17/22] Fix review comments --- src/librustc_infer/infer/mod.rs | 57 +++++---------- src/librustc_infer/infer/type_variable.rs | 8 +-- src/librustc_infer/infer/undo_log.rs | 85 +++++++++-------------- src/librustc_infer/traits/project.rs | 6 +- 4 files changed, 58 insertions(+), 98 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 0e0ab8550c6e5..67d330ac89255 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -13,7 +13,7 @@ use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::undo_log::{Rollback, Snapshots}; +use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; @@ -151,16 +151,16 @@ pub struct InferCtxtInner<'tcx> { /// We instantiate `UnificationTable` with `bounds` because the types /// that might instantiate a general type variable have an order, /// represented by its upper and lower bounds. - type_variables: type_variable::TypeVariableStorage<'tcx>, + type_variable_storage: type_variable::TypeVariableStorage<'tcx>, /// Map from const parameter variable to the kind of const it represents. - const_unification_table: ut::UnificationTableStorage>, + const_unification_storage: ut::UnificationTableStorage>, /// Map from integral variable to the kind of integer it represents. - int_unification_table: ut::UnificationTableStorage, + int_unification_storage: ut::UnificationTableStorage, /// Map from floating variable to the kind of float it represents. - float_unification_table: ut::UnificationTableStorage, + float_unification_storage: ut::UnificationTableStorage, /// Tracks the set of region variables and the constraints between them. /// This is initially `Some(_)` but when @@ -209,11 +209,11 @@ impl<'tcx> InferCtxtInner<'tcx> { fn new() -> InferCtxtInner<'tcx> { InferCtxtInner { projection_cache: Default::default(), - type_variables: type_variable::TypeVariableStorage::new(), + type_variable_storage: type_variable::TypeVariableStorage::new(), undo_log: InferCtxtUndoLogs::default(), - const_unification_table: ut::UnificationTableStorage::new(), - int_unification_table: ut::UnificationTableStorage::new(), - float_unification_table: ut::UnificationTableStorage::new(), + const_unification_storage: ut::UnificationTableStorage::new(), + int_unification_storage: ut::UnificationTableStorage::new(), + float_unification_storage: ut::UnificationTableStorage::new(), region_constraints: Some(RegionConstraintStorage::new()), region_obligations: vec![], } @@ -223,12 +223,12 @@ impl<'tcx> InferCtxtInner<'tcx> { &self.region_obligations } - pub fn projection_cache(&mut self) -> traits::ProjectionCache<'tcx, '_> { + 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_variables.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( @@ -240,7 +240,7 @@ impl<'tcx> InferCtxtInner<'tcx> { &mut InferCtxtUndoLogs<'tcx>, >, > { - self.int_unification_table.with_log(&mut self.undo_log) + self.int_unification_storage.with_log(&mut self.undo_log) } fn float_unification_table( @@ -252,7 +252,7 @@ impl<'tcx> InferCtxtInner<'tcx> { &mut InferCtxtUndoLogs<'tcx>, >, > { - self.float_unification_table.with_log(&mut self.undo_log) + self.float_unification_storage.with_log(&mut self.undo_log) } fn const_unification_table( @@ -264,7 +264,7 @@ impl<'tcx> InferCtxtInner<'tcx> { &mut InferCtxtUndoLogs<'tcx>, >, > { - self.const_unification_table.with_log(&mut self.undo_log) + self.const_unification_storage.with_log(&mut self.undo_log) } pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> { @@ -868,29 +868,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.in_snapshot.set(was_in_snapshot); self.universe.set(universe); - let InferCtxtInner { - type_variables, - const_unification_table, - int_unification_table, - float_unification_table, - region_constraints, - projection_cache, - region_obligations, - undo_log, - .. - } = &mut *self.inner.borrow_mut(); - undo_log.rollback_to( - || undo_log::RollbackView { - type_variables, - const_unification_table, - int_unification_table, - float_unification_table, - region_constraints: region_constraints.as_mut().unwrap(), - projection_cache, - region_obligations, - }, - undo_snapshot, - ); + self.inner.borrow_mut().rollback_to(undo_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { @@ -900,8 +878,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.in_snapshot.set(was_in_snapshot); - let mut inner = self.inner.borrow_mut(); - inner.undo_log.commit(undo_snapshot); + self.inner.borrow_mut().commit(undo_snapshot); } /// Executes `f` and commit the bindings. diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 78803eea3bc68..68f84d4d1c346 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -11,7 +11,7 @@ use std::cmp; use std::marker::PhantomData; use std::ops::Range; -use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs}; +use rustc_data_structures::undo_log::{Rollback, UndoLogs}; pub(crate) enum UndoLog<'tcx> { EqRelation(sv::UndoLog>>), @@ -81,7 +81,7 @@ pub struct TypeVariableStorage<'tcx> { sub_relations: ut::UnificationTableStorage, } -pub struct TypeVariableTable<'tcx, 'a> { +pub struct TypeVariableTable<'a, 'tcx> { values: &'a mut sv::SnapshotVecStorage, eq_relations: &'a mut ut::UnificationTableStorage>, @@ -168,13 +168,13 @@ impl<'tcx> TypeVariableStorage<'tcx> { pub(crate) fn with_log<'a>( &'a mut self, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, - ) -> TypeVariableTable<'tcx, 'a> { + ) -> TypeVariableTable<'a, 'tcx> { let TypeVariableStorage { values, eq_relations, sub_relations } = self; TypeVariableTable { values, eq_relations, sub_relations, undo_log } } } -impl<'tcx> TypeVariableTable<'tcx, '_> { +impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Returns the diverges flag given when `vid` was created. /// /// Note that this function does not return care whether diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index 0d94e32754ac8..5bb8ce8f66bb1 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -1,16 +1,12 @@ use std::marker::PhantomData; use rustc_data_structures::snapshot_vec as sv; -use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs}; +use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify as ut; -use rustc_hir as hir; use rustc_middle::ty; use crate::{ - infer::{ - region_constraints::{self, RegionConstraintStorage}, - type_variable, RegionObligation, - }, + infer::{region_constraints, type_variable, InferCtxtInner}, traits, }; @@ -19,6 +15,7 @@ pub struct Snapshot<'tcx> { _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>>), @@ -96,26 +93,18 @@ impl<'tcx> From> for UndoLog<'tcx> { } } -pub(super) struct RollbackView<'tcx, 'a> { - pub(super) type_variables: &'a mut type_variable::TypeVariableStorage<'tcx>, - pub(super) const_unification_table: &'a mut ut::UnificationTableStorage>, - pub(super) int_unification_table: &'a mut ut::UnificationTableStorage, - pub(super) float_unification_table: &'a mut ut::UnificationTableStorage, - pub(super) region_constraints: &'a mut RegionConstraintStorage<'tcx>, - pub(super) projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>, - pub(super) region_obligations: &'a mut Vec<(hir::HirId, RegionObligation<'tcx>)>, -} - -impl<'tcx> Rollback> for RollbackView<'tcx, '_> { +impl<'tcx> Rollback> for InferCtxtInner<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { match undo { - UndoLog::TypeVariables(undo) => self.type_variables.reverse(undo), - UndoLog::ConstUnificationTable(undo) => self.const_unification_table.reverse(undo), - UndoLog::IntUnificationTable(undo) => self.int_unification_table.reverse(undo), - UndoLog::FloatUnificationTable(undo) => self.float_unification_table.reverse(undo), - UndoLog::RegionConstraintCollector(undo) => self.region_constraints.reverse(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_constraints.as_mut().unwrap().reverse(undo) + } UndoLog::RegionUnificationTable(undo) => { - self.region_constraints.unification_table.reverse(undo) + self.region_constraints.as_mut().unwrap().unification_table.reverse(undo) } UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), UndoLog::PushRegionObligation => { @@ -163,58 +152,52 @@ where } } -impl<'tcx> Snapshots> for InferCtxtUndoLogs<'tcx> { - type Snapshot = Snapshot<'tcx>; - fn actions_since_snapshot(&self, snapshot: &Self::Snapshot) -> &[UndoLog<'tcx>] { - &self.logs[snapshot.undo_len..] - } - - fn start_snapshot(&mut self) -> Self::Snapshot { - self.num_open_snapshots += 1; - Snapshot { undo_len: self.logs.len(), _marker: PhantomData } - } - - fn rollback_to(&mut self, values: impl FnOnce() -> R, snapshot: Self::Snapshot) - where - R: Rollback>, - { +impl<'tcx> InferCtxtInner<'tcx> { + pub fn rollback_to(&mut self, snapshot: Snapshot<'tcx>) { debug!("rollback_to({})", snapshot.undo_len); - self.assert_open_snapshot(&snapshot); + self.undo_log.assert_open_snapshot(&snapshot); - if self.logs.len() > snapshot.undo_len { - let mut values = values(); - while self.logs.len() > snapshot.undo_len { - values.reverse(self.logs.pop().unwrap()); - } + while self.undo_log.logs.len() > snapshot.undo_len { + let undo = self.undo_log.logs.pop().unwrap(); + self.reverse(undo); } - if self.num_open_snapshots == 1 { + 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.logs.clear(); + self.undo_log.logs.clear(); } - self.num_open_snapshots -= 1; + self.undo_log.num_open_snapshots -= 1; } - fn commit(&mut self, snapshot: Self::Snapshot) { + pub fn commit(&mut self, snapshot: Snapshot<'tcx>) { debug!("commit({})", snapshot.undo_len); - if self.num_open_snapshots == 1 { + 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.logs.clear(); + self.undo_log.logs.clear(); } - self.num_open_snapshots -= 1; + 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>, diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 17bc54eed40df..f0d21a7d022da 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -65,7 +65,7 @@ impl<'tcx, T> Normalized<'tcx, T> { // // 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. -pub struct ProjectionCache<'tcx, 'a> { +pub struct ProjectionCache<'a, 'tcx> { map: &'a mut SnapshotMapStorage, ProjectionCacheEntry<'tcx>>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } @@ -98,12 +98,12 @@ impl<'tcx> ProjectionCacheStorage<'tcx> { pub(crate) fn with_log<'a>( &'a mut self, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, - ) -> ProjectionCache<'tcx, 'a> { + ) -> ProjectionCache<'a, 'tcx> { ProjectionCache { map: &mut self.map, undo_log } } } -impl<'tcx> ProjectionCache<'tcx, '_> { +impl<'tcx> ProjectionCache<'_, 'tcx> { fn map( &mut self, ) -> SnapshotMapRef< From 0d448cfcf8a8ebb4109d817b2aa416e9ba33610d Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Fri, 17 Apr 2020 09:00:02 +0200 Subject: [PATCH 18/22] Generate the UndoLog upcasts with a macro --- src/librustc_infer/infer/undo_log.rs | 78 ++++++++-------------------- 1 file changed, 22 insertions(+), 56 deletions(-) diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index 5bb8ce8f66bb1..2271da0152618 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -27,70 +27,36 @@ pub(crate) enum UndoLog<'tcx> { PushRegionObligation, } -impl<'tcx> From> for UndoLog<'tcx> { - fn from(l: region_constraints::UndoLog<'tcx>) -> Self { - UndoLog::RegionConstraintCollector(l) - } -} - -impl<'tcx> From>>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>>) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::EqRelation(l)) - } -} - -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::SubRelation(l)) - } -} - -impl<'tcx> From> for UndoLog<'tcx> { - fn from(l: sv::UndoLog) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::Values(l)) - } -} - -impl<'tcx> From for UndoLog<'tcx> { - fn from(l: type_variable::Instantiate) -> Self { - UndoLog::TypeVariables(type_variable::UndoLog::from(l)) +macro_rules! impl_from { + ($($ctor: ident ($ty: ty),)*) => { + $( + impl<'tcx> From<$ty> for UndoLog<'tcx> { + fn from(x: $ty) -> Self { + UndoLog::$ctor(x.into()) + } + } + )* } } -impl From> for UndoLog<'tcx> { - fn from(t: type_variable::UndoLog<'tcx>) -> Self { - Self::TypeVariables(t) - } -} +// Upcast from a single kind of "undoable action" to the general enum +impl_from! { + RegionConstraintCollector(region_constraints::UndoLog<'tcx>), + TypeVariables(type_variable::UndoLog<'tcx>), -impl<'tcx> From>>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>>) -> Self { - Self::ConstUnificationTable(l) - } -} + TypeVariables(sv::UndoLog>>), + TypeVariables(sv::UndoLog>), + TypeVariables(sv::UndoLog), + TypeVariables(type_variable::Instantiate), -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - Self::IntUnificationTable(l) - } -} + IntUnificationTable(sv::UndoLog>), -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - Self::FloatUnificationTable(l) - } -} + FloatUnificationTable(sv::UndoLog>), -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - Self::RegionUnificationTable(l) - } -} + ConstUnificationTable(sv::UndoLog>>), -impl<'tcx> From> for UndoLog<'tcx> { - fn from(l: traits::UndoLog<'tcx>) -> Self { - Self::ProjectionCache(l) - } + RegionUnificationTable(sv::UndoLog>), + ProjectionCache(traits::UndoLog<'tcx>), } impl<'tcx> Rollback> for InferCtxtInner<'tcx> { From 6f495f3466f510ac3db45fc3057b96efed971b7f Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Fri, 17 Apr 2020 09:15:28 +0200 Subject: [PATCH 19/22] Improve naming --- src/librustc_infer/infer/fudge.rs | 2 +- src/librustc_infer/infer/mod.rs | 25 +++++++++++++---------- src/librustc_infer/infer/type_variable.rs | 5 +++++ src/librustc_infer/infer/undo_log.rs | 13 ++++++++++-- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index ccc4a73d40f67..53fd70a28e8dd 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -82,7 +82,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("fudge_inference_if_ok()"); - let (mut fudger, value) = self.probe_full(|snapshot| { + let (mut fudger, value) = self.probe_fudge(|snapshot| { match f() { Ok(value) => { let value = self.resolve_vars_if_possible(&value); diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 67d330ac89255..e92008c68eba5 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -167,7 +167,7 @@ pub struct InferCtxtInner<'tcx> { /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` /// -- further attempts to perform unification, etc., may fail if new /// region constraints would've been added. - region_constraints: Option>, + region_constraint_storage: Option>, /// A set of constraints that regionck must validate. Each /// constraint has the form `T:'a`, meaning "some type `T` must @@ -214,7 +214,7 @@ impl<'tcx> InferCtxtInner<'tcx> { const_unification_storage: ut::UnificationTableStorage::new(), int_unification_storage: ut::UnificationTableStorage::new(), float_unification_storage: ut::UnificationTableStorage::new(), - region_constraints: Some(RegionConstraintStorage::new()), + region_constraint_storage: Some(RegionConstraintStorage::new()), region_obligations: vec![], } } @@ -268,7 +268,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> { - self.region_constraints + self.region_constraint_storage .as_mut() .expect("region constraints already solved") .with_log(&mut self.undo_log) @@ -705,8 +705,9 @@ impl<'tcx> InferOk<'tcx, ()> { } } +/// Extends `CombinedSnapshot` by tracking which variables were added in the snapshot #[must_use = "once you start a snapshot, you should always consume it"] -pub struct FullSnapshot<'a, 'tcx> { +pub struct FudgeSnapshot<'a, 'tcx> { snapshot: CombinedSnapshot<'a, 'tcx>, region_constraints_snapshot: RegionSnapshot, type_snapshot: type_variable::Snapshot<'tcx>, @@ -830,10 +831,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { result } - fn start_full_snapshot(&self) -> FullSnapshot<'a, 'tcx> { + fn start_fudge_snapshot(&self) -> FudgeSnapshot<'a, 'tcx> { let snapshot = self.start_snapshot(); let mut inner = self.inner.borrow_mut(); - FullSnapshot { + FudgeSnapshot { snapshot, type_snapshot: inner.type_variables().snapshot(), const_var_len: inner.const_unification_table().len(), @@ -925,12 +926,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - pub fn probe_full(&self, f: F) -> R + /// Like `probe` but provides information about which variables were created in the snapshot, + /// allowing for inference fudging + pub fn probe_fudge(&self, f: F) -> R where - F: FnOnce(&FullSnapshot<'a, 'tcx>) -> R, + F: FnOnce(&FudgeSnapshot<'a, 'tcx>) -> R, { debug!("probe()"); - let snapshot = self.start_full_snapshot(); + let snapshot = self.start_fudge_snapshot(); let r = f(&snapshot); self.rollback_to("probe", snapshot.snapshot); r @@ -1294,7 +1297,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { inner.region_obligations ); inner - .region_constraints + .region_constraint_storage .take() .expect("regions already resolved") .with_log(&mut inner.undo_log) @@ -1362,7 +1365,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn take_region_var_origins(&self) -> VarInfos { let mut inner = self.inner.borrow_mut(); let (var_infos, data) = inner - .region_constraints + .region_constraint_storage .take() .expect("regions already resolved") .with_log(&mut inner.undo_log) diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 68f84d4d1c346..ed8ee3b655d1b 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -13,30 +13,35 @@ use std::ops::Range; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; +/// Represents a single undo-able action that affects a type inference variable. pub(crate) enum UndoLog<'tcx> { EqRelation(sv::UndoLog>>), SubRelation(sv::UndoLog>), Values(sv::UndoLog), } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From>>> for UndoLog<'tcx> { fn from(l: sv::UndoLog>>) -> Self { UndoLog::EqRelation(l) } } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From>> for UndoLog<'tcx> { fn from(l: sv::UndoLog>) -> Self { UndoLog::SubRelation(l) } } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From> for UndoLog<'tcx> { fn from(l: sv::UndoLog) -> Self { UndoLog::Values(l) } } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From for UndoLog<'tcx> { fn from(l: Instantiate) -> Self { UndoLog::Values(sv::UndoLog::Other(l)) diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index 2271da0152618..56cb182dbf0f9 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -59,6 +59,7 @@ impl_from! { ProjectionCache(traits::UndoLog<'tcx>), } +/// The Rollback trait defines how to rollback a particular action. impl<'tcx> Rollback> for InferCtxtInner<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { match undo { @@ -67,10 +68,10 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo), UndoLog::RegionConstraintCollector(undo) => { - self.region_constraints.as_mut().unwrap().reverse(undo) + self.region_constraint_storage.as_mut().unwrap().reverse(undo) } UndoLog::RegionUnificationTable(undo) => { - self.region_constraints.as_mut().unwrap().unification_table.reverse(undo) + self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo) } UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), UndoLog::PushRegionObligation => { @@ -80,6 +81,8 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { } } +/// 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>, num_open_snapshots: usize, @@ -91,6 +94,8 @@ impl Default for InferCtxtUndoLogs<'_> { } } +/// 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 for InferCtxtUndoLogs<'tcx> where UndoLog<'tcx>: From, @@ -98,15 +103,18 @@ where 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(&mut self, undos: J) where Self: Sized, @@ -196,6 +204,7 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> { impl<'tcx> std::ops::Index for InferCtxtUndoLogs<'tcx> { type Output = UndoLog<'tcx>; + fn index(&self, key: usize) -> &Self::Output { &self.logs[key] } From 4a2a6bcfb1b014587daa543a9aa618502750e489 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 28 Apr 2020 20:46:02 +0200 Subject: [PATCH 20/22] refactor: Move probe_fudge into fudge.rs --- src/librustc_infer/infer/fudge.rs | 42 +++++++++++++++++++++++++++++-- src/librustc_infer/infer/mod.rs | 41 +----------------------------- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index 53fd70a28e8dd..abe952d60f129 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -1,9 +1,10 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; -use super::type_variable::TypeVariableOrigin; +use super::region_constraints::RegionSnapshot; +use super::type_variable::{self, TypeVariableOrigin}; use super::InferCtxt; -use super::{ConstVariableOrigin, RegionVariableOrigin, UnificationTable}; +use super::{CombinedSnapshot, ConstVariableOrigin, RegionVariableOrigin, UnificationTable}; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; @@ -35,7 +36,44 @@ fn const_vars_since_snapshot<'tcx>( ) } +/// Extends `CombinedSnapshot` by tracking which variables were added in the snapshot +#[must_use = "once you start a snapshot, you should always consume it"] +struct FudgeSnapshot<'a, 'tcx> { + snapshot: CombinedSnapshot<'a, 'tcx>, + region_constraints_snapshot: RegionSnapshot, + type_snapshot: type_variable::Snapshot<'tcx>, + const_var_len: usize, + int_var_len: usize, + float_var_len: usize, +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + /// Like `probe` but provides information about which variables were created in the snapshot, + /// allowing for inference fudging + fn probe_fudge(&self, f: F) -> R + where + F: FnOnce(&FudgeSnapshot<'a, 'tcx>) -> R, + { + debug!("probe()"); + let snapshot = self.start_fudge_snapshot(); + let r = f(&snapshot); + self.rollback_to("probe", snapshot.snapshot); + r + } + + fn start_fudge_snapshot(&self) -> FudgeSnapshot<'a, 'tcx> { + let snapshot = self.start_snapshot(); + let mut inner = self.inner.borrow_mut(); + FudgeSnapshot { + snapshot, + type_snapshot: inner.type_variables().snapshot(), + 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_snapshot: inner.unwrap_region_constraints().start_snapshot(), + } + } + /// This rather funky routine is used while processing expected /// types. What happens here is that we want to propagate a /// coercion through the return type of a fn to its diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index e92008c68eba5..679118d7698ef 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -45,9 +45,7 @@ use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; -use self::region_constraints::{ - RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, -}; +use self::region_constraints::{RegionConstraintCollector, RegionConstraintStorage}; use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; @@ -705,17 +703,6 @@ impl<'tcx> InferOk<'tcx, ()> { } } -/// Extends `CombinedSnapshot` by tracking which variables were added in the snapshot -#[must_use = "once you start a snapshot, you should always consume it"] -pub struct FudgeSnapshot<'a, 'tcx> { - snapshot: CombinedSnapshot<'a, 'tcx>, - region_constraints_snapshot: RegionSnapshot, - type_snapshot: type_variable::Snapshot<'tcx>, - const_var_len: usize, - int_var_len: usize, - float_var_len: usize, -} - #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx> { undo_snapshot: Snapshot<'tcx>, @@ -831,19 +818,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { result } - fn start_fudge_snapshot(&self) -> FudgeSnapshot<'a, 'tcx> { - let snapshot = self.start_snapshot(); - let mut inner = self.inner.borrow_mut(); - FudgeSnapshot { - snapshot, - type_snapshot: inner.type_variables().snapshot(), - 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_snapshot: inner.unwrap_region_constraints().start_snapshot(), - } - } - fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> { debug!("start_snapshot()"); @@ -926,19 +900,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - /// Like `probe` but provides information about which variables were created in the snapshot, - /// allowing for inference fudging - pub fn probe_fudge(&self, f: F) -> R - where - F: FnOnce(&FudgeSnapshot<'a, 'tcx>) -> R, - { - debug!("probe()"); - let snapshot = self.start_fudge_snapshot(); - let r = f(&snapshot); - self.rollback_to("probe", snapshot.snapshot); - r - } - /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R where From f7f62452e47bab1a8e649da77a0ab0f8505d7035 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 28 Apr 2020 20:59:34 +0200 Subject: [PATCH 21/22] refactor: Replace probe_fudge by an explict call for the lengths --- src/librustc_infer/infer/fudge.rs | 54 +++++++------------ .../infer/region_constraints/mod.rs | 10 ++-- src/librustc_infer/infer/type_variable.rs | 18 +------ 3 files changed, 23 insertions(+), 59 deletions(-) diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index abe952d60f129..c6651108df53d 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -1,10 +1,9 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; -use super::region_constraints::RegionSnapshot; -use super::type_variable::{self, TypeVariableOrigin}; +use super::type_variable::TypeVariableOrigin; use super::InferCtxt; -use super::{CombinedSnapshot, ConstVariableOrigin, RegionVariableOrigin, UnificationTable}; +use super::{ConstVariableOrigin, RegionVariableOrigin, UnificationTable}; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; @@ -14,13 +13,13 @@ use std::ops::Range; fn vars_since_snapshot<'tcx, T>( table: &mut UnificationTable<'_, 'tcx, T>, - snapshot: usize, + snapshot_var_len: usize, ) -> Range where T: UnifyKey, super::UndoLog<'tcx>: From>>, { - T::from_index(snapshot as u32)..T::from_index(table.len() as u32) + T::from_index(snapshot_var_len as u32)..T::from_index(table.len() as u32) } fn const_vars_since_snapshot<'tcx>( @@ -36,41 +35,23 @@ fn const_vars_since_snapshot<'tcx>( ) } -/// Extends `CombinedSnapshot` by tracking which variables were added in the snapshot -#[must_use = "once you start a snapshot, you should always consume it"] -struct FudgeSnapshot<'a, 'tcx> { - snapshot: CombinedSnapshot<'a, 'tcx>, - region_constraints_snapshot: RegionSnapshot, - type_snapshot: type_variable::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> { - /// Like `probe` but provides information about which variables were created in the snapshot, - /// allowing for inference fudging - fn probe_fudge(&self, f: F) -> R - where - F: FnOnce(&FudgeSnapshot<'a, 'tcx>) -> R, - { - debug!("probe()"); - let snapshot = self.start_fudge_snapshot(); - let r = f(&snapshot); - self.rollback_to("probe", snapshot.snapshot); - r - } - - fn start_fudge_snapshot(&self) -> FudgeSnapshot<'a, 'tcx> { - let snapshot = self.start_snapshot(); + fn variable_lengths(&self) -> VariableLengths { let mut inner = self.inner.borrow_mut(); - FudgeSnapshot { - snapshot, - type_snapshot: inner.type_variables().snapshot(), + 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_snapshot: inner.unwrap_region_constraints().start_snapshot(), + region_constraints_len: inner.unwrap_region_constraints().num_region_vars(), } } @@ -120,7 +101,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("fudge_inference_if_ok()"); - let (mut fudger, value) = self.probe_fudge(|snapshot| { + let variable_lengths = self.variable_lengths(); + let (mut fudger, value) = self.probe(|_| { match f() { Ok(value) => { let value = self.resolve_vars_if_possible(&value); @@ -133,21 +115,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut inner = self.inner.borrow_mut(); 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 = vars_since_snapshot( &mut inner.int_unification_table(), - snapshot.int_var_len, + variable_lengths.int_var_len, ); let float_vars = vars_since_snapshot( &mut inner.float_unification_table(), - snapshot.float_var_len, + variable_lengths.float_var_len, ); let region_vars = inner .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( &mut inner.const_unification_table(), - snapshot.const_var_len, + variable_lengths.const_var_len, ); let fudger = InferenceFudger { diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 74d31e744fc18..fae7f2db4c0d7 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -312,7 +312,6 @@ pub struct RegionVariableInfo { } pub struct RegionSnapshot { - value_count: usize, any_unifications: bool, } @@ -454,10 +453,7 @@ impl<'tcx> RegionConstraintCollector<'tcx, '_> { pub fn start_snapshot(&mut self) -> RegionSnapshot { debug!("RegionConstraintCollector: start_snapshot"); - RegionSnapshot { - value_count: self.unification_table.len(), - any_unifications: self.any_unifications, - } + RegionSnapshot { any_unifications: self.any_unifications } } pub fn rollback_to(&mut self, snapshot: RegionSnapshot) { @@ -776,9 +772,9 @@ impl<'tcx> RegionConstraintCollector<'tcx, '_> { pub fn vars_since_snapshot( &self, - mark: &RegionSnapshot, + value_count: usize, ) -> (Range, Vec) { - let range = RegionVid::from_index(mark.value_count as u32) + let range = RegionVid::from_index(value_count as u32) ..RegionVid::from_index(self.unification_table.len() as u32); ( range.clone(), diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index ed8ee3b655d1b..f68692391a288 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -150,11 +150,6 @@ impl<'tcx> TypeVariableValue<'tcx> { } } -pub struct Snapshot<'tcx> { - value_count: u32, - _marker: PhantomData<&'tcx ()>, -} - pub(crate) struct Instantiate { vid: ty::TyVid, } @@ -324,14 +319,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { } } - /// Creates a snapshot of the type variable state. This snapshot - /// must later be committed (`commit()`) or rolled back - /// (`rollback_to()`). Nested snapshots are permitted, but must - /// be processed in a stack-like fashion. - pub fn snapshot(&mut self) -> Snapshot<'tcx> { - Snapshot { value_count: self.eq_relations().len() as u32, _marker: PhantomData } - } - fn values( &mut self, ) -> sv::SnapshotVec, &mut InferCtxtUndoLogs<'tcx>> { @@ -349,10 +336,9 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Returns a range of the type variables created during the snapshot. pub fn vars_since_snapshot( &mut self, - s: &Snapshot<'tcx>, + value_count: usize, ) -> (Range, Vec) { - let range = - TyVid { index: s.value_count }..TyVid { index: self.eq_relations().len() as u32 }; + let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 }; ( range.start..range.end, (range.start.index..range.end.index) From 3f85338f3f2a8e03b90e65fafd0bbe998baae98e Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 28 Apr 2020 21:05:12 +0200 Subject: [PATCH 22/22] Restore the snapshot/rollback optimization for region constraints --- src/librustc_infer/infer/mod.rs | 30 ++++++++++++++----- .../infer/region_constraints/leak_check.rs | 2 +- .../infer/region_constraints/mod.rs | 10 +++---- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 679118d7698ef..2cf9dd882e4bb 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -45,7 +45,9 @@ use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; -use self::region_constraints::{RegionConstraintCollector, RegionConstraintStorage}; +use self::region_constraints::{ + RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, +}; use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; @@ -265,7 +267,7 @@ impl<'tcx> InferCtxtInner<'tcx> { self.const_unification_storage.with_log(&mut self.undo_log) } - pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> { + pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> { self.region_constraint_storage .as_mut() .expect("region constraints already solved") @@ -706,6 +708,7 @@ impl<'tcx> InferOk<'tcx, ()> { #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx> { undo_snapshot: Snapshot<'tcx>, + region_constraints_snapshot: RegionSnapshot, universe: ty::UniverseIndex, was_in_snapshot: bool, _in_progress_tables: Option>>, @@ -827,6 +830,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { CombinedSnapshot { undo_snapshot: inner.undo_log.start_snapshot(), + region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), universe: self.universe(), was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e., during typeck) @@ -837,19 +841,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("rollback_to(cause={})", cause); - let CombinedSnapshot { undo_snapshot, universe, was_in_snapshot, _in_progress_tables } = - snapshot; + let CombinedSnapshot { + undo_snapshot, + region_constraints_snapshot, + universe, + was_in_snapshot, + _in_progress_tables, + } = snapshot; self.in_snapshot.set(was_in_snapshot); self.universe.set(universe); - self.inner.borrow_mut().rollback_to(undo_snapshot); + let mut inner = self.inner.borrow_mut(); + inner.rollback_to(undo_snapshot); + inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("commit_from()"); - let CombinedSnapshot { undo_snapshot, universe: _, was_in_snapshot, _in_progress_tables } = - snapshot; + let CombinedSnapshot { + undo_snapshot, + region_constraints_snapshot: _, + universe: _, + was_in_snapshot, + _in_progress_tables, + } = snapshot; self.in_snapshot.set(was_in_snapshot); diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 480a5cb4dccee..473550d5433df 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -4,7 +4,7 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; -impl<'tcx> RegionConstraintCollector<'tcx, '_> { +impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Searches region constraints created since `snapshot` that /// affect one of the placeholders in `placeholder_map`, returning /// an error if any of the placeholders are related to another diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index fae7f2db4c0d7..0c9f002a2a21d 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -61,19 +61,19 @@ pub struct RegionConstraintStorage<'tcx> { any_unifications: bool, } -pub struct RegionConstraintCollector<'tcx, 'a> { +pub struct RegionConstraintCollector<'a, 'tcx> { storage: &'a mut RegionConstraintStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } -impl std::ops::Deref for RegionConstraintCollector<'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, '_> { +impl std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> { fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> { self.storage } @@ -348,7 +348,7 @@ impl<'tcx> RegionConstraintStorage<'tcx> { pub(crate) fn with_log<'a>( &'a mut self, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, - ) -> RegionConstraintCollector<'tcx, 'a> { + ) -> RegionConstraintCollector<'a, 'tcx> { RegionConstraintCollector { storage: self, undo_log } } @@ -381,7 +381,7 @@ impl<'tcx> RegionConstraintStorage<'tcx> { } } -impl<'tcx> RegionConstraintCollector<'tcx, '_> { +impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn num_region_vars(&self) -> usize { self.var_infos.len() }