diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 4f68569c60032..274a2df283cbd 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -606,3 +606,6 @@ impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation< } } } + +impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base, projs }); +impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 7c3d4713572b9..952783a91b2ed 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> { /// e.g. via `let x: T`, then we carry that type here. The MIR /// borrow checker needs this information since it can affect /// region inference. - pub user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>, + pub user_ty: UserTypeProjections<'tcx>, /// Name of the local, used in debuginfo and pretty-printing. /// @@ -882,7 +882,7 @@ impl<'tcx> LocalDecl<'tcx> { LocalDecl { mutability, ty, - user_ty: None, + user_ty: UserTypeProjections::none(), name: None, source_info: SourceInfo { span, @@ -903,7 +903,7 @@ impl<'tcx> LocalDecl<'tcx> { LocalDecl { mutability: Mutability::Mut, ty: return_ty, - user_ty: None, + user_ty: UserTypeProjections::none(), source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE, @@ -1741,7 +1741,7 @@ pub enum StatementKind<'tcx> { /// - `Contravariant` -- requires that `T_y :> T` /// - `Invariant` -- requires that `T_y == T` /// - `Bivariant` -- no effect - AscribeUserType(Place<'tcx>, ty::Variance, Box>), + AscribeUserType(Place<'tcx>, ty::Variance, Box>), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, @@ -1944,6 +1944,10 @@ pub type PlaceProjection<'tcx> = Projection<'tcx, Place<'tcx>, Local, Ty<'tcx>>; /// and the index is a local. pub type PlaceElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>; +/// Alias for projections as they appear in `UserTypeProjection`, where we +/// need neither the `V` parameter for `Index` nor the `T` for `Field`. +pub type ProjectionKind<'tcx> = ProjectionElem<'tcx, (), ()>; + newtype_index! { pub struct Field { DEBUG_FORMAT = "field[{}]" @@ -2449,6 +2453,117 @@ EnumLiftImpl! { } } +/// A collection of projections into user types. +/// +/// They are projections because a binding can occur a part of a +/// parent pattern that has been ascribed a type. +/// +/// Its a collection because there can be multiple type ascriptions on +/// the path from the root of the pattern down to the binding itself. +/// +/// An example: +/// +/// ```rust +/// struct S<'a>((i32, &'a str), String); +/// let S((_, w): (i32, &'static str), _): S = ...; +/// // ------ ^^^^^^^^^^^^^^^^^^^ (1) +/// // --------------------------------- ^ (2) +/// ``` +/// +/// The highlights labelled `(1)` show the subpattern `(_, w)` being +/// ascribed the type `(i32, &'static str)`. +/// +/// The highlights labelled `(2)` show the whole pattern being +/// ascribed the type `S`. +/// +/// In this example, when we descend to `w`, we will have built up the +/// following two projected types: +/// +/// * base: `S`, projection: `(base.0).1` +/// * base: `(i32, &'static str)`, projection: `base.1` +/// +/// The first will lead to the constraint `w: &'1 str` (for some +/// inferred region `'1`). The second will lead to the constraint `w: +/// &'static str`. +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UserTypeProjections<'tcx> { + pub(crate) contents: Vec<(UserTypeProjection<'tcx>, Span)>, +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections<'tcx> { + contents + } +} + +impl<'tcx> UserTypeProjections<'tcx> { + pub fn none() -> Self { + UserTypeProjections { contents: vec![] } + } + + pub fn from_projections(projs: impl Iterator, Span)>) -> Self { + UserTypeProjections { contents: projs.collect() } + } + + pub fn projections_and_spans(&self) -> impl Iterator, Span)> { + self.contents.iter() + } + + pub fn projections(&self) -> impl Iterator> { + self.contents.iter().map(|&(ref user_type, _span)| user_type) + } +} + +/// Encodes the effect of a user-supplied type annotation on the +/// subcomponents of a pattern. The effect is determined by applying the +/// given list of proejctions to some underlying base type. Often, +/// the projection element list `projs` is empty, in which case this +/// directly encodes a type in `base`. But in the case of complex patterns with +/// subpatterns and bindings, we want to apply only a *part* of the type to a variable, +/// in which case the `projs` vector is used. +/// +/// Examples: +/// +/// * `let x: T = ...` -- here, the `projs` vector is empty. +/// +/// * `let (x, _): T = ...` -- here, the `projs` vector would contain +/// `field[0]` (aka `.0`), indicating that the type of `s` is +/// 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 projs: Vec>, +} + +impl<'tcx> Copy for ProjectionKind<'tcx> { } + +CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, } + +impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::ProjectionElem::*; + + let base = self.base.fold_with(folder); + let projs: Vec<_> = self.projs + .iter() + .map(|elem| { + match elem { + Deref => Deref, + Field(f, ()) => Field(f.clone(), ()), + Index(()) => Index(()), + elem => elem.clone(), + }}) + .collect(); + + UserTypeProjection { base, projs } + } + + fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + self.base.visit_with(visitor) + // Note: there's nothing in `self.proj` to visit. + } +} + newtype_index! { pub struct Promoted { DEBUG_FORMAT = "promoted[{}]" diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index fc7b4862b0ae5..473730c548990 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -44,11 +44,59 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { } } + /// `place_ty.field_ty(tcx, f)` computes the type at a given field + /// of a record or enum-variant. (Most clients of `PlaceTy` can + /// instead just extract the relevant type directly from their + /// `PlaceElem`, but some instances of `ProjectionElem` do + /// not carry a `Ty` for `T`.) + /// + /// Note that the resulting type has not been normalized. + pub fn field_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, f: &Field) -> Ty<'tcx> + { + // Pass `0` here so it can be used as a "default" variant_index in first arm below + let answer = match (self, 0) { + (PlaceTy::Ty { + ty: &ty::TyS { sty: ty::TyKind::Adt(adt_def, substs), .. } }, variant_index) | + (PlaceTy::Downcast { adt_def, substs, variant_index }, _) => { + let variant_def = &adt_def.variants[variant_index]; + let field_def = &variant_def.fields[f.index()]; + field_def.ty(tcx, substs) + } + (PlaceTy::Ty { ty }, _) => { + match ty.sty { + ty::Tuple(ref tys) => tys[f.index()], + _ => bug!("extracting field of non-tuple non-adt: {:?}", self), + } + } + }; + debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer); + answer + } + + /// Convenience wrapper around `projection_ty_core` for + /// `PlaceElem`, where we can just use the `Ty` that is already + /// stored inline on field projection elems. pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> { - match *elem { + self.projection_ty_core(tcx, elem, |_, _, ty| ty) + } + + /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` + /// projects `place_ty` onto `elem`, returning the appropriate + /// `Ty` or downcast variant corresponding to that projection. + /// The `handle_field` callback must map a `Field` to its `Ty`, + /// (which should be trivial when `T` = `Ty`). + pub fn projection_ty_core(self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + elem: &ProjectionElem<'tcx, V, T>, + mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>) + -> PlaceTy<'tcx> + where + V: ::std::fmt::Debug, T: ::std::fmt::Debug + { + let answer = match *elem { ProjectionElem::Deref => { let ty = self.to_ty(tcx) .builtin_deref(true) @@ -94,8 +142,10 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { bug!("cannot downcast non-ADT type: `{:?}`", self) } }, - ProjectionElem::Field(_, fty) => PlaceTy::Ty { ty: fty } - } + ProjectionElem::Field(ref f, ref fty) => PlaceTy::Ty { ty: handle_field(&self, f, fty) } + }; + debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); + answer } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 76c76404d2fd2..bfc03923f6011 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -147,7 +147,7 @@ macro_rules! make_mir_visitor { fn visit_ascribe_user_ty(&mut self, place: & $($mutability)* Place<'tcx>, variance: & $($mutability)* ty::Variance, - user_ty: & $($mutability)* UserTypeAnnotation<'tcx>, + user_ty: & $($mutability)* UserTypeProjection<'tcx>, location: Location) { self.super_ascribe_user_ty(place, variance, user_ty, location); } @@ -175,9 +175,8 @@ macro_rules! make_mir_visitor { fn visit_projection_elem(&mut self, place: & $($mutability)* PlaceElem<'tcx>, - context: PlaceContext<'tcx>, location: Location) { - self.super_projection_elem(place, context, location); + self.super_projection_elem(place, location); } fn visit_branch(&mut self, @@ -214,6 +213,13 @@ macro_rules! make_mir_visitor { self.super_ty(ty); } + fn visit_user_type_projection( + &mut self, + ty: & $($mutability)* UserTypeProjection<'tcx>, + ) { + self.super_user_type_projection(ty); + } + fn visit_user_type_annotation( &mut self, ty: & $($mutability)* UserTypeAnnotation<'tcx>, @@ -640,10 +646,10 @@ macro_rules! make_mir_visitor { fn super_ascribe_user_ty(&mut self, place: & $($mutability)* Place<'tcx>, _variance: & $($mutability)* ty::Variance, - user_ty: & $($mutability)* UserTypeAnnotation<'tcx>, + user_ty: & $($mutability)* UserTypeProjection<'tcx>, location: Location) { self.visit_place(place, PlaceContext::Validate, location); - self.visit_user_type_annotation(user_ty); + self.visit_user_type_projection(user_ty); } fn super_place(&mut self, @@ -692,12 +698,11 @@ macro_rules! make_mir_visitor { PlaceContext::Projection(Mutability::Not) }; self.visit_place(base, context, location); - self.visit_projection_elem(elem, context, location); + self.visit_projection_elem(elem, location); } fn super_projection_elem(&mut self, proj: & $($mutability)* PlaceElem<'tcx>, - _context: PlaceContext<'tcx>, location: Location) { match *proj { ProjectionElem::Deref => { @@ -738,8 +743,8 @@ macro_rules! make_mir_visitor { local, source_info: *source_info, }); - if let Some((user_ty, _)) = user_ty { - self.visit_user_type_annotation(user_ty); + for (user_ty, _) in & $($mutability)* user_ty.contents { + self.visit_user_type_projection(user_ty); } self.visit_source_info(source_info); self.visit_source_scope(visibility_scope); @@ -786,6 +791,17 @@ macro_rules! make_mir_visitor { self.visit_source_scope(scope); } + fn super_user_type_projection( + &mut self, + 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>, 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 b3955b8f864e5..23445781eb2f3 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -11,6 +11,7 @@ use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; use traits::query::Fallible; use hir::def_id::DefId; +use mir::ProjectionKind; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::UserSubsts; @@ -20,6 +21,7 @@ pub struct AscribeUserType<'tcx> { pub variance: ty::Variance, pub def_id: DefId, pub user_substs: UserSubsts<'tcx>, + pub projs: &'tcx ty::List>, } impl<'tcx> AscribeUserType<'tcx> { @@ -28,8 +30,9 @@ impl<'tcx> AscribeUserType<'tcx> { variance: ty::Variance, def_id: DefId, user_substs: UserSubsts<'tcx>, + projs: &'tcx ty::List>, ) -> Self { - AscribeUserType { mir_ty, variance, def_id, user_substs } + AscribeUserType { mir_ty, variance, def_id, user_substs, projs } } } @@ -59,19 +62,19 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx> BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> { - mir_ty, variance, def_id, user_substs + mir_ty, variance, def_id, user_substs, projs } } BraceStructLiftImpl! { impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> { type Lifted = AscribeUserType<'tcx>; - mir_ty, variance, def_id, user_substs + mir_ty, variance, def_id, user_substs, projs } } impl_stable_hash_for! { struct AscribeUserType<'tcx> { - mir_ty, variance, def_id, user_substs + mir_ty, variance, def_id, user_substs, projs } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1686e3e0e0c09..d4b47db608163 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -31,7 +31,7 @@ use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; -use mir::{self, Mir, interpret}; +use mir::{self, Mir, interpret, ProjectionKind}; use mir::interpret::Allocation; use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst}; use ty::ReprOptions; @@ -132,6 +132,7 @@ pub struct CtxtInterners<'tcx> { clauses: InternedSet<'tcx, List>>, goal: InternedSet<'tcx, GoalKind<'tcx>>, goal_list: InternedSet<'tcx, List>>, + projs: InternedSet<'tcx, List>>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { @@ -149,6 +150,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { clauses: Default::default(), goal: Default::default(), goal_list: Default::default(), + projs: Default::default(), } } @@ -1886,6 +1888,24 @@ impl<'a, 'tcx> Lift<'tcx> for &'a List { } } +impl<'a, 'tcx> Lift<'tcx> for &'a List> { + type Lifted = &'tcx List>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + if self.len() == 0 { + return Some(List::empty()); + } + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + pub mod tls { use super::{GlobalCtxt, TyCtxt}; @@ -2294,6 +2314,13 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> { } } +impl<'tcx: 'lcx, 'lcx> Borrow<[ProjectionKind<'lcx>]> + for Interned<'tcx, List>> { + fn borrow<'a>(&'a self) -> &'a [ProjectionKind<'lcx>] { + &self.0[..] + } +} + impl<'tcx> Borrow for Interned<'tcx, RegionKind> { fn borrow<'a>(&'a self) -> &'a RegionKind { &self.0 @@ -2441,7 +2468,8 @@ slice_interners!( type_list: _intern_type_list(Ty), substs: _intern_substs(Kind), clauses: _intern_clauses(Clause), - goal_list: _intern_goals(Goal) + goal_list: _intern_goals(Goal), + projs: _intern_projs(ProjectionKind) ); // This isn't a perfect fit: CanonicalVarInfo slices are always @@ -2743,6 +2771,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn intern_projs(self, ps: &[ProjectionKind<'tcx>]) -> &'tcx List> { + if ps.len() == 0 { + List::empty() + } else { + self._intern_projs(ps) + } + } + pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'gcx> { if ts.len() == 0 { List::empty() diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index a93dca4af426b..62827ea20c31d 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -13,6 +13,7 @@ //! hand, though we've recently added some macros (e.g., //! `BraceStructLiftImpl!`) to help with the tedium. +use mir::ProjectionKind; use mir::interpret::ConstValue; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -628,6 +629,17 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + folder.tcx().intern_projs(&v) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { use ty::InstanceDef::*; diff --git a/src/librustc_codegen_llvm/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs index a0d6cc4629589..1602ef3c5b795 100644 --- a/src/librustc_codegen_llvm/mir/analyze.rs +++ b/src/librustc_codegen_llvm/mir/analyze.rs @@ -168,7 +168,9 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> { let base_ty = self.fx.monomorphize(&base_ty); // ZSTs don't require any actual memory access. - let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx); + let elem_ty = base_ty + .projection_ty(cx.tcx, &proj.elem) + .to_ty(cx.tcx); let elem_ty = self.fx.monomorphize(&elem_ty); if cx.layout_of(elem_ty).is_zst() { return; diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index e7b6f5908a4d1..062f7174680db 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -517,7 +517,8 @@ impl FunctionCx<'a, 'll, 'tcx> { let mut subslice = cg_base.project_index(bx, C_usize(bx.cx, from as u64)); let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty } - .projection_ty(tcx, &projection.elem).to_ty(bx.tcx()); + .projection_ty(tcx, &projection.elem) + .to_ty(bx.tcx()); subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 495e84528a3c3..1d8d028137a5b 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -18,7 +18,7 @@ use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue}; use rustc::mir::{Statement, Terminator}; -use rustc::mir::UserTypeAnnotation; +use rustc::mir::UserTypeProjection; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid}; @@ -183,7 +183,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx &mut self, _place: &Place<'tcx>, _variance: &ty::Variance, - _user_ty: &UserTypeAnnotation<'tcx>, + _user_ty: &UserTypeProjection<'tcx>, _location: Location, ) { } 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 ff4651dfb45cd..953fe0c9521e6 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -284,7 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { if let Err(terr) = self.cx.relate_type_and_user_type( constant.ty, ty::Variance::Invariant, - user_ty, + &UserTypeProjection { base: user_ty, projs: vec![], }, location.to_locations(), ConstraintCategory::Boring, ) { @@ -310,12 +310,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { self.super_local_decl(local, local_decl); self.sanitize_type(local_decl, local_decl.ty); - if let Some((user_ty, span)) = local_decl.user_ty { + for (user_ty, span) in local_decl.user_ty.projections_and_spans() { if let Err(terr) = self.cx.relate_type_and_user_type( local_decl.ty, ty::Variance::Invariant, user_ty, - Locations::All(span), + Locations::All(*span), ConstraintCategory::TypeAnnotation, ) { span_mirbug!( @@ -971,7 +971,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, a: Ty<'tcx>, v: ty::Variance, - user_ty: UserTypeAnnotation<'tcx>, + user_ty: &UserTypeProjection<'tcx>, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { @@ -980,7 +980,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { a, v, user_ty, locations, ); - match user_ty { + match user_ty.base { UserTypeAnnotation::Ty(canonical_ty) => { let (ty, _) = self.infcx .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); @@ -990,6 +990,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // ambient variance to get the right relationship. let v1 = ty::Contravariant.xform(v); + let tcx = self.infcx.tcx; + let mut projected_ty = PlaceTy::from_ty(ty); + for proj in &user_ty.projs { + projected_ty = projected_ty.projection_ty_core( + tcx, proj, |this, field, &()| { + let ty = this.field_ty(tcx, field); + self.normalize(ty, locations) + }); + } + debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", + user_ty.base, ty, user_ty.projs, projected_ty); + + let ty = projected_ty.to_ty(tcx); + self.relate_types(ty, v1, a, locations, category)?; } UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { @@ -999,11 +1013,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) = self.infcx .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + let projs = self.infcx.tcx.intern_projs(&user_ty.projs); self.fully_perform_op( locations, category, self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( - a, v, def_id, user_substs, + a, v, def_id, user_substs, projs, )), )?; } @@ -1172,7 +1187,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Err(terr) = self.relate_type_and_user_type( rv_ty, ty::Variance::Invariant, - user_ty, + &UserTypeProjection { base: user_ty, projs: vec![], }, location.to_locations(), ConstraintCategory::Boring, ) { @@ -1225,7 +1240,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); }; } - StatementKind::AscribeUserType(ref place, variance, box c_ty) => { + StatementKind::AscribeUserType(ref place, variance, box ref c_ty) => { let place_ty = place.ty(mir, tcx).to_ty(tcx); if let Err(terr) = self.relate_type_and_user_type( place_ty, diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index b754d63f7183b..aa383a123b69a 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -151,10 +151,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { None, remainder_span, lint_level, slice::from_ref(&pattern), ArmHasGuard(false), None); - this.visit_bindings(&pattern, None, &mut |this, _, _, _, node, span, _, _| { - this.storage_live_binding(block, node, span, OutsideGuard); - this.schedule_drop_for_binding(node, span, OutsideGuard); - }) + this.visit_bindings( + &pattern, + &PatternTypeProjections::none(), + &mut |this, _, _, _, node, span, _, _| { + this.storage_live_binding(block, node, span, OutsideGuard); + this.schedule_drop_for_binding(node, span, OutsideGuard); + }) } // Enter the source scope, after evaluating the initializer. diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 8d6b6bb5c74f1..77746e5538d65 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -147,7 +147,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( place.clone(), Variance::Invariant, - box user_ty, + box UserTypeProjection { base: user_ty, projs: vec![], }, ), }, ); @@ -167,7 +167,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( Place::Local(temp.clone()), Variance::Invariant, - box user_ty, + box UserTypeProjection { base: user_ty, projs: vec![], }, ), }, ); diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 4f5ed34a46133..d2913872fca45 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -306,7 +306,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let ptr_temp = this.local_decls.push(LocalDecl { mutability: Mutability::Mut, ty: ptr_ty, - user_ty: None, + user_ty: UserTypeProjections::none(), name: None, source_info, visibility_scope: source_info.scope, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 2f271e072c6e3..b92f270255af4 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -18,6 +18,7 @@ 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::hir; use rustc::mir::*; use rustc::ty::{self, Ty}; @@ -31,6 +32,8 @@ mod simplify; mod test; mod util; +use std::convert::TryFrom; + /// ArmHasGuard is isomorphic to a boolean flag. It indicates whether /// a match arm has a guard expression attached to it. #[derive(Copy, Clone, Debug)] @@ -240,7 +243,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { end_block.unit() } - pub fn expr_into_pattern( + pub(super) fn expr_into_pattern( &mut self, mut block: BasicBlock, irrefutable_pat: Pattern<'tcx>, @@ -291,7 +294,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }, .. }, - user_ty: ascription_user_ty, + user_ty: pat_ascription_ty, user_ty_span, } => { let place = @@ -316,7 +319,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( place, ty::Variance::Invariant, - box ascription_user_ty, + box pat_ascription_ty.user_ty(), ), }, ); @@ -415,7 +418,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let num_patterns = patterns.len(); self.visit_bindings( &patterns[0], - None, + &PatternTypeProjections::none(), &mut |this, mutability, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { visibility_scope = @@ -488,10 +491,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); } - pub fn visit_bindings( + pub(super) fn visit_bindings( &mut self, pattern: &Pattern<'tcx>, - mut pattern_user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>, + pattern_user_ty: &PatternTypeProjections<'tcx>, f: &mut impl FnMut( &mut Self, Mutability, @@ -500,7 +503,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { NodeId, Span, Ty<'tcx>, - Option<(UserTypeAnnotation<'tcx>, Span)>, + &PatternTypeProjections<'tcx>, ), ) { match *pattern.kind { @@ -513,20 +516,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ref subpattern, .. } => { - match mode { - BindingMode::ByValue => { } + 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`, so ignore - // `pattern_user_ty` for now. - // - // FIXME(#47184): extract or handle `pattern_user_ty` somehow - pattern_user_ty = None; + // `T` but rather `&T`. + pattern_ref_binding = pattern_user_ty.ref_binding(); + &pattern_ref_binding } - } + }; - f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty); + f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty); if let Some(subpattern) = subpattern.as_ref() { self.visit_bindings(subpattern, pattern_user_ty, f); } @@ -541,33 +543,44 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ref slice, ref suffix, } => { - // FIXME(#47184): extract or handle `pattern_user_ty` somehow - for subpattern in prefix.iter().chain(slice).chain(suffix) { - self.visit_bindings(subpattern, None, f); + 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); + } + for subpattern in slice { + self.visit_bindings(subpattern, &pattern_user_ty.subslice(from, to), f); + } + for subpattern in suffix { + self.visit_bindings(subpattern, &pattern_user_ty.index(), f); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {} PatternKind::Deref { ref subpattern } => { - // FIXME(#47184): extract or handle `pattern_user_ty` somehow - self.visit_bindings(subpattern, None, f); + self.visit_bindings(subpattern, &pattern_user_ty.deref(), f); } - PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => { + PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => { // This corresponds to something like // // ``` // let A::<'a>(_): A<'static> = ...; // ``` - // - // FIXME(#47184): handle `pattern_user_ty` somehow - self.visit_bindings(subpattern, Some((user_ty, user_ty_span)), f) + let subpattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span); + self.visit_bindings(subpattern, &subpattern_user_ty, f) } - PatternKind::Leaf { ref subpatterns } - | PatternKind::Variant { - ref subpatterns, .. - } => { - // FIXME(#47184): extract or handle `pattern_user_ty` somehow + + 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); + } + } + + PatternKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => { for subpattern in subpatterns { - self.visit_bindings(&subpattern.pattern, None, f); + let subpattern_user_ty = pattern_user_ty.variant( + adt_def, variant_index, subpattern.field); + self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f); } } } @@ -626,7 +639,7 @@ struct Binding<'tcx> { struct Ascription<'tcx> { span: Span, source: Place<'tcx>, - user_ty: UserTypeAnnotation<'tcx>, + user_ty: PatternTypeProjection<'tcx>, } #[derive(Clone, Debug)] @@ -1323,7 +1336,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::AscribeUserType( ascription.source.clone(), ty::Variance::Covariant, - box ascription.user_ty, + box ascription.user_ty.clone().user_ty(), ), }, ); @@ -1470,7 +1483,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { num_patterns: usize, var_id: NodeId, var_ty: Ty<'tcx>, - user_var_ty: Option<(UserTypeAnnotation<'tcx>, Span)>, + user_var_ty: &PatternTypeProjections<'tcx>, has_guard: ArmHasGuard, opt_match_place: Option<(Option>, Span)>, pat_span: Span, @@ -1489,7 +1502,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let local = LocalDecl::<'tcx> { mutability, ty: var_ty, - user_ty: user_var_ty, + user_ty: user_var_ty.clone().user_ty(), name: Some(name), source_info, visibility_scope, @@ -1522,7 +1535,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // See previous comment. mutability: Mutability::Not, ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty), - user_ty: None, + user_ty: UserTypeProjections::none(), name: Some(name), source_info, visibility_scope, diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 494e7c03c3e68..349d877d52474 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -63,10 +63,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>) -> Result<(), MatchPair<'pat, 'tcx>> { match *match_pair.pattern.kind { - PatternKind::AscribeUserType { ref subpattern, user_ty, user_ty_span } => { + PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => { candidate.ascriptions.push(Ascription { span: user_ty_span, - user_ty, + user_ty: user_ty.clone(), source: match_pair.place.clone(), }); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 6ea4628de24e9..5b4001f0652ad 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -845,7 +845,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.local_decls.push(LocalDecl { mutability: Mutability::Mut, ty, - user_ty: None, + user_ty: UserTypeProjections::none(), source_info, visibility_scope: source_info.scope, name, diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 9865867a196ca..586d6d87fa0dc 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -91,7 +91,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty: pattern.ty, span: pattern.span, kind: Box::new(PatternKind::AscribeUserType { - user_ty: UserTypeAnnotation::Ty(user_ty), + user_ty: PatternTypeProjection::from_canonical_ty(user_ty), user_ty_span: ty.span, subpattern: pattern }) diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 788db5c0b7e52..8a24851de8149 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -28,6 +28,7 @@ pub mod cx; pub mod pattern; pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; +pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections}; mod util; diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 4649c28aff518..bff87da9c771d 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -20,7 +20,8 @@ use const_eval::{const_field, const_variant_index}; use hair::util::UserAnnotatedTyHelpers; -use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability, UserTypeAnnotation}; +use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; +use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty}; use rustc::ty::subst::{Substs, Kind}; @@ -64,12 +65,123 @@ pub struct Pattern<'tcx> { pub kind: Box>, } + +#[derive(Clone, Debug)] +pub(crate) struct PatternTypeProjections<'tcx> { + contents: Vec<(PatternTypeProjection<'tcx>, Span)>, +} + +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(#47184): 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: usize, + 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: usize, + 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_proj(u_ty: UserTypeProjection<'tcx>) -> Self { + PatternTypeProjection(u_ty) + } + + pub(crate) fn user_ty(self) -> UserTypeProjection<'tcx> { self.0 } +} + #[derive(Clone, Debug)] pub enum PatternKind<'tcx> { Wild, AscribeUserType { - user_ty: UserTypeAnnotation<'tcx>, + user_ty: PatternTypeProjection<'tcx>, subpattern: Pattern<'tcx>, user_ty_span: Span, }, @@ -690,9 +802,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span); + let pat_ty = PatternTypeProjection::from_user_type(user_ty); kind = PatternKind::AscribeUserType { subpattern, - user_ty, + user_ty: pat_ty, user_ty_span: span, }; } @@ -980,7 +1093,8 @@ macro_rules! CloneImpls { CloneImpls!{ <'tcx> Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, - &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx> + &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>, + UserTypeProjection<'tcx>, PatternTypeProjection<'tcx> } impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { @@ -1016,7 +1130,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { PatternKind::Wild => PatternKind::Wild, PatternKind::AscribeUserType { ref subpattern, - user_ty, + ref user_ty, user_ty_span, } => PatternKind::AscribeUserType { subpattern: subpattern.fold_with(folder), diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index d8f627fcf4dd7..6c32690cdb340 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -142,7 +142,7 @@ fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl { LocalDecl { mutability, ty, - user_ty: None, + user_ty: UserTypeProjections::none(), name: None, source_info, visibility_scope: source_info.scope, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index c2ae6832cc09f..5889fabee9d6e 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -303,7 +303,7 @@ fn replace_result_variable<'tcx>( let new_ret = LocalDecl { mutability: Mutability::Mut, ty: ret_ty, - user_ty: None, + user_ty: UserTypeProjections::none(), name: None, source_info, visibility_scope: source_info.scope, @@ -658,7 +658,7 @@ fn create_generator_drop_shim<'a, 'tcx>( mir.local_decls[RETURN_PLACE] = LocalDecl { mutability: Mutability::Mut, ty: tcx.mk_unit(), - user_ty: None, + user_ty: UserTypeProjections::none(), name: None, source_info, visibility_scope: source_info.scope, @@ -676,7 +676,7 @@ fn create_generator_drop_shim<'a, 'tcx>( ty: gen_ty, mutbl: hir::Mutability::MutMutable, }), - user_ty: None, + user_ty: UserTypeProjections::none(), name: None, source_info, visibility_scope: source_info.scope, diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 25bd02ff6dc5d..c74492fe64936 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -502,7 +502,7 @@ fn write_scope_tree( local, var.ty ); - if let Some(user_ty) = var.user_ty { + for user_ty in var.user_ty.projections() { write!(indented_var, " as {:?}", user_ty).unwrap(); } indented_var.push_str(";"); diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 0b9b20d3c4539..06c8545aacfd8 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -211,7 +211,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { fn visit_projection_elem(&mut self, place: &PlaceElem<'tcx>, - context: mir_visit::PlaceContext<'tcx>, location: Location) { self.record("PlaceElem", place); self.record(match *place { @@ -222,7 +221,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { ProjectionElem::ConstantIndex { .. } => "PlaceElem::ConstantIndex", ProjectionElem::Downcast(..) => "PlaceElem::Downcast", }, place); - self.super_projection_elem(place, context, location); + self.super_projection_elem(place, location); } fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index cf274a9c85105..2ed02a4cdab1e 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -12,6 +12,8 @@ use rustc::infer::at::ToTrace; use rustc::infer::canonical::{Canonical, QueryResponse}; 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::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; @@ -58,14 +60,15 @@ fn type_op_ascribe_user_type<'tcx>( variance, def_id, user_substs, + projs, }, ) = key.into_parts(); debug!( "type_op_ascribe_user_type(\ - mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\ + mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}, projs={:?}\ )", - mir_ty, variance, def_id, user_substs, + mir_ty, variance, def_id, user_substs, projs, ); let mut cx = AscribeUserTypeCx { @@ -73,7 +76,7 @@ fn type_op_ascribe_user_type<'tcx>( param_env, fulfill_cx, }; - cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?; + cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs, projs)?; Ok(()) }) @@ -134,17 +137,30 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { variance: Variance, def_id: DefId, user_substs: UserSubsts<'tcx>, + projs: &[ProjectionKind<'tcx>], ) -> Result<(), NoSolution> { let UserSubsts { substs, user_self_ty, } = user_substs; - let ty = self.tcx().type_of(def_id); + let tcx = self.tcx(); + + let ty = tcx.type_of(def_id); let ty = self.subst(ty, substs); debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); let ty = self.normalize(ty); + let mut projected_ty = PlaceTy::from_ty(ty); + for proj in projs { + projected_ty = projected_ty.projection_ty_core( + tcx, proj, |this, field, &()| { + let ty = this.field_ty(tcx, field); + self.normalize(ty) + }); + } + let ty = projected_ty.to_ty(tcx); + self.relate(mir_ty, variance, ty)?; if let Some(UserSelfTy { diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index 64e574fa8aee0..7ca1d01f20b7b 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -56,7 +56,7 @@ fn main() { // StorageLive(_4); // _4 = std::option::Option>::None; // FakeRead(ForLet, _4); -// AscribeUserType(_4, o, Ty(Canonical { variables: [], value: std::option::Option> })); +// AscribeUserType(_4, o, UserTypeProjection { base: Ty(Canonical { variables: [], value: std::option::Option> }), projs: [] }); // StorageLive(_5); // StorageLive(_6); // _6 = move _4; diff --git a/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs b/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs new file mode 100644 index 0000000000000..0a8a6793dc782 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs @@ -0,0 +1,31 @@ +// compile-pass +#![feature(nll)] + +// This test is reduced from a scenario pnkfelix encountered while +// bootstrapping the compiler. + +#[derive(Copy, Clone)] +pub struct Spanned { + pub node: T, + pub span: Span, +} + +pub type Variant = Spanned; +// #[derive(Clone)] pub struct Variant { pub node: VariantKind, pub span: Span, } + +#[derive(Clone)] +pub struct VariantKind { } + +#[derive(Copy, Clone)] +pub struct Span; + +pub fn variant_to_span(variant: Variant) { + match variant { + Variant { + span: _span, + .. + } => { } + }; +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/patterns.rs b/src/test/ui/nll/user-annotations/patterns.rs index e3bac513fa874..8c8e61cd6fbeb 100644 --- a/src/test/ui/nll/user-annotations/patterns.rs +++ b/src/test/ui/nll/user-annotations/patterns.rs @@ -9,11 +9,11 @@ fn variable_no_initializer() { } fn tuple_no_initializer() { - // FIXME(#47187): We are not propagating ascribed type through tuples. + let x = 22; let (y, z): (&'static u32, &'static u32); - y = &x; + y = &x; //~ ERROR } fn ref_with_ascribed_static_type() -> u32 { @@ -34,11 +34,23 @@ fn ref_with_ascribed_any_type() -> u32 { struct Single { value: T } fn struct_no_initializer() { - // FIXME(#47187): We are not propagating ascribed type through patterns. + let x = 22; let Single { value: y }: Single<&'static u32>; - y = &x; + y = &x; //~ ERROR +} + + +fn struct_no_initializer_must_normalize() { + trait Indirect { type Assoc; } + struct StaticU32; + impl Indirect for StaticU32 { type Assoc = &'static u32; } + struct Single2 { value: ::Assoc } + + let x = 22; + let Single2 { value: mut _y }: Single2; + _y = &x; //~ ERROR } fn variable_with_initializer() { @@ -91,26 +103,31 @@ fn struct_double_field_underscore_with_initializer() { } fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { - // The error in this test is inconsistency with - // `static_to_a_to_static_through_tuple`, but "feels right" to - // me. It occurs because we special case the single binding case - // and force the type of `y` to be `&'a u32`, even though the - // right-hand side has type `&'static u32`. + + + + + let y: &'a u32 = &22; y //~ ERROR } fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 { - // FIXME(#47187): The fact that this type-checks is perhaps surprising. - // What happens is that the right-hand side is constrained to have - // type `&'a u32`, which is possible, because it has type - // `&'static u32`. The variable `y` is then forced to have type - // `&'static u32`, but it is constrained only by the right-hand - // side, not the ascribed type, and hence it passes. + + + + + + let (y, _z): (&'a u32, u32) = (&22, 44); - y + y //~ ERROR +} + +fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 { + let Single { value: y }: Single<&'a u32> = Single { value: &22 }; + y //~ ERROR } fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr index 0c50b98ee2713..b0c554e6ca1d4 100644 --- a/src/test/ui/nll/user-annotations/patterns.stderr +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -8,6 +8,16 @@ LL | y = &x; //~ ERROR LL | } | - `x` dropped here while still borrowed +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:16:9 + | +LL | let (y, z): (&'static u32, &'static u32); + | ---------------------------- type annotation requires that `x` is borrowed for `'static` +LL | y = &x; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + error[E0597]: `x` does not live long enough --> $DIR/patterns.rs:22:13 | @@ -20,7 +30,27 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:46:27 + --> $DIR/patterns.rs:41:9 + | +LL | let Single { value: y }: Single<&'static u32>; + | -------------------- type annotation requires that `x` is borrowed for `'static` +LL | y = &x; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:53:10 + | +LL | let Single2 { value: mut _y }: Single2; + | ------------------ type annotation requires that `x` is borrowed for `'static` +LL | _y = &x; //~ ERROR + | ^^ borrowed value does not live long enough +LL | } + | - `x` dropped here while still borrowed + +error[E0597]: `x` does not live long enough + --> $DIR/patterns.rs:58:27 | LL | let y: &'static u32 = &x; //~ ERROR | ------------ ^^ borrowed value does not live long enough @@ -30,7 +60,7 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:51:27 + --> $DIR/patterns.rs:63:27 | LL | let _: &'static u32 = &x; //~ ERROR | ------------ ^^ borrowed value does not live long enough @@ -41,7 +71,7 @@ LL | } | - `x` dropped here while still borrowed error[E0716]: temporary value dropped while borrowed - --> $DIR/patterns.rs:53:41 + --> $DIR/patterns.rs:65:41 | LL | let _: Vec<&'static String> = vec![&String::new()]; | -------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -50,7 +80,7 @@ LL | let _: Vec<&'static String> = vec![&String::new()]; | type annotation requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/patterns.rs:56:52 + --> $DIR/patterns.rs:68:52 | LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); | ------------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -59,7 +89,7 @@ LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); | type annotation requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/patterns.rs:59:53 + --> $DIR/patterns.rs:71:53 | LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); | ------------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -68,7 +98,7 @@ LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); | type annotation requires that borrow lasts for `'static` error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:65:40 + --> $DIR/patterns.rs:77:40 | LL | let (_, _): (&'static u32, u32) = (&x, 44); //~ ERROR | ------------------- ^^ borrowed value does not live long enough @@ -78,7 +108,7 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:70:40 + --> $DIR/patterns.rs:82:40 | LL | let (y, _): (&'static u32, u32) = (&x, 44); //~ ERROR | ------------------- ^^ borrowed value does not live long enough @@ -88,7 +118,7 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:75:69 + --> $DIR/patterns.rs:87:69 | LL | let Single { value: y }: Single<&'static u32> = Single { value: &x }; //~ ERROR | -------------------- ^^ borrowed value does not live long enough @@ -98,7 +128,7 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:80:69 + --> $DIR/patterns.rs:92:69 | LL | let Single { value: _ }: Single<&'static u32> = Single { value: &x }; //~ ERROR | -------------------- ^^ borrowed value does not live long enough @@ -108,7 +138,7 @@ LL | } | - `x` dropped here while still borrowed error[E0597]: `x` does not live long enough - --> $DIR/patterns.rs:88:17 + --> $DIR/patterns.rs:100:17 | LL | let Double { value1: _, value2: _ }: Double<&'static u32> = Double { | -------------------- type annotation requires that `x` is borrowed for `'static` @@ -119,7 +149,7 @@ LL | } | - `x` dropped here while still borrowed error: unsatisfied lifetime constraints - --> $DIR/patterns.rs:101:5 + --> $DIR/patterns.rs:113:5 | LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here @@ -128,14 +158,32 @@ LL | y //~ ERROR | ^ returning this value requires that `'a` must outlive `'static` error: unsatisfied lifetime constraints - --> $DIR/patterns.rs:117:18 + --> $DIR/patterns.rs:125:5 + | +LL | fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y //~ ERROR + | ^ returning this value requires that `'a` must outlive `'static` + +error: unsatisfied lifetime constraints + --> $DIR/patterns.rs:130:5 + | +LL | fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here +LL | let Single { value: y }: Single<&'a u32> = Single { value: &22 }; +LL | y //~ ERROR + | ^ returning this value requires that `'a` must outlive `'static` + +error: unsatisfied lifetime constraints + --> $DIR/patterns.rs:134:18 | LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` -error: aborting due to 14 previous errors +error: aborting due to 19 previous errors Some errors occurred: E0597, E0716. For more information about an error, try `rustc --explain E0597`.