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.
This commit is contained in:
David Wood 2018-12-19 16:47:06 +01:00
parent 28fd1b04e5
commit 0bfe184b1a
No known key found for this signature in database
GPG Key ID: 01760B4F9F53F154
5 changed files with 99 additions and 114 deletions

View File

@ -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> {

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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
}
}