1 use wasmtime::*;
2
3 #[test]
bad_globals()4 fn bad_globals() {
5 let mut store = Store::<()>::default();
6 let ty = GlobalType::new(ValType::I32, Mutability::Var);
7 assert!(Global::new(&mut store, ty.clone(), Val::I64(0)).is_err());
8 assert!(Global::new(&mut store, ty.clone(), Val::F32(0)).is_err());
9 assert!(Global::new(&mut store, ty.clone(), Val::F64(0)).is_err());
10
11 let ty = GlobalType::new(ValType::I32, Mutability::Const);
12 let g = Global::new(&mut store, ty.clone(), Val::I32(0)).unwrap();
13 assert!(g.set(&mut store, Val::I32(1)).is_err());
14
15 let ty = GlobalType::new(ValType::I32, Mutability::Var);
16 let g = Global::new(&mut store, ty.clone(), Val::I32(0)).unwrap();
17 assert!(g.set(&mut store, Val::I64(0)).is_err());
18 }
19
20 #[test]
bad_tables()21 fn bad_tables() {
22 let mut store = Store::<()>::default();
23
24 // mismatched initializer
25 let ty = TableType::new(RefType::FUNCREF, 0, Some(1));
26 assert!(Table::new(&mut store, ty.clone(), Ref::Extern(None)).is_err());
27
28 // get out of bounds
29 let ty = TableType::new(RefType::FUNCREF, 0, Some(1));
30 let t = Table::new(&mut store, ty.clone(), Ref::Func(None)).unwrap();
31 assert!(t.get(&mut store, 0).is_none());
32 assert!(t.get(&mut store, u64::from(u32::MAX)).is_none());
33 assert!(t.get(&mut store, u64::MAX).is_none());
34
35 // set out of bounds or wrong type
36 let ty = TableType::new(RefType::FUNCREF, 1, Some(1));
37 let t = Table::new(&mut store, ty.clone(), Ref::Func(None)).unwrap();
38 assert!(t.set(&mut store, 0, Ref::Extern(None)).is_err());
39 assert!(t.set(&mut store, 0, Ref::Func(None)).is_ok());
40 assert!(t.set(&mut store, 1, Ref::Func(None)).is_err());
41
42 // grow beyond max
43 let ty = TableType::new(RefType::FUNCREF, 1, Some(1));
44 let t = Table::new(&mut store, ty.clone(), Ref::Func(None)).unwrap();
45 assert!(t.grow(&mut store, 0, Ref::Func(None)).is_ok());
46 assert!(t.grow(&mut store, 1, Ref::Func(None)).is_err());
47 assert_eq!(t.size(&store), 1);
48
49 // grow wrong type
50 let ty = TableType::new(RefType::FUNCREF, 1, Some(2));
51 let t = Table::new(&mut store, ty.clone(), Ref::Func(None)).unwrap();
52 assert!(t.grow(&mut store, 1, Ref::Extern(None)).is_err());
53 assert_eq!(t.size(&store), 1);
54 }
55
56 #[test]
57 #[cfg_attr(miri, ignore)]
cross_store() -> wasmtime::Result<()>58 fn cross_store() -> wasmtime::Result<()> {
59 let mut cfg = Config::new();
60 cfg.wasm_reference_types(true);
61 let engine = Engine::new(&cfg)?;
62 let mut store1 = Store::new(&engine, ());
63 let mut store2 = Store::new(&engine, ());
64
65 eprintln!("============ Cross-store instantiation ==============");
66
67 let func = Func::wrap(&mut store2, || {});
68 let ty = GlobalType::new(ValType::I32, Mutability::Const);
69 let global = Global::new(&mut store2, ty, Val::I32(0))?;
70 let ty = MemoryType::new(1, None);
71 let memory = Memory::new(&mut store2, ty)?;
72 let ty = TableType::new(RefType::FUNCREF, 1, None);
73 let table = Table::new(&mut store2, ty, Ref::Func(None))?;
74
75 let need_func = Module::new(&engine, r#"(module (import "" "" (func)))"#)?;
76 assert!(Instance::new(&mut store1, &need_func, &[func.into()]).is_err());
77
78 let need_global = Module::new(&engine, r#"(module (import "" "" (global i32)))"#)?;
79 assert!(Instance::new(&mut store1, &need_global, &[global.into()]).is_err());
80
81 let need_table = Module::new(&engine, r#"(module (import "" "" (table 1 funcref)))"#)?;
82 assert!(Instance::new(&mut store1, &need_table, &[table.into()]).is_err());
83
84 let need_memory = Module::new(&engine, r#"(module (import "" "" (memory 1)))"#)?;
85 assert!(Instance::new(&mut store1, &need_memory, &[memory.into()]).is_err());
86
87 eprintln!("============ Cross-store globals ==============");
88
89 let store1val = Val::FuncRef(Some(Func::wrap(&mut store1, || {})));
90 let store1ref = store1val.ref_().unwrap();
91 let store2val = Val::FuncRef(Some(Func::wrap(&mut store2, || {})));
92 let store2ref = store2val.ref_().unwrap();
93
94 let ty = GlobalType::new(ValType::FUNCREF, Mutability::Var);
95 assert!(Global::new(&mut store2, ty.clone(), store1val).is_err());
96 if let Ok(g) = Global::new(&mut store2, ty.clone(), store2val) {
97 assert!(g.set(&mut store2, store1val).is_err());
98 }
99
100 eprintln!("============ Cross-store tables ==============");
101
102 let ty = TableType::new(RefType::FUNCREF, 1, None);
103 assert!(Table::new(&mut store2, ty.clone(), store1ref.clone()).is_err());
104 let t1 = Table::new(&mut store2, ty.clone(), store2ref.clone())?;
105 assert!(t1.set(&mut store2, 0, store1ref.clone()).is_err());
106 assert!(t1.grow(&mut store2, 0, store1ref.clone()).is_err());
107 assert!(t1.fill(&mut store2, 0, store1ref.clone(), 1).is_err());
108
109 eprintln!("============ Cross-store funcs ==============");
110
111 let module = Module::new(&engine, r#"(module (func (export "f") (param funcref)))"#)?;
112 let s1_inst = Instance::new(&mut store1, &module, &[])?;
113 let s2_inst = Instance::new(&mut store2, &module, &[])?;
114 let s1_f = s1_inst.get_func(&mut store1, "f").unwrap();
115 let s2_f = s2_inst.get_func(&mut store2, "f").unwrap();
116
117 assert!(
118 s1_f.call(&mut store1, &[Val::FuncRef(None)], &mut [])
119 .is_ok()
120 );
121 assert!(
122 s2_f.call(&mut store2, &[Val::FuncRef(None)], &mut [])
123 .is_ok()
124 );
125 assert!(
126 s1_f.call(&mut store1, &[Some(s1_f).into()], &mut [])
127 .is_ok()
128 );
129 assert!(
130 s1_f.call(&mut store1, &[Some(s2_f).into()], &mut [])
131 .is_err()
132 );
133 assert!(
134 s2_f.call(&mut store2, &[Some(s1_f).into()], &mut [])
135 .is_err()
136 );
137 assert!(
138 s2_f.call(&mut store2, &[Some(s2_f).into()], &mut [])
139 .is_ok()
140 );
141
142 let s1_f_t = s1_f.typed::<Option<Func>, ()>(&store1)?;
143 let s2_f_t = s2_f.typed::<Option<Func>, ()>(&store2)?;
144
145 assert!(s1_f_t.call(&mut store1, None).is_ok());
146 assert!(s2_f_t.call(&mut store2, None).is_ok());
147 assert!(s1_f_t.call(&mut store1, Some(s1_f)).is_ok());
148 assert!(s1_f_t.call(&mut store1, Some(s2_f)).is_err());
149 assert!(s2_f_t.call(&mut store2, Some(s1_f)).is_err());
150 assert!(s2_f_t.call(&mut store2, Some(s2_f)).is_ok());
151
152 Ok(())
153 }
154
155 #[test]
get_set_externref_globals_via_api() -> wasmtime::Result<()>156 fn get_set_externref_globals_via_api() -> wasmtime::Result<()> {
157 let mut cfg = Config::new();
158 cfg.wasm_reference_types(true);
159 let engine = Engine::new(&cfg)?;
160 let mut store = Store::new(&engine, ());
161
162 // Initialize with a null externref.
163
164 let global = Global::new(
165 &mut store,
166 GlobalType::new(ValType::EXTERNREF, Mutability::Var),
167 Val::ExternRef(None),
168 )?;
169 assert!(global.get(&mut store).unwrap_externref().is_none());
170
171 let hello = ExternRef::new(&mut store, "hello".to_string())?;
172 global.set(&mut store, hello.into())?;
173 let r = global.get(&mut store).unwrap_externref().cloned().unwrap();
174 assert!(
175 r.data(&store)?
176 .expect("should have host data")
177 .is::<String>()
178 );
179 assert_eq!(
180 r.data(&store)?
181 .expect("should have host data")
182 .downcast_ref::<String>()
183 .unwrap(),
184 "hello"
185 );
186
187 // Initialize with a non-null externref.
188
189 let externref = ExternRef::new(&mut store, 42_i32)?;
190 let global = Global::new(
191 &mut store,
192 GlobalType::new(ValType::EXTERNREF, Mutability::Const),
193 externref.into(),
194 )?;
195 let r = global.get(&mut store).unwrap_externref().cloned().unwrap();
196 assert!(r.data(&store)?.expect("should have host data").is::<i32>());
197 assert_eq!(
198 r.data(&store)?
199 .expect("should have host data")
200 .downcast_ref::<i32>()
201 .copied()
202 .unwrap(),
203 42
204 );
205
206 Ok(())
207 }
208
209 #[test]
get_set_funcref_globals_via_api() -> wasmtime::Result<()>210 fn get_set_funcref_globals_via_api() -> wasmtime::Result<()> {
211 let mut cfg = Config::new();
212 cfg.wasm_reference_types(true);
213 let engine = Engine::new(&cfg)?;
214 let mut store = Store::new(&engine, ());
215
216 let f = Func::wrap(&mut store, || {});
217
218 // Initialize with a null funcref.
219
220 let global = Global::new(
221 &mut store,
222 GlobalType::new(ValType::FUNCREF, Mutability::Var),
223 Val::FuncRef(None),
224 )?;
225 assert!(global.get(&mut store).unwrap_funcref().is_none());
226
227 global.set(&mut store, Val::FuncRef(Some(f)))?;
228 let f2 = global.get(&mut store).unwrap_funcref().cloned().unwrap();
229 assert!(FuncType::eq(&f.ty(&store), &f2.ty(&store)));
230
231 // Initialize with a non-null funcref.
232
233 let global = Global::new(
234 &mut store,
235 GlobalType::new(ValType::FUNCREF, Mutability::Var),
236 Val::FuncRef(Some(f)),
237 )?;
238 let f2 = global.get(&mut store).unwrap_funcref().cloned().unwrap();
239 assert!(FuncType::eq(&f.ty(&store), &f2.ty(&store)));
240
241 Ok(())
242 }
243
244 #[test]
create_get_set_funcref_tables_via_api() -> wasmtime::Result<()>245 fn create_get_set_funcref_tables_via_api() -> wasmtime::Result<()> {
246 let mut cfg = Config::new();
247 cfg.wasm_reference_types(true);
248 let engine = Engine::new(&cfg)?;
249 let mut store = Store::new(&engine, ());
250
251 let table_ty = TableType::new(RefType::FUNCREF, 10, None);
252 let init = Ref::Func(Some(Func::wrap(&mut store, || {})));
253 let table = Table::new(&mut store, table_ty, init)?;
254
255 assert!(table.get(&mut store, 5).unwrap().unwrap_func().is_some());
256 table.set(&mut store, 5, Ref::Func(None))?;
257 assert!(table.get(&mut store, 5).unwrap().unwrap_func().is_none());
258
259 Ok(())
260 }
261
262 #[test]
fill_funcref_tables_via_api() -> wasmtime::Result<()>263 fn fill_funcref_tables_via_api() -> wasmtime::Result<()> {
264 let mut cfg = Config::new();
265 cfg.wasm_reference_types(true);
266 let engine = Engine::new(&cfg)?;
267 let mut store = Store::new(&engine, ());
268
269 let table_ty = TableType::new(RefType::FUNCREF, 10, None);
270 let table = Table::new(&mut store, table_ty, Ref::Func(None))?;
271
272 for i in 0..10 {
273 assert!(table.get(&mut store, i).unwrap().unwrap_func().is_none());
274 }
275
276 let fill = Ref::Func(Some(Func::wrap(&mut store, || {})));
277 table.fill(&mut store, 2, fill, 4)?;
278
279 for i in (0..2).chain(7..10) {
280 assert!(table.get(&mut store, i).unwrap().unwrap_func().is_none());
281 }
282 for i in 2..6 {
283 assert!(table.get(&mut store, i).unwrap().unwrap_func().is_some());
284 }
285
286 Ok(())
287 }
288
289 #[test]
grow_funcref_tables_via_api() -> wasmtime::Result<()>290 fn grow_funcref_tables_via_api() -> wasmtime::Result<()> {
291 let mut cfg = Config::new();
292 cfg.wasm_reference_types(true);
293 let engine = Engine::new(&cfg)?;
294 let mut store = Store::new(&engine, ());
295
296 let table_ty = TableType::new(RefType::FUNCREF, 10, None);
297 let table = Table::new(&mut store, table_ty, Ref::Func(None))?;
298
299 assert_eq!(table.size(&store), 10);
300 table.grow(&mut store, 3, Ref::Func(None))?;
301 assert_eq!(table.size(&store), 13);
302
303 Ok(())
304 }
305
306 #[test]
create_get_set_externref_tables_via_api() -> wasmtime::Result<()>307 fn create_get_set_externref_tables_via_api() -> wasmtime::Result<()> {
308 let mut cfg = Config::new();
309 cfg.wasm_reference_types(true);
310 let engine = Engine::new(&cfg)?;
311 let mut store = Store::new(&engine, ());
312
313 let table_ty = TableType::new(RefType::EXTERNREF, 10, None);
314 let init = ExternRef::new(&mut store, 42_usize)?;
315 let table = Table::new(&mut store, table_ty, init.into())?;
316
317 assert_eq!(
318 *table
319 .get(&mut store, 5)
320 .unwrap()
321 .unwrap_extern()
322 .unwrap()
323 .data(&store)?
324 .expect("should have host data")
325 .downcast_ref::<usize>()
326 .unwrap(),
327 42
328 );
329 table.set(&mut store, 5, Ref::Extern(None))?;
330 assert!(table.get(&mut store, 5).unwrap().unwrap_extern().is_none());
331
332 Ok(())
333 }
334
335 #[test]
fill_externref_tables_via_api() -> wasmtime::Result<()>336 fn fill_externref_tables_via_api() -> wasmtime::Result<()> {
337 let mut cfg = Config::new();
338 cfg.wasm_reference_types(true);
339 let engine = Engine::new(&cfg)?;
340 let mut store = Store::new(&engine, ());
341
342 let table_ty = TableType::new(RefType::EXTERNREF, 10, None);
343 let table = Table::new(&mut store, table_ty, Ref::Extern(None))?;
344
345 for i in 0..10 {
346 assert!(table.get(&mut store, i).unwrap().unwrap_extern().is_none());
347 }
348
349 let val = ExternRef::new(&mut store, 42_usize)?;
350 table.fill(&mut store, 2, val.into(), 4)?;
351
352 for i in (0..2).chain(7..10) {
353 assert!(table.get(&mut store, i).unwrap().unwrap_extern().is_none());
354 }
355 for i in 2..6 {
356 assert_eq!(
357 *table
358 .get(&mut store, i)
359 .unwrap()
360 .unwrap_extern()
361 .unwrap()
362 .data(&store)?
363 .expect("should have host data")
364 .downcast_ref::<usize>()
365 .unwrap(),
366 42
367 );
368 }
369
370 Ok(())
371 }
372
373 #[test]
grow_externref_tables_via_api() -> wasmtime::Result<()>374 fn grow_externref_tables_via_api() -> wasmtime::Result<()> {
375 let mut cfg = Config::new();
376 cfg.wasm_reference_types(true);
377 let engine = Engine::new(&cfg)?;
378 let mut store = Store::new(&engine, ());
379
380 let table_ty = TableType::new(RefType::EXTERNREF, 10, None);
381 let table = Table::new(&mut store, table_ty, Ref::Extern(None))?;
382
383 assert_eq!(table.size(&store), 10);
384 table.grow(&mut store, 3, Ref::Extern(None))?;
385 assert_eq!(table.size(&store), 13);
386
387 Ok(())
388 }
389
390 #[test]
read_write_memory_via_api()391 fn read_write_memory_via_api() {
392 let cfg = Config::new();
393 let mut store = Store::new(&Engine::new(&cfg).unwrap(), ());
394 let ty = MemoryType::new(1, None);
395 let mem = Memory::new(&mut store, ty).unwrap();
396 mem.grow(&mut store, 1).unwrap();
397
398 let value = b"hello wasm";
399 let size = mem.data_size(&store);
400 mem.write(&mut store, size - value.len(), value).unwrap();
401
402 let mut buffer = [0u8; 10];
403 mem.read(&store, mem.data_size(&store) - buffer.len(), &mut buffer)
404 .unwrap();
405 assert_eq!(value, &buffer);
406
407 // Error conditions.
408
409 // Out of bounds write.
410
411 let size = mem.data_size(&store);
412 let res = mem.write(&mut store, size - value.len() + 1, value);
413 assert!(res.is_err());
414 assert_ne!(
415 mem.data(&store)[mem.data_size(&store) - value.len() + 1],
416 value[0],
417 "no data is written",
418 );
419
420 // Out of bounds read.
421
422 buffer[0] = 0x42;
423 let res = mem.read(
424 &store,
425 mem.data_size(&store) - buffer.len() + 1,
426 &mut buffer,
427 );
428 assert!(res.is_err());
429 assert_eq!(buffer[0], 0x42, "no data is read");
430
431 // Read offset overflow.
432 let res = mem.read(&store, usize::MAX, &mut buffer);
433 assert!(res.is_err());
434
435 // Write offset overflow.
436 let res = mem.write(&mut store, usize::MAX, &buffer);
437 assert!(res.is_err());
438 }
439
440 // Returns (a, b, c) pairs of function type and function such that
441 //
442 // a <: b <: c
443 //
444 // The functions will panic if actually called.
dummy_funcs_and_subtypes( store: &mut Store<()>, ) -> (FuncType, Func, FuncType, Func, FuncType, Func)445 fn dummy_funcs_and_subtypes(
446 store: &mut Store<()>,
447 ) -> (FuncType, Func, FuncType, Func, FuncType, Func) {
448 let engine = store.engine().clone();
449
450 let c_ty = FuncType::with_finality_and_supertype(
451 &engine,
452 Finality::NonFinal,
453 None,
454 [],
455 [ValType::FUNCREF],
456 )
457 .unwrap();
458 let c = Func::new(
459 &mut *store,
460 c_ty.clone(),
461 |_caller, _args, _results| unreachable!(),
462 );
463
464 let b_ty = FuncType::with_finality_and_supertype(
465 &engine,
466 Finality::NonFinal,
467 Some(&c_ty),
468 [],
469 [ValType::Ref(RefType::new(
470 true,
471 HeapType::ConcreteFunc(FuncType::new(&engine, None, None)),
472 ))],
473 )
474 .unwrap();
475 let b = Func::new(
476 &mut *store,
477 b_ty.clone(),
478 |_caller, _args, _results| unreachable!(),
479 );
480
481 let a_ty = FuncType::with_finality_and_supertype(
482 &engine,
483 Finality::NonFinal,
484 Some(&b_ty),
485 [],
486 [ValType::NULLFUNCREF],
487 )
488 .unwrap();
489 let a = Func::new(
490 &mut *store,
491 a_ty.clone(),
492 |_caller, _args, _results| unreachable!(),
493 );
494
495 assert!(a_ty.matches(&a_ty));
496 assert!(a_ty.matches(&b_ty));
497 assert!(a_ty.matches(&c_ty));
498 assert!(!b_ty.matches(&a_ty));
499 assert!(b_ty.matches(&b_ty));
500 assert!(b_ty.matches(&c_ty));
501 assert!(!c_ty.matches(&a_ty));
502 assert!(!c_ty.matches(&b_ty));
503 assert!(c_ty.matches(&c_ty));
504
505 assert!(a.matches_ty(&store, &a_ty));
506 assert!(a.matches_ty(&store, &b_ty));
507 assert!(a.matches_ty(&store, &c_ty));
508 assert!(!b.matches_ty(&store, &a_ty));
509 assert!(b.matches_ty(&store, &b_ty));
510 assert!(b.matches_ty(&store, &c_ty));
511 assert!(!c.matches_ty(&store, &a_ty));
512 assert!(!c.matches_ty(&store, &b_ty));
513 assert!(c.matches_ty(&store, &c_ty));
514
515 (a_ty, a, b_ty, b, c_ty, c)
516 }
517
518 #[test]
519 #[cfg_attr(miri, ignore)]
new_global_func_subtyping()520 fn new_global_func_subtyping() {
521 let engine = Engine::default();
522 let mut store = Store::new(&engine, ());
523
524 let (a_ty, a, b_ty, b, c_ty, c) = dummy_funcs_and_subtypes(&mut store);
525
526 for (global_ty, a_expected, b_expected, c_expected) in [
527 // a <: a, b </: a, c </: a
528 (a_ty, true, false, false),
529 // a <: b, b <: b, c </: a
530 (b_ty, true, true, false),
531 // a <: c, b <: c, c <: c
532 (c_ty, true, true, true),
533 ] {
534 for (val, expected) in [(a, a_expected), (b, b_expected), (c, c_expected)] {
535 for mutability in [Mutability::Var, Mutability::Const] {
536 match Global::new(
537 &mut store,
538 GlobalType::new(
539 RefType::new(true, global_ty.clone().into()).into(),
540 mutability,
541 ),
542 val.into(),
543 ) {
544 Ok(_) if expected => {}
545 Ok(_) => panic!("should have got type mismatch, but didn't"),
546 Err(e) if !expected => assert!(e.to_string().contains("type mismatch")),
547 Err(e) => panic!("should have created global, but got error: {e:?}"),
548 }
549 }
550 }
551 }
552 }
553
554 #[test]
555 #[cfg_attr(miri, ignore)]
global_set_func_subtyping()556 fn global_set_func_subtyping() {
557 let engine = Engine::default();
558 let mut store = Store::new(&engine, ());
559
560 let (a_ty, a, b_ty, b, c_ty, c) = dummy_funcs_and_subtypes(&mut store);
561
562 for (global_ty, a_expected, b_expected, c_expected) in [
563 // a <: a, b </: a, c </: a
564 (a_ty, true, false, false),
565 // a <: b, b <: b, c </: a
566 (b_ty, true, true, false),
567 // a <: c, b <: c, c <: c
568 (c_ty, true, true, true),
569 ] {
570 let global = Global::new(
571 &mut store,
572 GlobalType::new(
573 RefType::new(true, global_ty.clone().into()).into(),
574 Mutability::Var,
575 ),
576 Val::null_func_ref(),
577 )
578 .unwrap();
579
580 for (val, expected) in [(a, a_expected), (b, b_expected), (c, c_expected)] {
581 match global.set(&mut store, val.into()) {
582 Ok(_) if expected => {}
583 Ok(_) => panic!("should have got type mismatch, but didn't"),
584 Err(e) if !expected => assert!(e.to_string().contains("type mismatch")),
585 Err(e) => panic!("should have set global, but got error: {e:?}"),
586 }
587 }
588 }
589 }
590
591 #[test]
592 #[cfg_attr(miri, ignore)]
new_table_func_subtyping()593 fn new_table_func_subtyping() {
594 let engine = Engine::default();
595 let mut store = Store::new(&engine, ());
596
597 let (a_ty, a, b_ty, b, c_ty, c) = dummy_funcs_and_subtypes(&mut store);
598
599 for (table_ty, a_expected, b_expected, c_expected) in [
600 // a <: a, b </: a, c </: a
601 (a_ty, true, false, false),
602 // a <: b, b <: b, c </: a
603 (b_ty, true, true, false),
604 // a <: c, b <: c, c <: c
605 (c_ty, true, true, true),
606 ] {
607 for (val, expected) in [(a, a_expected), (b, b_expected), (c, c_expected)] {
608 match Table::new(
609 &mut store,
610 TableType::new(RefType::new(true, table_ty.clone().into()), 0, None),
611 val.into(),
612 ) {
613 Ok(_) if expected => {}
614 Ok(_) => panic!("should have got type mismatch, but didn't"),
615 Err(e) if !expected => assert!(e.to_string().contains("type mismatch")),
616 Err(e) => panic!("should have created table, but got error: {e:?}"),
617 }
618 }
619 }
620 }
621
622 #[test]
623 #[cfg_attr(miri, ignore)]
table_set_func_subtyping()624 fn table_set_func_subtyping() {
625 let engine = Engine::default();
626 let mut store = Store::new(&engine, ());
627
628 let (a_ty, a, b_ty, b, c_ty, c) = dummy_funcs_and_subtypes(&mut store);
629
630 for (table_ty, a_expected, b_expected, c_expected) in [
631 // a <: a, b </: a, c </: a
632 (a_ty, true, false, false),
633 // a <: b, b <: b, c </: a
634 (b_ty, true, true, false),
635 // a <: c, b <: c, c <: c
636 (c_ty, true, true, true),
637 ] {
638 let table = Table::new(
639 &mut store,
640 TableType::new(RefType::new(true, table_ty.clone().into()), 3, None),
641 Ref::Func(None),
642 )
643 .unwrap();
644
645 let mut i = 0;
646 for (val, expected) in [(a, a_expected), (b, b_expected), (c, c_expected)] {
647 assert!(table.get(&mut store, i).expect("in bounds").is_null());
648
649 match table.set(&mut store, i, val.into()) {
650 Ok(_) if expected => {}
651 Ok(_) => panic!("should have got type mismatch, but didn't"),
652 Err(e) if !expected => assert!(e.to_string().contains("type mismatch")),
653 Err(e) => panic!("should have set table element, but got error: {e:?}"),
654 }
655
656 if expected {
657 assert!(table.get(&mut store, i).expect("in bounds").is_non_null());
658 }
659
660 i += 1;
661 }
662 }
663 }
664
665 #[test]
666 #[cfg_attr(miri, ignore)]
table_grow_func_subtyping()667 fn table_grow_func_subtyping() {
668 let engine = Engine::default();
669 let mut store = Store::new(&engine, ());
670
671 let (a_ty, a, b_ty, b, c_ty, c) = dummy_funcs_and_subtypes(&mut store);
672
673 for (table_ty, a_expected, b_expected, c_expected) in [
674 // a <: a, b </: a, c </: a
675 (a_ty, true, false, false),
676 // a <: b, b <: b, c </: a
677 (b_ty, true, true, false),
678 // a <: c, b <: c, c <: c
679 (c_ty, true, true, true),
680 ] {
681 let table = Table::new(
682 &mut store,
683 TableType::new(RefType::new(true, table_ty.clone().into()), 3, None),
684 Ref::Func(None),
685 )
686 .unwrap();
687
688 for (val, expected) in [(a, a_expected), (b, b_expected), (c, c_expected)] {
689 let orig_size = table.size(&store);
690
691 match table.grow(&mut store, 10, val.into()) {
692 Ok(_) if expected => {}
693 Ok(_) => panic!("should have got type mismatch, but didn't"),
694 Err(e) if !expected => assert!(e.to_string().contains("type mismatch")),
695 Err(e) => panic!("should have done table grow, but got error: {e:?}"),
696 }
697
698 if expected {
699 let new_size = table.size(&store);
700 assert_eq!(new_size, orig_size + 10);
701 for i in orig_size..new_size {
702 assert!(table.get(&mut store, i).expect("in bounds").is_non_null());
703 }
704 }
705 }
706 }
707 }
708
709 #[test]
710 #[cfg_attr(miri, ignore)]
table_fill_func_subtyping()711 fn table_fill_func_subtyping() {
712 let engine = Engine::default();
713 let mut store = Store::new(&engine, ());
714
715 let (a_ty, a, b_ty, b, c_ty, c) = dummy_funcs_and_subtypes(&mut store);
716
717 for (table_ty, a_expected, b_expected, c_expected) in [
718 // a <: a, b </: a, c </: a
719 (a_ty, true, false, false),
720 // a <: b, b <: b, c </: a
721 (b_ty, true, true, false),
722 // a <: c, b <: c, c <: c
723 (c_ty, true, true, true),
724 ] {
725 for (val, expected) in [(a, a_expected), (b, b_expected), (c, c_expected)] {
726 let table = Table::new(
727 &mut store,
728 TableType::new(RefType::new(true, table_ty.clone().into()), 10, None),
729 Ref::Func(None),
730 )
731 .unwrap();
732
733 match table.fill(&mut store, 3, val.into(), 4) {
734 Ok(_) if expected => {}
735 Ok(_) => panic!("should have got type mismatch, but didn't"),
736 Err(e) if !expected => assert!(e.to_string().contains("type mismatch")),
737 Err(e) => panic!("should have done table fill, but got error: {e:?}"),
738 }
739
740 if expected {
741 for i in 3..7 {
742 assert!(table.get(&mut store, i).expect("in bounds").is_non_null());
743 }
744 }
745 }
746 }
747 }
748
749 #[test]
750 #[cfg_attr(miri, ignore)]
table_copy_func_subtyping()751 fn table_copy_func_subtyping() {
752 let _ = env_logger::try_init();
753
754 let engine = Engine::default();
755 let mut store = Store::new(&engine, ());
756
757 let (a_ty, a, b_ty, b, c_ty, c) = dummy_funcs_and_subtypes(&mut store);
758
759 for (dst_ty, a_expected, b_expected, c_expected) in [
760 // a <: a, b </: a, c </: a
761 (a_ty.clone(), true, false, false),
762 // a <: b, b <: b, c </: a
763 (b_ty.clone(), true, true, false),
764 // a <: c, b <: c, c <: c
765 (c_ty.clone(), true, true, true),
766 ] {
767 let dest_table = Table::new(
768 &mut store,
769 TableType::new(RefType::new(true, dst_ty.clone().into()), 10, None),
770 Ref::Func(None),
771 )
772 .unwrap();
773
774 for (val, src_ty, expected) in [
775 (a, a_ty.clone(), a_expected),
776 (b, b_ty.clone(), b_expected),
777 (c, c_ty.clone(), c_expected),
778 ] {
779 dest_table.fill(&mut store, 0, Ref::Func(None), 10).unwrap();
780
781 let src_table = Table::new(
782 &mut store,
783 TableType::new(RefType::new(true, src_ty.into()), 10, None),
784 val.into(),
785 )
786 .unwrap();
787
788 match Table::copy(&mut store, &dest_table, 2, &src_table, 3, 5) {
789 Ok(_) if expected => {}
790 Ok(_) => panic!("should have got type mismatch, but didn't"),
791 Err(e) if !expected => assert!(e.to_string().contains("type mismatch")),
792 Err(e) => panic!("should have done table copy, but got error: {e:?}"),
793 }
794
795 if expected {
796 for i in 2..7 {
797 assert!(
798 dest_table
799 .get(&mut store, i)
800 .expect("in bounds")
801 .is_non_null()
802 );
803 }
804 }
805 }
806 }
807 }
808