Skip to content

Commit 0db74e2

Browse files
committed
Store UserTypeProjections as a flat list of "ops"
1 parent b5245cc commit 0db74e2

File tree

3 files changed

+155
-93
lines changed
  • compiler
    • rustc_borrowck/src/type_check
    • rustc_middle/src/mir
    • rustc_mir_build/src/builder/matches

3 files changed

+155
-93
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
458458
self.super_local_decl(local, local_decl);
459459

460460
for user_ty in
461-
local_decl.user_ty.as_deref().into_iter().flat_map(UserTypeProjections::projections)
461+
local_decl.user_ty.as_ref().into_iter().flat_map(UserTypeProjections::projections)
462462
{
463463
let span = self.typeck.user_type_annotations[user_ty.base].span;
464464

@@ -476,7 +476,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
476476
if let Err(terr) = self.typeck.relate_type_and_user_type(
477477
ty,
478478
ty::Invariant,
479-
user_ty,
479+
&user_ty,
480480
Locations::All(span),
481481
ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration),
482482
) {

compiler/rustc_middle/src/mir/mod.rs

+72-65
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
44
5+
use std::assert_matches::assert_matches;
56
use std::borrow::Cow;
67
use std::fmt::{self, Debug, Formatter};
78
use std::ops::{Index, IndexMut};
@@ -37,7 +38,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder};
3738
use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
3839
use crate::ty::visit::TypeVisitableExt;
3940
use crate::ty::{
40-
self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingEnv,
41+
self, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingEnv,
4142
UserTypeAnnotationIndex,
4243
};
4344

@@ -64,6 +65,7 @@ use pretty::pretty_print_const_value;
6465
pub use statement::*;
6566
pub use syntax::*;
6667
pub use terminator::*;
68+
use thin_vec::ThinVec;
6769

6870
pub use self::generic_graph::graphviz_safe_def_name;
6971
pub use self::graphviz::write_mir_graphviz;
@@ -985,7 +987,7 @@ pub struct LocalDecl<'tcx> {
985987
/// borrow checker needs this information since it can affect
986988
/// region inference.
987989
// FIXME(matthewjasper) Don't store in this in `Body`
988-
pub user_ty: Option<Box<UserTypeProjections>>,
990+
pub user_ty: Option<UserTypeProjections>,
989991

990992
/// The *syntactic* (i.e., not visibility) source scope the local is defined
991993
/// in. If the local was defined in a let-statement, this
@@ -1560,55 +1562,73 @@ pub struct SourceScopeLocalData {
15601562
/// &'static str`.
15611563
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
15621564
pub struct UserTypeProjections {
1563-
pub contents: Vec<UserTypeProjection>,
1565+
/// Instead of storing the projected user types directly, we store a flat list
1566+
/// of "operations" that can be used to build the projections as needed.
1567+
///
1568+
/// The list happens to be stored in reverse order, because that's slightly
1569+
/// more convenient for the code that builds the list of ops.
1570+
ops_reversed: ThinVec<ProjectedUserTypesOp>,
1571+
// If this struct ever ceases to be pointer-sized, its field in `LocalDecl`
1572+
// should probably be boxed again.
15641573
}
15651574

1566-
impl<'tcx> UserTypeProjections {
1567-
pub fn none() -> Self {
1568-
UserTypeProjections { contents: vec![] }
1569-
}
1570-
1571-
pub fn is_empty(&self) -> bool {
1572-
self.contents.is_empty()
1573-
}
1574-
1575-
pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator {
1576-
self.contents.iter()
1577-
}
1578-
1579-
pub fn push_user_type(mut self, base_user_type: UserTypeAnnotationIndex) -> Self {
1580-
self.contents.push(UserTypeProjection { base: base_user_type, projs: vec![] });
1581-
self
1582-
}
1583-
1584-
fn map_projections(mut self, f: impl FnMut(UserTypeProjection) -> UserTypeProjection) -> Self {
1585-
self.contents = self.contents.into_iter().map(f).collect();
1586-
self
1587-
}
1588-
1589-
pub fn index(self) -> Self {
1590-
self.map_projections(|pat_ty_proj| pat_ty_proj.index())
1591-
}
1592-
1593-
pub fn subslice(self, from: u64, to: u64) -> Self {
1594-
self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to))
1595-
}
1575+
/// One of a list of "operations" that can be used to reconstruct user-type projections.
1576+
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
1577+
pub enum ProjectedUserTypesOp {
1578+
PushUserType { base: UserTypeAnnotationIndex },
1579+
1580+
Index,
1581+
Subslice { from: u64, to: u64 },
1582+
Deref,
1583+
Leaf { field: FieldIdx },
1584+
Variant { name: Symbol, variant: VariantIdx, field: FieldIdx },
1585+
}
15961586

