/src/wasm-tools/crates/wit-parser/src/abi.rs
Line | Count | Source |
1 | | use crate::{Function, Handle, Int, Resolve, Type, TypeDefKind}; |
2 | | use alloc::vec::Vec; |
3 | | |
4 | | /// A core WebAssembly signature with params and results. |
5 | | #[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] |
6 | | pub struct WasmSignature { |
7 | | /// The WebAssembly parameters of this function. |
8 | | pub params: Vec<WasmType>, |
9 | | |
10 | | /// The WebAssembly results of this function. |
11 | | pub results: Vec<WasmType>, |
12 | | |
13 | | /// Whether or not this signature is passing all of its parameters |
14 | | /// indirectly through a pointer within `params`. |
15 | | /// |
16 | | /// Note that `params` still reflects the true wasm parameters of this |
17 | | /// function, this is auxiliary information for code generators if |
18 | | /// necessary. |
19 | | pub indirect_params: bool, |
20 | | |
21 | | /// Whether or not this signature is using a return pointer to store the |
22 | | /// result of the function, which is reflected either in `params` or |
23 | | /// `results` depending on the context this function is used (e.g. an import |
24 | | /// or an export). |
25 | | pub retptr: bool, |
26 | | } |
27 | | |
28 | | /// Enumerates wasm types used by interface types when lowering/lifting. |
29 | | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
30 | | pub enum WasmType { |
31 | | I32, |
32 | | I64, |
33 | | F32, |
34 | | F64, |
35 | | |
36 | | /// A pointer type. In core Wasm this typically lowers to either `i32` or |
37 | | /// `i64` depending on the index type of the exported linear memory, |
38 | | /// however bindings can use different source-level types to preserve |
39 | | /// provenance. |
40 | | /// |
41 | | /// Users that don't do anything special for pointers can treat this as |
42 | | /// `i32`. |
43 | | Pointer, |
44 | | |
45 | | /// A type for values which can be either pointers or 64-bit integers. |
46 | | /// This occurs in variants, when pointers and non-pointers are unified. |
47 | | /// |
48 | | /// Users that don't do anything special for pointers can treat this as |
49 | | /// `i64`. |
50 | | PointerOrI64, |
51 | | |
52 | | /// An array length type. In core Wasm this lowers to either `i32` or `i64` |
53 | | /// depending on the index type of the exported linear memory. |
54 | | /// |
55 | | /// Users that don't do anything special for pointers can treat this as |
56 | | /// `i32`. |
57 | | Length, |
58 | | // NOTE: we don't lower interface types to any other Wasm type, |
59 | | // e.g. externref, so we don't need to define them here. |
60 | | } |
61 | | |
62 | 2.72k | fn join(a: WasmType, b: WasmType) -> WasmType { |
63 | | use WasmType::*; |
64 | | |
65 | 2.72k | match (a, b) { |
66 | | (I32, I32) |
67 | | | (I64, I64) |
68 | | | (F32, F32) |
69 | | | (F64, F64) |
70 | | | (Pointer, Pointer) |
71 | | | (PointerOrI64, PointerOrI64) |
72 | 2.48k | | (Length, Length) => a, |
73 | | |
74 | 39 | (I32, F32) | (F32, I32) => I32, |
75 | | |
76 | | // A length is at least an `i32`, maybe more, so it wins over |
77 | | // 32-bit types. |
78 | 4 | (Length, I32 | F32) => Length, |
79 | 4 | (I32 | F32, Length) => Length, |
80 | | |
81 | | // A length might be an `i64`, but might not be, so if we have |
82 | | // 64-bit types, they win. |
83 | 0 | (Length, I64 | F64) => I64, |
84 | 0 | (I64 | F64, Length) => I64, |
85 | | |
86 | | // Pointers have provenance and are at least an `i32`, so they |
87 | | // win over 32-bit and length types. |
88 | 10 | (Pointer, I32 | F32 | Length) => Pointer, |
89 | 12 | (I32 | F32 | Length, Pointer) => Pointer, |
90 | | |
91 | | // If we need 64 bits and provenance, we need to use the special |
92 | | // `PointerOrI64`. |
93 | 0 | (Pointer, I64 | F64) => PointerOrI64, |
94 | 4 | (I64 | F64, Pointer) => PointerOrI64, |
95 | | |
96 | | // PointerOrI64 wins over everything. |
97 | 0 | (PointerOrI64, _) => PointerOrI64, |
98 | 0 | (_, PointerOrI64) => PointerOrI64, |
99 | | |
100 | | // Otherwise, `i64` wins. |
101 | 165 | (_, I64 | F64) | (I64 | F64, _) => I64, |
102 | | } |
103 | 2.72k | } |
104 | | |
105 | | impl From<Int> for WasmType { |
106 | 186 | fn from(i: Int) -> WasmType { |
107 | 186 | match i { |
108 | 186 | Int::U8 | Int::U16 | Int::U32 => WasmType::I32, |
109 | 0 | Int::U64 => WasmType::I64, |
110 | | } |
111 | 186 | } |
112 | | } |
113 | | |
114 | | /// We use a different ABI for wasm importing functions exported by the host |
115 | | /// than for wasm exporting functions imported by the host. |
116 | | /// |
117 | | /// Note that this reflects the flavor of ABI we generate, and not necessarily |
118 | | /// the way the resulting bindings will be used by end users. See the comments |
119 | | /// on the `Direction` enum in gen-core for details. |
120 | | /// |
121 | | /// The bindings ABI has a concept of a "guest" and a "host". There are two |
122 | | /// variants of the ABI, one specialized for the "guest" importing and calling |
123 | | /// a function defined and exported in the "host", and the other specialized for |
124 | | /// the "host" importing and calling a function defined and exported in the "guest". |
125 | | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] |
126 | | pub enum AbiVariant { |
127 | | /// The guest is importing and calling the function. |
128 | | GuestImport, |
129 | | /// The guest is defining and exporting the function. |
130 | | GuestExport, |
131 | | GuestImportAsync, |
132 | | GuestExportAsync, |
133 | | GuestExportAsyncStackful, |
134 | | } |
135 | | |
136 | | impl AbiVariant { |
137 | 0 | pub fn is_async(&self) -> bool { |
138 | 0 | match self { |
139 | 0 | Self::GuestImport | Self::GuestExport => false, |
140 | | Self::GuestImportAsync | Self::GuestExportAsync | Self::GuestExportAsyncStackful => { |
141 | 0 | true |
142 | | } |
143 | | } |
144 | 0 | } |
145 | | } |
146 | | |
147 | | pub struct FlatTypes<'a> { |
148 | | types: &'a mut [WasmType], |
149 | | cur: usize, |
150 | | overflow: bool, |
151 | | } |
152 | | |
153 | | impl<'a> FlatTypes<'a> { |
154 | 40.2k | pub fn new(types: &'a mut [WasmType]) -> FlatTypes<'a> { |
155 | 40.2k | FlatTypes { |
156 | 40.2k | types, |
157 | 40.2k | cur: 0, |
158 | 40.2k | overflow: false, |
159 | 40.2k | } |
160 | 40.2k | } |
161 | | |
162 | 100k | pub fn push(&mut self, ty: WasmType) -> bool { |
163 | 100k | match self.types.get_mut(self.cur) { |
164 | 96.8k | Some(next) => { |
165 | 96.8k | *next = ty; |
166 | 96.8k | self.cur += 1; |
167 | 96.8k | true |
168 | | } |
169 | | None => { |
170 | 3.81k | self.overflow = true; |
171 | 3.81k | false |
172 | | } |
173 | | } |
174 | 100k | } |
175 | | |
176 | 34.1k | pub fn to_vec(&self) -> Vec<WasmType> { |
177 | 34.1k | self.types[..self.cur].to_vec() |
178 | 34.1k | } |
179 | | } |
180 | | |
181 | | impl Resolve { |
182 | | pub const MAX_FLAT_PARAMS: usize = 16; |
183 | | pub const MAX_FLAT_ASYNC_PARAMS: usize = 4; |
184 | | pub const MAX_FLAT_RESULTS: usize = 1; |
185 | | |
186 | | /// Get the WebAssembly type signature for this interface function |
187 | | /// |
188 | | /// The first entry returned is the list of parameters and the second entry |
189 | | /// is the list of results for the wasm function signature. |
190 | 17.0k | pub fn wasm_signature(&self, variant: AbiVariant, func: &Function) -> WasmSignature { |
191 | | // Note that one extra parameter is allocated in case a return pointer |
192 | | // is needed down below for imports. |
193 | 17.0k | let mut storage = [WasmType::I32; Self::MAX_FLAT_PARAMS + 1]; |
194 | 17.0k | let mut params = FlatTypes::new(&mut storage); |
195 | 17.0k | let ok = self.push_flat_list(func.params.iter().map(|p| &p.ty), &mut params); |
196 | 17.0k | assert_eq!(ok, !params.overflow); |
197 | | |
198 | 17.0k | let max = match variant { |
199 | | AbiVariant::GuestImport |
200 | | | AbiVariant::GuestExport |
201 | | | AbiVariant::GuestExportAsync |
202 | 15.9k | | AbiVariant::GuestExportAsyncStackful => Self::MAX_FLAT_PARAMS, |
203 | 1.08k | AbiVariant::GuestImportAsync => Self::MAX_FLAT_ASYNC_PARAMS, |
204 | | }; |
205 | | |
206 | 17.0k | let indirect_params = !ok || params.cur > max; |
207 | 17.0k | if indirect_params { |
208 | 1.24k | params.types[0] = WasmType::Pointer; |
209 | 1.24k | params.cur = 1; |
210 | 1.24k | } else { |
211 | 14.1k | if matches!( |
212 | 15.8k | (&func.kind, variant), |
213 | | ( |
214 | | crate::FunctionKind::Method(_) |
215 | | | crate::FunctionKind::AsyncMethod(_) |
216 | | | crate::FunctionKind::MethodGetter(_) |
217 | | | crate::FunctionKind::MethodSetter(_), |
218 | | AbiVariant::GuestExport |
219 | | | AbiVariant::GuestExportAsync |
220 | | | AbiVariant::GuestExportAsyncStackful |
221 | | ) |
222 | | ) { |
223 | | // Guest exported methods always receive resource rep as first argument |
224 | | // |
225 | | // TODO: Ideally you would distinguish between imported and exported |
226 | | // resource Handles and then use either I32 or Pointer in abi::push_flat(). |
227 | | // But this contextual information isn't available, yet. |
228 | | // See https://github.com/bytecodealliance/wasm-tools/pull/1438 for more details. |
229 | 1.66k | assert!(matches!(params.types[0], WasmType::I32)); |
230 | 1.66k | params.types[0] = WasmType::Pointer; |
231 | 14.1k | } |
232 | | } |
233 | | |
234 | 17.0k | let mut storage = [WasmType::I32; Self::MAX_FLAT_RESULTS]; |
235 | 17.0k | let mut results = FlatTypes::new(&mut storage); |
236 | 17.0k | let mut retptr = false; |
237 | 17.0k | match variant { |
238 | | AbiVariant::GuestImport | AbiVariant::GuestExport => { |
239 | 15.2k | if let Some(ty) = &func.result { |
240 | 12.1k | self.push_flat(ty, &mut results); |
241 | 12.1k | } |
242 | 15.2k | retptr = results.overflow; |
243 | | |
244 | | // Rust/C don't support multi-value well right now, so if a |
245 | | // function would have multiple results then instead truncate |
246 | | // it. Imports take a return pointer to write into and exports |
247 | | // return a pointer they wrote into. |
248 | 15.2k | if retptr { |
249 | 2.72k | results.cur = 0; |
250 | 2.72k | match variant { |
251 | | AbiVariant::GuestImport => { |
252 | 647 | assert!(params.push(WasmType::Pointer)); |
253 | | } |
254 | | AbiVariant::GuestExport => { |
255 | 2.07k | assert!(results.push(WasmType::Pointer)); |
256 | | } |
257 | 0 | _ => unreachable!(), |
258 | | } |
259 | 12.5k | } |
260 | | } |
261 | | AbiVariant::GuestImportAsync => { |
262 | | // If this function has a result, a pointer must be passed to |
263 | | // get filled in by the async runtime. |
264 | 1.08k | if func.result.is_some() { |
265 | 709 | assert!(params.push(WasmType::Pointer)); |
266 | 709 | retptr = true; |
267 | 377 | } |
268 | | |
269 | | // The result of this function is a status code. |
270 | 1.08k | assert!(results.push(WasmType::I32)); |
271 | | } |
272 | | AbiVariant::GuestExportAsync => { |
273 | | // The result of this function is a status code. Note that the |
274 | | // function results are entirely ignored here as they aren't |
275 | | // part of the ABI and are handled in the `task.return` |
276 | | // intrinsic. |
277 | 567 | assert!(results.push(WasmType::I32)); |
278 | | } |
279 | 138 | AbiVariant::GuestExportAsyncStackful => { |
280 | 138 | // No status code, and like async exports no result handling. |
281 | 138 | } |
282 | | } |
283 | | |
284 | 17.0k | WasmSignature { |
285 | 17.0k | params: params.to_vec(), |
286 | 17.0k | indirect_params, |
287 | 17.0k | results: results.to_vec(), |
288 | 17.0k | retptr, |
289 | 17.0k | } |
290 | 17.0k | } |
291 | | |
292 | 33.1k | fn push_flat_list<'a>( |
293 | 33.1k | &self, |
294 | 33.1k | mut list: impl Iterator<Item = &'a Type>, |
295 | 33.1k | result: &mut FlatTypes<'_>, |
296 | 33.1k | ) -> bool { |
297 | 88.4k | list.all(|ty| self.push_flat(ty, result)) <wit_parser::resolve::Resolve>::push_flat_list::<core::slice::iter::Iter<wit_parser::Type>>::{closure#0}Line | Count | Source | 297 | 30.8k | list.all(|ty| self.push_flat(ty, result)) |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::ops::range::Range<usize>, <wit_parser::resolve::Resolve>::push_flat::{closure#1}>>::{closure#0}Line | Count | Source | 297 | 31 | list.all(|ty| self.push_flat(ty, result)) |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::ops::range::Range<u32>, <wit_parser::resolve::Resolve>::push_flat::{closure#2}>>::{closure#0}Line | Count | Source | 297 | 5.22k | list.all(|ty| self.push_flat(ty, result)) |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Field>, <wit_parser::resolve::Resolve>::push_flat::{closure#0}>>::{closure#0}Line | Count | Source | 297 | 256 | list.all(|ty| self.push_flat(ty, result)) |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Param>, <wit_parser::resolve::Resolve>::wasm_signature::{closure#0}>>::{closure#0}Line | Count | Source | 297 | 52.0k | list.all(|ty| self.push_flat(ty, result)) |
|
298 | 33.1k | } <wit_parser::resolve::Resolve>::push_flat_list::<core::slice::iter::Iter<wit_parser::Type>> Line | Count | Source | 292 | 13.1k | fn push_flat_list<'a>( | 293 | 13.1k | &self, | 294 | 13.1k | mut list: impl Iterator<Item = &'a Type>, | 295 | 13.1k | result: &mut FlatTypes<'_>, | 296 | 13.1k | ) -> bool { | 297 | 13.1k | list.all(|ty| self.push_flat(ty, result)) | 298 | 13.1k | } |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::ops::range::Range<usize>, <wit_parser::resolve::Resolve>::push_flat::{closure#1}>>Line | Count | Source | 292 | 31 | fn push_flat_list<'a>( | 293 | 31 | &self, | 294 | 31 | mut list: impl Iterator<Item = &'a Type>, | 295 | 31 | result: &mut FlatTypes<'_>, | 296 | 31 | ) -> bool { | 297 | 31 | list.all(|ty| self.push_flat(ty, result)) | 298 | 31 | } |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::ops::range::Range<u32>, <wit_parser::resolve::Resolve>::push_flat::{closure#2}>>Line | Count | Source | 292 | 2.72k | fn push_flat_list<'a>( | 293 | 2.72k | &self, | 294 | 2.72k | mut list: impl Iterator<Item = &'a Type>, | 295 | 2.72k | result: &mut FlatTypes<'_>, | 296 | 2.72k | ) -> bool { | 297 | 2.72k | list.all(|ty| self.push_flat(ty, result)) | 298 | 2.72k | } |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Field>, <wit_parser::resolve::Resolve>::push_flat::{closure#0}>>Line | Count | Source | 292 | 168 | fn push_flat_list<'a>( | 293 | 168 | &self, | 294 | 168 | mut list: impl Iterator<Item = &'a Type>, | 295 | 168 | result: &mut FlatTypes<'_>, | 296 | 168 | ) -> bool { | 297 | 168 | list.all(|ty| self.push_flat(ty, result)) | 298 | 168 | } |
<wit_parser::resolve::Resolve>::push_flat_list::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Param>, <wit_parser::resolve::Resolve>::wasm_signature::{closure#0}>>Line | Count | Source | 292 | 17.0k | fn push_flat_list<'a>( | 293 | 17.0k | &self, | 294 | 17.0k | mut list: impl Iterator<Item = &'a Type>, | 295 | 17.0k | result: &mut FlatTypes<'_>, | 296 | 17.0k | ) -> bool { | 297 | 17.0k | list.all(|ty| self.push_flat(ty, result)) | 298 | 17.0k | } |
|
299 | | |
300 | | /// Appends the flat wasm types representing `ty` onto the `result` |
301 | | /// list provided. |
302 | 109k | pub fn push_flat(&self, ty: &Type, result: &mut FlatTypes<'_>) -> bool { |
303 | 109k | match ty { |
304 | | Type::Bool |
305 | | | Type::S8 |
306 | | | Type::U8 |
307 | | | Type::S16 |
308 | | | Type::U16 |
309 | | | Type::S32 |
310 | | | Type::U32 |
311 | | | Type::Char |
312 | 68.2k | | Type::ErrorContext => result.push(WasmType::I32), |
313 | | |
314 | 2.37k | Type::U64 | Type::S64 => result.push(WasmType::I64), |
315 | 5.94k | Type::F32 => result.push(WasmType::F32), |
316 | 1.04k | Type::F64 => result.push(WasmType::F64), |
317 | 1.89k | Type::String => result.push(WasmType::Pointer) && result.push(WasmType::Length), |
318 | | |
319 | 29.8k | Type::Id(id) => match &self.types[*id].kind { |
320 | 449 | TypeDefKind::Type(t) => self.push_flat(t, result), |
321 | | |
322 | | TypeDefKind::Handle(Handle::Own(_) | Handle::Borrow(_)) => { |
323 | 2.60k | result.push(WasmType::I32) |
324 | | } |
325 | | |
326 | 0 | TypeDefKind::Resource => todo!(), |
327 | | |
328 | 168 | TypeDefKind::Record(r) => { |
329 | 168 | self.push_flat_list(r.fields.iter().map(|f| &f.ty), result) |
330 | | } |
331 | | |
332 | 13.1k | TypeDefKind::Tuple(t) => self.push_flat_list(t.types.iter(), result), |
333 | | |
334 | 31 | TypeDefKind::Flags(r) => { |
335 | 31 | self.push_flat_list((0..r.repr().count()).map(|_| &Type::U32), result) |
336 | | } |
337 | | |
338 | | TypeDefKind::List(_) => { |
339 | 933 | result.push(WasmType::Pointer) && result.push(WasmType::Length) |
340 | | } |
341 | | |
342 | | TypeDefKind::Map(_, _) => { |
343 | 0 | result.push(WasmType::Pointer) && result.push(WasmType::Length) |
344 | | } |
345 | | |
346 | 2.72k | TypeDefKind::FixedLengthList(ty, size) => { |
347 | 2.72k | self.push_flat_list((0..*size).map(|_| ty), result) |
348 | | } |
349 | | |
350 | 25 | TypeDefKind::Variant(v) => { |
351 | 25 | result.push(v.tag().into()) |
352 | 156 | && self.push_flat_variants(v.cases.iter().map(|c| c.ty.as_ref()), result) |
353 | | } |
354 | | |
355 | 161 | TypeDefKind::Enum(e) => result.push(e.tag().into()), |
356 | | |
357 | 2.76k | TypeDefKind::Option(t) => { |
358 | 2.76k | result.push(WasmType::I32) && self.push_flat_variants([None, Some(t)], result) |
359 | | } |
360 | | |
361 | 3.53k | TypeDefKind::Result(r) => { |
362 | 3.53k | result.push(WasmType::I32) |
363 | 3.42k | && self.push_flat_variants([r.ok.as_ref(), r.err.as_ref()], result) |
364 | | } |
365 | | |
366 | 2.44k | TypeDefKind::Future(_) => result.push(WasmType::I32), |
367 | 831 | TypeDefKind::Stream(_) => result.push(WasmType::I32), |
368 | | |
369 | 0 | TypeDefKind::Unknown => unreachable!(), |
370 | | }, |
371 | | } |
372 | 109k | } |
373 | | |
374 | 6.04k | fn push_flat_variants<'a>( |
375 | 6.04k | &self, |
376 | 6.04k | tys: impl IntoIterator<Item = Option<&'a Type>>, |
377 | 6.04k | result: &mut FlatTypes<'_>, |
378 | 6.04k | ) -> bool { |
379 | 6.04k | let mut temp = result.types[result.cur..].to_vec(); |
380 | 6.04k | let mut temp = FlatTypes::new(&mut temp); |
381 | 6.04k | let start = result.cur; |
382 | | |
383 | | // Push each case's type onto a temporary vector, and then |
384 | | // merge that vector into our final list starting at |
385 | | // `start`. Note that this requires some degree of |
386 | | // "unification" so we can handle things like `Result<i32, |
387 | | // f32>` where that turns into `[i32 i32]` where the second |
388 | | // `i32` might be the `f32` bitcasted. |
389 | 12.0k | for ty in tys { |
390 | 12.0k | if let Some(ty) = ty { |
391 | 8.39k | if !self.push_flat(ty, &mut temp) { |
392 | 966 | result.overflow = true; |
393 | 966 | return false; |
394 | 7.42k | } |
395 | | |
396 | 17.3k | for (i, ty) in temp.types[..temp.cur].iter().enumerate() { |
397 | 17.3k | let i = i + start; |
398 | 17.3k | if i < result.cur { |
399 | 2.72k | result.types[i] = join(result.types[i], *ty); |
400 | 14.6k | } else if result.cur == result.types.len() { |
401 | 0 | result.overflow = true; |
402 | 0 | return false; |
403 | 14.6k | } else { |
404 | 14.6k | result.types[i] = *ty; |
405 | 14.6k | result.cur += 1; |
406 | 14.6k | } |
407 | | } |
408 | 7.42k | temp.cur = 0; |
409 | 3.68k | } |
410 | | } |
411 | | |
412 | 5.07k | true |
413 | 6.04k | } <wit_parser::resolve::Resolve>::push_flat_variants::<[core::option::Option<&wit_parser::Type>; 2]> Line | Count | Source | 374 | 6.02k | fn push_flat_variants<'a>( | 375 | 6.02k | &self, | 376 | 6.02k | tys: impl IntoIterator<Item = Option<&'a Type>>, | 377 | 6.02k | result: &mut FlatTypes<'_>, | 378 | 6.02k | ) -> bool { | 379 | 6.02k | let mut temp = result.types[result.cur..].to_vec(); | 380 | 6.02k | let mut temp = FlatTypes::new(&mut temp); | 381 | 6.02k | let start = result.cur; | 382 | | | 383 | | // Push each case's type onto a temporary vector, and then | 384 | | // merge that vector into our final list starting at | 385 | | // `start`. Note that this requires some degree of | 386 | | // "unification" so we can handle things like `Result<i32, | 387 | | // f32>` where that turns into `[i32 i32]` where the second | 388 | | // `i32` might be the `f32` bitcasted. | 389 | 11.9k | for ty in tys { | 390 | 11.9k | if let Some(ty) = ty { | 391 | 8.28k | if !self.push_flat(ty, &mut temp) { | 392 | 966 | result.overflow = true; | 393 | 966 | return false; | 394 | 7.31k | } | 395 | | | 396 | 17.2k | for (i, ty) in temp.types[..temp.cur].iter().enumerate() { | 397 | 17.2k | let i = i + start; | 398 | 17.2k | if i < result.cur { | 399 | 2.63k | result.types[i] = join(result.types[i], *ty); | 400 | 14.6k | } else if result.cur == result.types.len() { | 401 | 0 | result.overflow = true; | 402 | 0 | return false; | 403 | 14.6k | } else { | 404 | 14.6k | result.types[i] = *ty; | 405 | 14.6k | result.cur += 1; | 406 | 14.6k | } | 407 | | } | 408 | 7.31k | temp.cur = 0; | 409 | 3.63k | } | 410 | | } | 411 | | | 412 | 5.05k | true | 413 | 6.02k | } |
<wit_parser::resolve::Resolve>::push_flat_variants::<core::iter::adapters::map::Map<core::slice::iter::Iter<wit_parser::Case>, <wit_parser::resolve::Resolve>::push_flat::{closure#3}>>Line | Count | Source | 374 | 25 | fn push_flat_variants<'a>( | 375 | 25 | &self, | 376 | 25 | tys: impl IntoIterator<Item = Option<&'a Type>>, | 377 | 25 | result: &mut FlatTypes<'_>, | 378 | 25 | ) -> bool { | 379 | 25 | let mut temp = result.types[result.cur..].to_vec(); | 380 | 25 | let mut temp = FlatTypes::new(&mut temp); | 381 | 25 | let start = result.cur; | 382 | | | 383 | | // Push each case's type onto a temporary vector, and then | 384 | | // merge that vector into our final list starting at | 385 | | // `start`. Note that this requires some degree of | 386 | | // "unification" so we can handle things like `Result<i32, | 387 | | // f32>` where that turns into `[i32 i32]` where the second | 388 | | // `i32` might be the `f32` bitcasted. | 389 | 156 | for ty in tys { | 390 | 156 | if let Some(ty) = ty { | 391 | 108 | if !self.push_flat(ty, &mut temp) { | 392 | 0 | result.overflow = true; | 393 | 0 | return false; | 394 | 108 | } | 395 | | | 396 | 123 | for (i, ty) in temp.types[..temp.cur].iter().enumerate() { | 397 | 123 | let i = i + start; | 398 | 123 | if i < result.cur { | 399 | 95 | result.types[i] = join(result.types[i], *ty); | 400 | 95 | } else if result.cur == result.types.len() { | 401 | 0 | result.overflow = true; | 402 | 0 | return false; | 403 | 28 | } else { | 404 | 28 | result.types[i] = *ty; | 405 | 28 | result.cur += 1; | 406 | 28 | } | 407 | | } | 408 | 108 | temp.cur = 0; | 409 | 48 | } | 410 | | } | 411 | | | 412 | 25 | true | 413 | 25 | } |
|
414 | | } |