mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-03 10:33:34 +00:00
Auto merge of #59415 - varkor:values_since_snapshot, r=eddyb
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](https://github.com/rust-lang-nursery/ena/pull/21). - Some other refactoring in the area. r? @eddyb
This commit is contained in:
commit
33ef0bad21
11
Cargo.lock
11
Cargo.lock
@ -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"
|
||||
@ -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)",
|
||||
@ -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"
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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,
|
||||
);
|
||||
|
||||
Ok((type_variables, region_vars, value))
|
||||
let fudger = InferenceFudger {
|
||||
infcx: self,
|
||||
type_vars,
|
||||
int_vars,
|
||||
float_vars,
|
||||
region_vars,
|
||||
};
|
||||
|
||||
Ok((fudger, value))
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
@ -84,29 +101,26 @@ 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: ®ion_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
|
||||
}
|
||||
@ -114,25 +128,36 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, '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),
|
||||
@ -140,13 +165,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
@ -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`].
|
||||
|
@ -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;
|
||||
|
||||
@ -58,8 +58,6 @@ pub enum TypeVariableOrigin {
|
||||
Generalized(ty::TyVid),
|
||||
}
|
||||
|
||||
pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>;
|
||||
|
||||
struct TypeVariableData {
|
||||
origin: TypeVariableOrigin,
|
||||
diverging: bool,
|
||||
@ -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`
|
||||
|
@ -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)]
|
||||
|
@ -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"
|
||||
|
@ -92,7 +92,7 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
use crate::middle::lang_items;
|
||||
use crate::namespace::Namespace;
|
||||
use rustc::infer::{self, InferCtxt, InferOk, InferResult, RegionVariableOrigin};
|
||||
use rustc::infer::{self, InferCtxt, InferOk, InferResult};
|
||||
use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
@ -3097,8 +3097,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
_ => None
|
||||
}
|
||||
});
|
||||
opt_ty.unwrap_or_else(
|
||||
|| tcx.mk_int_var(self.next_int_var_id()))
|
||||
opt_ty.unwrap_or_else(|| self.next_int_var())
|
||||
}
|
||||
ast::LitKind::Float(_, t) => tcx.mk_mach_float(t),
|
||||
ast::LitKind::FloatUnsuffixed(_) => {
|
||||
@ -3108,8 +3107,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
_ => None
|
||||
}
|
||||
});
|
||||
opt_ty.unwrap_or_else(
|
||||
|| tcx.mk_float_var(self.next_float_var_id()))
|
||||
opt_ty.unwrap_or_else(|| self.next_float_var())
|
||||
}
|
||||
ast::LitKind::Bool(_) => tcx.types.bool,
|
||||
ast::LitKind::Err(_) => tcx.types.err,
|
||||
@ -3231,7 +3229,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
Some(ret) => ret,
|
||||
None => return Vec::new()
|
||||
};
|
||||
let expect_args = self.fudge_regions_if_ok(&RegionVariableOrigin::Coercion(call_span), || {
|
||||
let expect_args = self.fudge_inference_if_ok(|| {
|
||||
// Attempt to apply a subtyping relationship between the formal
|
||||
// return type (likely containing type variables if the function
|
||||
// is polymorphic) and the expected return type.
|
||||
|
Loading…
Reference in New Issue
Block a user