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..2936405ebd0b7 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 @@ -2537,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 @@ -2556,12 +2580,45 @@ 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>, } 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> { @@ -2970,6 +3027,7 @@ CloneTypeFoldableAndLiftImpls! { SourceScope, SourceScopeData, SourceScopeLocalData, + UserTypeAnnotationIndex, } BraceStructTypeFoldableImpl! { @@ -2983,6 +3041,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/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index 365c1d67ef97a..b2f30564de93a 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -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 } } } 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/query/mod.rs b/src/librustc/ty/query/mod.rs index 22bd1cd90a754..842aea07614dd 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -26,8 +26,8 @@ use session::config::OutputFilenames; use traits::{self, Vtable}; use traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, - CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, - CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, + CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, + CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution, }; use traits::query::method_autoderef::MethodAutoderefStepsResult; 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/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/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/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..796a2f79f7554 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, ); @@ -303,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), @@ -715,6 +731,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 +885,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 +896,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 +1057,14 @@ 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); - + 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` // 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 +1098,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 +1269,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 +1327,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 +2002,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/block.rs b/src/librustc_mir/build/block.rs index ad4e5a50dcd14..f3d89a7a02515 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -141,9 +141,10 @@ 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(), + 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/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..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; @@ -302,6 +301,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 +311,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( place, ty::Variance::Invariant, - box pat_ascription_ty.user_ty(), + user_ty, ), }, ); @@ -406,9 +408,10 @@ 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(), + UserTypeProjections::none(), &mut |this, mutability, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { visibility_scope = @@ -484,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, @@ -493,9 +496,10 @@ 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); match *pattern.kind { PatternKind::Binding { mutability, @@ -506,19 +510,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.clone()); if let Some(subpattern) = subpattern.as_ref() { self.visit_bindings(subpattern, pattern_user_ty, f); } @@ -536,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 @@ -555,22 +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); - self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f); + 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); } } 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); } } } @@ -1314,6 +1312,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 +1322,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, ), }, ); @@ -1468,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, @@ -1484,10 +1485,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()), BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()), }; + 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..b56e3d4e77395 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; @@ -20,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; @@ -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..10d2d7bc1b18b 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}; 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}; @@ -58,113 +59,29 @@ pub struct Pattern<'tcx> { #[derive(Clone, Debug)] -pub(crate) struct PatternTypeProjections<'tcx> { - contents: Vec<(PatternTypeProjection<'tcx>, Span)>, +pub struct PatternTypeProjection<'tcx> { + pub base: CanonicalUserTypeAnnotation<'tcx>, + pub projs: Vec>, } -impl<'tcx> PatternTypeProjections<'tcx> { - pub(crate) fn user_ty(self) -> UserTypeProjections<'tcx> { - UserTypeProjections::from_projections( - self.contents.into_iter().map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(), span))) - } - - pub(crate) fn none() -> Self { - 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 - { - 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>(UserTypeProjection<'tcx>); - impl<'tcx> PatternTypeProjection<'tcx> { - pub(crate) fn index(&self) -> Self { - let mut new = self.clone(); - new.0.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 - } - - pub(crate) fn deref(&self) -> Self { - let mut new = self.clone(); - new.0.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 - } - - pub(crate) fn variant(&self, - adt_def: &'tcx AdtDef, - 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 - } - - 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> { + UserTypeProjection { + base: annotations.push((span, self.base)), + projs: self.projs + } } - - pub(crate) fn user_ty(self) -> UserTypeProjection<'tcx> { self.0 } } #[derive(Clone, Debug)] @@ -788,18 +705,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: kind={:?} user_ty={:?} span={:?}", kind, 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, }; } @@ -837,7 +750,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( @@ -927,7 +861,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( @@ -945,6 +879,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_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_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] diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index d38ce3478d93d..52fcb5b80f4ae 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_ascribe_user_type: 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); @@ -171,20 +158,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` @@ -198,6 +171,19 @@ 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 @@ -210,7 +196,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { // 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/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 39beb2832851b..36de41ef8a170 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"); } } @@ -2377,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 @@ -2386,8 +2398,9 @@ 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)); + 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); } ty @@ -3734,7 +3747,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); @@ -4573,6 +4586,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, @@ -5093,6 +5107,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) @@ -5290,7 +5305,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..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,7 +358,8 @@ 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() { + 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, local_id, @@ -374,8 +376,30 @@ 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); + // 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(); + } } } @@ -573,22 +597,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/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/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/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-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/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 new file mode 100644 index 0000000000000..c720f62797580 --- /dev/null +++ b/src/test/ui/issue-54943.rs @@ -0,0 +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 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-55511.nll.stderr b/src/test/ui/issue-55511.nll.stderr new file mode 100644 index 0000000000000..bf3e58e8cdb19 --- /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 | <() 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..4b9475ba62718 --- /dev/null +++ b/src/test/ui/issue-55511.rs @@ -0,0 +1,19 @@ +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)); + //~^ ERROR `a` does not live long enough [E0597] + 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`. 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 + 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..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,22 +1,22 @@ -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-fn-method.rs:26:13 | LL | let x = foo::; //~ ERROR [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 } } +error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } --> $DIR/dump-fn-method.rs:44:5 | LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] 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