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