Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor InferenceFudger (née RegionFudger) #59415

Merged
merged 16 commits into from
Mar 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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