/rust/registry/src/index.crates.io-6f17d22bba15001f/wast-64.0.0/src/core/resolve/types.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::core::*; |
2 | | use crate::gensym; |
3 | | use crate::token::{Index, Span}; |
4 | | use std::collections::HashMap; |
5 | | |
6 | 0 | pub fn expand<'a>(fields: &mut Vec<ModuleField<'a>>) { |
7 | 0 | let mut expander = Expander::default(); |
8 | 0 | expander.process(fields); |
9 | 0 | } |
10 | | |
11 | | #[derive(Default)] |
12 | | pub(crate) struct Expander<'a> { |
13 | | // Maps used to "intern" types. These maps are populated as type annotations |
14 | | // are seen and inline type annotations use previously defined ones if |
15 | | // there's a match. |
16 | | func_type_to_idx: HashMap<FuncKey<'a>, Index<'a>>, |
17 | | |
18 | | /// Fields, during processing, which should be prepended to the |
19 | | /// currently-being-processed field. This should always be empty after |
20 | | /// processing is complete. |
21 | | to_prepend: Vec<ModuleField<'a>>, |
22 | | } |
23 | | |
24 | | impl<'a> Expander<'a> { |
25 | 0 | fn process(&mut self, fields: &mut Vec<ModuleField<'a>>) { |
26 | 0 | // Next we expand "header" fields which are those like types and |
27 | 0 | // imports. In this context "header" is defined by the previous |
28 | 0 | // `process_imports_early` annotation. |
29 | 0 | let mut cur = 0; |
30 | 0 | while cur < fields.len() { |
31 | 0 | self.expand_header(&mut fields[cur]); |
32 | 0 | for item in self.to_prepend.drain(..) { |
33 | 0 | fields.insert(cur, item); |
34 | 0 | cur += 1; |
35 | 0 | } |
36 | 0 | cur += 1; |
37 | | } |
38 | | |
39 | | // Next after we've done that we expand remaining fields. Note that |
40 | | // after this we actually append instead of prepend. This is because |
41 | | // injected types are intended to come at the end of the type section |
42 | | // and types will be sorted before all other items processed here in the |
43 | | // final module anyway. |
44 | 0 | for field in fields.iter_mut() { |
45 | 0 | self.expand(field); |
46 | 0 | } |
47 | 0 | fields.append(&mut self.to_prepend); |
48 | 0 | } |
49 | | |
50 | 0 | fn expand_header(&mut self, item: &mut ModuleField<'a>) { |
51 | 0 | match item { |
52 | 0 | ModuleField::Type(ty) => { |
53 | 0 | let id = gensym::fill(ty.span, &mut ty.id); |
54 | 0 | match &mut ty.def { |
55 | 0 | TypeDef::Func(f) => { |
56 | 0 | f.key().insert(self, Index::Id(id)); |
57 | 0 | } |
58 | 0 | TypeDef::Array(_) | TypeDef::Struct(_) => {} |
59 | | } |
60 | | } |
61 | 0 | _ => {} |
62 | | } |
63 | 0 | } |
64 | | |
65 | 0 | fn expand(&mut self, item: &mut ModuleField<'a>) { |
66 | 0 | match item { |
67 | | // This is pre-expanded above |
68 | 0 | ModuleField::Type(_) => {} |
69 | 0 | ModuleField::Rec(_) => {} |
70 | | |
71 | 0 | ModuleField::Import(i) => { |
72 | 0 | self.expand_item_sig(&mut i.item); |
73 | 0 | } |
74 | 0 | ModuleField::Func(f) => { |
75 | 0 | self.expand_type_use(&mut f.ty); |
76 | 0 | if let FuncKind::Inline { expression, .. } = &mut f.kind { |
77 | 0 | self.expand_expression(expression); |
78 | 0 | } |
79 | | } |
80 | 0 | ModuleField::Global(g) => { |
81 | 0 | if let GlobalKind::Inline(expr) = &mut g.kind { |
82 | 0 | self.expand_expression(expr); |
83 | 0 | } |
84 | | } |
85 | 0 | ModuleField::Data(d) => { |
86 | 0 | if let DataKind::Active { offset, .. } = &mut d.kind { |
87 | 0 | self.expand_expression(offset); |
88 | 0 | } |
89 | | } |
90 | 0 | ModuleField::Elem(e) => { |
91 | 0 | if let ElemKind::Active { offset, .. } = &mut e.kind { |
92 | 0 | self.expand_expression(offset); |
93 | 0 | } |
94 | 0 | if let ElemPayload::Exprs { exprs, .. } = &mut e.payload { |
95 | 0 | for expr in exprs { |
96 | 0 | self.expand_expression(expr); |
97 | 0 | } |
98 | 0 | } |
99 | | } |
100 | 0 | ModuleField::Tag(t) => match &mut t.ty { |
101 | 0 | TagType::Exception(ty) => { |
102 | 0 | self.expand_type_use(ty); |
103 | 0 | } |
104 | | }, |
105 | | |
106 | 0 | ModuleField::Table(t) => match &mut t.kind { |
107 | 0 | TableKind::Normal { init_expr, .. } => { |
108 | 0 | if let Some(expr) = init_expr { |
109 | 0 | self.expand_expression(expr); |
110 | 0 | } |
111 | | } |
112 | 0 | TableKind::Import { .. } | TableKind::Inline { .. } => {} |
113 | | }, |
114 | | |
115 | | ModuleField::Memory(_) |
116 | | | ModuleField::Start(_) |
117 | | | ModuleField::Export(_) |
118 | 0 | | ModuleField::Custom(_) => {} |
119 | | } |
120 | 0 | } |
121 | | |
122 | 0 | fn expand_item_sig(&mut self, item: &mut ItemSig<'a>) { |
123 | 0 | match &mut item.kind { |
124 | 0 | ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => { |
125 | 0 | self.expand_type_use(t); |
126 | 0 | } |
127 | 0 | ItemKind::Global(_) | ItemKind::Table(_) | ItemKind::Memory(_) => {} |
128 | | } |
129 | 0 | } |
130 | | |
131 | 0 | fn expand_expression(&mut self, expr: &mut Expression<'a>) { |
132 | 0 | for instr in expr.instrs.iter_mut() { |
133 | 0 | self.expand_instr(instr); |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | 0 | fn expand_instr(&mut self, instr: &mut Instruction<'a>) { |
138 | 0 | match instr { |
139 | 0 | Instruction::Block(bt) |
140 | 0 | | Instruction::If(bt) |
141 | 0 | | Instruction::Loop(bt) |
142 | 0 | | Instruction::Let(LetType { block: bt, .. }) |
143 | 0 | | Instruction::Try(bt) => { |
144 | | // No expansion necessary, a type reference is already here. |
145 | | // We'll verify that it's the same as the inline type, if any, |
146 | | // later. |
147 | 0 | if bt.ty.index.is_some() { |
148 | 0 | return; |
149 | 0 | } |
150 | 0 |
|
151 | 0 | match &bt.ty.inline { |
152 | | // Only actually expand `TypeUse` with an index which appends a |
153 | | // type if it looks like we need one. This way if the |
154 | | // multi-value proposal isn't enabled and/or used we won't |
155 | | // encode it. |
156 | 0 | Some(inline) => { |
157 | 0 | if inline.params.len() == 0 && inline.results.len() <= 1 { |
158 | 0 | return; |
159 | 0 | } |
160 | | } |
161 | | |
162 | | // If we didn't have either an index or an inline type |
163 | | // listed then assume our block has no inputs/outputs, so |
164 | | // fill in the inline type here. |
165 | | // |
166 | | // Do not fall through to expanding the `TypeUse` because |
167 | | // this doesn't force an empty function type to go into the |
168 | | // type section. |
169 | | None => { |
170 | 0 | bt.ty.inline = Some(FunctionType::default()); |
171 | 0 | return; |
172 | | } |
173 | | } |
174 | 0 | self.expand_type_use(&mut bt.ty); |
175 | | } |
176 | 0 | Instruction::FuncBind(b) => { |
177 | 0 | self.expand_type_use(&mut b.ty); |
178 | 0 | } |
179 | 0 | Instruction::CallIndirect(c) | Instruction::ReturnCallIndirect(c) => { |
180 | 0 | self.expand_type_use(&mut c.ty); |
181 | 0 | } |
182 | 0 | _ => {} |
183 | | } |
184 | 0 | } |
185 | | |
186 | 0 | fn expand_type_use<T>(&mut self, item: &mut TypeUse<'a, T>) -> Index<'a> |
187 | 0 | where |
188 | 0 | T: TypeReference<'a>, |
189 | 0 | { |
190 | 0 | if let Some(idx) = &item.index { |
191 | 0 | return *idx; |
192 | 0 | } |
193 | 0 | let key = match item.inline.as_mut() { |
194 | 0 | Some(ty) => { |
195 | 0 | ty.expand(self); |
196 | 0 | ty.key() |
197 | | } |
198 | 0 | None => T::default().key(), |
199 | | }; |
200 | 0 | let span = Span::from_offset(0); // FIXME(#613): don't manufacture |
201 | 0 | let idx = self.key_to_idx(span, key); |
202 | 0 | item.index = Some(idx); |
203 | 0 | idx |
204 | 0 | } |
205 | | |
206 | 0 | fn key_to_idx(&mut self, span: Span, key: impl TypeKey<'a>) -> Index<'a> { |
207 | | // First see if this `key` already exists in the type definitions we've |
208 | | // seen so far... |
209 | 0 | if let Some(idx) = key.lookup(self) { |
210 | 0 | return idx; |
211 | 0 | } |
212 | 0 |
|
213 | 0 | // ... and failing that we insert a new type definition. |
214 | 0 | let id = gensym::gen(span); |
215 | 0 | self.to_prepend.push(ModuleField::Type(Type { |
216 | 0 | span, |
217 | 0 | id: Some(id), |
218 | 0 | name: None, |
219 | 0 | def: key.to_def(span), |
220 | 0 | parent: None, |
221 | 0 | final_type: None, |
222 | 0 | })); |
223 | 0 | let idx = Index::Id(id); |
224 | 0 | key.insert(self, idx); |
225 | 0 | idx |
226 | 0 | } |
227 | | } |
228 | | |
229 | | pub(crate) trait TypeReference<'a>: Default { |
230 | | type Key: TypeKey<'a>; |
231 | | fn key(&self) -> Self::Key; |
232 | | fn expand(&mut self, cx: &mut Expander<'a>); |
233 | | } |
234 | | |
235 | | pub(crate) trait TypeKey<'a> { |
236 | | fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>>; |
237 | | fn to_def(&self, span: Span) -> TypeDef<'a>; |
238 | | fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>); |
239 | | } |
240 | | |
241 | | pub(crate) type FuncKey<'a> = (Box<[ValType<'a>]>, Box<[ValType<'a>]>); |
242 | | |
243 | | impl<'a> TypeReference<'a> for FunctionType<'a> { |
244 | | type Key = FuncKey<'a>; |
245 | | |
246 | 0 | fn key(&self) -> Self::Key { |
247 | 0 | let params = self.params.iter().map(|p| p.2).collect(); |
248 | 0 | let results = self.results.clone(); |
249 | 0 | (params, results) |
250 | 0 | } |
251 | | |
252 | 0 | fn expand(&mut self, _cx: &mut Expander<'a>) {} |
253 | | } |
254 | | |
255 | | impl<'a> TypeKey<'a> for FuncKey<'a> { |
256 | 0 | fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>> { |
257 | 0 | cx.func_type_to_idx.get(self).cloned() |
258 | 0 | } |
259 | | |
260 | 0 | fn to_def(&self, _span: Span) -> TypeDef<'a> { |
261 | 0 | TypeDef::Func(FunctionType { |
262 | 0 | params: self.0.iter().map(|t| (None, None, *t)).collect(), |
263 | 0 | results: self.1.clone(), |
264 | 0 | }) |
265 | 0 | } |
266 | | |
267 | 0 | fn insert(&self, cx: &mut Expander<'a>, idx: Index<'a>) { |
268 | 0 | cx.func_type_to_idx.entry(self.clone()).or_insert(idx); |
269 | 0 | } |
270 | | } |