1597-
pub fn deref(self) -> Self {
1598-
self.map_projections(|pat_ty_proj| pat_ty_proj.deref())
1587+
impl UserTypeProjections {
1588+
pub fn from_ops_reversed(ops_reversed: impl Iterator<Item = ProjectedUserTypesOp>) -> Self {
1589+
let ops_reversed = ops_reversed.collect::<ThinVec<_>>();
1590+
// The "first" op should always be `PushUserType`, because it would be
1591+
// useless for other ops to modify an empty list of projections.
1592+
assert_matches!(
1593+
ops_reversed.last(),
1594+
None | Some(ProjectedUserTypesOp::PushUserType { .. })
1595+
);
1596+
Self { ops_reversed }
15991597
}
16001598

1601-
pub fn leaf(self, field: FieldIdx) -> Self {
1602-
self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field))
1603-
}
1599+
pub fn is_empty(&self) -> bool {
1600+
self.ops_reversed.is_empty()
1601+
}
1602+
1603+
pub fn projections(&self) -> impl Iterator<Item = UserTypeProjection> + ExactSizeIterator {
1604+
let mut projections = vec![];
1605+
// Iterate over the list of ops in "non-reversed" order.
1606+
for op in self.ops_reversed.iter().rev() {
1607+
match *op {
1608+
ProjectedUserTypesOp::PushUserType { base } => {
1609+
// Add a new user type to the list of projections, which
1610+
// will then be modified by subsequent projection ops.
1611+
projections.push(UserTypeProjection { base, projs: vec![] });
1612+
}
16041613

1605-
pub fn variant(
1606-
self,
1607-
adt_def: AdtDef<'tcx>,
1608-
variant_index: VariantIdx,
1609-
field_index: FieldIdx,
1610-
) -> Self {
1611-
self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field_index))
1614+
ProjectedUserTypesOp::Index => {
1615+
projections.iter_mut().for_each(|p| p.index());
1616+
}
1617+
ProjectedUserTypesOp::Subslice { from, to } => {
1618+
projections.iter_mut().for_each(|p| p.subslice(from, to));
1619+
}
1620+
ProjectedUserTypesOp::Deref => {
1621+
projections.iter_mut().for_each(|p| p.deref());
1622+
}
1623+
ProjectedUserTypesOp::Leaf { field } => {
1624+
projections.iter_mut().for_each(|p| p.leaf(field));
1625+
}
1626+
ProjectedUserTypesOp::Variant { name, variant, field } => {
1627+
projections.iter_mut().for_each(|p| p.variant(name, variant, field));
1628+
}
1629+
}
1630+
}
1631+
projections.into_iter()
16121632
}
16131633
}
16141634

@@ -1635,38 +1655,25 @@ pub struct UserTypeProjection {
16351655
}
16361656

16371657
impl UserTypeProjection {
1638-
pub(crate) fn index(mut self) -> Self {
1658+
fn index(&mut self) {
16391659
self.projs.push(ProjectionElem::Index(()));
1640-
self
16411660
}
16421661

1643-
pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self {
1662+
fn subslice(&mut self, from: u64, to: u64) {
16441663
self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
1645-
self
16461664
}
16471665

1648-
pub(crate) fn deref(mut self) -> Self {
1666+
fn deref(&mut self) {
16491667
self.projs.push(ProjectionElem::Deref);
1650-
self
16511668
}
16521669

1653-
pub(crate) fn leaf(mut self, field: FieldIdx) -> Self {
1670+
fn leaf(&mut self, field: FieldIdx) {
16541671
self.projs.push(ProjectionElem::Field(field, ()));
1655-
self
16561672
}
16571673

1658-
pub(crate) fn variant(
1659-
mut self,
1660-
adt_def: AdtDef<'_>,
1661-
variant_index: VariantIdx,
1662-
field_index: FieldIdx,
1663-
) -> Self {
1664-
self.projs.push(ProjectionElem::Downcast(
1665-
Some(adt_def.variant(variant_index).name),
1666-
variant_index,
1667-
));
1668-
self.projs.push(ProjectionElem::Field(field_index, ()));
1669-
self
1674+
fn variant(&mut self, name: Symbol, variant: VariantIdx, field: FieldIdx) {
1675+
self.projs.push(ProjectionElem::Downcast(Some(name), variant));
1676+
self.projs.push(ProjectionElem::Field(field, ()));
16701677
}
16711678
}
16721679

0 commit comments

Comments
 (0)