Skip to content

Commit

Permalink
Auto merge of #59415 - varkor:values_since_snapshot, r=eddyb
Browse files Browse the repository at this point in the history
Refactor InferenceFudger (née RegionFudger)

- Rename `RegionFudger` (and related methods) to `InferenceFudger`.
- Take integer and float inference variables into account.
- Refactor `types_created_since_snapshot` and `vars_created_since_snapshot` with the [new version of ena](rust-lang/ena#21).
- Some other refactoring in the area.

r? @eddyb
  • Loading branch information
bors committed Mar 27, 2019
2 parents c5fb4d0 + 86d5a69 commit 33ef0ba
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 100 deletions.
11 changes: 10 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,14 @@ dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "ena"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "env_logger"
version = "0.5.13"
Expand Down Expand Up @@ -2662,7 +2670,7 @@ name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"jobserver 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
Expand Down Expand Up @@ -4043,6 +4051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum elasticlunr-rs 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a99a310cd1f9770e7bf8e48810c7bcbb0e078c8fb23a8c7bcf0da4c2bf61a455"
"checksum ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f56c93cc076508c549d9bb747f79aa9b4eb098be7b8cad8830c3137ef52d1e00"
"checksum ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc01d68e08ca384955a3aeba9217102ca1aa85b6e168639bf27739f1d749d87"
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
)
}

CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()),
CanonicalTyVarKind::Int => self.next_int_var(),

CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()),
CanonicalTyVarKind::Float => self.next_float_var(),
};
ty.into()
}
Expand Down
143 changes: 84 additions & 59 deletions src/librustc/infer/fudge.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::infer::type_variable::TypeVariableMap;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, TyVid, IntVid, FloatVid, RegionVid};
use crate::ty::fold::{TypeFoldable, TypeFolder};

use super::InferCtxt;
use super::RegionVariableOrigin;
use super::type_variable::TypeVariableOrigin;

use std::ops::Range;

impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// This rather funky routine is used while processing expected
Expand All @@ -17,7 +19,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// from `&[u32; 3]` to `&[u32]` and make the users life more
/// pleasant.
///
/// The way we do this is using `fudge_regions_if_ok`. What the
/// The way we do this is using `fudge_inference_if_ok`. What the
/// routine actually does is to start a snapshot and execute the
/// closure `f`. In our example above, what this closure will do
/// is to unify the expectation (`Option<&[u32]>`) with the actual
Expand All @@ -26,7 +28,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// with `&?a [u32]`, where `?a` is a fresh lifetime variable. The
/// input type (`?T`) is then returned by `f()`.
///
/// At this point, `fudge_regions_if_ok` will normalize all type
/// At this point, `fudge_inference_if_ok` will normalize all type
/// variables, converting `?T` to `&?a [u32]` and end the
/// snapshot. The problem is that we can't just return this type
/// out, because it references the region variable `?a`, and that
Expand All @@ -42,36 +44,51 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// regions in question are not particularly important. We will
/// use the expected types to guide coercions, but we will still
/// type-check the resulting types from those coercions against
/// the actual types (`?T`, `Option<?T`) -- and remember that
/// the actual types (`?T`, `Option<?T>`) -- and remember that
/// after the snapshot is popped, the variable `?T` is no longer
/// unified.
pub fn fudge_regions_if_ok<T, E, F>(&self,
origin: &RegionVariableOrigin,
f: F) -> Result<T, E> where
pub fn fudge_inference_if_ok<T, E, F>(
&self,
f: F,
) -> Result<T, E> where
F: FnOnce() -> Result<T, E>,
T: TypeFoldable<'tcx>,
{
debug!("fudge_regions_if_ok(origin={:?})", origin);
debug!("fudge_inference_if_ok()");

let (type_variables, region_vars, value) = self.probe(|snapshot| {
let (mut fudger, value) = self.probe(|snapshot| {
match f() {
Ok(value) => {
let value = self.resolve_type_vars_if_possible(&value);

// At this point, `value` could in principle refer
// to types/regions that have been created during
// to inference variables that have been created during
// the snapshot. Once we exit `probe()`, those are
// going to be popped, so we will have to
// eliminate any references to them.

let type_variables =
self.type_variables.borrow_mut().types_created_since_snapshot(
&snapshot.type_snapshot);
let region_vars =
self.borrow_region_constraints().vars_created_since_snapshot(
&snapshot.region_constraints_snapshot);
let type_vars = self.type_variables.borrow_mut().vars_since_snapshot(
&snapshot.type_snapshot,
);
let int_vars = self.int_unification_table.borrow_mut().vars_since_snapshot(
&snapshot.int_snapshot,
);
let float_vars = self.float_unification_table.borrow_mut().vars_since_snapshot(
&snapshot.float_snapshot,
);
let region_vars = self.borrow_region_constraints().vars_since_snapshot(
&snapshot.region_constraints_snapshot,
);

let fudger = InferenceFudger {
infcx: self,
type_vars,
int_vars,
float_vars,
region_vars,
};

Ok((type_variables, region_vars, value))
Ok((fudger, value))
}
Err(e) => Err(e),
}
Expand All @@ -84,69 +101,77 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {

// Micro-optimization: if no variables have been created, then
// `value` can't refer to any of them. =) So we can just return it.
if type_variables.is_empty() && region_vars.is_empty() {
return Ok(value);
if fudger.type_vars.0.is_empty() &&
fudger.int_vars.is_empty() &&
fudger.float_vars.is_empty() &&
fudger.region_vars.0.is_empty() {
Ok(value)
} else {
Ok(value.fold_with(&mut fudger))
}

let mut fudger = RegionFudger {
infcx: self,
type_variables: &type_variables,
region_vars: &region_vars,
origin,
};

Ok(value.fold_with(&mut fudger))
}
}

pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
pub struct InferenceFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
type_variables: &'a TypeVariableMap,
region_vars: &'a Vec<ty::RegionVid>,
origin: &'a RegionVariableOrigin,
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
}

impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for InferenceFudger<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
self.infcx.tcx
}

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
ty::Infer(ty::InferTy::TyVar(vid)) => {
match self.type_variables.get(&vid) {
None => {
// This variable was created before the
// "fudging". Since we refresh all type
// variables to their binding anyhow, we know
// that it is unbound, so we can just return
// it.
debug_assert!(self.infcx.type_variables.borrow_mut()
.probe(vid)
.is_unknown());
ty
}

Some(&origin) => {
// This variable was created during the
// fudging. Recreate it with a fresh variable
// here.
self.infcx.next_ty_var(origin)
}
if self.type_vars.0.contains(&vid) {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
let idx = (vid.index - self.type_vars.0.start.index) as usize;
let origin = self.type_vars.1[idx];
self.infcx.next_ty_var(origin)
} else {
// This variable was created before the
// "fudging". Since we refresh all type
// variables to their binding anyhow, we know
// that it is unbound, so we can just return
// it.
debug_assert!(self.infcx.type_variables.borrow_mut()
.probe(vid)
.is_unknown());
ty
}
}
ty::Infer(ty::InferTy::IntVar(vid)) => {
if self.int_vars.contains(&vid) {
self.infcx.next_int_var()
} else {
ty
}
}
ty::Infer(ty::InferTy::FloatVar(vid)) => {
if self.float_vars.contains(&vid) {
self.infcx.next_float_var()
} else {
ty
}
}
_ => ty.super_fold_with(self),
}
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReVar(v) if self.region_vars.contains(&v) => {
self.infcx.next_region_var(self.origin.clone())
}
_ => {
r
if let ty::ReVar(vid) = r {
if self.region_vars.0.contains(&vid) {
let idx = (vid.index() - self.region_vars.0.start.index()) as usize;
let origin = self.region_vars.1[idx];
return self.infcx.next_region_var(origin);
}
}
r
}
}
12 changes: 10 additions & 2 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -999,14 +999,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
}

pub fn next_int_var_id(&self) -> IntVid {
fn next_int_var_id(&self) -> IntVid {
self.int_unification_table.borrow_mut().new_key(None)
}

pub fn next_float_var_id(&self) -> FloatVid {
pub fn next_int_var(&self) -> Ty<'tcx> {
self.tcx.mk_int_var(self.next_int_var_id())
}

fn next_float_var_id(&self) -> FloatVid {
self.float_unification_table.borrow_mut().new_key(None)
}

pub fn next_float_var(&self) -> Ty<'tcx> {
self.tcx.mk_float_var(self.next_float_var_id())
}

/// Creates a fresh region variable with the next available index.
/// The variable will be created in the maximum universe created
/// thus far, allowing it to name any region created thus far.
Expand Down
16 changes: 9 additions & 7 deletions src/librustc/infer/region_constraints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::ty::{Region, RegionVid};

use std::collections::BTreeMap;
use std::{cmp, fmt, mem, u32};
use std::ops::Range;

mod leak_check;

Expand Down Expand Up @@ -840,13 +841,14 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
}
}

pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec<RegionVid> {
self.undo_log[mark.length..]
.iter()
.filter_map(|&elt| match elt {
AddVar(vid) => Some(vid),
_ => None,
}).collect()
pub fn vars_since_snapshot(
&self,
mark: &RegionSnapshot,
) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
let range = self.unification_table.vars_since_snapshot(&mark.region_snapshot);
(range.clone(), (range.start.index()..range.end.index()).map(|index| {
self.var_infos[ty::RegionVid::from(index)].origin.clone()
}).collect())
}

/// See [`RegionInference::region_constraints_added_in_snapshot`].
Expand Down
33 changes: 11 additions & 22 deletions src/librustc/infer/type_variable.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use syntax::symbol::InternedString;
use syntax_pos::Span;
use crate::ty::{self, Ty};
use crate::ty::{self, Ty, TyVid};

use std::cmp;
use std::marker::PhantomData;
use std::u32;
use rustc_data_structures::fx::FxHashMap;
use std::ops::Range;
use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::unify as ut;

Expand Down Expand Up @@ -58,8 +58,6 @@ pub enum TypeVariableOrigin {
Generalized(ty::TyVid),
}

pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>;

struct TypeVariableData {
origin: TypeVariableOrigin,
diverging: bool,
Expand Down Expand Up @@ -292,24 +290,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
self.sub_relations.commit(sub_snapshot);
}

/// Returns a map `{V1 -> V2}`, where the keys `{V1}` are
/// ty-variables created during the snapshot, and the values
/// `{V2}` are the root variables that they were unified with,
/// along with their origin.
pub fn types_created_since_snapshot(&mut self, s: &Snapshot<'tcx>) -> TypeVariableMap {
let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);

actions_since_snapshot
.iter()
.filter_map(|action| match action {
&sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }),
_ => None,
})
.map(|vid| {
let origin = self.values.get(vid.index as usize).origin.clone();
(vid, origin)
})
.collect()
/// Returns a range of the type variables created during the snapshot.
pub fn vars_since_snapshot(
&mut self,
s: &Snapshot<'tcx>,
) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
let range = self.eq_relations.vars_since_snapshot(&s.eq_snapshot);
(range.start.vid..range.end.vid, (range.start.vid.index..range.end.vid.index).map(|index| {
self.values.get(index as usize).origin.clone()
}).collect())
}

/// Finds the set of type variables that existed *before* `s`
Expand Down
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#![feature(non_exhaustive)]
#![feature(proc_macro_internals)]
#![feature(optin_builtin_traits)]
#![feature(range_is_empty)]
#![feature(refcell_replace_swap)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_attrs)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_data_structures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ path = "lib.rs"
crate-type = ["dylib"]

[dependencies]
ena = "0.11"
ena = "0.13"
log = "0.4"
jobserver_crate = { version = "0.1", package = "jobserver" }
lazy_static = "1"
Expand Down
Loading

0 comments on commit 33ef0ba

Please sign in to comment.