/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 | 1.33k | fn join(a: WasmType, b: WasmType) -> WasmType { |
63 | | use WasmType::*; |
64 | | |
65 | 1.33k | match (a, b) { |
66 | | (I32, I32) |
67 | | | (I64, I64) |
68 | | | (F32, F32) |
69 | | | (F64, F64) |
70 | | | (Pointer, Pointer) |
71 | | | (PointerOrI64, PointerOrI64) |
72 | 925 | | (Length, Length) => a, |
73 | | |
74 | 47 | (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 | 0 | (Length, I32 | F32) => Length, |
79 | 12 | (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 | 4 | (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 | 24 | (Pointer, I32 | F32 | Length) => Pointer, |
89 | 19 | (I32 | F32 | Length, Pointer) => Pointer, |
90 | | |
91 | | // If we need 64 bits and provenance, we need to use the special |
92 | | // `PointerOrI64`. |
93 | 12 | (Pointer, I64 | F64) => PointerOrI64, |
94 | 8 | (I64 | F64, Pointer) => PointerOrI64, |
95 | | |
96 | | // PointerOrI64 wins over everything. |
97 | 0 | (PointerOrI64, _) => PointerOrI64, |
98 | 0 | (_, PointerOrI64) => PointerOrI64, |
99 | | |
100 | | // Otherwise, `i64` wins. |
101 | 285 | (_, I64 | F64) | (I64 | F64, _) => I64, |
102 | | } |
103 | 1.33k | } |
104 | | |
105 | | impl From<Int> for WasmType { |
106 | 210 | fn from(i: Int) -> WasmType { |
107 | 210 | match i { |
108 | 210 | Int::U8 | Int::U16 | Int::U32 => WasmType::I32, |
109 | 0 | Int::U64 => WasmType::I64, |
110 | | } |
111 | 210 | } |
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 | 31.9k | pub fn new(types: &'a mut [WasmType]) -> FlatTypes<'a> { |
155 | 31.9k | FlatTypes { |
156 | 31.9k | types, |
157 | 31.9k | cur: 0, |
158 | 31.9k | overflow: false, |
159 | 31.9k | } |
160 | 31.9k | } |
161 | | |
162 | 49.3k | pub fn push(&mut self, ty: WasmType) -> bool { |
163 | 49.3k | match self.types.get_mut(self.cur) { |
164 | 48.2k | Some(next) => { |
165 | 48.2k | *next = ty; |
166 | 48.2k | self.cur += 1; |
167 | 48.2k | true |
168 | | } |
169 | | None => { |
170 | 1.08k | self.overflow = true; |
171 | 1.08k | false |
172 | | } |
173 | | } |
174 | 49.3k | } |
175 | | |
176 | 24.9k | pub fn to_vec(&self) -> Vec<WasmType> { |
177 | 24.9k | self.types[..self.cur].to_vec() |
178 | 24.9k | } |
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 | 12.4k | 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 | 12.4k | let mut storage = [WasmType::I32; Self::MAX_FLAT_PARAMS + 1]; |
194 | 12.4k | let mut params = FlatTypes::new(&mut storage); |
195 | 12.4k | let ok = self.push_flat_list(func.params.iter().map(|p| &p.ty), &mut params); |
196 | 12.4k | assert_eq!(ok, !params.overflow); |
197 | | |
198 | 12.4k | let max = match variant { |
199 | | AbiVariant::GuestImport |
200 | | | AbiVariant::GuestExport |
201 | | | AbiVariant::GuestExportAsync |
202 | 11.0k | | AbiVariant::GuestExportAsyncStackful => Self::MAX_FLAT_PARAMS, |
203 | 1.40k | AbiVariant::GuestImportAsync => Self::MAX_FLAT_ASYNC_PARAMS, |
204 | | }; |
205 | | |
206 | 12.4k | let indirect_params = !ok || params.cur > max; |
207 | 12.4k | if indirect_params { |
208 | 648 | params.types[0] = WasmType::Pointer; |
209 | 648 | params.cur = 1; |
210 | 648 | } else { |
211 | 11.3k | if matches!( |
212 | 11.8k | (&func.kind, variant), |
213 | | ( |
214 | | crate::FunctionKind::Method(_) | crate::FunctionKind::AsyncMethod(_), |
215 | | AbiVariant::GuestExport |
216 | | | AbiVariant::GuestExportAsync |
217 | | | AbiVariant::GuestExportAsyncStackful |
218 | | ) |
219 | | ) { |
220 | | // Guest exported methods always receive resource rep as first argument |
221 | | // |
222 | | // TODO: Ideally you would distinguish between imported and exported |
223 | | // resource Handles and then use either I32 or Pointer in abi::push_flat(). |
224 | | // But this contextual information isn't available, yet. |
225 | | // See https://github.com/bytecodealliance/wasm-tools/pull/1438 for more details. |
226 | 529 | assert!(matches!(params.types[0], WasmType::I32)); |
227 | 529 | params.types[0] = WasmType::Pointer; |
228 | 11.3k | } |
229 | | } |
230 | | |
231 | 12.4k | let mut storage = [WasmType::I32; Self::MAX_FLAT_RESULTS]; |
232 | 12.4k | let mut results = FlatTypes::new(&mut storage); |
233 | 12.4k | let mut retptr = false; |
234 | 12.4k | match variant { |
235 | | AbiVariant::GuestImport | AbiVariant::GuestExport => { |
236 | 10.3k | if let Some(ty) = &func.result { |
237 | 5.88k | self.push_flat(ty, &mut results); |
238 | 5.88k | } |
239 | 10.3k | retptr = results.overflow; |
240 | | |
241 | | // Rust/C don't support multi-value well right now, so if a |
242 | | // function would have multiple results then instead truncate |
243 | | // it. Imports take a return pointer to write into and exports |
244 | | // return a pointer they wrote into. |
245 | 10.3k | if retptr { |
246 | 681 | results.cur = 0; |
247 | 681 | match variant { |
248 | | AbiVariant::GuestImport => { |
249 | 405 | assert!(params.push(WasmType::Pointer)); |
250 | | } |
251 | | AbiVariant::GuestExport => { |
252 | 276 | assert!(results.push(WasmType::Pointer)); |
253 | | } |
254 | 0 | _ => unreachable!(), |
255 | | } |
256 | 9.71k | } |
257 | | } |
258 | | AbiVariant::GuestImportAsync => { |
259 | | // If this function has a result, a pointer must be passed to |
260 | | // get filled in by the async runtime. |
261 | 1.40k | if func.result.is_some() { |
262 | 1.01k | assert!(params.push(WasmType::Pointer)); |
263 | 1.01k | retptr = true; |
264 | 391 | } |
265 | | |
266 | | // The result of this function is a status code. |
267 | 1.40k | assert!(results.push(WasmType::I32)); |
268 | | } |
269 | | AbiVariant::GuestExportAsync => { |
270 | | // The result of this function is a status code. Note that the |
271 | | // function results are entirely ignored here as they aren't |
272 | | // part of the ABI and are handled in the `task.return` |
273 | | // intrinsic. |
274 | 492 | assert!(results.push(WasmType::I32)); |
275 | | } |
276 | 192 | AbiVariant::GuestExportAsyncStackful => { |
277 | 192 | // No status code, and like async exports no result handling. |
278 | 192 | } |
279 | | } |
280 | | |
281 | 12.4k | WasmSignature { |
282 | 12.4k | params: params.to_vec(), |
283 | 12.4k | indirect_params, |
284 | 12.4k | results: results.to_vec(), |
285 | 12.4k | retptr, |
286 | 12.4k | } |
287 | 12.4k | } |
288 | | |
289 | 18.6k | fn push_flat_list<'a>( |
290 | 18.6k | &self, |
291 | 18.6k | mut list: impl Iterator<Item = &'a Type>, |
292 | 18.6k | result: &mut FlatTypes<'_>, |
293 | 18.6k | ) -> bool { |
294 | 36.8k | 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 | 294 | 8.70k | 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 | 294 | 18 | 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 | 294 | 4.00k | 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 | 294 | 103 | 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 | 294 | 24.0k | list.all(|ty| self.push_flat(ty, result)) |
|
295 | 18.6k | } <wit_parser::resolve::Resolve>::push_flat_list::<core::slice::iter::Iter<wit_parser::Type>> Line | Count | Source | 289 | 4.64k | fn push_flat_list<'a>( | 290 | 4.64k | &self, | 291 | 4.64k | mut list: impl Iterator<Item = &'a Type>, | 292 | 4.64k | result: &mut FlatTypes<'_>, | 293 | 4.64k | ) -> bool { | 294 | 4.64k | list.all(|ty| self.push_flat(ty, result)) | 295 | 4.64k | } |
<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 | 289 | 18 | fn push_flat_list<'a>( | 290 | 18 | &self, | 291 | 18 | mut list: impl Iterator<Item = &'a Type>, | 292 | 18 | result: &mut FlatTypes<'_>, | 293 | 18 | ) -> bool { | 294 | 18 | list.all(|ty| self.push_flat(ty, result)) | 295 | 18 | } |
<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 | 289 | 1.47k | fn push_flat_list<'a>( | 290 | 1.47k | &self, | 291 | 1.47k | mut list: impl Iterator<Item = &'a Type>, | 292 | 1.47k | result: &mut FlatTypes<'_>, | 293 | 1.47k | ) -> bool { | 294 | 1.47k | list.all(|ty| self.push_flat(ty, result)) | 295 | 1.47k | } |
<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 | 289 | 43 | fn push_flat_list<'a>( | 290 | 43 | &self, | 291 | 43 | mut list: impl Iterator<Item = &'a Type>, | 292 | 43 | result: &mut FlatTypes<'_>, | 293 | 43 | ) -> bool { | 294 | 43 | list.all(|ty| self.push_flat(ty, result)) | 295 | 43 | } |
<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 | 289 | 12.4k | fn push_flat_list<'a>( | 290 | 12.4k | &self, | 291 | 12.4k | mut list: impl Iterator<Item = &'a Type>, | 292 | 12.4k | result: &mut FlatTypes<'_>, | 293 | 12.4k | ) -> bool { | 294 | 12.4k | list.all(|ty| self.push_flat(ty, result)) | 295 | 12.4k | } |
|
296 | | |
297 | | /// Appends the flat wasm types representing `ty` onto the `result` |
298 | | /// list provided. |
299 | 50.7k | pub fn push_flat(&self, ty: &Type, result: &mut FlatTypes<'_>) -> bool { |
300 | 50.7k | match ty { |
301 | | Type::Bool |
302 | | | Type::S8 |
303 | | | Type::U8 |
304 | | | Type::S16 |
305 | | | Type::U16 |
306 | | | Type::S32 |
307 | | | Type::U32 |
308 | | | Type::Char |
309 | 26.7k | | Type::ErrorContext => result.push(WasmType::I32), |
310 | | |
311 | 2.86k | Type::U64 | Type::S64 => result.push(WasmType::I64), |
312 | 1.73k | Type::F32 => result.push(WasmType::F32), |
313 | 1.30k | Type::F64 => result.push(WasmType::F64), |
314 | 704 | Type::String => result.push(WasmType::Pointer) && result.push(WasmType::Length), |
315 | | |
316 | 17.4k | Type::Id(id) => match &self.types[*id].kind { |
317 | 52 | TypeDefKind::Type(t) => self.push_flat(t, result), |
318 | | |
319 | | TypeDefKind::Handle(Handle::Own(_) | Handle::Borrow(_)) => { |
320 | 2.08k | result.push(WasmType::I32) |
321 | | } |
322 | | |
323 | 0 | TypeDefKind::Resource => todo!(), |
324 | | |
325 | 43 | TypeDefKind::Record(r) => { |
326 | 43 | self.push_flat_list(r.fields.iter().map(|f| &f.ty), result) |
327 | | } |
328 | | |
329 | 4.64k | TypeDefKind::Tuple(t) => self.push_flat_list(t.types.iter(), result), |
330 | | |
331 | 18 | TypeDefKind::Flags(r) => { |
332 | 18 | self.push_flat_list((0..r.repr().count()).map(|_| &Type::U32), result) |
333 | | } |
334 | | |
335 | | TypeDefKind::List(_) => { |
336 | 497 | result.push(WasmType::Pointer) && result.push(WasmType::Length) |
337 | | } |
338 | | |
339 | | TypeDefKind::Map(_, _) => { |
340 | 0 | result.push(WasmType::Pointer) && result.push(WasmType::Length) |
341 | | } |
342 | | |
343 | 1.47k | TypeDefKind::FixedLengthList(ty, size) => { |
344 | 1.47k | self.push_flat_list((0..*size).map(|_| ty), result) |
345 | | } |
346 | | |
347 | 59 | TypeDefKind::Variant(v) => { |
348 | 59 | result.push(v.tag().into()) |
349 | 223 | && self.push_flat_variants(v.cases.iter().map(|c| c.ty.as_ref()), result) |
350 | | } |
351 | | |
352 | 151 | TypeDefKind::Enum(e) => result.push(e.tag().into()), |
353 | | |
354 | 3.70k | TypeDefKind::Option(t) => { |
355 | 3.70k | result.push(WasmType::I32) && self.push_flat_variants([None, Some(t)], result) |
356 | | } |
357 | | |
358 | 3.53k | TypeDefKind::Result(r) => { |
359 | 3.53k | result.push(WasmType::I32) |
360 | 3.36k | && self.push_flat_variants([r.ok.as_ref(), r.err.as_ref()], result) |
361 | | } |
362 | | |
363 | 410 | TypeDefKind::Future(_) => result.push(WasmType::I32), |
364 | 723 | TypeDefKind::Stream(_) => result.push(WasmType::I32), |
365 | | |
366 | 0 | TypeDefKind::Unknown => unreachable!(), |
367 | | }, |
368 | | } |
369 | 50.7k | } |
370 | | |
371 | 6.93k | fn push_flat_variants<'a>( |
372 | 6.93k | &self, |
373 | 6.93k | tys: impl IntoIterator<Item = Option<&'a Type>>, |
374 | 6.93k | result: &mut FlatTypes<'_>, |
375 | 6.93k | ) -> bool { |
376 | 6.93k | let mut temp = result.types[result.cur..].to_vec(); |
377 | 6.93k | let mut temp = FlatTypes::new(&mut temp); |
378 | 6.93k | let start = result.cur; |
379 | | |
380 | | // Push each case's type onto a temporary vector, and then |
381 | | // merge that vector into our final list starting at |
382 | | // `start`. Note that this requires some degree of |
383 | | // "unification" so we can handle things like `Result<i32, |
384 | | // f32>` where that turns into `[i32 i32]` where the second |
385 | | // `i32` might be the `f32` bitcasted. |
386 | 13.4k | for ty in tys { |
387 | 13.4k | if let Some(ty) = ty { |
388 | 7.98k | if !self.push_flat(ty, &mut temp) { |
389 | 1.55k | result.overflow = true; |
390 | 1.55k | return false; |
391 | 6.42k | } |
392 | | |
393 | 18.7k | for (i, ty) in temp.types[..temp.cur].iter().enumerate() { |
394 | 18.7k | let i = i + start; |
395 | 18.7k | if i < result.cur { |
396 | 1.33k | result.types[i] = join(result.types[i], *ty); |
397 | 17.4k | } else if result.cur == result.types.len() { |
398 | 0 | result.overflow = true; |
399 | 0 | return false; |
400 | 17.4k | } else { |
401 | 17.4k | result.types[i] = *ty; |
402 | 17.4k | result.cur += 1; |
403 | 17.4k | } |
404 | | } |
405 | 6.42k | temp.cur = 0; |
406 | 5.43k | } |
407 | | } |
408 | | |
409 | 5.37k | true |
410 | 6.93k | } <wit_parser::resolve::Resolve>::push_flat_variants::<[core::option::Option<&wit_parser::Type>; 2]> Line | Count | Source | 371 | 6.87k | fn push_flat_variants<'a>( | 372 | 6.87k | &self, | 373 | 6.87k | tys: impl IntoIterator<Item = Option<&'a Type>>, | 374 | 6.87k | result: &mut FlatTypes<'_>, | 375 | 6.87k | ) -> bool { | 376 | 6.87k | let mut temp = result.types[result.cur..].to_vec(); | 377 | 6.87k | let mut temp = FlatTypes::new(&mut temp); | 378 | 6.87k | let start = result.cur; | 379 | | | 380 | | // Push each case's type onto a temporary vector, and then | 381 | | // merge that vector into our final list starting at | 382 | | // `start`. Note that this requires some degree of | 383 | | // "unification" so we can handle things like `Result<i32, | 384 | | // f32>` where that turns into `[i32 i32]` where the second | 385 | | // `i32` might be the `f32` bitcasted. | 386 | 13.1k | for ty in tys { | 387 | 13.1k | if let Some(ty) = ty { | 388 | 7.81k | if !self.push_flat(ty, &mut temp) { | 389 | 1.53k | result.overflow = true; | 390 | 1.53k | return false; | 391 | 6.28k | } | 392 | | | 393 | 18.4k | for (i, ty) in temp.types[..temp.cur].iter().enumerate() { | 394 | 18.4k | let i = i + start; | 395 | 18.4k | if i < result.cur { | 396 | 1.15k | result.types[i] = join(result.types[i], *ty); | 397 | 17.2k | } else if result.cur == result.types.len() { | 398 | 0 | result.overflow = true; | 399 | 0 | return false; | 400 | 17.2k | } else { | 401 | 17.2k | result.types[i] = *ty; | 402 | 17.2k | result.cur += 1; | 403 | 17.2k | } | 404 | | } | 405 | 6.28k | temp.cur = 0; | 406 | 5.38k | } | 407 | | } | 408 | | | 409 | 5.34k | true | 410 | 6.87k | } |
<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 | 371 | 59 | fn push_flat_variants<'a>( | 372 | 59 | &self, | 373 | 59 | tys: impl IntoIterator<Item = Option<&'a Type>>, | 374 | 59 | result: &mut FlatTypes<'_>, | 375 | 59 | ) -> bool { | 376 | 59 | let mut temp = result.types[result.cur..].to_vec(); | 377 | 59 | let mut temp = FlatTypes::new(&mut temp); | 378 | 59 | let start = result.cur; | 379 | | | 380 | | // Push each case's type onto a temporary vector, and then | 381 | | // merge that vector into our final list starting at | 382 | | // `start`. Note that this requires some degree of | 383 | | // "unification" so we can handle things like `Result<i32, | 384 | | // f32>` where that turns into `[i32 i32]` where the second | 385 | | // `i32` might be the `f32` bitcasted. | 386 | 223 | for ty in tys { | 387 | 223 | if let Some(ty) = ty { | 388 | 171 | if !self.push_flat(ty, &mut temp) { | 389 | 24 | result.overflow = true; | 390 | 24 | return false; | 391 | 147 | } | 392 | | | 393 | 307 | for (i, ty) in temp.types[..temp.cur].iter().enumerate() { | 394 | 307 | let i = i + start; | 395 | 307 | if i < result.cur { | 396 | 180 | result.types[i] = join(result.types[i], *ty); | 397 | 180 | } else if result.cur == result.types.len() { | 398 | 0 | result.overflow = true; | 399 | 0 | return false; | 400 | 127 | } else { | 401 | 127 | result.types[i] = *ty; | 402 | 127 | result.cur += 1; | 403 | 127 | } | 404 | | } | 405 | 147 | temp.cur = 0; | 406 | 52 | } | 407 | | } | 408 | | | 409 | 35 | true | 410 | 59 | } |
|
411 | | } |