From 24a7a010d1015731418852d893d889f4bcbdeb51 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 16 Nov 2018 22:56:18 +0100 Subject: [PATCH 01/11] Refactor `UserTypeAnnotation`. This commit refactors the `UserTypeAnnotation` type to be referred to by an index within `UserTypeProjection`. `UserTypeAnnotation` is instead kept in an `IndexVec` within the `Mir` struct. Further, instead of `UserTypeAnnotation` containing canonicalized types, it now contains normal types and the entire `UserTypeAnnotation` is canonicalized. To support this, the type was moved from the `rustc::mir` module to `rustc::ty` module. --- src/librustc/ich/impls_mir.rs | 17 -- src/librustc/ich/impls_ty.rs | 26 ++++ src/librustc/mir/mod.rs | 50 ++---- src/librustc/mir/visit.rs | 24 +-- src/librustc/ty/context.rs | 146 +++++++++++++----- src/librustc/ty/mod.rs | 4 + src/librustc/ty/subst.rs | 40 +---- src/librustc_mir/borrow_check/nll/renumber.rs | 14 +- .../borrow_check/nll/type_check/mod.rs | 88 +++++++---- src/librustc_mir/build/expr/as_constant.rs | 15 +- src/librustc_mir/build/expr/as_place.rs | 10 +- src/librustc_mir/build/expr/as_rvalue.rs | 3 + src/librustc_mir/build/matches/mod.rs | 14 +- src/librustc_mir/build/mod.rs | 3 + src/librustc_mir/hair/cx/block.rs | 5 +- src/librustc_mir/hair/cx/expr.rs | 63 +++++--- src/librustc_mir/hair/mod.rs | 13 +- src/librustc_mir/hair/pattern/mod.rs | 73 +++++---- src/librustc_mir/hair/util.rs | 34 ++-- src/librustc_mir/shim.rs | 4 + src/librustc_mir/transform/promote_consts.rs | 1 + src/librustc_traits/type_op.rs | 30 +--- src/librustc_typeck/check/mod.rs | 101 ++++++------ src/librustc_typeck/check/writeback.rs | 29 ++-- src/test/mir-opt/basic_assignment.rs | 2 +- .../dump-adt-brace-struct.stderr | 2 +- .../user-annotations/dump-fn-method.stderr | 20 +-- 27 files changed, 476 insertions(+), 355 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index dbabff9ee88c2..002ac7cc7a9bb 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -494,22 +494,5 @@ impl<'a, 'gcx> HashStable> for mir::ClosureOutlivesSubj impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted }); -impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation<'gcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - mir::UserTypeAnnotation::Ty(ref ty) => { - ty.hash_stable(hcx, hasher); - } - mir::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => { - def_id.hash_stable(hcx, hasher); - substs.hash_stable(hcx, hasher); - } - } - } -} - impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base, projs }); impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents }); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 65b8f04e30a12..b2fe4b7561c5a 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1251,3 +1251,29 @@ impl_stable_hash_for!( goal, } ); + +impl<'a, 'gcx> HashStable> for ty::UserTypeAnnotation<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::UserTypeAnnotation::Ty(ref ty) => { + ty.hash_stable(hcx, hasher); + } + ty::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a> HashStable> for ty::UserTypeAnnotationIndex { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + self.index().hash_stable(hcx, hasher); + } +} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 36d51c5971278..ecbe14c093f40 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -27,9 +27,12 @@ use syntax::ast::{self, Name}; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use ty::subst::{CanonicalUserSubsts, Subst, Substs}; -use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt}; +use ty::subst::{Subst, Substs}; use ty::layout::VariantIdx; +use ty::{ + self, AdtDef, CanonicalUserTypeAnnotations, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt, + UserTypeAnnotationIndex, UserTypeAnnotation, +}; use util::ppaux; pub use mir::interpret::AssertMessage; @@ -121,6 +124,9 @@ pub struct Mir<'tcx> { /// variables and temporaries. pub local_decls: LocalDecls<'tcx>, + /// User type annotations + pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, + /// Number of arguments this function takes. /// /// Starting at local 1, `arg_count` locals will be provided by the caller @@ -161,7 +167,8 @@ impl<'tcx> Mir<'tcx> { source_scope_local_data: ClearCrossCrate>, promoted: IndexVec>, yield_ty: Option>, - local_decls: IndexVec>, + local_decls: LocalDecls<'tcx>, + user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, arg_count: usize, upvar_decls: Vec, span: Span, @@ -185,6 +192,7 @@ impl<'tcx> Mir<'tcx> { generator_drop: None, generator_layout: None, local_decls, + user_type_annotations, arg_count, upvar_decls, spread_arg: None, @@ -418,6 +426,7 @@ impl_stable_hash_for!(struct Mir<'tcx> { generator_drop, generator_layout, local_decls, + user_type_annotations, arg_count, upvar_decls, spread_arg, @@ -2232,7 +2241,7 @@ pub enum AggregateKind<'tcx> { &'tcx AdtDef, VariantIdx, &'tcx Substs<'tcx>, - Option>, + Option, Option, ), @@ -2446,38 +2455,11 @@ pub struct Constant<'tcx> { /// indicate that `Vec<_>` was explicitly specified. /// /// Needed for NLL to impose user-given type constraints. - pub user_ty: Option>, + pub user_ty: Option, pub literal: &'tcx ty::Const<'tcx>, } -/// A user-given type annotation attached to a constant. These arise -/// from constants that are named via paths, like `Foo::::new` and -/// so forth. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub enum UserTypeAnnotation<'tcx> { - Ty(CanonicalTy<'tcx>), - - /// The canonical type is the result of `type_of(def_id)` with the - /// given substitutions applied. - TypeOf(DefId, CanonicalUserSubsts<'tcx>), -} - -EnumTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { - (UserTypeAnnotation::Ty)(ty), - (UserTypeAnnotation::TypeOf)(def, substs), - } -} - -EnumLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> { - type Lifted = UserTypeAnnotation<'tcx>; - (UserTypeAnnotation::Ty)(ty), - (UserTypeAnnotation::TypeOf)(def, substs), - } -} - /// A collection of projections into user types. /// /// They are projections because a binding can occur a part of a @@ -2556,7 +2538,7 @@ impl<'tcx> UserTypeProjections<'tcx> { /// determined by finding the type of the `.0` field from `T`. #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct UserTypeProjection<'tcx> { - pub base: UserTypeAnnotation<'tcx>, + pub base: UserTypeAnnotationIndex, pub projs: Vec>, } @@ -2970,6 +2952,7 @@ CloneTypeFoldableAndLiftImpls! { SourceScope, SourceScopeData, SourceScopeLocalData, + UserTypeAnnotationIndex, } BraceStructTypeFoldableImpl! { @@ -2983,6 +2966,7 @@ BraceStructTypeFoldableImpl! { generator_drop, generator_layout, local_decls, + user_type_annotations, arg_count, upvar_decls, spread_arg, diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index a20b8231f88a2..67f85fbc8679e 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -1,4 +1,5 @@ use hir::def_id::DefId; +use infer::canonical::Canonical; use ty::subst::Substs; use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty}; use mir::*; @@ -219,9 +220,10 @@ macro_rules! make_mir_visitor { fn visit_user_type_annotation( &mut self, - ty: & $($mutability)* UserTypeAnnotation<'tcx>, + index: UserTypeAnnotationIndex, + ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>, ) { - self.super_user_type_annotation(ty); + self.super_user_type_annotation(index, ty); } fn visit_region(&mut self, @@ -307,6 +309,14 @@ macro_rules! make_mir_visitor { self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]); } + for index in mir.user_type_annotations.indices() { + let (span, annotation) = & $($mutability)* mir.user_type_annotations[index]; + self.visit_user_type_annotation( + index, annotation + ); + self.visit_span(span); + } + self.visit_span(&$($mutability)* mir.span); } @@ -865,18 +875,14 @@ macro_rules! make_mir_visitor { fn super_user_type_projection( &mut self, - ty: & $($mutability)* UserTypeProjection<'tcx>, + _ty: & $($mutability)* UserTypeProjection<'tcx>, ) { - let UserTypeProjection { - ref $($mutability)* base, - projs: _, // Note: Does not visit projection elems! - } = *ty; - self.visit_user_type_annotation(base); } fn super_user_type_annotation( &mut self, - _ty: & $($mutability)* UserTypeAnnotation<'tcx>, + _index: UserTypeAnnotationIndex, + _ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>, ) { } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ea69d466ba6c5..32348e2e5046d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,7 @@ use hir::map as hir_map; use hir::map::DefPathHash; use lint::{self, Lint}; use ich::{StableHashingContext, NodeIdHashingMode}; -use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; +use infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use infer::outlives::free_region_map::FreeRegionMap; use middle::cstore::CrateStoreDyn; use middle::cstore::EncodedMetadata; @@ -23,7 +23,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret, ProjectionKind}; use mir::interpret::Allocation; -use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst}; +use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; use traits; use traits::{Clause, Clauses, GoalKind, Goal, Goals}; @@ -38,8 +38,8 @@ use ty::GenericParamDefKind; use ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx}; use ty::query; use ty::steal::Steal; -use ty::BindingMode; -use ty::CanonicalTy; +use ty::subst::{UserSubsts, UnpackedKind}; +use ty::{BoundVar, BindingMode}; use ty::CanonicalPolyFnSig; use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; @@ -49,7 +49,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableHasher, StableHasherResult, StableVec}; use arena::{TypedArena, SyncDroplessArena}; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::sync::{self, Lrc, Lock, WorkerLocal}; use std::any::Any; use std::borrow::Borrow; @@ -342,26 +342,21 @@ pub struct TypeckTables<'tcx> { /// other items. node_substs: ItemLocalMap<&'tcx Substs<'tcx>>, - /// Stores the canonicalized types provided by the user. See also - /// `AscribeUserType` statement in MIR. - user_provided_tys: ItemLocalMap>, + /// This will either store the canonicalized types provided by the user + /// or the substitutions that the user explicitly gave (if any) attached + /// to `id`. These will not include any inferred values. The canonical form + /// is used to capture things like `_` or other unspecified values. + /// + /// For example, if the user wrote `foo.collect::>()`, then the + /// canonical substitutions would include only `for { Vec }`. + /// + /// See also `AscribeUserType` statement in MIR. + user_provided_types: ItemLocalMap>, /// Stores the canonicalized types provided by the user. See also /// `AscribeUserType` statement in MIR. pub user_provided_sigs: DefIdMap>, - /// Stores the substitutions that the user explicitly gave (if any) - /// attached to `id`. These will not include any inferred - /// values. The canonical form is used to capture things like `_` - /// or other unspecified values. - /// - /// Example: - /// - /// If the user wrote `foo.collect::>()`, then the - /// canonical substitutions would include only `for { Vec - /// }`. - user_substs: ItemLocalMap>, - adjustments: ItemLocalMap>>, /// Stores the actual binding mode for all instances of hir::BindingAnnotation. @@ -432,11 +427,10 @@ impl<'tcx> TypeckTables<'tcx> { local_id_root, type_dependent_defs: Default::default(), field_indices: Default::default(), - user_provided_tys: Default::default(), + user_provided_types: Default::default(), user_provided_sigs: Default::default(), node_types: Default::default(), node_substs: Default::default(), - user_substs: Default::default(), adjustments: Default::default(), pat_binding_modes: Default::default(), pat_adjustments: Default::default(), @@ -491,17 +485,21 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn user_provided_tys(&self) -> LocalTableInContext<'_, CanonicalTy<'tcx>> { + pub fn user_provided_types( + &self + ) -> LocalTableInContext<'_, CanonicalUserTypeAnnotation<'tcx>> { LocalTableInContext { local_id_root: self.local_id_root, - data: &self.user_provided_tys + data: &self.user_provided_types } } - pub fn user_provided_tys_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalTy<'tcx>> { + pub fn user_provided_types_mut( + &mut self + ) -> LocalTableInContextMut<'_, CanonicalUserTypeAnnotation<'tcx>> { LocalTableInContextMut { local_id_root: self.local_id_root, - data: &mut self.user_provided_tys + data: &mut self.user_provided_types } } @@ -551,18 +549,6 @@ impl<'tcx> TypeckTables<'tcx> { self.node_substs.get(&id.local_id).cloned() } - pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalUserSubsts<'tcx>> { - LocalTableInContextMut { - local_id_root: self.local_id_root, - data: &mut self.user_substs - } - } - - pub fn user_substs(&self, id: hir::HirId) -> Option> { - validate_hir_id_for_typeck_tables(self.local_id_root, id, false); - self.user_substs.get(&id.local_id).cloned() - } - // Returns the type of a pattern as a monotype. Like @expr_ty, this function // doesn't provide type parameter substitutions. pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { @@ -739,11 +725,10 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { local_id_root, ref type_dependent_defs, ref field_indices, - ref user_provided_tys, + ref user_provided_types, ref user_provided_sigs, ref node_types, ref node_substs, - ref user_substs, ref adjustments, ref pat_binding_modes, ref pat_adjustments, @@ -763,11 +748,10 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { type_dependent_defs.hash_stable(hcx, hasher); field_indices.hash_stable(hcx, hasher); - user_provided_tys.hash_stable(hcx, hasher); + user_provided_types.hash_stable(hcx, hasher); user_provided_sigs.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); - user_substs.hash_stable(hcx, hasher); adjustments.hash_stable(hcx, hasher); pat_binding_modes.hash_stable(hcx, hasher); pat_adjustments.hash_stable(hcx, hasher); @@ -805,6 +789,84 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { } } +newtype_index! { + pub struct UserTypeAnnotationIndex { + DEBUG_FORMAT = "UserTypeAnnotation({})", + const START_INDEX = 0, + } +} + +/// Mapping of type annotation indices to canonical user type annotations. +pub type CanonicalUserTypeAnnotations<'tcx> = + IndexVec)>; + +/// Canonicalized user type annotation. +pub type CanonicalUserTypeAnnotation<'gcx> = Canonical<'gcx, UserTypeAnnotation<'gcx>>; + +impl CanonicalUserTypeAnnotation<'gcx> { + /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, + /// i.e. each thing is mapped to a canonical variable with the same index. + pub fn is_identity(&self) -> bool { + match self.value { + UserTypeAnnotation::Ty(_) => false, + UserTypeAnnotation::TypeOf(_, user_substs) => { + if user_substs.user_self_ty.is_some() { + return false; + } + + user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { + match kind.unpack() { + UnpackedKind::Type(ty) => match ty.sty { + ty::Bound(debruijn, b) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(debruijn, ty::INNERMOST); + cvar == b.var + } + _ => false, + }, + + UnpackedKind::Lifetime(r) => match r { + ty::ReLateBound(debruijn, br) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(*debruijn, ty::INNERMOST); + cvar == br.assert_bound_var() + } + _ => false, + }, + } + }) + }, + } + } +} + +/// A user-given type annotation attached to a constant. These arise +/// from constants that are named via paths, like `Foo::::new` and +/// so forth. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum UserTypeAnnotation<'tcx> { + Ty(Ty<'tcx>), + + /// The canonical type is the result of `type_of(def_id)` with the + /// given substitutions applied. + TypeOf(DefId, UserSubsts<'tcx>), +} + +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { + (UserTypeAnnotation::Ty)(ty), + (UserTypeAnnotation::TypeOf)(def, substs), + } +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> { + type Lifted = UserTypeAnnotation<'tcx>; + (UserTypeAnnotation::Ty)(ty), + (UserTypeAnnotation::TypeOf)(def, substs), + } +} + impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8348aa8a95612..d40dd830e9fb9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -73,6 +73,10 @@ pub use self::binding::BindingMode::*; pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local}; pub use self::context::{Lift, TypeckTables, CtxtInterners}; +pub use self::context::{ + UserTypeAnnotationIndex, UserTypeAnnotation, CanonicalUserTypeAnnotation, + CanonicalUserTypeAnnotations, +}; pub use self::instance::{Instance, InstanceDef}; diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 560e80abb9cbd..64e7af815b4bf 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -2,12 +2,11 @@ use hir::def_id::DefId; use infer::canonical::Canonical; -use ty::{self, BoundVar, Lift, List, Ty, TyCtxt}; +use ty::{self, Lift, List, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; -use rustc_data_structures::indexed_vec::Idx; use smallvec::SmallVec; use core::intrinsics; @@ -559,43 +558,6 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>; -impl CanonicalUserSubsts<'tcx> { - /// True if this represents a substitution like - /// - /// ```text - /// [?0, ?1, ?2] - /// ``` - /// - /// i.e., each thing is mapped to a canonical variable with the same index. - pub fn is_identity(&self) -> bool { - if self.value.user_self_ty.is_some() { - return false; - } - - self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { - match kind.unpack() { - UnpackedKind::Type(ty) => match ty.sty { - ty::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); - cvar == b.var - } - _ => false, - }, - - UnpackedKind::Lifetime(r) => match r { - ty::ReLateBound(debruijn, br) => { - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*debruijn, ty::INNERMOST); - cvar == br.assert_bound_var() - } - _ => false, - }, - } - }) - } -} - /// Stores the user-given substs to reach some fully qualified path /// (e.g., `::Item` or `::Item`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 673ee4ec017ac..55af7399aab8f 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,6 +1,10 @@ +use rustc::infer::canonical::Canonical; use rustc::ty::subst::Substs; -use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable}; -use rustc::mir::{Location, Mir, UserTypeAnnotation}; +use rustc::ty::{ + self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable, UserTypeAnnotation, + UserTypeAnnotationIndex, +}; +use rustc::mir::{Location, Mir}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -55,7 +59,11 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_ty: ty={:?}", ty); } - fn visit_user_type_annotation(&mut self, _ty: &mut UserTypeAnnotation<'tcx>) { + fn visit_user_type_annotation( + &mut self, + _index: UserTypeAnnotationIndex, + _ty: &mut Canonical<'tcx, UserTypeAnnotation<'tcx>>, + ) { // User type annotations represent the types that the user // wrote in the progarm. We don't want to erase the regions // from these types: rather, we want to add them as 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 6d2fb54587ea3..8f8abe09810a2 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -36,7 +36,10 @@ use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::{Subst, Substs, UnpackedKind}; -use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; +use rustc::ty::{ + self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserTypeAnnotation, + UserTypeAnnotationIndex, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::ty::layout::VariantIdx; @@ -272,19 +275,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.sanitize_constant(constant, location); self.sanitize_type(constant, constant.ty); - if let Some(user_ty) = constant.user_ty { + if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( constant.ty, ty::Variance::Invariant, - &UserTypeProjection { base: user_ty, projs: vec![], }, + &UserTypeProjection { base: annotation_index, projs: vec![], }, location.to_locations(), ConstraintCategory::Boring, ) { + let annotation = self.cx.instantiated_type_annotations[&annotation_index]; span_mirbug!( self, constant, "bad constant user type {:?} vs {:?}: {:?}", - user_ty, + annotation, constant.ty, terr, ); @@ -715,6 +719,15 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, + /// For each user-type annotation (identified by a UserTypeAnnotationIndex), we create + /// an "instantiated" version at the beginning of type check, which replaces each + /// canonical variable with a fresh inference variable. These instantiated versions are + /// stored either in this field or in user_substs, depending on the kind of user-type + /// annotation. They are then referenced by the code which has the job of enforcing these + /// annotations. Part of the reason for this setup is that it allows us to enforce basic + /// WF criteria on the types even if the code that referenced them is dead + /// code (see #54943). + instantiated_type_annotations: FxHashMap>, } struct BorrowCheckContext<'a, 'tcx: 'a> { @@ -860,7 +873,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, ) -> Self { - TypeChecker { + let mut checker = Self { infcx, last_span: DUMMY_SP, mir, @@ -871,7 +884,36 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { borrowck_context, reported_errors: Default::default(), universal_region_relations, + instantiated_type_annotations: Default::default(), + }; + checker.instantiate_user_type_annotations(); + checker + } + + /// Instantiate canonical types from user type annotations in the `Mir` into the + /// `TypeChecker`. Used when relating user type annotations and when checking if + /// annotations are well-formed. + fn instantiate_user_type_annotations(&mut self) { + debug!( + "instantiate_user_type_annotations: user_type_annotations={:?}", + self.mir.user_type_annotations + ); + for annotation_index in self.mir.user_type_annotations.indices() { + let (span, canonical_annotation) = &self.mir.user_type_annotations[annotation_index]; + let (mut annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars( + *span, &canonical_annotation + ); + match annotation { + UserTypeAnnotation::Ty(ref mut ty) => + *ty = self.normalize(ty, Locations::All(*span)), + _ => {}, + } + self.instantiated_type_annotations.insert(annotation_index, annotation); } + debug!( + "instantiate_user_type_annotations: instantiated_type_annotations={:?}", + self.instantiated_type_annotations, + ); } /// Given some operation `op` that manipulates types, proves @@ -1003,18 +1045,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { a, v, user_ty, locations, ); - match user_ty.base { - UserTypeAnnotation::Ty(canonical_ty) => { - let (ty, _) = self.infcx - .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); - + match self.instantiated_type_annotations[&user_ty.base] { + UserTypeAnnotation::Ty(ty) => { // The `TypeRelating` code assumes that "unresolved inference // variables" appear in the "a" side, so flip `Contravariant` // ambient variance to get the right relationship. let v1 = ty::Contravariant.xform(v); - let tcx = self.infcx.tcx; - let ty = self.normalize(ty, locations); // We need to follow any provided projetions into the type. // @@ -1048,13 +1085,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.relate_types(ty, v1, a, locations, category)?; } } - UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { - let ( - user_substs, - _, - ) = self.infcx - .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - + UserTypeAnnotation::TypeOf(def_id, user_substs) => { let projs = self.infcx.tcx.intern_projs(&user_ty.projs); self.fully_perform_op( locations, @@ -1225,19 +1256,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); } - if let Some(user_ty) = self.rvalue_user_ty(rv) { + if let Some(annotation_index) = self.rvalue_user_ty(rv) { if let Err(terr) = self.relate_type_and_user_type( rv_ty, ty::Variance::Invariant, - &UserTypeProjection { base: user_ty, projs: vec![], }, + &UserTypeProjection { base: annotation_index, projs: vec![], }, location.to_locations(), ConstraintCategory::Boring, ) { + let annotation = self.instantiated_type_annotations[&annotation_index]; span_mirbug!( self, stmt, "bad user type on rvalue ({:?} = {:?}): {:?}", - user_ty, + annotation, rv_ty, terr ); @@ -1282,21 +1314,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); }; } - StatementKind::AscribeUserType(ref place, variance, box ref c_ty) => { + StatementKind::AscribeUserType(ref place, variance, box ref projection) => { let place_ty = place.ty(mir, tcx).to_ty(tcx); if let Err(terr) = self.relate_type_and_user_type( place_ty, variance, - c_ty, + projection, Locations::All(stmt.source_info.span), ConstraintCategory::TypeAnnotation, ) { + let annotation = self.instantiated_type_annotations[&projection.base]; span_mirbug!( self, stmt, - "bad type assert ({:?} <: {:?}): {:?}", + "bad type assert ({:?} <: {:?} with projections {:?}): {:?}", place_ty, - c_ty, + annotation, + projection.projs, terr ); } @@ -1955,7 +1989,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { /// If this rvalue supports a user-given type annotation, then /// extract and return it. This represents the final type of the /// rvalue and will be unified with the inferred type. - fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option> { + fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option { match rvalue { Rvalue::Use(_) | Rvalue::Repeat(..) diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index a5fbe566a4a73..a431bfc61b37a 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -29,11 +29,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { lint_level: _, value, } => this.as_constant(value), - ExprKind::Literal { literal, user_ty } => Constant { - span, - ty, - user_ty, - literal, + ExprKind::Literal { literal, user_ty } => { + let user_ty = user_ty.map(|ty| { + this.canonical_user_type_annotations.push((span, ty)) + }); + Constant { + span, + ty, + user_ty, + literal, + } }, _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index d651b6bdca01f..3ed00d5797907 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -133,6 +133,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::PlaceTypeAscription { source, user_ty } => { let place = unpack!(block = this.as_place(block, source)); if let Some(user_ty) = user_ty { + let annotation_index = this.canonical_user_type_annotations.push( + (source_info.span, user_ty) + ); this.cfg.push( block, Statement { @@ -140,7 +143,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( place.clone(), Variance::Invariant, - box UserTypeProjection { base: user_ty, projs: vec![], }, + box UserTypeProjection { base: annotation_index, projs: vec![], }, ), }, ); @@ -153,6 +156,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block = this.as_temp(block, source.temp_lifetime, source, mutability) ); if let Some(user_ty) = user_ty { + let annotation_index = this.canonical_user_type_annotations.push( + (source_info.span, user_ty) + ); this.cfg.push( block, Statement { @@ -160,7 +166,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( Place::Local(temp.clone()), Variance::Invariant, - box UserTypeProjection { base: user_ty, projs: vec![], }, + box UserTypeProjection { base: annotation_index, projs: vec![], }, ), }, ); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 2f0e06cd4da29..7dcac05e702a3 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -331,6 +331,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .collect() }; + let user_ty = user_ty.map(|ty| { + this.canonical_user_type_annotations.push((expr_span, ty)) + }); let adt = box AggregateKind::Adt( adt_def, variant_index, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 86dbf1422738a..92642dff3dc68 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -302,6 +302,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); let ty_source_info = self.source_info(user_ty_span); + let user_ty = box pat_ascription_ty.user_ty( + &mut self.canonical_user_type_annotations, ty_source_info.span + ); self.cfg.push( block, Statement { @@ -309,7 +312,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( place, ty::Variance::Invariant, - box pat_ascription_ty.user_ty(), + user_ty, ), }, ); @@ -1314,6 +1317,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ascription.user_ty, ); + let user_ty = box ascription.user_ty.clone().user_ty( + &mut self.canonical_user_type_annotations, source_info.span + ); self.cfg.push( block, Statement { @@ -1321,7 +1327,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( ascription.source.clone(), ty::Variance::Covariant, - box ascription.user_ty.clone().user_ty(), + user_ty, ), }, ); @@ -1484,10 +1490,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()), BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()), }; + let user_ty = user_var_ty.clone().user_ty(&mut self.canonical_user_type_annotations); + debug!("declare_binding: user_ty={:?}", user_ty); let local = LocalDecl::<'tcx> { mutability, ty: var_ty, - user_ty: user_var_ty.clone().user_ty(), + user_ty, name: Some(name), source_info, visibility_scope, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index a700963749f67..8acdecf6fa248 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -379,6 +379,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// (A match binding can have two locals; the 2nd is for the arm's guard.) var_indices: NodeMap, local_decls: IndexVec>, + canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, upvar_decls: Vec, unit_temp: Option>, @@ -812,6 +813,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { LocalDecl::new_return_place(return_ty, return_span), 1, ), + canonical_user_type_annotations: IndexVec::new(), upvar_decls, var_indices: Default::default(), unit_temp: None, @@ -845,6 +847,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { IndexVec::new(), yield_ty, self.local_decls, + self.canonical_user_type_annotations, self.arg_count, self.upvar_decls, self.fn_span, diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 91568f7ff6b58..e73cc40c8c6e4 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -78,12 +78,13 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let mut pattern = cx.pattern_from_hir(&local.pat); if let Some(ty) = &local.ty { - if let Some(&user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) { + if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) { + debug!("mirror_stmts: user_ty={:?}", user_ty); pattern = Pattern { ty: pattern.ty, span: pattern.span, kind: Box::new(PatternKind::AscribeUserType { - user_ty: PatternTypeProjection::from_canonical_ty(user_ty), + user_ty: PatternTypeProjection::from_user_type(user_ty), user_ty_span: ty.span, subpattern: pattern }) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 7b1ed2b0b26ea..293058a0f26f5 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -11,7 +11,7 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; use rustc::hir::def_id::LocalDefId; -use rustc::mir::{BorrowKind}; +use rustc::mir::BorrowKind; use syntax_pos::Span; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { @@ -283,9 +283,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; if let Some((adt_def, index)) = adt_data { let substs = cx.tables().node_substs(fun.hir_id); - - let user_ty = cx.tables().user_substs(fun.hir_id) - .map(|user_substs| UserTypeAnnotation::TypeOf(adt_def.did, user_substs)); + let user_provided_types = cx.tables().user_provided_types(); + let user_ty = user_provided_types.get(fun.hir_id) + .map(|u_ty| *u_ty) + .map(|mut u_ty| { + if let UserTypeAnnotation::TypeOf(ref mut did, _) = &mut u_ty.value { + *did = adt_def.did; + } + u_ty + }); + debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty); let field_refs = args.iter() .enumerate() @@ -464,11 +471,14 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::Adt(adt, substs) => { match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { + let user_provided_types = cx.tables().user_provided_types(); + let user_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); + debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty); ExprKind::Adt { adt_def: adt, variant_index: VariantIdx::new(0), substs, - user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt), + user_ty, fields: field_refs(cx, fields), base: base.as_ref().map(|base| { FruInfo { @@ -487,11 +497,18 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, assert!(base.is_none()); let index = adt.variant_index_with_id(variant_id); + let user_provided_types = cx.tables().user_provided_types(); + let user_ty = user_provided_types.get(expr.hir_id) + .map(|u_ty| *u_ty); + debug!( + "make_mirror_unadjusted: (variant) user_ty={:?}", + user_ty + ); ExprKind::Adt { adt_def: adt, variant_index: index, substs, - user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt), + user_ty, fields: field_refs(cx, fields), base: None, } @@ -635,8 +652,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Cast(ref source, ref cast_ty) => { // Check for a user-given type annotation on this `cast` - let user_ty = cx.tables.user_provided_tys().get(cast_ty.hir_id) - .map(|&t| UserTypeAnnotation::Ty(t)); + let user_provided_types = cx.tables.user_provided_types(); + let user_ty = user_provided_types.get(cast_ty.hir_id); debug!( "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}", @@ -742,20 +759,20 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span: expr.span, kind: cast, }; + debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty); ExprKind::ValueTypeAscription { source: cast_expr.to_ref(), - user_ty: Some(user_ty), + user_ty: Some(*user_ty), } } else { cast } } hir::ExprKind::Type(ref source, ref ty) => { - let user_provided_tys = cx.tables.user_provided_tys(); - let user_ty = user_provided_tys - .get(ty.hir_id) - .map(|&c_ty| UserTypeAnnotation::Ty(c_ty)); + let user_provided_types = cx.tables.user_provided_types(); + let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty); + debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty); if source.is_place_expr() { ExprKind::PlaceTypeAscription { source: source.to_ref(), @@ -792,8 +809,9 @@ fn user_substs_applied_to_def( cx: &mut Cx<'a, 'gcx, 'tcx>, hir_id: hir::HirId, def: &Def, -) -> Option> { - match def { +) -> Option> { + debug!("user_substs_applied_to_def: def={:?}", def); + let user_provided_type = match def { // A reference to something callable -- e.g., a fn, method, or // a tuple-struct or tuple-variant. This has the type of a // `Fn` but with the user-given substitutions. @@ -802,8 +820,7 @@ fn user_substs_applied_to_def( Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) | Def::Const(_) | - Def::AssociatedConst(_) => - Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)), + Def::AssociatedConst(_) => cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty), // A unit struct/variant which is used as a value (e.g., // `None`). This has the type of the enum/struct that defines @@ -819,7 +836,9 @@ fn user_substs_applied_to_def( _ => bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id) - } + }; + debug!("user_substs_applied_to_def: user_provided_type={:?}", user_provided_type); + user_provided_type } fn method_callee<'a, 'gcx, 'tcx>( @@ -839,6 +858,7 @@ fn method_callee<'a, 'gcx, 'tcx>( span_bug!(expr.span, "no type-dependent def for method callee") }); let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def); + debug!("method_callee: user_ty={:?}", user_ty); (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty) } }; @@ -906,6 +926,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::VariantCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => { let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); + debug!("convert_path_expr: user_ty={:?}", user_ty); ExprKind::Literal { literal: ty::Const::zero_sized( cx.tcx, @@ -918,6 +939,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::Const(def_id) | Def::AssociatedConst(def_id) => { let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); + debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { literal: ty::Const::unevaluated( cx.tcx, @@ -931,6 +953,9 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::StructCtor(def_id, CtorKind::Const) | Def::VariantCtor(def_id, CtorKind::Const) => { + let user_provided_types = cx.tables.user_provided_types(); + let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); + debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); match cx.tables().node_id_to_type(expr.hir_id).sty { // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. @@ -939,7 +964,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, adt_def, variant_index: adt_def.variant_index_with_id(def_id), substs, - user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt_def), + user_ty: user_provided_type, fields: vec![], base: None, } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index bcca501e600ac..d36a6eb58b85a 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -4,11 +4,12 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc::mir::{BinOp, BorrowKind, UserTypeAnnotation, Field, UnOp}; +use rustc::mir::{BinOp, BorrowKind, Field, UnOp}; use rustc::hir::def_id::DefId; +use rustc::infer::canonical::Canonical; use rustc::middle::region; use rustc::ty::subst::Substs; -use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const}; +use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const, UserTypeAnnotation}; use rustc::ty::layout::VariantIdx; use rustc::hir; use syntax::ast; @@ -265,7 +266,7 @@ pub enum ExprKind<'tcx> { /// Optional user-given substs: for something like `let x = /// Bar:: { ... }`. - user_ty: Option>, + user_ty: Option>>, fields: Vec>, base: Option> @@ -273,12 +274,12 @@ pub enum ExprKind<'tcx> { PlaceTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: Option>, + user_ty: Option>>, }, ValueTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: Option>, + user_ty: Option>>, }, Closure { closure_id: DefId, @@ -288,7 +289,7 @@ pub enum ExprKind<'tcx> { }, Literal { literal: &'tcx Const<'tcx>, - user_ty: Option>, + user_ty: Option>>, }, InlineAsm { asm: &'tcx hir::InlineAsm, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 62ec52aac1346..fd3b07c0357b5 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -12,9 +12,10 @@ use hair::util::UserAnnotatedTyHelpers; use hair::constant::*; use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; -use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections}; +use rustc::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift}; +use rustc::ty::{CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotation}; use rustc::ty::subst::{Substs, Kind}; use rustc::ty::layout::VariantIdx; use rustc::hir::{self, PatKind, RangeEnd}; @@ -63,9 +64,15 @@ pub(crate) struct PatternTypeProjections<'tcx> { } impl<'tcx> PatternTypeProjections<'tcx> { - pub(crate) fn user_ty(self) -> UserTypeProjections<'tcx> { + pub(crate) fn user_ty( + self, + annotations: &mut CanonicalUserTypeAnnotations<'tcx>, + ) -> UserTypeProjections<'tcx> { UserTypeProjections::from_projections( - self.contents.into_iter().map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(), span))) + self.contents + .into_iter() + .map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(annotations, span), span)) + ) } pub(crate) fn none() -> Self { @@ -115,30 +122,33 @@ impl<'tcx> PatternTypeProjections<'tcx> { } #[derive(Clone, Debug)] -pub struct PatternTypeProjection<'tcx>(UserTypeProjection<'tcx>); +pub struct PatternTypeProjection<'tcx> { + pub base: CanonicalUserTypeAnnotation<'tcx>, + pub projs: Vec>, +} impl<'tcx> PatternTypeProjection<'tcx> { pub(crate) fn index(&self) -> Self { let mut new = self.clone(); - new.0.projs.push(ProjectionElem::Index(())); + new.projs.push(ProjectionElem::Index(())); new } pub(crate) fn subslice(&self, from: u32, to: u32) -> Self { let mut new = self.clone(); - new.0.projs.push(ProjectionElem::Subslice { from, to }); + new.projs.push(ProjectionElem::Subslice { from, to }); new } pub(crate) fn deref(&self) -> Self { let mut new = self.clone(); - new.0.projs.push(ProjectionElem::Deref); + new.projs.push(ProjectionElem::Deref); new } pub(crate) fn leaf(&self, field: Field) -> Self { let mut new = self.clone(); - new.0.projs.push(ProjectionElem::Field(field, ())); + new.projs.push(ProjectionElem::Field(field, ())); new } @@ -147,24 +157,29 @@ impl<'tcx> PatternTypeProjection<'tcx> { variant_index: VariantIdx, field: Field) -> Self { let mut new = self.clone(); - new.0.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); - new.0.projs.push(ProjectionElem::Field(field, ())); + new.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); + new.projs.push(ProjectionElem::Field(field, ())); new } - pub(crate) fn from_canonical_ty(c_ty: ty::CanonicalTy<'tcx>) -> Self { - Self::from_user_type(UserTypeAnnotation::Ty(c_ty)) - } - - pub(crate) fn from_user_type(u_ty: UserTypeAnnotation<'tcx>) -> Self { - Self::from_user_type_proj(UserTypeProjection { base: u_ty, projs: vec![], }) + pub(crate) fn from_user_type(user_annotation: CanonicalUserTypeAnnotation<'tcx>) -> Self { + Self { + base: user_annotation, + projs: Vec::new(), + } } - pub(crate) fn from_user_type_proj(u_ty: UserTypeProjection<'tcx>) -> Self { - PatternTypeProjection(u_ty) + pub(crate) fn user_ty( + self, + annotations: &mut CanonicalUserTypeAnnotations<'tcx>, + span: Span, + ) -> UserTypeProjection<'tcx> { + let annotation_index = annotations.push((span, self.base)); + UserTypeProjection { + base: annotation_index, + projs: self.projs + } } - - pub(crate) fn user_ty(self) -> UserTypeProjection<'tcx> { self.0 } } #[derive(Clone, Debug)] @@ -788,18 +803,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }; if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { - let subpattern = Pattern { - span, - ty, - kind: Box::new(kind), - }; - - debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span); - - let pat_ty = PatternTypeProjection::from_user_type(user_ty); + debug!("lower_variant_or_leaf: user_ty={:?} span={:?}", user_ty, span); kind = PatternKind::AscribeUserType { - subpattern, - user_ty: pat_ty, + subpattern: Pattern { + span, + ty, + kind: Box::new(kind), + }, + user_ty: PatternTypeProjection::from_user_type(user_ty), user_ty_span: span, }; } diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index 050fb8b846ee0..f0f8263b64de5 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -1,37 +1,31 @@ use rustc::hir; -use rustc::mir::UserTypeAnnotation; -use rustc::ty::{self, AdtDef, TyCtxt}; +use rustc::ty::{self, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotation}; crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>; fn tables(&self) -> &ty::TypeckTables<'tcx>; - fn user_substs_applied_to_adt( - &self, - hir_id: hir::HirId, - adt_def: &'tcx AdtDef, - ) -> Option> { - let user_substs = self.tables().user_substs(hir_id)?; - Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)) - } - /// Looks up the type associated with this hir-id and applies the /// user-given substitutions; the hir-id must map to a suitable /// type. fn user_substs_applied_to_ty_of_hir_id( &self, hir_id: hir::HirId, - ) -> Option> { - let user_substs = self.tables().user_substs(hir_id)?; + ) -> Option> { + let user_provided_types = self.tables().user_provided_types(); + let mut user_ty = *user_provided_types.get(hir_id)?; + debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty); match &self.tables().node_id_to_type(hir_id).sty { - ty::Adt(adt_def, _) => Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)), - ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)), - sty => bug!( - "sty: {:?} should not have user-substs {:?} recorded ", - sty, - user_substs - ), + ty::Adt(adt_def, ..) => { + if let UserTypeAnnotation::TypeOf(ref mut did, _) = &mut user_ty.value { + *did = adt_def.did; + } + Some(user_ty) + } + ty::FnDef(..) => Some(user_ty), + sty => + bug!("sty: {:?} should not have user provided type {:?} recorded ", sty, user_ty), } } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 1029611cecd56..4c123d4a44b05 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -207,6 +207,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, IndexVec::new(), None, local_decls_for_sig(&sig, span), + IndexVec::new(), sig.inputs().len(), vec![], span, @@ -376,6 +377,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { IndexVec::new(), None, self.local_decls, + IndexVec::new(), self.sig.inputs().len(), vec![], self.span, @@ -825,6 +827,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, IndexVec::new(), None, local_decls, + IndexVec::new(), sig.inputs().len(), vec![], span, @@ -903,6 +906,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, IndexVec::new(), None, local_decls, + IndexVec::new(), sig.inputs().len(), vec![], span, diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 7e6554ae3d478..1602fc35a2c95 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -400,6 +400,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, IndexVec::new(), None, initial_locals, + IndexVec::new(), 0, vec![], mir.span, diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index d38ce3478d93d..b9ac0394306be 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -14,7 +14,7 @@ use rustc::traits::{ Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt, }; use rustc::ty::query::Providers; -use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts}; +use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy}; use rustc::ty::{ FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance, }; @@ -44,28 +44,16 @@ fn type_op_ascribe_user_type<'tcx>( tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { let ( - param_env, - AscribeUserType { - mir_ty, - variance, - def_id, - user_substs, - projs, - }, + param_env, AscribeUserType { mir_ty, variance, def_id, user_substs, projs } ) = key.into_parts(); debug!( - "type_op_ascribe_user_type(\ - mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}, projs={:?}\ - )", - mir_ty, variance, def_id, user_substs, projs, + "type_op_user_type_relation: mir_ty={:?} variance={:?} def_id={:?} \ + user_substs={:?} projs={:?}", + mir_ty, variance, def_id, user_substs, projs ); - let mut cx = AscribeUserTypeCx { - infcx, - param_env, - fulfill_cx, - }; + let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx }; cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs, projs)?; Ok(()) @@ -130,10 +118,9 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { projs: &[ProjectionKind<'tcx>], ) -> Result<(), NoSolution> { let UserSubsts { - substs, user_self_ty, + substs, } = user_substs; - let tcx = self.tcx(); let ty = tcx.type_of(def_id); @@ -174,8 +161,7 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { if let Some(UserSelfTy { impl_def_id, self_ty, - }) = user_self_ty - { + }) = user_self_ty { let impl_self_ty = self.tcx().type_of(impl_def_id); let impl_self_ty = self.subst(impl_self_ty, &substs); let impl_self_ty = self.normalize(impl_self_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 39beb2832851b..acb873206d5ab 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -102,13 +102,14 @@ use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; -use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility, - ToPolyTraitRef, ToPredicate}; +use rustc::ty::{ + self, AdtKind, CanonicalUserTypeAnnotation, Ty, TyCtxt, GenericParamDefKind, Visibility, + ToPolyTraitRef, ToPredicate, RegionKind, UserTypeAnnotation +}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; -use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, - UserSelfTy, UserSubsts}; +use rustc::ty::subst::{UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts}; use rustc::ty::util::{Representability, IntTypeExt, Discr}; use rustc::ty::layout::VariantIdx; use syntax_pos::{self, BytePos, Span, MultiSpan}; @@ -974,10 +975,12 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { o_ty }; - let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(&revealed_ty); + let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation( + &UserTypeAnnotation::Ty(revealed_ty) + ); debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", ty.hir_id, o_ty, revealed_ty, c_ty); - self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); + self.fcx.tables.borrow_mut().user_provided_types_mut().insert(ty.hir_id, c_ty); Some(LocalTy { decl_ty: o_ty, revealed_ty }) }, @@ -2108,8 +2111,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tables.borrow_mut().field_indices_mut().insert(hir_id, index); } - // The NodeId and the ItemLocalId must identify the same item. We just pass - // both of them for consistency checking. pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { @@ -2138,23 +2139,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !method.substs.is_noop() { let method_generics = self.tcx.generics_of(method.def_id); if !method_generics.params.is_empty() { - let user_substs = self.infcx.probe(|_| { - let just_method_substs = Substs::for_item(self.tcx, method.def_id, |param, _| { - let i = param.index as usize; - if i < method_generics.parent_count { - self.infcx.var_for_def(DUMMY_SP, param) - } else { - method.substs[i] - } - }); - self.infcx.canonicalize_user_type_annotation(&UserSubsts { - substs: just_method_substs, + let user_type_annotation = self.infcx.probe(|_| { + let user_substs = UserSubsts { + substs: Substs::for_item(self.tcx, method.def_id, |param, _| { + let i = param.index as usize; + if i < method_generics.parent_count { + self.infcx.var_for_def(DUMMY_SP, param) + } else { + method.substs[i] + } + }), user_self_ty: None, // not relevant here - }) + }; + + self.infcx.canonicalize_user_type_annotation(&UserTypeAnnotation::TypeOf( + method.def_id, + user_substs, + )) }); - debug!("write_method_call: user_substs = {:?}", user_substs); - self.write_user_substs(hir_id, user_substs); + debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); + self.write_user_type_annotation(hir_id, user_type_annotation); } } } @@ -2177,41 +2182,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// This should be invoked **before any unifications have /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. - pub fn write_user_substs_from_substs( + pub fn write_user_type_annotation_from_substs( &self, hir_id: hir::HirId, + def_id: DefId, substs: &'tcx Substs<'tcx>, user_self_ty: Option>, ) { debug!( - "write_user_substs_from_substs({:?}, {:?}) in fcx {}", - hir_id, - substs, - self.tag(), + "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ + user_self_ty={:?} in fcx {}", + hir_id, def_id, substs, user_self_ty, self.tag(), ); if !substs.is_noop() { - let user_substs = self.infcx.canonicalize_user_type_annotation(&UserSubsts { - substs, - user_self_ty, - }); - debug!("instantiate_value_path: user_substs = {:?}", user_substs); - self.write_user_substs(hir_id, user_substs); + let canonicalized = self.infcx.canonicalize_user_type_annotation( + &UserTypeAnnotation::TypeOf(def_id, UserSubsts { + substs, + user_self_ty, + }) + ); + debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); + self.write_user_type_annotation(hir_id, canonicalized); } } - pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) { + pub fn write_user_type_annotation( + &self, + hir_id: hir::HirId, + canonical_user_type_annotation: CanonicalUserTypeAnnotation<'tcx>, + ) { debug!( - "write_user_substs({:?}, {:?}) in fcx {}", - hir_id, - substs, - self.tag(), + "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", + hir_id, canonical_user_type_annotation, self.tag(), ); - if !substs.is_identity() { - self.tables.borrow_mut().user_substs_mut().insert(hir_id, substs); + if !canonical_user_type_annotation.is_identity() { + self.tables.borrow_mut().user_provided_types_mut().insert( + hir_id, canonical_user_type_annotation + ); } else { - debug!("write_user_substs: skipping identity substs"); + debug!("write_user_type_annotation: skipping identity substs"); } } @@ -2386,8 +2397,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // although I have my doubts). Other sorts of things are // already sufficiently enforced with erased regions. =) if ty.has_free_regions() || ty.has_projections() { - let c_ty = self.infcx.canonicalize_response(&ty); - self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty); + let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty)); + self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); } ty @@ -3734,7 +3745,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((variant, did, substs)) = variant { debug!("check_struct_path: did={:?} substs={:?}", did, substs); let hir_id = self.tcx.hir().node_to_hir_id(node_id); - self.write_user_substs_from_substs(hir_id, substs, None); + self.write_user_type_annotation_from_substs(hir_id, did, substs, None); // Check bounds on type arguments used in the path. let bounds = self.instantiate_bounds(path_span, did, substs); @@ -5290,7 +5301,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // First, store the "user substs" for later. let hir_id = tcx.hir().node_to_hir_id(node_id); - self.write_user_substs_from_substs(hir_id, substs, user_self_ty); + self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); // Add all the obligations that are required, substituting and // normalized appropriately. diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8bd9b097d2df1..53ea497f01add 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -357,7 +357,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { 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() { + for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() { let hir_id = hir::HirId { owner: common_local_id_root.index, local_id, @@ -374,8 +374,17 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { }; self.tables - .user_provided_tys_mut() + .user_provided_types_mut() .insert(hir_id, c_ty.clone()); + + if let ty::UserTypeAnnotation::TypeOf(_, user_substs) = c_ty.value { + if self.rustc_dump_user_substs { + // This is a unit-testing mechanism. + let node_id = self.tcx().hir().hir_to_node_id(hir_id); + let span = self.tcx().hir().span(node_id); + self.tcx().sess.span_err(span, &format!("user substs: {:?}", user_substs)); + } + } } } @@ -573,22 +582,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { assert!(!substs.needs_infer() && !substs.has_placeholders()); self.tables.node_substs_mut().insert(hir_id, substs); } - - // Copy over any user-substs - if let Some(user_substs) = self.fcx.tables.borrow().user_substs(hir_id) { - let user_substs = self.tcx().lift_to_global(&user_substs).unwrap(); - self.tables.user_substs_mut().insert(hir_id, user_substs); - - // Unit-testing mechanism: - if self.rustc_dump_user_substs { - let node_id = self.tcx().hir().hir_to_node_id(hir_id); - let span = self.tcx().hir().span(node_id); - self.tcx().sess.span_err( - span, - &format!("user substs: {:?}", user_substs), - ); - } - } } fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) { diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index bb304ea12ca7f..88fd53d4ba59d 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -37,7 +37,7 @@ fn main() { // StorageLive(_4); // _4 = std::option::Option>::None; // FakeRead(ForLet, _4); -// AscribeUserType(_4, o, UserTypeProjection { base: Ty(Canonical { max_universe: U0, variables: [], value: std::option::Option> }), projs: [] }); +// AscribeUserType(_4, o, UserTypeProjection { base: UserTypeAnnotation(1), projs: [] }); // StorageLive(_5); // StorageLive(_6); // _6 = move _4; diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr index 5a359cf9ed8f1..123c26195d006 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr @@ -1,4 +1,4 @@ -error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } } +error: user substs: UserSubsts { substs: [u32], user_self_ty: None } --> $DIR/dump-adt-brace-struct.rs:18:5 | LL | SomeStruct:: { t: 22 }; //~ ERROR [u32] diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr index 3f159cc92b54f..fc4544437c5b1 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -1,26 +1,26 @@ -error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } } - --> $DIR/dump-fn-method.rs:26:13 +error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:44:5 | -LL | let x = foo::; //~ ERROR [u32] - | ^^^^^^^^^^ +LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] + | ^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } } +error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } --> $DIR/dump-fn-method.rs:32:13 | LL | let x = <_ as Bazoom>::method::<_>; //~ ERROR [^0, u32, ^1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } } +error: user substs: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } --> $DIR/dump-fn-method.rs:36:13 | LL | let x = >::method::; //~ ERROR [u8, u16, u32] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } } - --> $DIR/dump-fn-method.rs:44:5 +error: user substs: UserSubsts { substs: [u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:26:13 | -LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = foo::; //~ ERROR [u32] + | ^^^^^^^^^^ error: aborting due to 4 previous errors From f2532012dd51914f8cf27ba79cf0e4999761c9b4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 22 Nov 2018 20:35:24 +0100 Subject: [PATCH 02/11] Always check well-formedness. This commit uses the map introduced by the previous commit to ensure that types are always checked for well-formedness by the NLL type check. Previously, without the map introduced by the previous commit, types would not be checked for well-formedness if the `AscribeUserType` statement that would trigger that check was removed as unreachable code. --- src/librustc/dep_graph/dep_node.rs | 4 +- src/librustc/traits/query/mod.rs | 4 + .../traits/query/type_op/ascribe_user_type.rs | 60 +++++++++- src/librustc/ty/query/config.rs | 12 +- src/librustc/ty/query/mod.rs | 11 +- src/librustc/ty/query/plumbing.rs | 1 + .../borrow_check/nll/type_check/mod.rs | 24 ++++ src/librustc_traits/type_op.rs | 106 +++++++++++++----- ...ns-free-region-ordering-caller1.nll.stderr | 19 +++- ...egions-outlives-projection-container-wc.rs | 4 +- ...ns-outlives-projection-container-wc.stderr | 6 +- 11 files changed, 209 insertions(+), 42 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e5fd0aa3c9cbd..1f19e6fc689c1 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -62,7 +62,8 @@ use syntax_pos::symbol::InternedString; use traits; use traits::query::{ CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, - CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, + CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal, + CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, }; use ty::{TyCtxt, FnSig, Instance, InstanceDef, @@ -650,6 +651,7 @@ define_dep_nodes!( <'tcx> [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), [] EvaluateGoal(traits::ChalkCanonicalGoal<'tcx>), [] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>), + [] TypeOpAscribeUserTypeWellFormed(CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>), [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>), [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>), diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 59f786025b224..3203dc4e8cf82 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -28,6 +28,10 @@ pub type CanonicalPredicateGoal<'tcx> = pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>; +pub type CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, + type_op::ascribe_user_type::AscribeUserTypeWellFormed<'tcx>>>; + pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>; diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index 365c1d67ef97a..993d09d2ed02d 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -2,7 +2,7 @@ use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, Que use traits::query::Fallible; use hir::def_id::DefId; use mir::ProjectionKind; -use ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use ty::{self, ParamEnvAnd, Ty, TyCtxt, UserTypeAnnotation}; use ty::subst::UserSubsts; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -22,7 +22,7 @@ impl<'tcx> AscribeUserType<'tcx> { user_substs: UserSubsts<'tcx>, projs: &'tcx ty::List>, ) -> Self { - AscribeUserType { mir_ty, variance, def_id, user_substs, projs } + Self { mir_ty, variance, def_id, user_substs, projs } } } @@ -68,3 +68,59 @@ impl_stable_hash_for! { mir_ty, variance, def_id, user_substs, projs } } + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct AscribeUserTypeWellFormed<'tcx> { + pub user_type_annotation: UserTypeAnnotation<'tcx>, +} + +impl<'tcx> AscribeUserTypeWellFormed<'tcx> { + pub fn new( + user_type_annotation: UserTypeAnnotation<'tcx>, + ) -> Self { + Self { user_type_annotation, } + } +} + +impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserTypeWellFormed<'tcx> { + type QueryResponse = (); + + fn try_fast_path( + _tcx: TyCtxt<'_, 'gcx, 'tcx>, + _key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + None + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + tcx.type_op_ascribe_user_type_well_formed(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResponse<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for AscribeUserTypeWellFormed<'tcx> { + user_type_annotation + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for AscribeUserTypeWellFormed<'a> { + type Lifted = AscribeUserTypeWellFormed<'tcx>; + user_type_annotation + } +} + +impl_stable_hash_for! { + struct AscribeUserTypeWellFormed<'tcx> { + user_type_annotation + } +} diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index 3464464aa229c..bed4dfd97ca49 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -5,7 +5,8 @@ use mir::interpret::GlobalId; use traits; use traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpAscribeUserTypeWellFormedGoal, + CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; @@ -124,6 +125,15 @@ impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type_well_formed<'tcx> { + fn describe( + _tcx: TyCtxt<'_, '_, '_>, + goal: CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>, + ) -> Cow<'static, str> { + format!("evaluating `type_op_ascribe_user_type_well_formed` `{:?}`", goal).into() + } +} + impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> { format!("evaluating `type_op_eq` `{:?}`", goal).into() diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 22bd1cd90a754..c2f208308b2d1 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -26,7 +26,8 @@ use session::config::OutputFilenames; use traits::{self, Vtable}; use traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, - CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, + CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, + CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution, }; @@ -609,6 +610,14 @@ define_queries! { <'tcx> NoSolution, >, + /// Do not call this query directly: part of the `Eq` type-op + [] fn type_op_ascribe_user_type_well_formed: TypeOpAscribeUserTypeWellFormed( + CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx> + ) -> Result< + Lrc>>, + NoSolution, + >, + /// Do not call this query directly: part of the `Eq` type-op [] fn type_op_eq: TypeOpEq( CanonicalTypeOpEqGoal<'tcx> diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 5d23ee0994a06..cdb3cd3ffcb6b 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1208,6 +1208,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::EvaluateObligation | DepKind::EvaluateGoal | DepKind::TypeOpAscribeUserType | + DepKind::TypeOpAscribeUserTypeWellFormed | DepKind::TypeOpEq | DepKind::TypeOpSubtype | DepKind::TypeOpProvePredicate | 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 8f8abe09810a2..51ade33f74cf0 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -916,6 +916,28 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); } + /// Check that user type annotations are well formed. + fn check_user_type_annotations_are_well_formed(&mut self) { + for index in self.mir.user_type_annotations.indices() { + let (span, _) = &self.mir.user_type_annotations[index]; + let type_annotation = self.instantiated_type_annotations[&index]; + if let Err(terr) = self.fully_perform_op( + Locations::All(*span), + ConstraintCategory::Assignment, + self.param_env.and(type_op::ascribe_user_type::AscribeUserTypeWellFormed::new( + type_annotation, + )), + ) { + span_mirbug!( + self, + type_annotation, + "bad user type annotation: {:?}", + terr, + ); + } + } + } + /// Given some operation `op` that manipulates types, proves /// predicates, or otherwise uses the inference context, executes /// `op` and then executes all the further obligations that `op` @@ -2389,6 +2411,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.check_terminator(mir, block_data.terminator(), location); self.check_iscleanup(mir, block_data); } + + self.check_user_type_annotations_are_well_formed(); } fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index b9ac0394306be..6691a036ac28c 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -4,7 +4,7 @@ use rustc::infer::InferCtxt; use rustc::hir::def_id::DefId; use rustc::mir::ProjectionKind; use rustc::mir::tcx::PlaceTy; -use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType; +use rustc::traits::query::type_op::ascribe_user_type::{AscribeUserType, AscribeUserTypeWellFormed}; use rustc::traits::query::type_op::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; use rustc::traits::query::type_op::prove_predicate::ProvePredicate; @@ -17,6 +17,7 @@ use rustc::ty::query::Providers; use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy}; use rustc::ty::{ FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance, + UserTypeAnnotation, }; use rustc_data_structures::sync::Lrc; use std::fmt; @@ -26,6 +27,7 @@ use syntax_pos::DUMMY_SP; crate fn provide(p: &mut Providers) { *p = Providers { type_op_ascribe_user_type, + type_op_ascribe_user_type_well_formed, type_op_eq, type_op_prove_predicate, type_op_subtype, @@ -48,7 +50,7 @@ fn type_op_ascribe_user_type<'tcx>( ) = key.into_parts(); debug!( - "type_op_user_type_relation: mir_ty={:?} variance={:?} def_id={:?} \ + "type_op_ascribe_user_type: mir_ty={:?} variance={:?} def_id={:?} \ user_substs={:?} projs={:?}", mir_ty, variance, def_id, user_substs, projs ); @@ -60,6 +62,28 @@ fn type_op_ascribe_user_type<'tcx>( }) } +fn type_op_ascribe_user_type_well_formed<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserTypeWellFormed<'tcx>>>, +) -> Result>>, NoSolution> { + tcx.infer_ctxt() + .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + let ( + param_env, AscribeUserTypeWellFormed { user_type_annotation } + ) = key.into_parts(); + + debug!( + "type_op_ascribe_user_type_well_formed: user_type_annotation={:?}", + user_type_annotation, + ); + + let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx }; + cx.well_formed(user_type_annotation)?; + + Ok(()) + }) +} + struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> { infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, param_env: ParamEnv<'tcx>, @@ -109,6 +133,56 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { value.subst(self.tcx(), substs) } + fn well_formed( + &mut self, + type_annotation: UserTypeAnnotation<'tcx> + ) -> Result<(), NoSolution> { + match type_annotation { + UserTypeAnnotation::Ty(ty) => { + self.prove_predicate(Predicate::WellFormed(ty)); + Ok(()) + }, + UserTypeAnnotation::TypeOf(did, user_substs) => { + let UserSubsts { + user_self_ty, + substs, + } = user_substs; + + let ty = self.tcx().type_of(did); + let ty = self.subst(ty, substs); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); + let ty = self.normalize(ty); + + if let Some(UserSelfTy { + impl_def_id, + self_ty, + }) = user_self_ty { + let impl_self_ty = self.tcx().type_of(impl_def_id); + let impl_self_ty = self.subst(impl_self_ty, &substs); + let impl_self_ty = self.normalize(impl_self_ty); + + self.relate(self_ty, Variance::Invariant, impl_self_ty)?; + + self.prove_predicate(Predicate::WellFormed(impl_self_ty)); + } + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // them? This would only be relevant if some input + // type were ill-formed but did not appear in `ty`, + // which...could happen with normalization... + self.prove_predicate(Predicate::WellFormed(ty)); + Ok(()) + }, + } + } + fn relate_mir_and_user_ty( &mut self, mir_ty: Ty<'tcx>, @@ -118,7 +192,7 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { projs: &[ProjectionKind<'tcx>], ) -> Result<(), NoSolution> { let UserSubsts { - user_self_ty, + user_self_ty: _, substs, } = user_substs; let tcx = self.tcx(); @@ -158,19 +232,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { self.relate(mir_ty, variance, ty)?; } - if let Some(UserSelfTy { - impl_def_id, - self_ty, - }) = user_self_ty { - let impl_self_ty = self.tcx().type_of(impl_def_id); - let impl_self_ty = self.subst(impl_self_ty, &substs); - let impl_self_ty = self.normalize(impl_self_ty); - - self.relate(self_ty, Variance::Invariant, impl_self_ty)?; - - self.prove_predicate(Predicate::WellFormed(impl_self_ty)); - } - // Prove the predicates coming along with `def_id`. // // Also, normalize the `instantiated_predicates` @@ -184,19 +245,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { self.prove_predicate(instantiated_predicate); } - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - self.prove_predicate(Predicate::WellFormed(ty)); - Ok(()) } } diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr index 92c21fcb4aec5..abda7ec5e07a6 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr @@ -12,6 +12,21 @@ LL | let z: &'a & usize = &(&y); LL | } | - temporary value is freed at the end of this statement -error: aborting due to previous error +error[E0597]: `y` does not live long enough + --> $DIR/regions-free-region-ordering-caller1.rs:9:27 + | +LL | fn call1<'a>(x: &'a usize) { + | -- lifetime `'a` defined here +... +LL | let z: &'a & usize = &(&y); + | ----------- ^^^^ borrowed value does not live long enough + | | + | assignment requires that `y` is borrowed for `'a` +... +LL | } + | - `y` dropped here while still borrowed + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0716`. +Some errors occurred: E0597, E0716. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.rs b/src/test/ui/regions/regions-outlives-projection-container-wc.rs index d38706defe7ad..91a0d8590ff34 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.rs +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs @@ -31,9 +31,7 @@ fn with_assoc<'a,'b>() { // outlive 'a. In this case, that means TheType<'b>::TheAssocType, // which is &'b (), must outlive 'a. - // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if - // `_x` is changed to `_` - let _x: &'a WithAssoc> = loop { }; + let _: &'a WithAssoc> = loop { }; //~^ ERROR reference has a longer lifetime } diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr index 2ed9fd4f9b4cf..0d73d3d64322e 100644 --- a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr +++ b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr @@ -1,8 +1,8 @@ error[E0491]: in type `&'a WithAssoc>`, reference has a longer lifetime than the data it references - --> $DIR/regions-outlives-projection-container-wc.rs:36:13 + --> $DIR/regions-outlives-projection-container-wc.rs:34:12 | -LL | let _x: &'a WithAssoc> = loop { }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: &'a WithAssoc> = loop { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the pointer is valid for the lifetime 'a as defined on the function body at 28:15 --> $DIR/regions-outlives-projection-container-wc.rs:28:15 From b182a21163c673034a89acf01cd8797a8313ed11 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 23 Nov 2018 11:55:09 +0100 Subject: [PATCH 03/11] Add test for unreachable well-formedness. This commit adds a test for checking that types are well-formed when unreachable. --- src/test/ui/issue-54943.rs | 7 +++++++ src/test/ui/issue-54943.stderr | 11 +++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/ui/issue-54943.rs create mode 100644 src/test/ui/issue-54943.stderr diff --git a/src/test/ui/issue-54943.rs b/src/test/ui/issue-54943.rs new file mode 100644 index 0000000000000..c2214f57dafec --- /dev/null +++ b/src/test/ui/issue-54943.rs @@ -0,0 +1,7 @@ +fn foo() { } + +fn main<'a>() { + return; + + let x = foo::<&'a u32>(); +} diff --git a/src/test/ui/issue-54943.stderr b/src/test/ui/issue-54943.stderr new file mode 100644 index 0000000000000..62aacee811110 --- /dev/null +++ b/src/test/ui/issue-54943.stderr @@ -0,0 +1,11 @@ +error[E0477]: the type `&'a u32` does not fulfill the required lifetime + --> $DIR/issue-54943.rs:6:13 + | +LL | let x = foo::<&'a u32>(); + | ^^^^^^^^^^^^^^ + | + = note: type must satisfy the static lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0477`. From 4be7214d30b121762c8675c3e732083da262b136 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 24 Nov 2018 12:56:24 +0100 Subject: [PATCH 04/11] Type annotations in associated constant patterns. This commit adds support for respecting user type annotations with associated constants in patterns. --- src/librustc_mir/hair/pattern/mod.rs | 26 +++++++++++++++++-- src/librustc_typeck/check/method/mod.rs | 22 +++++++++------- src/librustc_typeck/check/mod.rs | 2 ++ .../associated-const-range-match-patterns.rs | 2 +- src/test/ui/issue-55511.nll.stderr | 15 +++++++++++ src/test/ui/issue-55511.rs | 18 +++++++++++++ src/test/ui/issue-55511.stderr | 14 ++++++++++ 7 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/issue-55511.nll.stderr create mode 100644 src/test/ui/issue-55511.rs create mode 100644 src/test/ui/issue-55511.stderr diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index fd3b07c0357b5..00de40d8cff83 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -848,7 +848,28 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }; match self.tcx.at(span).const_eval(self.param_env.and(cid)) { Ok(value) => { - return self.const_to_pat(instance, value, id, span) + let pattern = self.const_to_pat(instance, value, id, span); + if !is_associated_const { + return pattern; + } + + let user_provided_types = self.tables().user_provided_types(); + return if let Some(u_ty) = user_provided_types.get(id) { + let user_ty = PatternTypeProjection::from_user_type(*u_ty); + Pattern { + span, + kind: Box::new( + PatternKind::AscribeUserType { + subpattern: pattern, + user_ty, + user_ty_span: span, + } + ), + ty: value.ty, + } + } else { + pattern + } }, Err(_) => { self.tcx.sess.span_err( @@ -938,7 +959,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { id: hir::HirId, span: Span, ) -> Pattern<'tcx> { - debug!("const_to_pat: cv={:#?}", cv); + debug!("const_to_pat: cv={:#?} id={:?}", cv, id); let adt_subpattern = |i, variant_opt| { let field = Field::new(i); let val = const_field( @@ -956,6 +977,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } }).collect::>() }; + debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); let kind = match cv.ty.sty { ty::Float(_) => { let id = self.tcx.hir().hir_to_node_id(id); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index fe5f43e3c01ef..1758f76252456 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -357,16 +357,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } - pub fn resolve_ufcs(&self, - span: Span, - method_name: ast::Ident, - self_ty: Ty<'tcx>, - expr_id: ast::NodeId) - -> Result> { - debug!("resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}", - method_name, - self_ty, - expr_id + pub fn resolve_ufcs( + &self, + span: Span, + method_name: ast::Ident, + self_ty: Ty<'tcx>, + expr_id: ast::NodeId + ) -> Result> { + debug!( + "resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}", + method_name, self_ty, expr_id, ); let tcx = self.tcx; @@ -375,6 +375,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match self.probe_for_name(span, mode, method_name, IsSuggestion(false), self_ty, expr_id, ProbeScope::TraitsInScope) { Ok(pick) => { + debug!("resolve_ufcs: pick={:?}", pick); if let Some(import_id) = pick.import_id { let import_def_id = tcx.hir().local_def_id(import_id); debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); @@ -383,6 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let def = pick.item.def(); + debug!("resolve_ufcs: def={:?}", def); tcx.check_stability(def.def_id(), Some(expr_id), span); Ok(def) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index acb873206d5ab..ff4574eb283fd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4584,6 +4584,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span) -> (Def, Option>, &'b [hir::PathSegment]) { + debug!("resolve_ty_and_def_ufcs: qpath={:?} node_id={:?} span={:?}", qpath, node_id, span); let (ty, qself, item_segment) = match *qpath { QPath::Resolved(ref opt_qself, ref path) => { return (path.def, @@ -5104,6 +5105,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::Method(def_id) | Def::AssociatedConst(def_id) => { let container = tcx.associated_item(def_id).container; + debug!("instantiate_value_path: def={:?} container={:?}", def, container); match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(tcx, span, trait_did) diff --git a/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs b/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs index 647652d02734a..4801369cfd1a8 100644 --- a/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs +++ b/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(dead_code)] +#![allow(dead_code, unreachable_patterns)] struct Foo; diff --git a/src/test/ui/issue-55511.nll.stderr b/src/test/ui/issue-55511.nll.stderr new file mode 100644 index 0000000000000..97f8015dfc147 --- /dev/null +++ b/src/test/ui/issue-55511.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `a` does not live long enough + --> $DIR/issue-55511.rs:13:28 + | +LL | let b = Some(Cell::new(&a)); + | ^^ borrowed value does not live long enough +LL | match b { +LL | <() as Foo<'static>>::C => { } + | ----------------------- type annotation requires that `a` is borrowed for `'static` +... +LL | } + | - `a` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-55511.rs b/src/test/ui/issue-55511.rs new file mode 100644 index 0000000000000..93bd78c44d946 --- /dev/null +++ b/src/test/ui/issue-55511.rs @@ -0,0 +1,18 @@ +use std::cell::Cell; + +trait Foo<'a> { + const C: Option>; +} + +impl<'a, T> Foo<'a> for T { + const C: Option> = None; +} + +fn main() { + let a = 22; + let b = Some(Cell::new(&a)); + match b { + <() as Foo<'static>>::C => { } + _ => { } + } +} diff --git a/src/test/ui/issue-55511.stderr b/src/test/ui/issue-55511.stderr new file mode 100644 index 0000000000000..24668f045517a --- /dev/null +++ b/src/test/ui/issue-55511.stderr @@ -0,0 +1,14 @@ +error[E0597]: `a` does not live long enough + --> $DIR/issue-55511.rs:13:29 + | +LL | let b = Some(Cell::new(&a)); + | ^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 162dcdc16f9b004b35160c9dd69faab29fc459e4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 25 Nov 2018 13:31:34 +0100 Subject: [PATCH 05/11] Add user type annotations to MIR dump. This commit writes the user type annotations to the MIR dump so that they are visible again. --- src/librustc_mir/borrow_check/nll/mod.rs | 3 ++- src/librustc_mir/util/pretty.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index c5eabbbefa9a4..a092c3b8ecde2 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -230,13 +230,14 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( // Before the CFG, dump out the values for each region variable. PassWhere::BeforeCFG => { regioncx.dump_mir(out)?; + writeln!(out, "|")?; if let Some(closure_region_requirements) = closure_region_requirements { - writeln!(out, "|")?; writeln!(out, "| Free Region Constraints")?; for_each_region_constraint(closure_region_requirements, &mut |msg| { writeln!(out, "| {}", msg) })?; + writeln!(out, "|")?; } } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 35b367855ad28..6353eab6f6553 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -142,6 +142,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( } writeln!(file, "")?; extra_data(PassWhere::BeforeCFG, &mut file)?; + write_user_type_annotations(mir, &mut file)?; write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; extra_data(PassWhere::AfterCFG, &mut file)?; }; @@ -618,6 +619,19 @@ fn write_temp_decls(mir: &Mir, w: &mut dyn Write) -> io::Result<()> { Ok(()) } +fn write_user_type_annotations(mir: &Mir, w: &mut dyn Write) -> io::Result<()> { + if !mir.user_type_annotations.is_empty() { + writeln!(w, "| User Type Annotations")?; + } + for (index, (span, annotation)) in mir.user_type_annotations.iter_enumerated() { + writeln!(w, "| {:?}: {:?} at {:?}", index.index(), annotation, span)?; + } + if !mir.user_type_annotations.is_empty() { + writeln!(w, "|")?; + } + Ok(()) +} + pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option) -> Vec { if let Some(i) = single { vec![i] From dc41606ff403536afe4eda88a68b8faa8e3f9d55 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 25 Nov 2018 15:14:39 +0100 Subject: [PATCH 06/11] Support user type annotations in `ref` bindings. This commit adds support for user type annotations in variables declared using `ref` bindings. When a variable declared using a `ref` binding, then the `LocalDecl` has the type `&T` where the `&` was introduced by the `ref` binding but the canonicalized type annotation has only a `T` since the reference is implicit with the `ref` binding. Therefore, to support type annotations, the canonicalized type annotation either needs wrapped in a reference, or the `LocalDecl` type must have a wrapped reference removed for comparison. It is easier to remove the outer reference from the `LocalDecl` for the purpose of comparison, so that is the approach this commit takes. --- .../borrow_check/nll/type_check/mod.rs | 14 +++++++++++++- src/librustc_mir/build/block.rs | 1 + src/librustc_mir/build/matches/mod.rs | 17 ++++------------- src/librustc_mir/hair/pattern/mod.rs | 7 +------ src/librustc_typeck/check/mod.rs | 2 ++ src/test/ui/nll/issue-55401.rs | 8 ++++++++ src/test/ui/nll/issue-55401.stderr | 11 +++++++++++ 7 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/nll/issue-55401.rs create mode 100644 src/test/ui/nll/issue-55401.stderr 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 51ade33f74cf0..2c49dbd969d59 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -307,8 +307,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.sanitize_type(local_decl, local_decl.ty); for (user_ty, span) in local_decl.user_ty.projections_and_spans() { + let ty = if !local_decl.is_nonref_binding() { + // If we have a binding of the form `let ref x: T = ..` then remove the outermost + // reference so we can check the type annotation for the remaining type. + if let ty::Ref(_, rty, _) = local_decl.ty.sty { + rty + } else { + bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); + } + } else { + local_decl.ty + }; + if let Err(terr) = self.cx.relate_type_and_user_type( - local_decl.ty, + ty, ty::Variance::Invariant, user_ty, Locations::All(*span), diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index ad4e5a50dcd14..41718cfc87012 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -141,6 +141,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { None, remainder_span, lint_level, slice::from_ref(&pattern), ArmHasGuard(false), None); + debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_bindings( &pattern, &PatternTypeProjections::none(), diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 92642dff3dc68..085c58ef5ff66 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -409,6 +409,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); let mut scope = self.source_scope; let num_patterns = patterns.len(); + debug!("declare_bindings: patterns={:?}", patterns); self.visit_bindings( &patterns[0], &PatternTypeProjections::none(), @@ -499,6 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &PatternTypeProjections<'tcx>, ), ) { + debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); match *pattern.kind { PatternKind::Binding { mutability, @@ -509,19 +511,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ref subpattern, .. } => { - let pattern_ref_binding; // sidestep temp lifetime limitations. - let binding_user_ty = match mode { - BindingMode::ByValue => { pattern_user_ty } - BindingMode::ByRef(..) => { - // If this is a `ref` binding (e.g., `let ref - // x: T = ..`), then the type of `x` is not - // `T` but rather `&T`. - pattern_ref_binding = pattern_user_ty.ref_binding(); - &pattern_ref_binding - } - }; - - f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty); + f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty); if let Some(subpattern) = subpattern.as_ref() { self.visit_bindings(subpattern, pattern_user_ty, f); } @@ -565,6 +555,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field); + debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty); self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f); } } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 00de40d8cff83..6d562c69b2dc5 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -79,11 +79,6 @@ impl<'tcx> PatternTypeProjections<'tcx> { PatternTypeProjections { contents: vec![] } } - pub(crate) fn ref_binding(&self) -> Self { - // FIXME(#55401): ignore for now - PatternTypeProjections { contents: vec![] } - } - fn map_projs(&self, mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>) -> Self @@ -803,7 +798,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { }; if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { - debug!("lower_variant_or_leaf: user_ty={:?} span={:?}", user_ty, span); + debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); kind = PatternKind::AscribeUserType { subpattern: Pattern { span, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ff4574eb283fd..36de41ef8a170 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2388,6 +2388,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { let ty = self.to_ty(ast_ty); + debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); // If the type given by the user has free regions, save it for // later, since NLL would like to enforce those. Also pass in @@ -2398,6 +2399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // already sufficiently enforced with erased regions. =) if ty.has_free_regions() || ty.has_projections() { let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty)); + debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); } diff --git a/src/test/ui/nll/issue-55401.rs b/src/test/ui/nll/issue-55401.rs new file mode 100644 index 0000000000000..2fa234491087d --- /dev/null +++ b/src/test/ui/nll/issue-55401.rs @@ -0,0 +1,8 @@ +#![feature(nll)] + +fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 { + let (ref y, _z): (&'a u32, u32) = (&22, 44); + *y //~ ERROR +} + +fn main() {} diff --git a/src/test/ui/nll/issue-55401.stderr b/src/test/ui/nll/issue-55401.stderr new file mode 100644 index 0000000000000..9e50db7b6045d --- /dev/null +++ b/src/test/ui/nll/issue-55401.stderr @@ -0,0 +1,11 @@ +error: unsatisfied lifetime constraints + --> $DIR/issue-55401.rs:5:5 + | +LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | let (ref y, _z): (&'a u32, u32) = (&22, 44); +LL | *y //~ ERROR + | ^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to previous error + From 6092d92d70c81861ed46f2496e62dc74183857fd Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 8 Dec 2018 00:50:35 +0100 Subject: [PATCH 07/11] Add explicit error annotations to test. This commit adds explicit error annotations to tests after rebasing which is now required. --- src/test/ui/issue-54943.rs | 1 + src/test/ui/issue-55511.nll.stderr | 2 +- src/test/ui/issue-55511.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/ui/issue-54943.rs b/src/test/ui/issue-54943.rs index c2214f57dafec..d5d0ae1a5e295 100644 --- a/src/test/ui/issue-54943.rs +++ b/src/test/ui/issue-54943.rs @@ -4,4 +4,5 @@ fn main<'a>() { return; let x = foo::<&'a u32>(); + //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477] } diff --git a/src/test/ui/issue-55511.nll.stderr b/src/test/ui/issue-55511.nll.stderr index 97f8015dfc147..bf3e58e8cdb19 100644 --- a/src/test/ui/issue-55511.nll.stderr +++ b/src/test/ui/issue-55511.nll.stderr @@ -3,7 +3,7 @@ error[E0597]: `a` does not live long enough | LL | let b = Some(Cell::new(&a)); | ^^ borrowed value does not live long enough -LL | match b { +... LL | <() as Foo<'static>>::C => { } | ----------------------- type annotation requires that `a` is borrowed for `'static` ... diff --git a/src/test/ui/issue-55511.rs b/src/test/ui/issue-55511.rs index 93bd78c44d946..4b9475ba62718 100644 --- a/src/test/ui/issue-55511.rs +++ b/src/test/ui/issue-55511.rs @@ -11,6 +11,7 @@ impl<'a, T> Foo<'a> for T { fn main() { let a = 22; let b = Some(Cell::new(&a)); + //~^ ERROR `a` does not live long enough [E0597] match b { <() as Foo<'static>>::C => { } _ => { } From 95c18382cb01480b99b55163c19f35907de80eb4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 9 Dec 2018 03:07:31 +0100 Subject: [PATCH 08/11] Fix unresolved inference variable ICE. This commit moves well-formedness check for the `UserTypeAnnotation::Ty(..)` case from always running to only when the code is reachable. This solves the ICE that resulted from `src/test/ui/issue-54943-1.rs` (a minimal repro of `dropck-eyepatch` run-pass tests that failed). The main well-formedness check that was intended to be run despite unreachable code still is, that being the `UserTypeAnnotation::TypeOf(..)` case. Before this PR, the other case wasn't being checked at all. It is possible to fix this ICE while still always checking well-formedness for the `UserTypeAnnotation::Ty(..)` case but that solution will ICE in unreachable code for that case, the diff for that change [can be found here](0). [0]: https://gist.github.com/davidtwco/f9751ffd9c0508f7251c0f17adc3af53 --- .../borrow_check/nll/type_check/mod.rs | 58 ++++++++++++++----- .../incremental/hashes/let_expressions.rs | 2 +- src/test/ui/issue-54943-1.rs | 15 +++++ src/test/ui/issue-54943-2.rs | 18 ++++++ ...ns-free-region-ordering-caller1.nll.stderr | 2 +- 5 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/issue-54943-1.rs create mode 100644 src/test/ui/issue-54943-2.rs 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 2c49dbd969d59..d0ca050f0dff7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -933,19 +933,28 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { for index in self.mir.user_type_annotations.indices() { let (span, _) = &self.mir.user_type_annotations[index]; let type_annotation = self.instantiated_type_annotations[&index]; - if let Err(terr) = self.fully_perform_op( - Locations::All(*span), - ConstraintCategory::Assignment, - self.param_env.and(type_op::ascribe_user_type::AscribeUserTypeWellFormed::new( - type_annotation, - )), - ) { - span_mirbug!( - self, - type_annotation, - "bad user type annotation: {:?}", - terr, - ); + match type_annotation { + // We can't check the well-formedness of a `UserTypeAnnotation::Ty` here, it will + // cause ICEs (see comment in `relate_type_and_user_type`). + UserTypeAnnotation::TypeOf(..) => { + if let Err(terr) = self.fully_perform_op( + Locations::All(*span), + ConstraintCategory::Assignment, + self.param_env.and( + type_op::ascribe_user_type::AscribeUserTypeWellFormed::new( + type_annotation, + ) + ), + ) { + span_mirbug!( + self, + type_annotation, + "bad user type annotation: {:?}", + terr, + ); + } + }, + _ => {}, } } } @@ -1079,7 +1088,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { a, v, user_ty, locations, ); - match self.instantiated_type_annotations[&user_ty.base] { + let type_annotation = self.instantiated_type_annotations[&user_ty.base]; + match type_annotation { UserTypeAnnotation::Ty(ty) => { // The `TypeRelating` code assumes that "unresolved inference // variables" appear in the "a" side, so flip `Contravariant` @@ -1117,7 +1127,27 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Ok(projected_ty) = curr_projected_ty { let ty = projected_ty.to_ty(tcx); self.relate_types(ty, v1, a, locations, category)?; + + // We'll get an ICE if we check for well-formedness of a + // `UserTypeAnnotation::Ty` that hasn't had types related. + // + // Doing this without the types having been related will result in + // `probe_ty_var` failing in the canonicalizer - in practice, this + // results in three run-pass tests failing. You can work around that + // by keeping an vec of projections instead of annotations and performing + // the projections before storing into `instantiated_type_annotations` + // but that still fails in dead code. + self.fully_perform_op( + locations, + category, + self.param_env.and( + type_op::ascribe_user_type::AscribeUserTypeWellFormed::new( + UserTypeAnnotation::Ty(ty), + ) + ), + )?; } + } UserTypeAnnotation::TypeOf(def_id, user_substs) => { let projs = self.infcx.tcx.intern_projs(&user_ty.projs); diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 3aa66527ca7e8..b6050f059c27b 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -70,7 +70,7 @@ pub fn change_mutability_of_reference_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,MirValidated")] + except="HirBody,TypeckTables,MirValidated,MirOptimized")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_reference_type() { let _x: &mut u64; diff --git a/src/test/ui/issue-54943-1.rs b/src/test/ui/issue-54943-1.rs new file mode 100644 index 0000000000000..7750e34036192 --- /dev/null +++ b/src/test/ui/issue-54943-1.rs @@ -0,0 +1,15 @@ +#![feature(nll)] + +// This test is a minimal version of an ICE in the dropck-eyepatch tests +// found in the fix for #54943. + +// compile-pass + +fn foo(_t: T) { +} + +fn main() { + struct A<'a, B: 'a>(&'a B); + let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this")); + foo((a1, a2)); +} diff --git a/src/test/ui/issue-54943-2.rs b/src/test/ui/issue-54943-2.rs new file mode 100644 index 0000000000000..f829c38c35d23 --- /dev/null +++ b/src/test/ui/issue-54943-2.rs @@ -0,0 +1,18 @@ +#![feature(nll)] + +// This test is a minimal version of an ICE in the dropck-eyepatch tests +// found in the fix for #54943. In particular, this test is in unreachable +// code as the initial fix for this ICE only worked if the code was reachable. + +// compile-pass + +fn foo(_t: T) { +} + +fn main() { + return; + + struct A<'a, B: 'a>(&'a B); + let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this")); + foo((a1, a2)); +} diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr index abda7ec5e07a6..539343a68294f 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr @@ -21,7 +21,7 @@ LL | fn call1<'a>(x: &'a usize) { LL | let z: &'a & usize = &(&y); | ----------- ^^^^ borrowed value does not live long enough | | - | assignment requires that `y` is borrowed for `'a` + | type annotation requires that `y` is borrowed for `'a` ... LL | } | - `y` dropped here while still borrowed From 28fd1b04e56f33fecc843c0a78fc490b03100f43 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 18 Dec 2018 21:27:22 +0100 Subject: [PATCH 09/11] Stop well-formedness checking unreachable code. This commit stops well-formedness checking applying to unreachable code and therefore stops some of the ICEs that the intended solution taken by this PR causes. By disabling these checks, we can land the other fixes and larger refactors that this PR includes. --- src/librustc/dep_graph/dep_node.rs | 4 +- src/librustc/traits/query/mod.rs | 4 - .../traits/query/type_op/ascribe_user_type.rs | 58 +--------- src/librustc/ty/query/config.rs | 12 +- src/librustc/ty/query/mod.rs | 11 +- src/librustc/ty/query/plumbing.rs | 1 - src/librustc/ty/wf.rs | 7 +- .../borrow_check/nll/type_check/mod.rs | 53 --------- src/librustc_traits/type_op.rs | 103 +++++------------- src/test/ui/issue-54943-3.rs | 21 ++++ src/test/ui/issue-54943.rs | 11 +- src/test/ui/issue-54943.stderr | 11 -- ...ns-free-region-ordering-caller1.nll.stderr | 19 +--- 13 files changed, 70 insertions(+), 245 deletions(-) create mode 100644 src/test/ui/issue-54943-3.rs delete mode 100644 src/test/ui/issue-54943.stderr diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 1f19e6fc689c1..e5fd0aa3c9cbd 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -62,8 +62,7 @@ use syntax_pos::symbol::InternedString; use traits; use traits::query::{ CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, - CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal, - CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, + CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, }; use ty::{TyCtxt, FnSig, Instance, InstanceDef, @@ -651,7 +650,6 @@ define_dep_nodes!( <'tcx> [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), [] EvaluateGoal(traits::ChalkCanonicalGoal<'tcx>), [] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>), - [] TypeOpAscribeUserTypeWellFormed(CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>), [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>), [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>), diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 3203dc4e8cf82..59f786025b224 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -28,10 +28,6 @@ pub type CanonicalPredicateGoal<'tcx> = pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>; -pub type CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, - type_op::ascribe_user_type::AscribeUserTypeWellFormed<'tcx>>>; - pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>; diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index 993d09d2ed02d..b2f30564de93a 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -2,7 +2,7 @@ use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, Que use traits::query::Fallible; use hir::def_id::DefId; use mir::ProjectionKind; -use ty::{self, ParamEnvAnd, Ty, TyCtxt, UserTypeAnnotation}; +use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::UserSubsts; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -68,59 +68,3 @@ impl_stable_hash_for! { mir_ty, variance, def_id, user_substs, projs } } - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct AscribeUserTypeWellFormed<'tcx> { - pub user_type_annotation: UserTypeAnnotation<'tcx>, -} - -impl<'tcx> AscribeUserTypeWellFormed<'tcx> { - pub fn new( - user_type_annotation: UserTypeAnnotation<'tcx>, - ) -> Self { - Self { user_type_annotation, } - } -} - -impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserTypeWellFormed<'tcx> { - type QueryResponse = (); - - fn try_fast_path( - _tcx: TyCtxt<'_, 'gcx, 'tcx>, - _key: &ParamEnvAnd<'tcx, Self>, - ) -> Option { - None - } - - fn perform_query( - tcx: TyCtxt<'_, 'gcx, 'tcx>, - canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible> { - tcx.type_op_ascribe_user_type_well_formed(canonicalized) - } - - fn shrink_to_tcx_lifetime( - v: &'a CanonicalizedQueryResponse<'gcx, ()>, - ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { - v - } -} - -BraceStructTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for AscribeUserTypeWellFormed<'tcx> { - user_type_annotation - } -} - -BraceStructLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for AscribeUserTypeWellFormed<'a> { - type Lifted = AscribeUserTypeWellFormed<'tcx>; - user_type_annotation - } -} - -impl_stable_hash_for! { - struct AscribeUserTypeWellFormed<'tcx> { - user_type_annotation - } -} diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index bed4dfd97ca49..3464464aa229c 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -5,8 +5,7 @@ use mir::interpret::GlobalId; use traits; use traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpAscribeUserTypeWellFormedGoal, - CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; @@ -125,15 +124,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type_well_formed<'tcx> { - fn describe( - _tcx: TyCtxt<'_, '_, '_>, - goal: CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx>, - ) -> Cow<'static, str> { - format!("evaluating `type_op_ascribe_user_type_well_formed` `{:?}`", goal).into() - } -} - impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> { format!("evaluating `type_op_eq` `{:?}`", goal).into() diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index c2f208308b2d1..842aea07614dd 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -27,8 +27,7 @@ use traits::{self, Vtable}; use traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, - CanonicalTypeOpAscribeUserTypeWellFormedGoal, CanonicalTypeOpEqGoal, - CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, + CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution, }; use traits::query::method_autoderef::MethodAutoderefStepsResult; @@ -610,14 +609,6 @@ define_queries! { <'tcx> NoSolution, >, - /// Do not call this query directly: part of the `Eq` type-op - [] fn type_op_ascribe_user_type_well_formed: TypeOpAscribeUserTypeWellFormed( - CanonicalTypeOpAscribeUserTypeWellFormedGoal<'tcx> - ) -> Result< - Lrc>>, - NoSolution, - >, - /// Do not call this query directly: part of the `Eq` type-op [] fn type_op_eq: TypeOpEq( CanonicalTypeOpEqGoal<'tcx> diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index cdb3cd3ffcb6b..5d23ee0994a06 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1208,7 +1208,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::EvaluateObligation | DepKind::EvaluateGoal | DepKind::TypeOpAscribeUserType | - DepKind::TypeOpAscribeUserTypeWellFormed | DepKind::TypeOpEq | DepKind::TypeOpSubtype | DepKind::TypeOpProvePredicate | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index f4a998fb9905a..aacc63c47de61 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -289,6 +289,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.out.extend(obligations); } + ty::FnDef(did, substs) => { + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); + } + ty::Ref(r, rty, _) => { // WfReference if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { @@ -349,7 +354,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - ty::FnDef(..) | ty::FnPtr(_) => { + ty::FnPtr(_) => { // let the loop iterate into the argument/return // types appearing in the fn signature } 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 d0ca050f0dff7..796a2f79f7554 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -928,37 +928,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); } - /// Check that user type annotations are well formed. - fn check_user_type_annotations_are_well_formed(&mut self) { - for index in self.mir.user_type_annotations.indices() { - let (span, _) = &self.mir.user_type_annotations[index]; - let type_annotation = self.instantiated_type_annotations[&index]; - match type_annotation { - // We can't check the well-formedness of a `UserTypeAnnotation::Ty` here, it will - // cause ICEs (see comment in `relate_type_and_user_type`). - UserTypeAnnotation::TypeOf(..) => { - if let Err(terr) = self.fully_perform_op( - Locations::All(*span), - ConstraintCategory::Assignment, - self.param_env.and( - type_op::ascribe_user_type::AscribeUserTypeWellFormed::new( - type_annotation, - ) - ), - ) { - span_mirbug!( - self, - type_annotation, - "bad user type annotation: {:?}", - terr, - ); - } - }, - _ => {}, - } - } - } - /// Given some operation `op` that manipulates types, proves /// predicates, or otherwise uses the inference context, executes /// `op` and then executes all the further obligations that `op` @@ -1127,27 +1096,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Ok(projected_ty) = curr_projected_ty { let ty = projected_ty.to_ty(tcx); self.relate_types(ty, v1, a, locations, category)?; - - // We'll get an ICE if we check for well-formedness of a - // `UserTypeAnnotation::Ty` that hasn't had types related. - // - // Doing this without the types having been related will result in - // `probe_ty_var` failing in the canonicalizer - in practice, this - // results in three run-pass tests failing. You can work around that - // by keeping an vec of projections instead of annotations and performing - // the projections before storing into `instantiated_type_annotations` - // but that still fails in dead code. - self.fully_perform_op( - locations, - category, - self.param_env.and( - type_op::ascribe_user_type::AscribeUserTypeWellFormed::new( - UserTypeAnnotation::Ty(ty), - ) - ), - )?; } - } UserTypeAnnotation::TypeOf(def_id, user_substs) => { let projs = self.infcx.tcx.intern_projs(&user_ty.projs); @@ -2453,8 +2402,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.check_terminator(mir, block_data.terminator(), location); self.check_iscleanup(mir, block_data); } - - self.check_user_type_annotations_are_well_formed(); } fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 6691a036ac28c..52fcb5b80f4ae 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -4,7 +4,7 @@ use rustc::infer::InferCtxt; use rustc::hir::def_id::DefId; use rustc::mir::ProjectionKind; use rustc::mir::tcx::PlaceTy; -use rustc::traits::query::type_op::ascribe_user_type::{AscribeUserType, AscribeUserTypeWellFormed}; +use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType; use rustc::traits::query::type_op::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; use rustc::traits::query::type_op::prove_predicate::ProvePredicate; @@ -17,7 +17,6 @@ use rustc::ty::query::Providers; use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy}; use rustc::ty::{ FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance, - UserTypeAnnotation, }; use rustc_data_structures::sync::Lrc; use std::fmt; @@ -27,7 +26,6 @@ use syntax_pos::DUMMY_SP; crate fn provide(p: &mut Providers) { *p = Providers { type_op_ascribe_user_type, - type_op_ascribe_user_type_well_formed, type_op_eq, type_op_prove_predicate, type_op_subtype, @@ -62,28 +60,6 @@ fn type_op_ascribe_user_type<'tcx>( }) } -fn type_op_ascribe_user_type_well_formed<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserTypeWellFormed<'tcx>>>, -) -> Result>>, NoSolution> { - tcx.infer_ctxt() - .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - let ( - param_env, AscribeUserTypeWellFormed { user_type_annotation } - ) = key.into_parts(); - - debug!( - "type_op_ascribe_user_type_well_formed: user_type_annotation={:?}", - user_type_annotation, - ); - - let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx }; - cx.well_formed(user_type_annotation)?; - - Ok(()) - }) -} - struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> { infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, param_env: ParamEnv<'tcx>, @@ -133,56 +109,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { value.subst(self.tcx(), substs) } - fn well_formed( - &mut self, - type_annotation: UserTypeAnnotation<'tcx> - ) -> Result<(), NoSolution> { - match type_annotation { - UserTypeAnnotation::Ty(ty) => { - self.prove_predicate(Predicate::WellFormed(ty)); - Ok(()) - }, - UserTypeAnnotation::TypeOf(did, user_substs) => { - let UserSubsts { - user_self_ty, - substs, - } = user_substs; - - let ty = self.tcx().type_of(did); - let ty = self.subst(ty, substs); - debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); - let ty = self.normalize(ty); - - if let Some(UserSelfTy { - impl_def_id, - self_ty, - }) = user_self_ty { - let impl_self_ty = self.tcx().type_of(impl_def_id); - let impl_self_ty = self.subst(impl_self_ty, &substs); - let impl_self_ty = self.normalize(impl_self_ty); - - self.relate(self_ty, Variance::Invariant, impl_self_ty)?; - - self.prove_predicate(Predicate::WellFormed(impl_self_ty)); - } - - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - self.prove_predicate(Predicate::WellFormed(ty)); - Ok(()) - }, - } - } - fn relate_mir_and_user_ty( &mut self, mir_ty: Ty<'tcx>, @@ -192,7 +118,7 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { projs: &[ProjectionKind<'tcx>], ) -> Result<(), NoSolution> { let UserSubsts { - user_self_ty: _, + user_self_ty, substs, } = user_substs; let tcx = self.tcx(); @@ -245,6 +171,31 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { self.prove_predicate(instantiated_predicate); } + if let Some(UserSelfTy { + impl_def_id, + self_ty, + }) = user_self_ty { + let impl_self_ty = self.tcx().type_of(impl_def_id); + let impl_self_ty = self.subst(impl_self_ty, &substs); + let impl_self_ty = self.normalize(impl_self_ty); + + self.relate(self_ty, Variance::Invariant, impl_self_ty)?; + + self.prove_predicate(Predicate::WellFormed(impl_self_ty)); + } + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // them? This would only be relevant if some input + // type were ill-formed but did not appear in `ty`, + // which...could happen with normalization... + self.prove_predicate(Predicate::WellFormed(ty)); Ok(()) } } diff --git a/src/test/ui/issue-54943-3.rs b/src/test/ui/issue-54943-3.rs new file mode 100644 index 0000000000000..185077bd684a8 --- /dev/null +++ b/src/test/ui/issue-54943-3.rs @@ -0,0 +1,21 @@ +// compile-pass +// FIXME(#54943) This test targets the scenario where proving the WF requirements requires +// knowing the value of the `_` type present in the user type annotation - unfortunately, figuring +// out the value of that `_` requires type-checking the surrounding code, but that code is dead, +// so our NLL region checker doesn't have access to it. This test should actually fail to compile. + +#![feature(nll)] +#![allow(warnings)] + +use std::fmt::Debug; + +fn foo(_: T) { } + +fn bar<'a>() { + return; + + let _x = foo::>(Vec::<&'a u32>::new()); + //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477] +} + +fn main() {} diff --git a/src/test/ui/issue-54943.rs b/src/test/ui/issue-54943.rs index d5d0ae1a5e295..c720f62797580 100644 --- a/src/test/ui/issue-54943.rs +++ b/src/test/ui/issue-54943.rs @@ -1,8 +1,17 @@ +// compile-pass +// FIXME(#54943) This test targets the scenario where proving the WF requirements of a user +// type annotation requires checking dead code. This test should actually fail to compile. + +#![feature(nll)] +#![allow(warnings)] + fn foo() { } -fn main<'a>() { +fn boo<'a>() { return; let x = foo::<&'a u32>(); //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477] } + +fn main() {} diff --git a/src/test/ui/issue-54943.stderr b/src/test/ui/issue-54943.stderr deleted file mode 100644 index 62aacee811110..0000000000000 --- a/src/test/ui/issue-54943.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0477]: the type `&'a u32` does not fulfill the required lifetime - --> $DIR/issue-54943.rs:6:13 - | -LL | let x = foo::<&'a u32>(); - | ^^^^^^^^^^^^^^ - | - = note: type must satisfy the static lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr index 539343a68294f..92c21fcb4aec5 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr @@ -12,21 +12,6 @@ LL | let z: &'a & usize = &(&y); LL | } | - temporary value is freed at the end of this statement -error[E0597]: `y` does not live long enough - --> $DIR/regions-free-region-ordering-caller1.rs:9:27 - | -LL | fn call1<'a>(x: &'a usize) { - | -- lifetime `'a` defined here -... -LL | let z: &'a & usize = &(&y); - | ----------- ^^^^ borrowed value does not live long enough - | | - | type annotation requires that `y` is borrowed for `'a` -... -LL | } - | - `y` dropped here while still borrowed - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0597, E0716. -For more information about an error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`. From 0bfe184b1ad14db4b002c3a272adf44e1839822f Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 19 Dec 2018 16:47:06 +0100 Subject: [PATCH 10/11] Stop duplicating projections of type annotation. This commit changes how type annotations are handled in bindings during MIR building. Instead of building up a `PatternTypeProjections` with the `CanonicalUserTypeAnnotation` and projections, the `CanonicalUserTypeAnnotation` is stored in the `canonical_user_type_annotations` map at the start and the (equivalent) `UserTypeProjections` is built up with the new index and same projections. This has the effect of deduplicating type annotations as instead of type annotations being added to the `canonical_user_type_annotations` map multiple times at the end after being duplicated (which happens in building up `PatternTypeProjections`), it is instead added once. --- src/librustc/mir/mod.rs | 75 +++++++++++++++++++++ src/librustc_mir/build/block.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 37 +++++----- src/librustc_mir/hair/mod.rs | 2 +- src/librustc_mir/hair/pattern/mod.rs | 97 +-------------------------- 5 files changed, 99 insertions(+), 114 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ecbe14c093f40..2936405ebd0b7 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2519,6 +2519,48 @@ impl<'tcx> UserTypeProjections<'tcx> { pub fn projections(&self) -> impl Iterator> { self.contents.iter().map(|&(ref user_type, _span)| user_type) } + + pub fn push_projection( + mut self, + user_ty: &UserTypeProjection<'tcx>, + span: Span, + ) -> Self { + self.contents.push((user_ty.clone(), span)); + self + } + + fn map_projections( + mut self, + mut f: impl FnMut(UserTypeProjection<'tcx>) -> UserTypeProjection<'tcx> + ) -> Self { + self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect(); + self + } + + pub fn index(self) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.index()) + } + + pub fn subslice(self, from: u32, to: u32) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) + } + + pub fn deref(self) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) + } + + pub fn leaf(self, field: Field) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) + } + + pub fn variant( + self, + adt_def: &'tcx AdtDef, + variant_index: VariantIdx, + field: Field, + ) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) + } } /// Encodes the effect of a user-supplied type annotation on the @@ -2544,6 +2586,39 @@ pub struct UserTypeProjection<'tcx> { impl<'tcx> Copy for ProjectionKind<'tcx> { } +impl<'tcx> UserTypeProjection<'tcx> { + pub(crate) fn index(mut self) -> Self { + self.projs.push(ProjectionElem::Index(())); + self + } + + pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { + self.projs.push(ProjectionElem::Subslice { from, to }); + self + } + + pub(crate) fn deref(mut self) -> Self { + self.projs.push(ProjectionElem::Deref); + self + } + + pub(crate) fn leaf(mut self, field: Field) -> Self { + self.projs.push(ProjectionElem::Field(field, ())); + self + } + + pub(crate) fn variant( + mut self, + adt_def: &'tcx AdtDef, + variant_index: VariantIdx, + field: Field, + ) -> Self { + self.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); + self.projs.push(ProjectionElem::Field(field, ())); + self + } +} + CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, } impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> { diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 41718cfc87012..f3d89a7a02515 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -144,7 +144,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_bindings( &pattern, - &PatternTypeProjections::none(), + UserTypeProjections::none(), &mut |this, _, _, _, node, span, _, _| { this.storage_live_binding(block, node, span, OutsideGuard); this.schedule_drop_for_binding(node, span, OutsideGuard); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 085c58ef5ff66..fe5bc6e19db65 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -8,7 +8,6 @@ use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard}; use build::{BlockAnd, BlockAndExtension, Builder}; use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use hair::*; -use hair::pattern::PatternTypeProjections; use rustc::mir::*; use rustc::ty::{self, Ty}; use rustc::ty::layout::VariantIdx; @@ -412,7 +411,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("declare_bindings: patterns={:?}", patterns); self.visit_bindings( &patterns[0], - &PatternTypeProjections::none(), + UserTypeProjections::none(), &mut |this, mutability, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { visibility_scope = @@ -488,7 +487,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub(super) fn visit_bindings( &mut self, pattern: &Pattern<'tcx>, - pattern_user_ty: &PatternTypeProjections<'tcx>, + pattern_user_ty: UserTypeProjections<'tcx>, f: &mut impl FnMut( &mut Self, Mutability, @@ -497,7 +496,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { NodeId, Span, Ty<'tcx>, - &PatternTypeProjections<'tcx>, + UserTypeProjections<'tcx>, ), ) { debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); @@ -511,7 +510,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ref subpattern, .. } => { - f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty); + f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); if let Some(subpattern) = subpattern.as_ref() { self.visit_bindings(subpattern, pattern_user_ty, f); } @@ -529,18 +528,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let from = u32::try_from(prefix.len()).unwrap(); let to = u32::try_from(suffix.len()).unwrap(); for subpattern in prefix { - self.visit_bindings(subpattern, &pattern_user_ty.index(), f); + self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f); } for subpattern in slice { - self.visit_bindings(subpattern, &pattern_user_ty.subslice(from, to), f); + self.visit_bindings(subpattern, pattern_user_ty.clone().subslice(from, to), f); } for subpattern in suffix { - self.visit_bindings(subpattern, &pattern_user_ty.index(), f); + self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {} PatternKind::Deref { ref subpattern } => { - self.visit_bindings(subpattern, &pattern_user_ty.deref(), f); + self.visit_bindings(subpattern, pattern_user_ty.deref(), f); } PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => { // This corresponds to something like @@ -548,23 +547,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // ``` // let A::<'a>(_): A<'static> = ...; // ``` - let subpattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span); - self.visit_bindings(subpattern, &subpattern_user_ty, f) + let annotation = (user_ty_span, user_ty.base); + let projection = UserTypeProjection { + base: self.canonical_user_type_annotations.push(annotation), + projs: user_ty.projs.clone(), + }; + let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span); + self.visit_bindings(subpattern, subpattern_user_ty, f) } PatternKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { - let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field); + let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty); - self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f); + self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f); } } PatternKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => { for subpattern in subpatterns { - let subpattern_user_ty = pattern_user_ty.variant( + let subpattern_user_ty = pattern_user_ty.clone().variant( adt_def, variant_index, subpattern.field); - self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f); + self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f); } } } @@ -1465,7 +1469,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { num_patterns: usize, var_id: NodeId, var_ty: Ty<'tcx>, - user_var_ty: &PatternTypeProjections<'tcx>, + user_ty: UserTypeProjections<'tcx>, has_guard: ArmHasGuard, opt_match_place: Option<(Option>, Span)>, pat_span: Span, @@ -1481,7 +1485,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()), BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()), }; - let user_ty = user_var_ty.clone().user_ty(&mut self.canonical_user_type_annotations); debug!("declare_binding: user_ty={:?}", user_ty); let local = LocalDecl::<'tcx> { mutability, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index d36a6eb58b85a..b56e3d4e77395 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -21,7 +21,7 @@ mod constant; pub mod pattern; pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern}; -pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections}; +pub(crate) use self::pattern::PatternTypeProjection; mod util; diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 6d562c69b2dc5..10d2d7bc1b18b 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -12,7 +12,7 @@ use hair::util::UserAnnotatedTyHelpers; use hair::constant::*; use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; -use rustc::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; +use rustc::mir::{ProjectionElem, UserTypeProjection}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift}; use rustc::ty::{CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotation}; @@ -58,64 +58,6 @@ pub struct Pattern<'tcx> { } -#[derive(Clone, Debug)] -pub(crate) struct PatternTypeProjections<'tcx> { - contents: Vec<(PatternTypeProjection<'tcx>, Span)>, -} - -impl<'tcx> PatternTypeProjections<'tcx> { - pub(crate) fn user_ty( - self, - annotations: &mut CanonicalUserTypeAnnotations<'tcx>, - ) -> UserTypeProjections<'tcx> { - UserTypeProjections::from_projections( - self.contents - .into_iter() - .map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(annotations, span), span)) - ) - } - - pub(crate) fn none() -> Self { - PatternTypeProjections { contents: vec![] } - } - - fn map_projs(&self, - mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>) - -> Self - { - PatternTypeProjections { - contents: self.contents - .iter() - .map(|(proj, span)| (f(proj), *span)) - .collect(), } - } - - pub(crate) fn index(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.index()) } - - pub(crate) fn subslice(&self, from: u32, to: u32) -> Self { - self.map_projs(|pat_ty_proj| pat_ty_proj.subslice(from, to)) - } - - pub(crate) fn deref(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.deref()) } - - pub(crate) fn leaf(&self, field: Field) -> Self { - self.map_projs(|pat_ty_proj| pat_ty_proj.leaf(field)) - } - - pub(crate) fn variant(&self, - adt_def: &'tcx AdtDef, - variant_index: VariantIdx, - field: Field) -> Self { - self.map_projs(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) - } - - pub(crate) fn add_user_type(&self, user_ty: &PatternTypeProjection<'tcx>, sp: Span) -> Self { - let mut new = self.clone(); - new.contents.push((user_ty.clone(), sp)); - new - } -} - #[derive(Clone, Debug)] pub struct PatternTypeProjection<'tcx> { pub base: CanonicalUserTypeAnnotation<'tcx>, @@ -123,40 +65,6 @@ pub struct PatternTypeProjection<'tcx> { } impl<'tcx> PatternTypeProjection<'tcx> { - pub(crate) fn index(&self) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Index(())); - new - } - - pub(crate) fn subslice(&self, from: u32, to: u32) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Subslice { from, to }); - new - } - - pub(crate) fn deref(&self) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Deref); - new - } - - pub(crate) fn leaf(&self, field: Field) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Field(field, ())); - new - } - - pub(crate) fn variant(&self, - adt_def: &'tcx AdtDef, - variant_index: VariantIdx, - field: Field) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); - new.projs.push(ProjectionElem::Field(field, ())); - new - } - pub(crate) fn from_user_type(user_annotation: CanonicalUserTypeAnnotation<'tcx>) -> Self { Self { base: user_annotation, @@ -169,9 +77,8 @@ impl<'tcx> PatternTypeProjection<'tcx> { annotations: &mut CanonicalUserTypeAnnotations<'tcx>, span: Span, ) -> UserTypeProjection<'tcx> { - let annotation_index = annotations.push((span, self.base)); UserTypeProjection { - base: annotation_index, + base: annotations.push((span, self.base)), projs: self.projs } } From c20ba65a0b3142bbd88031fbf6eb7ef46bc1f7b3 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 22 Dec 2018 15:32:44 +0100 Subject: [PATCH 11/11] Guarantee `rustc_dump_user_substs` error order. This commit buffers the errors output by the `rustc_dump_user_substs` attribute so that they can be output in order of span and would therefore be consistent. --- src/librustc_typeck/check/writeback.rs | 17 ++++++++++++++++- .../nll/user-annotations/dump-fn-method.stderr | 16 ++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 53ea497f01add..38de936a027ff 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -3,6 +3,7 @@ // substitutions. use check::FnCtxt; +use errors::DiagnosticBuilder; use rustc::hir; use rustc::hir::def_id::{DefId, DefIndex}; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -357,6 +358,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); let common_local_id_root = fcx_tables.local_id_root.unwrap(); + let mut errors_buffer = Vec::new(); for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() { let hir_id = hir::HirId { owner: common_local_id_root.index, @@ -382,10 +384,23 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // This is a unit-testing mechanism. let node_id = self.tcx().hir().hir_to_node_id(hir_id); let span = self.tcx().hir().span(node_id); - self.tcx().sess.span_err(span, &format!("user substs: {:?}", user_substs)); + // We need to buffer the errors in order to guarantee a consistent + // order when emitting them. + let err = self.tcx().sess.struct_span_err( + span, + &format!("user substs: {:?}", user_substs) + ); + err.buffer(&mut errors_buffer); } } } + + if !errors_buffer.is_empty() { + errors_buffer.sort_by_key(|diag| diag.span.primary_span()); + for diag in errors_buffer.drain(..) { + DiagnosticBuilder::new_diagnostic(self.tcx().sess.diagnostic(), diag).emit(); + } + } } fn visit_user_provided_sigs(&mut self) { diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr index fc4544437c5b1..a1a4e43e8a3e9 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -1,8 +1,8 @@ -error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:44:5 +error: user substs: UserSubsts { substs: [u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:26:13 | -LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = foo::; //~ ERROR [u32] + | ^^^^^^^^^^ error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } --> $DIR/dump-fn-method.rs:32:13 @@ -16,11 +16,11 @@ error: user substs: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } LL | let x = >::method::; //~ ERROR [u8, u16, u32] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: UserSubsts { substs: [u32], user_self_ty: None } - --> $DIR/dump-fn-method.rs:26:13 +error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } + --> $DIR/dump-fn-method.rs:44:5 | -LL | let x = foo::; //~ ERROR [u32] - | ^^^^^^^^^^ +LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors