diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index ff73f135ce6436a3b0b1afef26cfc21f4bc6258d..c73f171806e42510e766cc4f347143b4effe9f8a 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -277,8 +277,8 @@ fn hash_stable(&self, 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 22526c7751d5021dfb4809f3b5a1d061e164aa6f..debddd708ea22bd3e0f69979739b0aaa5df3c608 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 @@ /// 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 struct Canonical<'gcx, V> { /// 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 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { } 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 @@ impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> { } 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 c36e401e8d69b07cd0f24d71bf8b639b6b6ae3dd..9229724f0941dcff625038c591ea20b74a6c29d8 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -27,7 +27,7 @@ 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 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { 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 cc5d9692e7a607a08210aa6915887066941b09ca..a3fdb6f73abb0e97f13c49244a33f39fa16ff7d3 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 @@ fn visit_operand(&mut self, } 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 @@ fn super_statement(&mut self, 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 @@ fn super_operand(&mut self, } 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 fd3465f59ebf2c79661fc694f21dde7dff3f9072..573d2771322967665da41afb5af8ea54a95d8064 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -48,6 +48,7 @@ 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 @@ pub fn empty(local_id_root: Option) -> 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 @@ pub fn type_dependent_defs_mut(&mut self) -> LocalTableInContextMut { } } + 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 @@ fn hash_stable(&self, 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 @@ fn hash_stable(&self, 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 @@ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) } } +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 95c5cd377d71f4c190adf60e2eca2374be9d3f5a..68bc244971138d683c8b46d366d0ded30324edd6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,6 +21,7 @@ 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 @@ fn hash_stable(&self, 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 c06f77b2d84913a1bd091a32c0f7e4b96f7fd66d..afaedecdf0abe307400847586aebaf1c0a98a838 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::{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 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { 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 38a14be8eb2627940c388d71631d4fd84a51929e..04c206b5c0c40b4d0f82891e6b7ce11672d5c04b 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 @@ fn visit_closure_substs(&mut self, substs: &mut ClosureSubsts<'tcx>, location: L 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 2c06c93cd9d24ebaffc19cb0712d629600e53db0..80a439b183058d1c12b2cff3f2ba497be454558f 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 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca ); }; } - 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 4353eb5e4bd38449f6697c5a76271b21566fe100..b9a6616fd076c7fceec90fb39dce8fe08a4eefab 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -145,18 +145,24 @@ pub fn match_expr(&mut self, 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 f04973383037806535c9eb0a875654c3443796d3..14aa307f0ae1f1a24652a4b6a60cb3cf44da2edc 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 138944189ff5aad19884c2ef4412a46980eae64d..fe82b8158f76dbed8188e15843443d9259b32bde 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 69879bbe85d6e4e50d22af815d071c08be95a4f2..e2f6c965c18e91973576d4cec56b8e4ddac9b1e7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -960,10 +960,19 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { // 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 862b15743c701d60aa769128bb96a57563fbc221..bbd04e0b19ae194a3e9365bf2df24d1437aa88dd 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -46,6 +46,7 @@ pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) -> &'gcx ty::Type 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 @@ fn visit_free_region_map(&mut self) { 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() {