diff --git a/Cargo.lock b/Cargo.lock index 7fd39bd1f6eb6..73adb762e485b 100644 --- a/Cargo.lock +++ b/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" diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 95fdd6f01e2a8..39b84fabff6fb 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -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() } diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 5f6a8802b4def..7788ae2b88f21 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -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`) -- and remember that /// after the snapshot is popped, the variable `?T` is no longer /// unified. - pub fn fudge_regions_if_ok(&self, - origin: &RegionVariableOrigin, - f: F) -> Result where + pub fn fudge_inference_if_ok( + &self, + f: F, + ) -> Result where F: FnOnce() -> Result, 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), } @@ -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, - origin: &'a RegionVariableOrigin, + type_vars: (Range, Vec), + int_vars: Range, + float_vars: Range, + region_vars: (Range, Vec), } -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 } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index cc1c439f3bd94..16140d006bf09 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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. diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 8389f0ab1aa79..6a20d95cc3ad3 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -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 { - 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, Vec) { + 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`]. diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 4c76818346b43..8a719ff2bf31c 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -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; - 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, Vec) { + 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` diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4b2fda3b02f9d..e905c3688518b 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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)] diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 6002bf69b7069..63e44d82a28c3 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -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" diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b11bd9c2408bf..ec4fc2a3bfb88 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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.