Skip to content

Commit 9543e62

Browse files
committed
Build UserTypeProjections lazily when visiting bindings
1 parent 393f7f3 commit 9543e62

File tree

3 files changed

+153
-109
lines changed

3 files changed

+153
-109
lines changed

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 2 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder};
3636
use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
3737
use crate::ty::visit::TypeVisitableExt;
3838
use crate::ty::{
39-
self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingEnv,
39+
self, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingEnv,
4040
UserTypeAnnotationIndex,
4141
};
4242

@@ -1497,7 +1497,7 @@ pub struct UserTypeProjections {
14971497
pub contents: Vec<UserTypeProjection>,
14981498
}
14991499

1500-
impl<'tcx> UserTypeProjections {
1500+
impl UserTypeProjections {
15011501
pub fn none() -> Self {
15021502
UserTypeProjections { contents: vec![] }
15031503
}
@@ -1509,41 +1509,6 @@ impl<'tcx> UserTypeProjections {
15091509
pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator {
15101510
self.contents.iter()
15111511
}
1512-
1513-
pub fn push_user_type(mut self, base_user_type: UserTypeAnnotationIndex) -> Self {
1514-
self.contents.push(UserTypeProjection { base: base_user_type, projs: vec![] });
1515-
self
1516-
}
1517-
1518-
fn map_projections(mut self, f: impl FnMut(UserTypeProjection) -> UserTypeProjection) -> Self {
1519-
self.contents = self.contents.into_iter().map(f).collect();
1520-
self
1521-
}
1522-
1523-
pub fn index(self) -> Self {
1524-
self.map_projections(|pat_ty_proj| pat_ty_proj.index())
1525-
}
1526-
1527-
pub fn subslice(self, from: u64, to: u64) -> Self {
1528-
self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to))
1529-
}
1530-
1531-
pub fn deref(self) -> Self {
1532-
self.map_projections(|pat_ty_proj| pat_ty_proj.deref())
1533-
}
1534-
1535-
pub fn leaf(self, field: FieldIdx) -> Self {
1536-
self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field))
1537-
}
1538-
1539-
pub fn variant(
1540-
self,
1541-
adt_def: AdtDef<'tcx>,
1542-
variant_index: VariantIdx,
1543-
field_index: FieldIdx,
1544-
) -> Self {
1545-
self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field_index))
1546-
}
15471512
}
15481513

15491514
/// Encodes the effect of a user-supplied type annotation on the
@@ -1568,42 +1533,6 @@ pub struct UserTypeProjection {
15681533
pub projs: Vec<ProjectionKind>,
15691534
}
15701535

1571-
impl UserTypeProjection {
1572-
pub(crate) fn index(mut self) -> Self {
1573-
self.projs.push(ProjectionElem::Index(()));
1574-
self
1575-
}
1576-
1577-
pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self {
1578-
self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
1579-
self
1580-
}
1581-
1582-
pub(crate) fn deref(mut self) -> Self {
1583-
self.projs.push(ProjectionElem::Deref);
1584-
self
1585-
}
1586-
1587-
pub(crate) fn leaf(mut self, field: FieldIdx) -> Self {
1588-
self.projs.push(ProjectionElem::Field(field, ()));
1589-
self
1590-
}
1591-
1592-
pub(crate) fn variant(
1593-
mut self,
1594-
adt_def: AdtDef<'_>,
1595-
variant_index: VariantIdx,
1596-
field_index: FieldIdx,
1597-
) -> Self {
1598-
self.projs.push(ProjectionElem::Downcast(
1599-
Some(adt_def.variant(variant_index).name),
1600-
variant_index,
1601-
));
1602-
self.projs.push(ProjectionElem::Field(field_index, ()));
1603-
self
1604-
}
1605-
}
1606-
16071536
rustc_index::newtype_index! {
16081537
#[derive(HashStable)]
16091538
#[encodable]

compiler/rustc_mir_build/src/builder/matches/mod.rs

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
//! This also includes code for pattern bindings in `let` statements and
66
//! function parameters.
77
8+
use std::assert_matches::assert_matches;
9+
use std::borrow::Borrow;
10+
use std::mem;
11+
use std::sync::Arc;
12+
813
use rustc_abi::VariantIdx;
914
use rustc_data_structures::fx::FxIndexMap;
1015
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -19,6 +24,7 @@ use tracing::{debug, instrument};
1924

2025
use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard};
2126
use crate::builder::expr::as_place::PlaceBuilder;
27+
use crate::builder::matches::user_ty::ProjectedUserTypesNode;
2228
use crate::builder::scope::DropKind;
2329
use crate::builder::{
2430
BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode,
@@ -28,13 +34,9 @@ use crate::builder::{
2834
mod match_pair;
2935
mod simplify;
3036
mod test;
37+
mod user_ty;
3138
mod util;
3239

33-
use std::assert_matches::assert_matches;
34-
use std::borrow::Borrow;
35-
use std::mem;
36-
use std::sync::Arc;
37-
3840
/// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded
3941
/// to recursive invocations.
4042
#[derive(Clone, Copy)]
@@ -758,7 +760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
758760
) -> Option<SourceScope> {
759761
self.visit_primary_bindings_full(
760762
pattern,
761-
UserTypeProjections::none(),
763+
&ProjectedUserTypesNode::None,
762764
&mut |this, name, mode, var, span, ty, user_ty| {
763765
let vis_scope = *visibility_scope
764766
.get_or_insert_with(|| this.new_source_scope(scope_span, LintLevel::Inherited));
@@ -875,7 +877,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
875877
fn visit_primary_bindings_full(
876878
&mut self,
877879
pattern: &Pat<'tcx>,
878-
pattern_user_ty: UserTypeProjections,
880+
user_tys: &ProjectedUserTypesNode<'_>,
879881
f: &mut impl FnMut(
880882
&mut Self,
881883
Symbol,
@@ -889,10 +891,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
889891
match pattern.kind {
890892
PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => {
891893
if is_primary {
892-
f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
894+
let user_ty_projections = user_tys.build_user_type_projections();
895+
f(self, name, mode, var, pattern.span, ty, user_ty_projections);
893896
}
894897
if let Some(subpattern) = subpattern.as_ref() {
895-
self.visit_primary_bindings_full(subpattern, pattern_user_ty, f);
898+
self.visit_primary_bindings_full(subpattern, user_tys, f);
896899
}
897900
}
898901

@@ -901,25 +904,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
901904
let from = u64::try_from(prefix.len()).unwrap();
902905
let to = u64::try_from(suffix.len()).unwrap();
903906
for subpattern in prefix.iter() {
904-
self.visit_primary_bindings_full(
905-
subpattern,
906-
pattern_user_ty.clone().index(),
907-
f,
908-
);
907+
self.visit_primary_bindings_full(subpattern, &user_tys.index(), f);
909908
}
910909
if let Some(subpattern) = slice {
911-
self.visit_primary_bindings_full(
912-
subpattern,
913-
pattern_user_ty.clone().subslice(from, to),
914-
f,
915-
);
910+
self.visit_primary_bindings_full(subpattern, &user_tys.subslice(from, to), f);
916911
}
917912
for subpattern in suffix.iter() {
918-
self.visit_primary_bindings_full(
919-
subpattern,
920-
pattern_user_ty.clone().index(),
921-
f,
922-
);
913+
self.visit_primary_bindings_full(subpattern, &user_tys.index(), f);
923914
}
924915
}
925916

@@ -930,11 +921,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
930921
| PatKind::Error(_) => {}
931922

932923
PatKind::Deref { ref subpattern } => {
933-
self.visit_primary_bindings_full(subpattern, pattern_user_ty.deref(), f);
924+
self.visit_primary_bindings_full(subpattern, &user_tys.deref(), f);
934925
}
935926

936927
PatKind::DerefPattern { ref subpattern, .. } => {
937-
self.visit_primary_bindings_full(subpattern, UserTypeProjections::none(), f);
928+
self.visit_primary_bindings_full(subpattern, &ProjectedUserTypesNode::None, f);
938929
}
939930

940931
PatKind::AscribeUserType {
@@ -951,27 +942,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
951942
// of `user_ty` on any bindings contained with subpattern.
952943

953944
let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone());
954-
let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty);
955-
self.visit_primary_bindings_full(subpattern, subpattern_user_ty, f)
945+
let subpattern_user_tys = user_tys.push_user_type(base_user_ty);
946+
self.visit_primary_bindings_full(subpattern, &subpattern_user_tys, f)
956947
}
957948

958949
PatKind::ExpandedConstant { ref subpattern, .. } => {
959-
self.visit_primary_bindings_full(subpattern, pattern_user_ty, f)
950+
self.visit_primary_bindings_full(subpattern, user_tys, f)
960951
}
961952

962953
PatKind::Leaf { ref subpatterns } => {
963954
for subpattern in subpatterns {
964-
let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
965-
debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
966-
self.visit_primary_bindings_full(&subpattern.pattern, subpattern_user_ty, f);
955+
let subpattern_user_tys = user_tys.leaf(subpattern.field);
956+
debug!("visit_primary_bindings: subpattern_user_tys={subpattern_user_tys:?}");
957+
self.visit_primary_bindings_full(&subpattern.pattern, &subpattern_user_tys, f);
967958
}
968959
}
969960

970961
PatKind::Variant { adt_def, args: _, variant_index, ref subpatterns } => {
971962
for subpattern in subpatterns {
972-
let subpattern_user_ty =
973-
pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field);
974-
self.visit_primary_bindings_full(&subpattern.pattern, subpattern_user_ty, f);
963+
let subpattern_user_tys =
964+
user_tys.variant(adt_def, variant_index, subpattern.field);
965+
self.visit_primary_bindings_full(&subpattern.pattern, &subpattern_user_tys, f);
975966
}
976967
}
977968
PatKind::Or { ref pats } => {
@@ -980,7 +971,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
980971
// `let (x | y) = ...`, the primary binding of `y` occurs in
981972
// the right subpattern
982973
for subpattern in pats.iter() {
983-
self.visit_primary_bindings_full(subpattern, pattern_user_ty.clone(), f);
974+
self.visit_primary_bindings_full(subpattern, user_tys, f);
984975
}
985976
}
986977
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use std::iter;
2+
3+
use rustc_abi::{FieldIdx, VariantIdx};
4+
use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections};
5+
use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex};
6+
use rustc_span::Symbol;
7+
8+
/// One of a list of "operations" that can be used to lazily build projections
9+
/// of user-specified types.
10+
#[derive(Clone, Debug)]
11+
pub(crate) enum ProjectedUserTypesOp {
12+
PushUserType { base: UserTypeAnnotationIndex },
13+
14+
Index,
15+
Subslice { from: u64, to: u64 },
16+
Deref,
17+
Leaf { field: FieldIdx },
18+
Variant { name: Symbol, variant: VariantIdx, field: FieldIdx },
19+
}
20+
21+
#[derive(Debug)]
22+
pub(crate) enum ProjectedUserTypesNode<'a> {
23+
None,
24+
Chain { parent: &'a Self, op: ProjectedUserTypesOp },
25+
}
26+
27+
impl<'a> ProjectedUserTypesNode<'a> {
28+
pub(crate) fn push_user_type(&'a self, base: UserTypeAnnotationIndex) -> Self {
29+
// Only `PushUserType` ops can cause an empty chain to become non-empty.
30+
Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserType { base } }
31+
}
32+
33+
/// Push another projection op onto the chain, but only if it is already non-empty.
34+
fn maybe_push(&'a self, op_fn: impl FnOnce() -> ProjectedUserTypesOp) -> Self {
35+
match self {
36+
Self::None => Self::None,
37+
Self::Chain { .. } => Self::Chain { parent: self, op: op_fn() },
38+
}
39+
}
40+
41+
pub(crate) fn index(&'a self) -> Self {
42+
self.maybe_push(|| ProjectedUserTypesOp::Index)
43+
}
44+
45+
pub(crate) fn subslice(&'a self, from: u64, to: u64) -> Self {
46+
self.maybe_push(|| ProjectedUserTypesOp::Subslice { from, to })
47+
}
48+
49+
pub(crate) fn deref(&'a self) -> Self {
50+
self.maybe_push(|| ProjectedUserTypesOp::Deref)
51+
}
52+
53+
pub(crate) fn leaf(&'a self, field: FieldIdx) -> Self {
54+
self.maybe_push(|| ProjectedUserTypesOp::Leaf { field })
55+
}
56+
57+
pub(crate) fn variant(
58+
&'a self,
59+
adt_def: AdtDef<'_>,
60+
variant: VariantIdx,
61+
field: FieldIdx,
62+
) -> Self {
63+
self.maybe_push(|| {
64+
let name = adt_def.variant(variant).name;
65+
ProjectedUserTypesOp::Variant { name, variant, field }
66+
})
67+
}
68+
69+
/// Traverses the chain of nodes to yield each op in the chain.
70+
/// Because this walks from child node to parent node, the ops are
71+
/// naturally yielded in "reverse" order.
72+
fn iter_ops_reversed(&'a self) -> impl Iterator<Item = &'a ProjectedUserTypesOp> {
73+
let mut next = self;
74+
iter::from_fn(move || match next {
75+
Self::None => None,
76+
Self::Chain { parent, op } => {
77+
next = parent;
78+
Some(op)
79+
}
80+
})
81+
}
82+
83+
pub(crate) fn build_user_type_projections(&self) -> UserTypeProjections {
84+
let ops_reversed = self.iter_ops_reversed().cloned().collect::<Vec<_>>();
85+
86+
let mut projections = vec![];
87+
for op in ops_reversed.into_iter().rev() {
88+
match op {
89+
ProjectedUserTypesOp::PushUserType { base } => {
90+
projections.push(UserTypeProjection { base, projs: vec![] })
91+
}
92+
93+
ProjectedUserTypesOp::Index => {
94+
for p in &mut projections {
95+
p.projs.push(ProjectionElem::Index(()))
96+
}
97+
}
98+
ProjectedUserTypesOp::Subslice { from, to } => {
99+
for p in &mut projections {
100+
p.projs.push(ProjectionElem::Subslice { from, to, from_end: true })
101+
}
102+
}
103+
ProjectedUserTypesOp::Deref => {
104+
for p in &mut projections {
105+
p.projs.push(ProjectionElem::Deref)
106+
}
107+
}
108+
ProjectedUserTypesOp::Leaf { field } => {
109+
for p in &mut projections {
110+
p.projs.push(ProjectionElem::Field(field, ()))
111+
}
112+
}
113+
ProjectedUserTypesOp::Variant { name, variant, field } => {
114+
for p in &mut projections {
115+
p.projs.push(ProjectionElem::Downcast(Some(name), variant));
116+
p.projs.push(ProjectionElem::Field(field, ()));
117+
}
118+
}
119+
}
120+
}
121+
122+
UserTypeProjections { contents: projections }
123+
}
124+
}

0 commit comments

Comments
 (0)