xref: /wasmtime-44.0.1/tests/all/types.rs (revision f947672a)
1 use wasmtime::*;
2 
field(heap_ty: HeapType) -> FieldType3 fn field(heap_ty: HeapType) -> FieldType {
4     FieldType::new(
5         Mutability::Var,
6         StorageType::ValType(RefType::new(true, heap_ty).into()),
7     )
8 }
9 
imm_field(heap_ty: HeapType) -> FieldType10 fn imm_field(heap_ty: HeapType) -> FieldType {
11     FieldType::new(
12         Mutability::Const,
13         StorageType::ValType(RefType::new(true, heap_ty).into()),
14     )
15 }
16 
valty(heap_ty: HeapType) -> ValType17 fn valty(heap_ty: HeapType) -> ValType {
18     ValType::Ref(RefType::new(true, heap_ty))
19 }
20 
21 #[test]
basic_array_types() -> Result<()>22 fn basic_array_types() -> Result<()> {
23     let engine = Engine::default();
24     for mutability in [Mutability::Const, Mutability::Var] {
25         for storage_ty in [
26             StorageType::I8,
27             StorageType::I16,
28             StorageType::ValType(ValType::I32),
29             StorageType::ValType(RefType::new(true, FuncType::new(&engine, [], []).into()).into()),
30         ] {
31             let field_ty = FieldType::new(mutability, storage_ty.clone());
32             assert_eq!(field_ty.mutability(), mutability);
33             assert!(StorageType::eq(field_ty.element_type(), &storage_ty));
34 
35             let array_ty = ArrayType::new(&engine, field_ty.clone());
36             assert!(Engine::same(array_ty.engine(), &engine));
37             assert!(FieldType::eq(&array_ty.field_type(), &field_ty));
38             assert_eq!(array_ty.mutability(), mutability);
39             assert!(StorageType::eq(&array_ty.element_type(), &storage_ty));
40         }
41     }
42     Ok(())
43 }
44 
45 #[test]
empty_struct_type() -> Result<()>46 fn empty_struct_type() -> Result<()> {
47     let engine = Engine::default();
48     let struct_ty = StructType::new(&engine, [])?;
49     assert_eq!(struct_ty.fields().len(), 0);
50     assert!(struct_ty.field(0).is_none());
51     Ok(())
52 }
53 
54 #[test]
basic_struct_types() -> Result<()>55 fn basic_struct_types() -> Result<()> {
56     let engine = Engine::default();
57 
58     let field_types = || {
59         [Mutability::Const, Mutability::Var]
60             .into_iter()
61             .flat_map(|mutability| {
62                 [
63                     StorageType::I8,
64                     StorageType::I16,
65                     StorageType::ValType(ValType::I32),
66                     StorageType::ValType(
67                         RefType::new(true, FuncType::new(&engine, [], []).into()).into(),
68                     ),
69                 ]
70                 .into_iter()
71                 .map(move |storage_ty| FieldType::new(mutability, storage_ty))
72             })
73     };
74 
75     let struct_ty = StructType::new(&engine, field_types())?;
76 
77     assert_eq!(struct_ty.fields().len(), field_types().count());
78     for ((i, expected), actual) in field_types().enumerate().zip(struct_ty.fields()) {
79         assert!(FieldType::eq(&expected, &actual));
80         assert!(FieldType::eq(&expected, &struct_ty.field(i).unwrap()));
81     }
82     assert!(struct_ty.field(struct_ty.fields().len()).is_none());
83 
84     Ok(())
85 }
86 
87 #[test]
struct_type_matches() -> Result<()>88 fn struct_type_matches() -> Result<()> {
89     let engine = Engine::default();
90 
91     let super_ty = StructType::with_finality_and_supertype(
92         &engine,
93         Finality::NonFinal,
94         None,
95         [imm_field(HeapType::Func)],
96     )?;
97 
98     // Depth.
99     let sub_ty = StructType::with_finality_and_supertype(
100         &engine,
101         Finality::Final,
102         Some(&super_ty),
103         [imm_field(HeapType::NoFunc)],
104     )?;
105     assert!(sub_ty.matches(&super_ty));
106     let not_sub_ty = StructType::new(&engine, [imm_field(HeapType::NoFunc)])?;
107     assert!(!not_sub_ty.matches(&super_ty));
108 
109     // Width.
110     let sub_ty = StructType::with_finality_and_supertype(
111         &engine,
112         Finality::Final,
113         Some(&super_ty),
114         [imm_field(HeapType::Func), imm_field(HeapType::Extern)],
115     )?;
116     assert!(sub_ty.matches(&super_ty));
117     let not_sub_ty = StructType::new(
118         &engine,
119         [imm_field(HeapType::Func), imm_field(HeapType::Extern)],
120     )?;
121     assert!(!not_sub_ty.matches(&super_ty));
122 
123     // Depth and width.
124     let sub_ty = StructType::with_finality_and_supertype(
125         &engine,
126         Finality::Final,
127         Some(&super_ty),
128         [imm_field(HeapType::NoFunc), imm_field(HeapType::Extern)],
129     )?;
130     assert!(sub_ty.matches(&super_ty));
131     let not_sub_ty = StructType::new(
132         &engine,
133         [imm_field(HeapType::NoFunc), imm_field(HeapType::Extern)],
134     )?;
135     assert!(!not_sub_ty.matches(&super_ty));
136 
137     // Unrelated structs.
138     let not_sub_ty = StructType::new(&engine, [imm_field(HeapType::Extern)])?;
139     assert!(!not_sub_ty.matches(&super_ty));
140     let not_sub_ty = StructType::new(&engine, [field(HeapType::Extern)])?;
141     assert!(!not_sub_ty.matches(&super_ty));
142     let not_sub_ty = StructType::new(&engine, [])?;
143     assert!(!not_sub_ty.matches(&super_ty));
144 
145     Ok(())
146 }
147 
148 #[test]
struct_subtyping_fields_must_match() -> Result<()>149 fn struct_subtyping_fields_must_match() -> Result<()> {
150     let engine = Engine::default();
151 
152     let a = StructType::with_finality_and_supertype(
153         &engine,
154         Finality::NonFinal,
155         None,
156         [imm_field(HeapType::Any)],
157     )?;
158 
159     for (msg, expected, fields) in [
160         ("Missing field", false, vec![]),
161         (
162             "Non-matching field",
163             false,
164             vec![imm_field(HeapType::Extern)],
165         ),
166         ("Wrong mutability field", false, vec![field(HeapType::Any)]),
167         ("Exact match is okay", true, vec![imm_field(HeapType::Any)]),
168         (
169             "Subtype of the field is okay",
170             true,
171             vec![imm_field(HeapType::Eq)],
172         ),
173         (
174             "Extra fields are okay",
175             true,
176             vec![imm_field(HeapType::Any), imm_field(HeapType::Extern)],
177         ),
178     ] {
179         let actual =
180             StructType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&a), fields)
181                 .is_ok();
182         assert_eq!(
183             expected, actual,
184             "expected valid? {expected}; actually valid? {actual}; {msg}"
185         );
186     }
187 
188     Ok(())
189 }
190 
191 #[test]
struct_subtyping_supertype_and_finality() -> Result<()>192 fn struct_subtyping_supertype_and_finality() -> Result<()> {
193     let engine = Engine::default();
194 
195     for (expected, finality) in [(true, Finality::NonFinal), (false, Finality::Final)] {
196         let a = StructType::with_finality_and_supertype(&engine, finality, None, [])?;
197         let actual =
198             StructType::with_finality_and_supertype(&engine, Finality::Final, Some(&a), []).is_ok();
199         assert_eq!(expected, actual);
200     }
201 
202     Ok(())
203 }
204 
205 #[test]
struct_subtyping() -> Result<()>206 fn struct_subtyping() -> Result<()> {
207     let engine = Engine::default();
208 
209     // These types produce the following trees:
210     //
211     //                base               g
212     //               /    \             /
213     //              a      b           h
214     //             / \                /
215     //            c   d              i
216     //           /
217     //          e
218     //         /
219     //        f
220     let base = StructType::with_finality_and_supertype(&engine, Finality::NonFinal, None, [])?;
221     let a = StructType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&base), [])?;
222     let b = StructType::with_finality_and_supertype(
223         &engine,
224         Finality::NonFinal,
225         Some(&base),
226         // Have to add a field so that `b` doesn't dedupe to `a`.
227         [field(HeapType::Any)],
228     )?;
229     let c = StructType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&a), [])?;
230     let d = StructType::with_finality_and_supertype(
231         &engine,
232         Finality::NonFinal,
233         Some(&a),
234         // Have to add a field so that `d` doesn't dedupe to `c`.
235         [field(HeapType::Any)],
236     )?;
237     let e = StructType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&c), [])?;
238     let f = StructType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&e), [])?;
239     let g = StructType::with_finality_and_supertype(
240         &engine,
241         Finality::NonFinal,
242         None,
243         // Have to add a field so that `g` doesn't dedupe to `base`.
244         [field(HeapType::Any)],
245     )?;
246     let h = StructType::with_finality_and_supertype(
247         &engine,
248         Finality::NonFinal,
249         Some(&g),
250         [field(HeapType::Any)],
251     )?;
252     let i = StructType::with_finality_and_supertype(
253         &engine,
254         Finality::NonFinal,
255         Some(&h),
256         [field(HeapType::Any)],
257     )?;
258 
259     for (expected, sub_name, sub, sup_name, sup) in [
260         // Identity, at root.
261         (true, "base", &base, "base", &base),
262         // Identity, in middle.
263         (true, "c", &c, "c", &c),
264         // Identity, at leaf.
265         (true, "f", &f, "f", &f),
266         // Direct, at root.
267         (true, "a", &a, "base", &base),
268         // Direct, in middle.
269         (true, "c", &c, "a", &a),
270         // Direct, at leaf.
271         (true, "f", &f, "e", &e),
272         // Transitive, at root.
273         (true, "c", &c, "base", &base),
274         // Transitive, in middle.
275         (true, "e", &e, "a", &a),
276         // Transitive, at leaf.
277         (true, "f", &f, "c", &c),
278         // Unrelated roots.
279         (false, "base", &base, "g", &g),
280         (false, "g", &g, "base", &base),
281         // Unrelated siblings.
282         (false, "a", &a, "b", &b),
283         (false, "b", &b, "a", &a),
284         (false, "c", &c, "d", &d),
285         (false, "d", &d, "c", &c),
286         // Unrelated root and middle.
287         (false, "base", &base, "h", &h),
288         (false, "h", &h, "base", &base),
289         // Unrelated root and leaf.
290         (false, "base", &base, "i", &i),
291         (false, "i", &i, "base", &base),
292         // Unrelated middles.
293         (false, "a", &a, "h", &h),
294         (false, "h", &h, "a", &a),
295         // Unrelated middle and leaf.
296         (false, "a", &a, "i", &i),
297         (false, "i", &i, "a", &a),
298     ] {
299         eprintln!("expect that `{sub_name} <: {sup_name}` is `{expected}`");
300         let sub = HeapType::ConcreteStruct(sub.clone());
301         let sup = HeapType::ConcreteStruct(sup.clone());
302         let actual = sub.matches(&sup);
303         assert_eq!(expected, actual);
304     }
305 
306     Ok(())
307 }
308 
309 #[test]
array_subtyping_field_must_match() -> Result<()>310 fn array_subtyping_field_must_match() -> Result<()> {
311     let engine = Engine::default();
312 
313     let a = ArrayType::with_finality_and_supertype(
314         &engine,
315         Finality::NonFinal,
316         None,
317         imm_field(HeapType::Any),
318     )?;
319 
320     for (expected, field) in [
321         // Non-matching field.
322         (false, imm_field(HeapType::Extern)),
323         // Wrong mutability field.
324         (false, field(HeapType::Any)),
325         // Exact match is okay.
326         (true, imm_field(HeapType::Any)),
327         // Subtype of the field is okay.
328         (true, imm_field(HeapType::Eq)),
329     ] {
330         let actual =
331             ArrayType::with_finality_and_supertype(&engine, Finality::NonFinal, Some(&a), field)
332                 .is_ok();
333         assert_eq!(expected, actual);
334     }
335 
336     Ok(())
337 }
338 
339 #[test]
array_subtyping_supertype_and_finality() -> Result<()>340 fn array_subtyping_supertype_and_finality() -> Result<()> {
341     let engine = Engine::default();
342 
343     for (expected, finality) in [(true, Finality::NonFinal), (false, Finality::Final)] {
344         let superty =
345             ArrayType::with_finality_and_supertype(&engine, finality, None, field(HeapType::Any))?;
346         let actual = ArrayType::with_finality_and_supertype(
347             &engine,
348             Finality::Final,
349             Some(&superty),
350             field(HeapType::Any),
351         )
352         .is_ok();
353         assert_eq!(expected, actual);
354     }
355 
356     Ok(())
357 }
358 
359 #[test]
array_subtyping() -> Result<()>360 fn array_subtyping() -> Result<()> {
361     let engine = Engine::default();
362 
363     // These types produce the following trees:
364     //
365     //                base               g
366     //               /    \             /
367     //              a      b           h
368     //             / \                /
369     //            c   d              i
370     //           /
371     //          e
372     //         /
373     //        f
374     let base = ArrayType::with_finality_and_supertype(
375         &engine,
376         Finality::NonFinal,
377         None,
378         imm_field(HeapType::Any),
379     )?;
380     let a = ArrayType::with_finality_and_supertype(
381         &engine,
382         Finality::NonFinal,
383         Some(&base),
384         imm_field(HeapType::Any),
385     )?;
386     let b = ArrayType::with_finality_and_supertype(
387         &engine,
388         Finality::NonFinal,
389         Some(&base),
390         imm_field(HeapType::Eq),
391     )?;
392     let c = ArrayType::with_finality_and_supertype(
393         &engine,
394         Finality::NonFinal,
395         Some(&a),
396         imm_field(HeapType::Any),
397     )?;
398     let d = ArrayType::with_finality_and_supertype(
399         &engine,
400         Finality::NonFinal,
401         Some(&a),
402         imm_field(HeapType::Eq),
403     )?;
404     let e = ArrayType::with_finality_and_supertype(
405         &engine,
406         Finality::NonFinal,
407         Some(&c),
408         imm_field(HeapType::Any),
409     )?;
410     let f = ArrayType::with_finality_and_supertype(
411         &engine,
412         Finality::NonFinal,
413         Some(&e),
414         imm_field(HeapType::Any),
415     )?;
416     let g = ArrayType::with_finality_and_supertype(
417         &engine,
418         Finality::NonFinal,
419         None,
420         imm_field(HeapType::Eq),
421     )?;
422     let h = ArrayType::with_finality_and_supertype(
423         &engine,
424         Finality::NonFinal,
425         Some(&g),
426         imm_field(HeapType::Eq),
427     )?;
428     let i = ArrayType::with_finality_and_supertype(
429         &engine,
430         Finality::NonFinal,
431         Some(&h),
432         imm_field(HeapType::Eq),
433     )?;
434 
435     for (expected, sub_name, sub, sup_name, sup) in [
436         // Identity, at root.
437         (true, "base", &base, "base", &base),
438         // Identity, in middle.
439         (true, "c", &c, "c", &c),
440         // Identity, at leaf.
441         (true, "f", &f, "f", &f),
442         // Direct, at root.
443         (true, "a", &a, "base", &base),
444         // Direct, in middle.
445         (true, "c", &c, "a", &a),
446         // Direct, at leaf.
447         (true, "f", &f, "e", &e),
448         // Transitive, at root.
449         (true, "c", &c, "base", &base),
450         // Transitive, in middle.
451         (true, "e", &e, "a", &a),
452         // Transitive, at leaf.
453         (true, "f", &f, "c", &c),
454         // Unrelated roots.
455         (false, "base", &base, "g", &g),
456         (false, "g", &g, "base", &base),
457         // Unrelated siblings.
458         (false, "a", &a, "b", &b),
459         (false, "b", &b, "a", &a),
460         (false, "c", &c, "d", &d),
461         (false, "d", &d, "c", &c),
462         // Unrelated root and middle.
463         (false, "base", &base, "h", &h),
464         (false, "h", &h, "base", &base),
465         // Unrelated root and leaf.
466         (false, "base", &base, "i", &i),
467         (false, "i", &i, "base", &base),
468         // Unrelated middles.
469         (false, "a", &a, "h", &h),
470         (false, "h", &h, "a", &a),
471         // Unrelated middle and leaf.
472         (false, "a", &a, "i", &i),
473         (false, "i", &i, "a", &a),
474     ] {
475         eprintln!("expect that `{sub_name} <: {sup_name}` is `{expected}`");
476         let sub = HeapType::ConcreteArray(sub.clone());
477         let sup = HeapType::ConcreteArray(sup.clone());
478         let actual = sub.matches(&sup);
479         assert_eq!(expected, actual);
480     }
481 
482     Ok(())
483 }
484 
485 #[test]
func_subtyping_field_must_match() -> Result<()>486 fn func_subtyping_field_must_match() -> Result<()> {
487     let engine = Engine::default();
488 
489     let superty = FuncType::with_finality_and_supertype(
490         &engine,
491         Finality::NonFinal,
492         None,
493         [valty(HeapType::Struct)],
494         [valty(HeapType::Any)],
495     )?;
496 
497     for (expected, param, ret) in [
498         // Non-matching param type.
499         (false, valty(HeapType::Extern), valty(HeapType::Any)),
500         // Non-matching return type.
501         (false, valty(HeapType::Struct), valty(HeapType::Extern)),
502         // Exact match is okay.
503         (true, valty(HeapType::Struct), valty(HeapType::Any)),
504         // Subtype of the return type is okay.
505         (true, valty(HeapType::Struct), valty(HeapType::Eq)),
506         // Supertype of the param type is okay.
507         (true, valty(HeapType::Eq), valty(HeapType::Any)),
508     ] {
509         let actual = FuncType::with_finality_and_supertype(
510             &engine,
511             Finality::NonFinal,
512             Some(&superty),
513             [param],
514             [ret],
515         )
516         .is_ok();
517         assert_eq!(expected, actual);
518     }
519 
520     Ok(())
521 }
522 
523 #[test]
func_subtyping_supertype_and_finality() -> Result<()>524 fn func_subtyping_supertype_and_finality() -> Result<()> {
525     let engine = Engine::default();
526 
527     for (expected, finality) in [(true, Finality::NonFinal), (false, Finality::Final)] {
528         let superty = FuncType::with_finality_and_supertype(
529             &engine,
530             finality,
531             None,
532             [],
533             [valty(HeapType::Any)],
534         )?;
535         let actual = FuncType::with_finality_and_supertype(
536             &engine,
537             Finality::Final,
538             Some(&superty),
539             [],
540             [valty(HeapType::Any)],
541         )
542         .is_ok();
543         assert_eq!(expected, actual);
544     }
545 
546     Ok(())
547 }
548 
549 #[test]
func_subtyping() -> Result<()>550 fn func_subtyping() -> Result<()> {
551     let engine = Engine::default();
552 
553     // These types produce the following trees:
554     //
555     //                base               g
556     //               /    \             /
557     //              a      b           h
558     //             / \                /
559     //            c   d              i
560     //           /
561     //          e
562     //         /
563     //        f
564     let base = FuncType::with_finality_and_supertype(
565         &engine,
566         Finality::NonFinal,
567         None,
568         [],
569         [valty(HeapType::Any)],
570     )?;
571     let a = FuncType::with_finality_and_supertype(
572         &engine,
573         Finality::NonFinal,
574         Some(&base),
575         [],
576         [valty(HeapType::Any)],
577     )?;
578     let b = FuncType::with_finality_and_supertype(
579         &engine,
580         Finality::NonFinal,
581         Some(&base),
582         [],
583         [valty(HeapType::Eq)],
584     )?;
585     let c = FuncType::with_finality_and_supertype(
586         &engine,
587         Finality::NonFinal,
588         Some(&a),
589         [],
590         [valty(HeapType::Any)],
591     )?;
592     let d = FuncType::with_finality_and_supertype(
593         &engine,
594         Finality::NonFinal,
595         Some(&a),
596         [],
597         [valty(HeapType::Eq)],
598     )?;
599     let e = FuncType::with_finality_and_supertype(
600         &engine,
601         Finality::NonFinal,
602         Some(&c),
603         [],
604         [valty(HeapType::Any)],
605     )?;
606     let f = FuncType::with_finality_and_supertype(
607         &engine,
608         Finality::NonFinal,
609         Some(&e),
610         [],
611         [valty(HeapType::Any)],
612     )?;
613     let g = FuncType::with_finality_and_supertype(
614         &engine,
615         Finality::NonFinal,
616         None,
617         [],
618         [valty(HeapType::Eq)],
619     )?;
620     let h = FuncType::with_finality_and_supertype(
621         &engine,
622         Finality::NonFinal,
623         Some(&g),
624         [],
625         [valty(HeapType::Eq)],
626     )?;
627     let i = FuncType::with_finality_and_supertype(
628         &engine,
629         Finality::NonFinal,
630         Some(&h),
631         [],
632         [valty(HeapType::Eq)],
633     )?;
634 
635     for (expected, sub_name, sub, sup_name, sup) in [
636         // Identity, at root.
637         (true, "base", &base, "base", &base),
638         // Identity, in middle.
639         (true, "c", &c, "c", &c),
640         // Identity, at leaf.
641         (true, "f", &f, "f", &f),
642         // Direct, at root.
643         (true, "a", &a, "base", &base),
644         // Direct, in middle.
645         (true, "c", &c, "a", &a),
646         // Direct, at leaf.
647         (true, "f", &f, "e", &e),
648         // Transitive, at root.
649         (true, "c", &c, "base", &base),
650         // Transitive, in middle.
651         (true, "e", &e, "a", &a),
652         // Transitive, at leaf.
653         (true, "f", &f, "c", &c),
654         // Unrelated roots.
655         (false, "base", &base, "g", &g),
656         (false, "g", &g, "base", &base),
657         // Unrelated siblings.
658         (false, "a", &a, "b", &b),
659         (false, "b", &b, "a", &a),
660         (false, "c", &c, "d", &d),
661         (false, "d", &d, "c", &c),
662         // Unrelated root and middle.
663         (false, "base", &base, "h", &h),
664         (false, "h", &h, "base", &base),
665         // Unrelated root and leaf.
666         (false, "base", &base, "i", &i),
667         (false, "i", &i, "base", &base),
668         // Unrelated middles.
669         (false, "a", &a, "h", &h),
670         (false, "h", &h, "a", &a),
671         // Unrelated middle and leaf.
672         (false, "a", &a, "i", &i),
673         (false, "i", &i, "a", &a),
674     ] {
675         eprintln!("expect that `{sub_name} <: {sup_name}` is `{expected}`");
676         let sub = HeapType::ConcreteFunc(sub.clone());
677         let sup = HeapType::ConcreteFunc(sup.clone());
678         let actual = sub.matches(&sup);
679         assert_eq!(expected, actual);
680     }
681 
682     Ok(())
683 }
684 
685 #[test]
heap_type_matches_noexn() -> Result<()>686 fn heap_type_matches_noexn() -> Result<()> {
687     // Test that NoExn only matches exception-related types.
688     // NoExn should NOT match unrelated heap types like Func, Extern, Any, etc.
689 
690     // NoExn should match exception hierarchy types
691     assert!(HeapType::NoExn.matches(&HeapType::Exn));
692     assert!(HeapType::NoExn.matches(&HeapType::NoExn));
693 
694     // NoExn should NOT match types outside the exception hierarchy
695     assert!(!HeapType::NoExn.matches(&HeapType::Func));
696     assert!(!HeapType::NoExn.matches(&HeapType::NoFunc));
697     assert!(!HeapType::NoExn.matches(&HeapType::Extern));
698     assert!(!HeapType::NoExn.matches(&HeapType::NoExtern));
699     assert!(!HeapType::NoExn.matches(&HeapType::Any));
700     assert!(!HeapType::NoExn.matches(&HeapType::Eq));
701     assert!(!HeapType::NoExn.matches(&HeapType::I31));
702     assert!(!HeapType::NoExn.matches(&HeapType::Struct));
703     assert!(!HeapType::NoExn.matches(&HeapType::Array));
704     assert!(!HeapType::NoExn.matches(&HeapType::None));
705     assert!(!HeapType::NoExn.matches(&HeapType::Cont));
706     assert!(!HeapType::NoExn.matches(&HeapType::NoCont));
707 
708     Ok(())
709 }
710