diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index ff73f135ce6..c73f171806e 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -277,8 +277,8 @@ for mir::StatementKind<'gcx> { op.hash_stable(hcx, hasher); places.hash_stable(hcx, hasher); } - mir::StatementKind::UserAssertTy(ref ty, ref local) => { - ty.hash_stable(hcx, hasher); + mir::StatementKind::UserAssertTy(ref c_ty, ref local) => { + c_ty.hash_stable(hcx, hasher); local.hash_stable(hcx, hasher); } mir::StatementKind::Nop => {} diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs index 22526c7751d..debddd708ea 100644 --- a/src/librustc/infer/canonical.rs +++ b/src/librustc/infer/canonical.rs @@ -33,6 +33,7 @@ use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin}; use rustc_data_structures::indexed_vec::Idx; +use serialize::UseSpecializedDecodable; use std::fmt::Debug; use std::ops::Index; use syntax::codemap::Span; @@ -49,7 +50,7 @@ use rustc_data_structures::fx::FxHashMap; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewriten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub struct Canonical<'gcx, V> { pub variables: CanonicalVarInfos<'gcx>, pub value: V, @@ -57,6 +58,8 @@ pub struct Canonical<'gcx, V> { pub type CanonicalVarInfos<'gcx> = &'gcx Slice; +impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> { } + /// A set of values corresponding to the canonical variables from some /// `Canonical`. You can give these values to /// `canonical_value.substitute` to substitute them into the canonical @@ -69,7 +72,7 @@ pub type CanonicalVarInfos<'gcx> = &'gcx Slice; /// You can also use `infcx.fresh_inference_vars_for_canonical_vars` /// to get back a `CanonicalVarValues` containing fresh inference /// variables. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub struct CanonicalVarValues<'tcx> { pub var_values: IndexVec>, } @@ -78,7 +81,7 @@ pub struct CanonicalVarValues<'tcx> { /// canonical value. This is sufficient information for code to create /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub struct CanonicalVarInfo { pub kind: CanonicalVarKind, } @@ -86,7 +89,7 @@ pub struct CanonicalVarInfo { /// Describes the "kind" of the canonical variable. This is a "kind" /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub enum CanonicalVarKind { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), @@ -100,7 +103,7 @@ pub enum CanonicalVarKind { /// 22.) can only be instantiated with integral/float types (e.g., /// usize or f32). In order to faithfully reproduce a type, we need to /// know what set of types a given type variable can be unified with. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub enum CanonicalTyVarKind { /// General type variable `?T` that can be unified with arbitrary types. General, @@ -855,11 +858,14 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'g } CloneTypeFoldableAndLiftImpls! { + ::infer::canonical::Certainty, + ::infer::canonical::CanonicalVarInfo, + ::infer::canonical::CanonicalVarKind, +} + +CloneTypeFoldableImpls! { for <'tcx> { - ::infer::canonical::Certainty, - ::infer::canonical::CanonicalVarInfo, ::infer::canonical::CanonicalVarInfos<'tcx>, - ::infer::canonical::CanonicalVarKind, } } @@ -870,6 +876,13 @@ BraceStructTypeFoldableImpl! { } where C: TypeFoldable<'tcx> } +BraceStructLiftImpl! { + impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> { + type Lifted = Canonical<'tcx, T::Lifted>; + variables, value + } where T: Lift<'tcx> +} + impl<'tcx> CanonicalVarValues<'tcx> { fn iter<'a>(&'a self) -> impl Iterator> + 'a { self.var_values.iter().cloned() diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c36e401e8d6..9229724f094 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -27,7 +27,7 @@ use hir::def_id::DefId; use mir::visit::MirVisitable; use mir::interpret::{Value, PrimVal}; use ty::subst::{Subst, Substs}; -use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; +use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::TypeAndMut; use util::ppaux; @@ -1260,7 +1260,7 @@ pub enum StatementKind<'tcx> { /// /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y` /// is the right thing. - UserAssertTy(Ty<'tcx>, Local), + UserAssertTy(CanonicalTy<'tcx>, Local), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, @@ -1333,7 +1333,8 @@ impl<'tcx> Debug for Statement<'tcx> { InlineAsm { ref asm, ref outputs, ref inputs } => { write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs) }, - UserAssertTy(ref ty, ref local) => write!(fmt, "UserAssertTy({:?}, {:?})", ty, local), + UserAssertTy(ref c_ty, ref local) => write!(fmt, "UserAssertTy({:?}, {:?})", + c_ty, local), Nop => write!(fmt, "nop"), } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index cc5d9692e7a..a3fdb6f73ab 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::subst::Substs; -use ty::{ClosureSubsts, Region, Ty, GeneratorInterior}; +use ty::{CanonicalTy, ClosureSubsts, Region, Ty, GeneratorInterior}; use mir::*; use syntax_pos::Span; @@ -145,10 +145,10 @@ macro_rules! make_mir_visitor { } fn visit_user_assert_ty(&mut self, - ty: & $($mutability)* Ty<'tcx>, + c_ty: & $($mutability)* CanonicalTy<'tcx>, local: & $($mutability)* Local, location: Location) { - self.super_user_assert_ty(ty, local, location); + self.super_user_assert_ty(c_ty, local, location); } fn visit_place(&mut self, @@ -383,9 +383,9 @@ macro_rules! make_mir_visitor { self.visit_operand(input, location); } } - StatementKind::UserAssertTy(ref $($mutability)* ty, + StatementKind::UserAssertTy(ref $($mutability)* c_ty, ref $($mutability)* local) => { - self.visit_user_assert_ty(ty, local, location); + self.visit_user_assert_ty(c_ty, local, location); } StatementKind::Nop => {} } @@ -631,10 +631,9 @@ macro_rules! make_mir_visitor { } fn super_user_assert_ty(&mut self, - ty: & $($mutability)* Ty<'tcx>, + _c_ty: & $($mutability)* CanonicalTy<'tcx>, local: & $($mutability)* Local, location: Location) { - self.visit_ty(ty, TyContext::Location(location)); self.visit_local(local, PlaceContext::Validate, location); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fd3465f59eb..573d2771322 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -48,6 +48,7 @@ use ty::layout::{LayoutDetails, TargetDataLayout}; use ty::maps; use ty::steal::Steal; use ty::BindingMode; +use ty::CanonicalTy; use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -344,6 +345,9 @@ pub struct TypeckTables<'tcx> { /// method calls, including those of overloaded operators. type_dependent_defs: ItemLocalMap, + /// Stores the canonicalized types provided by the user. + user_provided_tys: ItemLocalMap>, + /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated until after typeck. See /// typeck::check::fn_ctxt for details. @@ -420,6 +424,7 @@ impl<'tcx> TypeckTables<'tcx> { TypeckTables { local_id_root, type_dependent_defs: ItemLocalMap(), + user_provided_tys: ItemLocalMap(), node_types: ItemLocalMap(), node_substs: ItemLocalMap(), adjustments: ItemLocalMap(), @@ -461,6 +466,20 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn user_provided_tys(&self) -> LocalTableInContext> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.user_provided_tys + } + } + + pub fn user_provided_tys_mut(&mut self) -> LocalTableInContextMut> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.user_provided_tys + } + } + pub fn node_types(&self) -> LocalTableInContext> { LocalTableInContext { local_id_root: self.local_id_root, @@ -685,6 +704,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { let ty::TypeckTables { local_id_root, ref type_dependent_defs, + ref user_provided_tys, ref node_types, ref node_substs, ref adjustments, @@ -704,6 +724,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { type_dependent_defs.hash_stable(hcx, hasher); + user_provided_tys.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); adjustments.hash_stable(hcx, hasher); @@ -1635,6 +1656,24 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { } } +impl<'a, 'tcx> Lift<'tcx> for &'a Slice { + type Lifted = &'tcx Slice; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + if self.len() == 0 { + return Some(Slice::empty()); + } + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + pub mod tls { use super::{CtxtInterners, GlobalCtxt, TyCtxt}; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 95c5cd377d7..68bc2449711 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,6 +21,7 @@ use hir::map::DefPathData; use hir::svh::Svh; use ich::Fingerprint; use ich::StableHashingContext; +use infer::canonical::{Canonical, Canonicalize}; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; @@ -554,6 +555,17 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {} +pub type CanonicalTy<'gcx> = Canonical<'gcx, Ty<'gcx>>; + +impl <'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> { + type Canonicalized = CanonicalTy<'gcx>; + + fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>, + value: Canonical<'gcx, Self::Lifted>) -> Self::Canonicalized { + value + } +} + /// A wrapper for slices with the additional invariant /// that the slice is interned and no other slice with /// the same contents can exist in the same context. diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index c06f77b2d84..afaedecdf0a 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -15,7 +15,7 @@ use rustc::mir::Place::Projection; use rustc::mir::{Local, PlaceProjection, ProjectionElem}; use rustc::mir::visit::TyContext; use rustc::infer::InferCtxt; -use rustc::ty::{self, ClosureSubsts, Ty}; +use rustc::ty::{self, CanonicalTy, ClosureSubsts}; use rustc::ty::subst::Substs; use rustc::ty::fold::TypeFoldable; @@ -107,7 +107,8 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx self.super_rvalue(rvalue, location); } - fn visit_user_assert_ty(&mut self, _ty: &Ty<'tcx>, _local: &Local, _location: Location) { } + fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>, + _local: &Local, _location: Location) { } } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 38a14be8eb2..04c206b5c0c 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::ty::subst::Substs; -use rustc::ty::{self, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable}; +use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable}; use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -118,7 +118,7 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_closure_substs: substs={:?}", substs); } - fn visit_user_assert_ty(&mut self, _ty: &mut Ty<'tcx>, _local: &mut Local, + fn visit_user_assert_ty(&mut self, _c_ty: &mut CanonicalTy<'tcx>, _local: &mut Local, _location: Location) { // User-assert-ty statements represent types that the user added explicitly. // We don't want to erase the regions from these types: rather, we want to diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 2c06c93cd9d..80a439b1830 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -761,12 +761,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); }; } - StatementKind::UserAssertTy(ref ty, ref local) => { + StatementKind::UserAssertTy(ref c_ty, ref local) => { let local_ty = mir.local_decls()[*local].ty; + let (ty, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars( + stmt.source_info.span, c_ty); debug!("check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty); - if let Err(terr) = - self.eq_types(ty, local_ty, location.at_self()) - { + if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) { span_mirbug!( self, stmt, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 4353eb5e4bd..b9a6616fd07 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -145,18 +145,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { end_block.unit() } - pub fn user_assert_ty(&mut self, block: BasicBlock, ty: Ty<'tcx>, var: NodeId, span: Span) { + pub fn user_assert_ty(&mut self, block: BasicBlock, hir_id: hir::HirId, + var: NodeId, span: Span) { let local_id = self.var_indices[&var]; let source_info = self.source_info(span); - self.cfg.push(block, Statement { - source_info, - kind: StatementKind::UserAssertTy(ty, local_id), - }); + + debug!("user_assert_ty: local_id={:?}", hir_id.local_id); + if let Some(c_ty) = self.hir.tables.user_provided_tys().get(hir_id) { + debug!("user_assert_ty: c_ty={:?}", c_ty); + self.cfg.push(block, Statement { + source_info, + kind: StatementKind::UserAssertTy(*c_ty, local_id), + }); + } } pub fn expr_into_pattern(&mut self, mut block: BasicBlock, - ty: Option>, + ty: Option, irrefutable_pat: Pattern<'tcx>, initializer: ExprRef<'tcx>) -> BlockAnd<()> { diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index f0497338303..14aa307f0ae 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -76,7 +76,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, first_statement_index: region::FirstStatementIndex::new(index), }); - let ty = local.ty.clone().map(|ty| cx.tables().node_id_to_type(ty.hir_id)); + let ty = local.ty.clone().map(|ty| ty.hir_id); let pattern = cx.pattern_from_hir(&local.pat); result.push(StmtRef::Mirror(Box::new(Stmt { kind: StmtKind::Let { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 138944189ff..fe82b8158f7 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -97,7 +97,7 @@ pub enum StmtKind<'tcx> { pattern: Pattern<'tcx>, /// let pat: = init ... - ty: Option>, + ty: Option, /// let pat: ty = ... initializer: Option>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 69879bbe85d..e2f6c965c18 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -960,10 +960,19 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Add explicitly-declared locals. fn visit_local(&mut self, local: &'gcx hir::Local) { let o_ty = match local.ty { - Some(ref ty) => Some(self.fcx.to_ty(&ty)), - None => None + Some(ref ty) => { + let o_ty = self.fcx.to_ty(&ty); + + let (c_ty, _orig_values) = self.fcx.inh.infcx.canonicalize_query(&o_ty); + debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); + self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); + + Some(o_ty) + }, + None => None, }; self.assign(local.span, local.id, o_ty); + debug!("Local variable {:?} is assigned type {}", local.pat, self.fcx.ty_to_string( diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 862b15743c7..bbd04e0b19a 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -46,6 +46,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_anon_types(); wbcx.visit_cast_types(); wbcx.visit_free_region_map(); + wbcx.visit_user_provided_tys(); let used_trait_imports = mem::replace( &mut self.tables.borrow_mut().used_trait_imports, @@ -341,6 +342,33 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.tables.free_region_map = free_region_map; } + fn visit_user_provided_tys(&mut self) { + let fcx_tables = self.fcx.tables.borrow(); + debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); + let common_local_id_root = fcx_tables.local_id_root.unwrap(); + + for (&local_id, c_ty) in fcx_tables.user_provided_tys().iter() { + let hir_id = hir::HirId { + owner: common_local_id_root.index, + local_id, + }; + + let c_ty = if let Some(c_ty) = self.tcx().lift_to_global(c_ty) { + c_ty + } else { + span_bug!( + hir_id.to_span(&self.fcx.tcx), + "writeback: `{:?}` missing from the global type context", + c_ty + ); + }; + + self.tables + .user_provided_tys_mut() + .insert(hir_id, c_ty.clone()); + } + } + fn visit_anon_types(&mut self) { let gcx = self.tcx().global_tcx(); for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {