rustc_mir_build/builder/matches/
user_ty.rs1use std::assert_matches::assert_matches;
8use std::iter;
9
10use rustc_abi::{FieldIdx, VariantIdx};
11use rustc_data_structures::smallvec::SmallVec;
12use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections};
13use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex};
14use rustc_span::Symbol;
15
16pub(crate) type UserTypeIndices = SmallVec<[UserTypeAnnotationIndex; 4]>;
19
20#[derive(Debug)]
23pub(crate) enum ProjectedUserTypesOp {
24 PushUserTypes { base_types: UserTypeIndices },
25
26 Index,
27 Subslice { from: u64, to: u64 },
28 Deref,
29 Leaf { field: FieldIdx },
30 Variant { name: Symbol, variant: VariantIdx, field: FieldIdx },
31}
32
33#[derive(Debug)]
34pub(crate) enum ProjectedUserTypesNode<'a> {
35 None,
36 Chain { parent: &'a Self, op: ProjectedUserTypesOp },
37}
38
39impl<'a> ProjectedUserTypesNode<'a> {
40 pub(crate) fn push_user_types(&'a self, base_types: UserTypeIndices) -> Self {
41 assert!(!base_types.is_empty());
42 Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserTypes { base_types } }
44 }
45
46 fn maybe_push(&'a self, op_fn: impl FnOnce() -> ProjectedUserTypesOp) -> Self {
48 match self {
49 Self::None => Self::None,
50 Self::Chain { .. } => Self::Chain { parent: self, op: op_fn() },
51 }
52 }
53
54 pub(crate) fn index(&'a self) -> Self {
55 self.maybe_push(|| ProjectedUserTypesOp::Index)
56 }
57
58 pub(crate) fn subslice(&'a self, from: u64, to: u64) -> Self {
59 self.maybe_push(|| ProjectedUserTypesOp::Subslice { from, to })
60 }
61
62 pub(crate) fn deref(&'a self) -> Self {
63 self.maybe_push(|| ProjectedUserTypesOp::Deref)
64 }
65
66 pub(crate) fn leaf(&'a self, field: FieldIdx) -> Self {
67 self.maybe_push(|| ProjectedUserTypesOp::Leaf { field })
68 }
69
70 pub(crate) fn variant(
71 &'a self,
72 adt_def: AdtDef<'_>,
73 variant: VariantIdx,
74 field: FieldIdx,
75 ) -> Self {
76 self.maybe_push(|| {
77 let name = adt_def.variant(variant).name;
78 ProjectedUserTypesOp::Variant { name, variant, field }
79 })
80 }
81
82 fn iter_ops_reversed(&'a self) -> impl Iterator<Item = &'a ProjectedUserTypesOp> {
86 let mut next = self;
87 iter::from_fn(move || match next {
88 Self::None => None,
89 Self::Chain { parent, op } => {
90 next = parent;
91 Some(op)
92 }
93 })
94 }
95
96 pub(crate) fn build_user_type_projections(&self) -> Option<Box<UserTypeProjections>> {
98 if matches!(self, Self::None) {
100 return None;
101 }
102
103 let ops_reversed = self.iter_ops_reversed().collect::<Vec<_>>();
104 assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserTypes { .. }));
107
108 let mut projections = vec![];
109 for op in ops_reversed.into_iter().rev() {
110 match *op {
111 ProjectedUserTypesOp::PushUserTypes { ref base_types } => {
112 assert!(!base_types.is_empty());
113 for &base in base_types {
114 projections.push(UserTypeProjection { base, projs: vec![] })
115 }
116 }
117
118 ProjectedUserTypesOp::Index => {
119 for p in &mut projections {
120 p.projs.push(ProjectionElem::Index(()))
121 }
122 }
123 ProjectedUserTypesOp::Subslice { from, to } => {
124 for p in &mut projections {
125 p.projs.push(ProjectionElem::Subslice { from, to, from_end: true })
126 }
127 }
128 ProjectedUserTypesOp::Deref => {
129 for p in &mut projections {
130 p.projs.push(ProjectionElem::Deref)
131 }
132 }
133 ProjectedUserTypesOp::Leaf { field } => {
134 for p in &mut projections {
135 p.projs.push(ProjectionElem::Field(field, ()))
136 }
137 }
138 ProjectedUserTypesOp::Variant { name, variant, field } => {
139 for p in &mut projections {
140 p.projs.push(ProjectionElem::Downcast(Some(name), variant));
141 p.projs.push(ProjectionElem::Field(field, ()));
142 }
143 }
144 }
145 }
146
147 Some(Box::new(UserTypeProjections { contents: projections }))
148 }
149}