From 0bfe184b1ad14db4b002c3a272adf44e1839822f Mon Sep 17 00:00:00 2001 From: David Wood <david@davidtw.co> Date: Wed, 19 Dec 2018 16:47:06 +0100 Subject: [PATCH] Stop duplicating projections of type annotation. This commit changes how type annotations are handled in bindings during MIR building. Instead of building up a `PatternTypeProjections` with the `CanonicalUserTypeAnnotation` and projections, the `CanonicalUserTypeAnnotation` is stored in the `canonical_user_type_annotations` map at the start and the (equivalent) `UserTypeProjections` is built up with the new index and same projections. This has the effect of deduplicating type annotations as instead of type annotations being added to the `canonical_user_type_annotations` map multiple times at the end after being duplicated (which happens in building up `PatternTypeProjections`), it is instead added once. --- src/librustc/mir/mod.rs | 75 +++++++++++++++++++++ src/librustc_mir/build/block.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 37 +++++----- src/librustc_mir/hair/mod.rs | 2 +- src/librustc_mir/hair/pattern/mod.rs | 97 +-------------------------- 5 files changed, 99 insertions(+), 114 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ecbe14c093f..2936405ebd0 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2519,6 +2519,48 @@ impl<'tcx> UserTypeProjections<'tcx> { pub fn projections(&self) -> impl Iterator<Item=&UserTypeProjection<'tcx>> { self.contents.iter().map(|&(ref user_type, _span)| user_type) } + + pub fn push_projection( + mut self, + user_ty: &UserTypeProjection<'tcx>, + span: Span, + ) -> Self { + self.contents.push((user_ty.clone(), span)); + self + } + + fn map_projections( + mut self, + mut f: impl FnMut(UserTypeProjection<'tcx>) -> UserTypeProjection<'tcx> + ) -> Self { + self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect(); + self + } + + pub fn index(self) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.index()) + } + + pub fn subslice(self, from: u32, to: u32) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) + } + + pub fn deref(self) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.deref()) + } + + pub fn leaf(self, field: Field) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field)) + } + + pub fn variant( + self, + adt_def: &'tcx AdtDef, + variant_index: VariantIdx, + field: Field, + ) -> Self { + self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) + } } /// Encodes the effect of a user-supplied type annotation on the @@ -2544,6 +2586,39 @@ pub struct UserTypeProjection<'tcx> { impl<'tcx> Copy for ProjectionKind<'tcx> { } +impl<'tcx> UserTypeProjection<'tcx> { + pub(crate) fn index(mut self) -> Self { + self.projs.push(ProjectionElem::Index(())); + self + } + + pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { + self.projs.push(ProjectionElem::Subslice { from, to }); + self + } + + pub(crate) fn deref(mut self) -> Self { + self.projs.push(ProjectionElem::Deref); + self + } + + pub(crate) fn leaf(mut self, field: Field) -> Self { + self.projs.push(ProjectionElem::Field(field, ())); + self + } + + pub(crate) fn variant( + mut self, + adt_def: &'tcx AdtDef, + variant_index: VariantIdx, + field: Field, + ) -> Self { + self.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); + self.projs.push(ProjectionElem::Field(field, ())); + self + } +} + CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, } impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> { diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 41718cfc870..f3d89a7a025 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -144,7 +144,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_bindings( &pattern, - &PatternTypeProjections::none(), + UserTypeProjections::none(), &mut |this, _, _, _, node, span, _, _| { this.storage_live_binding(block, node, span, OutsideGuard); this.schedule_drop_for_binding(node, span, OutsideGuard); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 085c58ef5ff..fe5bc6e19db 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -8,7 +8,6 @@ use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard}; use build::{BlockAnd, BlockAndExtension, Builder}; use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use hair::*; -use hair::pattern::PatternTypeProjections; use rustc::mir::*; use rustc::ty::{self, Ty}; use rustc::ty::layout::VariantIdx; @@ -412,7 +411,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("declare_bindings: patterns={:?}", patterns); self.visit_bindings( &patterns[0], - &PatternTypeProjections::none(), + UserTypeProjections::none(), &mut |this, mutability, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { visibility_scope = @@ -488,7 +487,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub(super) fn visit_bindings( &mut self, pattern: &Pattern<'tcx>, - pattern_user_ty: &PatternTypeProjections<'tcx>, + pattern_user_ty: UserTypeProjections<'tcx>, f: &mut impl FnMut( &mut Self, Mutability, @@ -497,7 +496,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { NodeId, Span, Ty<'tcx>, - &PatternTypeProjections<'tcx>, + UserTypeProjections<'tcx>, ), ) { debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); @@ -511,7 +510,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ref subpattern, .. } => { - f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty); + f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); if let Some(subpattern) = subpattern.as_ref() { self.visit_bindings(subpattern, pattern_user_ty, f); } @@ -529,18 +528,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let from = u32::try_from(prefix.len()).unwrap(); let to = u32::try_from(suffix.len()).unwrap(); for subpattern in prefix { - self.visit_bindings(subpattern, &pattern_user_ty.index(), f); + self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f); } for subpattern in slice { - self.visit_bindings(subpattern, &pattern_user_ty.subslice(from, to), f); + self.visit_bindings(subpattern, pattern_user_ty.clone().subslice(from, to), f); } for subpattern in suffix { - self.visit_bindings(subpattern, &pattern_user_ty.index(), f); + self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {} PatternKind::Deref { ref subpattern } => { - self.visit_bindings(subpattern, &pattern_user_ty.deref(), f); + self.visit_bindings(subpattern, pattern_user_ty.deref(), f); } PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => { // This corresponds to something like @@ -548,23 +547,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // ``` // let A::<'a>(_): A<'static> = ...; // ``` - let subpattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span); - self.visit_bindings(subpattern, &subpattern_user_ty, f) + let annotation = (user_ty_span, user_ty.base); + let projection = UserTypeProjection { + base: self.canonical_user_type_annotations.push(annotation), + projs: user_ty.projs.clone(), + }; + let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span); + self.visit_bindings(subpattern, subpattern_user_ty, f) } PatternKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { - let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field); + let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty); - self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f); + self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f); } } PatternKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => { for subpattern in subpatterns { - let subpattern_user_ty = pattern_user_ty.variant( + let subpattern_user_ty = pattern_user_ty.clone().variant( adt_def, variant_index, subpattern.field); - self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f); + self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f); } } } @@ -1465,7 +1469,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { num_patterns: usize, var_id: NodeId, var_ty: Ty<'tcx>, - user_var_ty: &PatternTypeProjections<'tcx>, + user_ty: UserTypeProjections<'tcx>, has_guard: ArmHasGuard, opt_match_place: Option<(Option<Place<'tcx>>, Span)>, pat_span: Span, @@ -1481,7 +1485,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()), BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()), }; - let user_ty = user_var_ty.clone().user_ty(&mut self.canonical_user_type_annotations); debug!("declare_binding: user_ty={:?}", user_ty); let local = LocalDecl::<'tcx> { mutability, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index d36a6eb58b8..b56e3d4e773 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -21,7 +21,7 @@ mod constant; pub mod pattern; pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern}; -pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections}; +pub(crate) use self::pattern::PatternTypeProjection; mod util; diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 6d562c69b2d..10d2d7bc1b1 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -12,7 +12,7 @@ use hair::util::UserAnnotatedTyHelpers; use hair::constant::*; use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; -use rustc::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; +use rustc::mir::{ProjectionElem, UserTypeProjection}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift}; use rustc::ty::{CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotation}; @@ -58,64 +58,6 @@ pub struct Pattern<'tcx> { } -#[derive(Clone, Debug)] -pub(crate) struct PatternTypeProjections<'tcx> { - contents: Vec<(PatternTypeProjection<'tcx>, Span)>, -} - -impl<'tcx> PatternTypeProjections<'tcx> { - pub(crate) fn user_ty( - self, - annotations: &mut CanonicalUserTypeAnnotations<'tcx>, - ) -> UserTypeProjections<'tcx> { - UserTypeProjections::from_projections( - self.contents - .into_iter() - .map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(annotations, span), span)) - ) - } - - pub(crate) fn none() -> Self { - PatternTypeProjections { contents: vec![] } - } - - fn map_projs(&self, - mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>) - -> Self - { - PatternTypeProjections { - contents: self.contents - .iter() - .map(|(proj, span)| (f(proj), *span)) - .collect(), } - } - - pub(crate) fn index(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.index()) } - - pub(crate) fn subslice(&self, from: u32, to: u32) -> Self { - self.map_projs(|pat_ty_proj| pat_ty_proj.subslice(from, to)) - } - - pub(crate) fn deref(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.deref()) } - - pub(crate) fn leaf(&self, field: Field) -> Self { - self.map_projs(|pat_ty_proj| pat_ty_proj.leaf(field)) - } - - pub(crate) fn variant(&self, - adt_def: &'tcx AdtDef, - variant_index: VariantIdx, - field: Field) -> Self { - self.map_projs(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field)) - } - - pub(crate) fn add_user_type(&self, user_ty: &PatternTypeProjection<'tcx>, sp: Span) -> Self { - let mut new = self.clone(); - new.contents.push((user_ty.clone(), sp)); - new - } -} - #[derive(Clone, Debug)] pub struct PatternTypeProjection<'tcx> { pub base: CanonicalUserTypeAnnotation<'tcx>, @@ -123,40 +65,6 @@ pub struct PatternTypeProjection<'tcx> { } impl<'tcx> PatternTypeProjection<'tcx> { - pub(crate) fn index(&self) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Index(())); - new - } - - pub(crate) fn subslice(&self, from: u32, to: u32) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Subslice { from, to }); - new - } - - pub(crate) fn deref(&self) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Deref); - new - } - - pub(crate) fn leaf(&self, field: Field) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Field(field, ())); - new - } - - pub(crate) fn variant(&self, - adt_def: &'tcx AdtDef, - variant_index: VariantIdx, - field: Field) -> Self { - let mut new = self.clone(); - new.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); - new.projs.push(ProjectionElem::Field(field, ())); - new - } - pub(crate) fn from_user_type(user_annotation: CanonicalUserTypeAnnotation<'tcx>) -> Self { Self { base: user_annotation, @@ -169,9 +77,8 @@ impl<'tcx> PatternTypeProjection<'tcx> { annotations: &mut CanonicalUserTypeAnnotations<'tcx>, span: Span, ) -> UserTypeProjection<'tcx> { - let annotation_index = annotations.push((span, self.base)); UserTypeProjection { - base: annotation_index, + base: annotations.push((span, self.base)), projs: self.projs } }