1 #![cfg(not(miri))]
2 
3 use super::engine;
4 use anyhow::Result;
5 use wasmtime::{
6     Config, Engine, Store,
7     component::{Component, Linker},
8 };
9 
10 mod ownership;
11 mod results;
12 
13 mod no_imports {
14     use super::*;
15     use std::rc::Rc;
16 
17     wasmtime::component::bindgen!({
18         inline: "
19             package foo:foo;
20 
21             world no-imports {
22                 export foo: interface {
23                     foo: func();
24                 }
25 
26                 export bar: func();
27             }
28         ",
29     });
30 
31     #[test]
32     fn run() -> Result<()> {
33         let engine = engine();
34 
35         let component = Component::new(
36             &engine,
37             r#"
38                 (component
39                     (core module $m
40                         (func (export ""))
41                     )
42                     (core instance $i (instantiate $m))
43 
44                     (func $f (export "bar") (canon lift (core func $i "")))
45 
46                     (instance $i (export "foo" (func $f)))
47                     (export "foo" (instance $i))
48                 )
49             "#,
50         )?;
51 
52         let linker = Linker::new(&engine);
53         let mut store = Store::new(&engine, ());
54         let no_imports = NoImports::instantiate(&mut store, &component, &linker)?;
55         no_imports.call_bar(&mut store)?;
56         no_imports.foo().call_foo(&mut store)?;
57 
58         let linker = Linker::new(&engine);
59         let mut non_send_store = Store::new(&engine, Rc::new(()));
60         let no_imports = NoImports::instantiate(&mut non_send_store, &component, &linker)?;
61         no_imports.call_bar(&mut non_send_store)?;
62         no_imports.foo().call_foo(&mut non_send_store)?;
63         Ok(())
64     }
65 }
66 
67 mod no_imports_concurrent {
68     use super::*;
69     use futures::{
70         FutureExt,
71         stream::{FuturesUnordered, TryStreamExt},
72     };
73 
74     wasmtime::component::bindgen!({
75         inline: "
76             package foo:foo;
77 
78             world no-imports {
79                 export foo: interface {
80                     foo: async func();
81                 }
82 
83                 export bar: async func();
84             }
85         ",
86     });
87 
88     #[tokio::test]
89     async fn run() -> Result<()> {
90         let mut config = Config::new();
91         config.wasm_component_model_async(true);
92         config.async_support(true);
93         let engine = &Engine::new(&config)?;
94 
95         let component = Component::new(
96             &engine,
97             r#"
98                 (component
99                     (core module $m
100                         (import "" "task.return" (func $task-return))
101                         (func (export "bar") (result i32)
102                             call $task-return
103                             i32.const 0
104                         )
105                         (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
106                     )
107                     (core func $task-return (canon task.return))
108                     (core instance $i (instantiate $m
109                         (with "" (instance (export "task.return" (func $task-return))))
110                     ))
111 
112                     (func $f (export "[async]bar")
113                         (canon lift (core func $i "bar") async (callback (func $i "callback")))
114                     )
115 
116                     (instance $i (export "[async]foo" (func $f)))
117                     (export "foo" (instance $i))
118                 )
119             "#,
120         )?;
121 
122         let linker = Linker::new(&engine);
123         let mut store = Store::new(&engine, ());
124         let instance = linker.instantiate_async(&mut store, &component).await?;
125         let no_imports = NoImports::new(&mut store, &instance)?;
126         instance
127             .run_concurrent(&mut store, async move |accessor| {
128                 let mut futures = FuturesUnordered::new();
129                 futures.push(no_imports.call_bar(accessor).boxed());
130                 futures.push(no_imports.foo().call_foo(accessor).boxed());
131                 assert!(futures.try_next().await?.is_some());
132                 assert!(futures.try_next().await?.is_some());
133                 Ok(())
134             })
135             .await?
136     }
137 }
138 
139 mod one_import {
140     use super::*;
141     use wasmtime::component::HasSelf;
142 
143     wasmtime::component::bindgen!({
144         inline: "
145             package foo:foo;
146 
147             world one-import {
148                 import foo: interface {
149                     foo: func();
150                 }
151 
152                 export bar: func();
153             }
154         ",
155     });
156 
157     #[test]
158     fn run() -> Result<()> {
159         let engine = engine();
160 
161         let component = Component::new(
162             &engine,
163             r#"
164                 (component
165                     (import "foo" (instance $i
166                         (export "foo" (func))
167                     ))
168                     (core module $m
169                         (import "" "" (func))
170                         (export "" (func 0))
171                     )
172                     (core func $f (canon lower (func $i "foo")))
173                     (core instance $i (instantiate $m
174                         (with "" (instance (export "" (func $f))))
175                     ))
176 
177                     (func $f (export "bar") (canon lift (core func $i "")))
178                 )
179             "#,
180         )?;
181 
182         #[derive(Default)]
183         struct MyImports {
184             hit: bool,
185         }
186 
187         impl foo::Host for MyImports {
188             fn foo(&mut self) {
189                 self.hit = true;
190             }
191         }
192 
193         let mut linker = Linker::new(&engine);
194         foo::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
195         let mut store = Store::new(&engine, MyImports::default());
196         let one_import = OneImport::instantiate(&mut store, &component, &linker)?;
197         one_import.call_bar(&mut store)?;
198         assert!(store.data().hit);
199         Ok(())
200     }
201 }
202 
203 mod one_import_concurrent {
204     use super::*;
205     use wasmtime::component::{Accessor, HasData};
206 
207     wasmtime::component::bindgen!({
208         inline: "
209             package foo:foo;
210 
211             world no-imports {
212                 import foo: interface {
213                     foo: async func();
214                 }
215 
216                 export bar: async func();
217             }
218         ",
219     });
220 
221     #[tokio::test]
222     async fn run() -> Result<()> {
223         let mut config = Config::new();
224         config.wasm_component_model_async(true);
225         config.async_support(true);
226         let engine = &Engine::new(&config)?;
227 
228         let component = Component::new(
229             &engine,
230             r#"
231                 (component
232                     (import "foo" (instance $foo-instance
233                         (export "[async]foo" (func))
234                     ))
235                     (core module $libc
236                         (memory (export "memory") 1)
237                     )
238                     (core instance $libc-instance (instantiate $libc))
239                     (core module $m
240                         (import "" "foo" (func $foo (param) (result i32)))
241                         (import "" "task.return" (func $task-return))
242                         (func (export "bar") (result i32)
243                             call $foo
244                             drop
245                             call $task-return
246                             i32.const 0
247                         )
248                         (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
249                     )
250                     (core func $foo (canon lower (func $foo-instance "[async]foo") async (memory $libc-instance "memory")))
251                     (core func $task-return (canon task.return))
252                     (core instance $i (instantiate $m
253                         (with "" (instance
254                             (export "task.return" (func $task-return))
255                             (export "foo" (func $foo))
256                         ))
257                     ))
258 
259                     (func $f (export "[async]bar")
260                         (canon lift (core func $i "bar") async (callback (func $i "callback")))
261                     )
262 
263                     (instance $i (export "[async]foo" (func $f)))
264                     (export "foo" (instance $i))
265                 )
266             "#,
267         )?;
268 
269         #[derive(Default)]
270         struct MyImports {
271             hit: bool,
272         }
273 
274         impl HasData for MyImports {
275             type Data<'a> = &'a mut MyImports;
276         }
277 
278         impl foo::HostWithStore for MyImports {
279             async fn foo<T>(accessor: &Accessor<T, Self>) {
280                 accessor.with(|mut view| view.get().hit = true);
281             }
282         }
283 
284         impl foo::Host for MyImports {}
285 
286         let mut linker = Linker::new(&engine);
287         foo::add_to_linker::<_, MyImports>(&mut linker, |x| x)?;
288         let mut store = Store::new(&engine, MyImports::default());
289         let instance = linker.instantiate_async(&mut store, &component).await?;
290         let no_imports = NoImports::new(&mut store, &instance)?;
291         instance
292             .run_concurrent(&mut store, async move |accessor| {
293                 no_imports.call_bar(accessor).await
294             })
295             .await??;
296         assert!(store.data().hit);
297         Ok(())
298     }
299 }
300 
301 mod resources_at_world_level {
302     use super::*;
303     use wasmtime::component::{HasSelf, Resource};
304 
305     wasmtime::component::bindgen!({
306         inline: "
307             package foo:foo;
308 
309             world resources {
310                 resource x {
311                     constructor();
312                 }
313 
314                 export y: func(x: x);
315             }
316         ",
317     });
318 
319     #[test]
320     fn run() -> Result<()> {
321         let engine = engine();
322 
323         let component = Component::new(
324             &engine,
325             r#"
326                 (component
327                     (import "x" (type $x (sub resource)))
328                     (import "[constructor]x" (func $ctor (result (own $x))))
329 
330                     (core func $dtor (canon resource.drop $x))
331                     (core func $ctor (canon lower (func $ctor)))
332 
333                     (core module $m
334                         (import "" "ctor" (func $ctor (result i32)))
335                         (import "" "dtor" (func $dtor (param i32)))
336 
337                         (func (export "x") (param i32)
338                             (call $dtor (local.get 0))
339                             (call $dtor (call $ctor))
340                         )
341                     )
342                     (core instance $i (instantiate $m
343                         (with "" (instance
344                             (export "ctor" (func $ctor))
345                             (export "dtor" (func $dtor))
346                         ))
347                     ))
348                     (func (export "y") (param "x" (own $x))
349                         (canon lift (core func $i "x")))
350                 )
351             "#,
352         )?;
353 
354         #[derive(Default)]
355         struct MyImports {
356             ctor_hit: bool,
357             drops: usize,
358         }
359 
360         impl HostX for MyImports {
361             fn new(&mut self) -> Resource<X> {
362                 self.ctor_hit = true;
363                 Resource::new_own(80)
364             }
365 
366             fn drop(&mut self, val: Resource<X>) -> Result<()> {
367                 match self.drops {
368                     0 => assert_eq!(val.rep(), 40),
369                     1 => assert_eq!(val.rep(), 80),
370                     _ => unreachable!(),
371                 }
372                 self.drops += 1;
373                 Ok(())
374             }
375         }
376 
377         impl ResourcesImports for MyImports {}
378 
379         let mut linker = Linker::new(&engine);
380         Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
381         let mut store = Store::new(&engine, MyImports::default());
382         let one_import = Resources::instantiate(&mut store, &component, &linker)?;
383         one_import.call_y(&mut store, Resource::new_own(40))?;
384         assert!(store.data().ctor_hit);
385         assert_eq!(store.data().drops, 2);
386         Ok(())
387     }
388 }
389 
390 mod resources_at_interface_level {
391     use super::*;
392     use wasmtime::component::{HasSelf, Resource};
393 
394     wasmtime::component::bindgen!({
395         inline: "
396             package foo:foo;
397 
398             interface def {
399                 resource x {
400                     constructor();
401                 }
402             }
403 
404             interface user {
405                 use def.{x};
406 
407                 y: func(x: x);
408             }
409 
410             world resources {
411                 export user;
412             }
413         ",
414     });
415 
416     #[test]
417     fn run() -> Result<()> {
418         let engine = engine();
419 
420         let component = Component::new(
421             &engine,
422             r#"
423                 (component
424                     (import (interface "foo:foo/def") (instance $i
425                         (export "x" (type $x (sub resource)))
426                         (export "[constructor]x" (func (result (own $x))))
427                     ))
428                     (alias export $i "x" (type $x))
429                     (core func $dtor (canon resource.drop $x))
430                     (core func $ctor (canon lower (func $i "[constructor]x")))
431 
432                     (core module $m
433                         (import "" "ctor" (func $ctor (result i32)))
434                         (import "" "dtor" (func $dtor (param i32)))
435 
436                         (func (export "x") (param i32)
437                             (call $dtor (local.get 0))
438                             (call $dtor (call $ctor))
439                         )
440                     )
441                     (core instance $i (instantiate $m
442                         (with "" (instance
443                             (export "ctor" (func $ctor))
444                             (export "dtor" (func $dtor))
445                         ))
446                     ))
447                     (func $y (param "x" (own $x))
448                         (canon lift (core func $i "x")))
449 
450                     (instance (export (interface "foo:foo/user"))
451                         (export "y" (func $y))
452                     )
453                 )
454             "#,
455         )?;
456 
457         #[derive(Default)]
458         struct MyImports {
459             ctor_hit: bool,
460             drops: usize,
461         }
462 
463         use foo::foo::def::X;
464 
465         impl foo::foo::def::HostX for MyImports {
466             fn new(&mut self) -> Resource<X> {
467                 self.ctor_hit = true;
468                 Resource::new_own(80)
469             }
470 
471             fn drop(&mut self, val: Resource<X>) -> Result<()> {
472                 match self.drops {
473                     0 => assert_eq!(val.rep(), 40),
474                     1 => assert_eq!(val.rep(), 80),
475                     _ => unreachable!(),
476                 }
477                 self.drops += 1;
478                 Ok(())
479             }
480         }
481 
482         impl foo::foo::def::Host for MyImports {}
483 
484         let mut linker = Linker::new(&engine);
485         Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
486         let mut store = Store::new(&engine, MyImports::default());
487         let one_import = Resources::instantiate(&mut store, &component, &linker)?;
488         one_import
489             .foo_foo_user()
490             .call_y(&mut store, Resource::new_own(40))?;
491         assert!(store.data().ctor_hit);
492         assert_eq!(store.data().drops, 2);
493         Ok(())
494     }
495 }
496 
497 mod async_config {
498     use super::*;
499 
500     wasmtime::component::bindgen!({
501         inline: "
502             package foo:foo;
503 
504             world t1 {
505                 import foo: interface {
506                     foo: func();
507                 }
508                 import x: func();
509                 import y: func();
510                 export z: func();
511             }
512         ",
513         imports: { default: async },
514         exports: { default: async },
515     });
516 
517     #[expect(dead_code, reason = "just here for bindings")]
518     struct T;
519 
520     impl T1Imports for T {
521         async fn x(&mut self) {}
522 
523         async fn y(&mut self) {}
524     }
525 
526     async fn _test_t1(t1: &T1, store: &mut Store<()>) {
527         let _ = t1.call_z(&mut *store).await;
528     }
529 
530     wasmtime::component::bindgen!({
531         inline: "
532             package foo:foo;
533 
534             world t2 {
535                 import x: func();
536                 import y: func();
537                 export z: func();
538             }
539         ",
540         imports: {
541             "x": tracing,
542             default: async,
543         },
544         exports: { default: async },
545     });
546 
547     impl T2Imports for T {
548         fn x(&mut self) {}
549 
550         async fn y(&mut self) {}
551     }
552 
553     async fn _test_t2(t2: &T2, store: &mut Store<()>) {
554         let _ = t2.call_z(&mut *store).await;
555     }
556 
557     wasmtime::component::bindgen!({
558         inline: "
559             package foo:foo;
560 
561             world t3 {
562                 import x: func();
563                 import y: func();
564                 export z: func();
565             }
566         ",
567         imports: { "x": async },
568         exports: { default: async },
569     });
570 
571     impl T3Imports for T {
572         async fn x(&mut self) {}
573 
574         fn y(&mut self) {}
575     }
576 
577     async fn _test_t3(t3: &T3, store: &mut Store<()>) {
578         let _ = t3.call_z(&mut *store).await;
579     }
580 }
581 
582 mod exported_resources {
583     use super::*;
584     use std::mem;
585     use wasmtime::component::{HasSelf, Resource};
586 
587     wasmtime::component::bindgen!({
588         inline: "
589             package foo:foo;
590 
591             interface a {
592                 resource x {
593                     constructor();
594                 }
595             }
596 
597             world resources {
598                 export b: interface {
599                     use a.{x as y};
600 
601                     resource x {
602                         constructor(y: y);
603                         foo: func() -> u32;
604                     }
605                 }
606 
607                 resource x;
608 
609                 export f: func(x1: x, x2: x) -> x;
610             }
611         ",
612     });
613 
614     #[derive(Default)]
615     struct MyImports {
616         hostcalls: Vec<Hostcall>,
617         next_a_x: u32,
618     }
619 
620     #[derive(PartialEq, Debug)]
621     enum Hostcall {
622         DropRootX(u32),
623         DropAX(u32),
624         NewA,
625     }
626 
627     use foo::foo::a;
628 
629     impl ResourcesImports for MyImports {}
630 
631     impl HostX for MyImports {
632         fn drop(&mut self, val: Resource<X>) -> Result<()> {
633             self.hostcalls.push(Hostcall::DropRootX(val.rep()));
634             Ok(())
635         }
636     }
637 
638     impl a::HostX for MyImports {
639         fn new(&mut self) -> Resource<a::X> {
640             let rep = self.next_a_x;
641             self.next_a_x += 1;
642             self.hostcalls.push(Hostcall::NewA);
643             Resource::new_own(rep)
644         }
645 
646         fn drop(&mut self, val: Resource<a::X>) -> Result<()> {
647             self.hostcalls.push(Hostcall::DropAX(val.rep()));
648             Ok(())
649         }
650     }
651 
652     impl foo::foo::a::Host for MyImports {}
653 
654     #[test]
655     fn run() -> Result<()> {
656         let engine = engine();
657 
658         let component = Component::new(
659             &engine,
660             r#"
661 (component
662   ;; setup the `foo:foo/a` import
663   (import (interface "foo:foo/a") (instance $a
664     (export "x" (type $x (sub resource)))
665     (export "[constructor]x" (func (result (own $x))))
666   ))
667   (alias export $a "x" (type $a-x))
668   (core func $a-x-drop (canon resource.drop $a-x))
669   (core func $a-x-ctor (canon lower (func $a "[constructor]x")))
670 
671   ;; setup the root import of the `x` resource
672   (import "x" (type $x (sub resource)))
673   (core func $root-x-dtor (canon resource.drop $x))
674 
675   ;; setup and declare the `x` resource for the `b` export.
676   (core module $indirect-dtor
677     (func (export "b-x-dtor") (param i32)
678       local.get 0
679       i32.const 0
680       call_indirect (param i32)
681     )
682     (table (export "$imports") 1 1 funcref)
683   )
684   (core instance $indirect-dtor (instantiate $indirect-dtor))
685   (type $b-x (resource (rep i32) (dtor (func $indirect-dtor "b-x-dtor"))))
686   (core func $b-x-drop (canon resource.drop $b-x))
687   (core func $b-x-rep (canon resource.rep $b-x))
688   (core func $b-x-new (canon resource.new $b-x))
689 
690   ;; main module implementation
691   (core module $main
692     (import "foo:foo/a" "[constructor]x" (func $a-x-ctor (result i32)))
693     (import "foo:foo/a" "[resource-drop]x" (func $a-x-dtor (param i32)))
694     (import "$root" "[resource-drop]x" (func $x-dtor (param i32)))
695     (import "[export]b" "[resource-drop]x" (func $b-x-dtor (param i32)))
696     (import "[export]b" "[resource-new]x" (func $b-x-new (param i32) (result i32)))
697     (import "[export]b" "[resource-rep]x" (func $b-x-rep (param i32) (result i32)))
698     (func (export "b#[constructor]x") (param i32) (result i32)
699       (call $a-x-dtor (local.get 0))
700       (call $b-x-new (call $a-x-ctor))
701     )
702     (func (export "b#[method]x.foo") (param i32) (result i32)
703       local.get 0)
704     (func (export "b#[dtor]x") (param i32)
705       (call $a-x-dtor (local.get 0))
706     )
707     (func (export "f") (param i32 i32) (result i32)
708       (call $x-dtor (local.get 0))
709       local.get 1
710     )
711   )
712   (core instance $main (instantiate $main
713     (with "foo:foo/a" (instance
714       (export "[resource-drop]x" (func $a-x-drop))
715       (export "[constructor]x" (func $a-x-ctor))
716     ))
717     (with "$root" (instance
718       (export "[resource-drop]x" (func $root-x-dtor))
719     ))
720     (with "[export]b" (instance
721       (export "[resource-drop]x" (func $b-x-drop))
722       (export "[resource-rep]x" (func $b-x-rep))
723       (export "[resource-new]x" (func $b-x-new))
724     ))
725   ))
726 
727   ;; fill in `$indirect-dtor`'s table with the actual destructor definition
728   ;; now that it's available.
729   (core module $fixup
730     (import "" "b-x-dtor" (func $b-x-dtor (param i32)))
731     (import "" "$imports" (table 1 1 funcref))
732     (elem (i32.const 0) func $b-x-dtor)
733   )
734   (core instance (instantiate $fixup
735     (with "" (instance
736       (export "$imports" (table 0 "$imports"))
737       (export "b-x-dtor" (func $main "b#[dtor]x"))
738     ))
739   ))
740 
741   ;; Create the `b` export through a subcomponent instantiation.
742   (func $b-x-ctor (param "y" (own $a-x)) (result (own $b-x))
743     (canon lift (core func $main "b#[constructor]x")))
744   (func $b-x-foo (param "self" (borrow $b-x)) (result u32)
745     (canon lift (core func $main "b#[method]x.foo")))
746   (component $b
747     (import "a-x" (type $y (sub resource)))
748     (import "b-x" (type $x' (sub resource)))
749     (import "ctor" (func $ctor (param "y" (own $y)) (result (own $x'))))
750     (import "foo" (func $foo (param "self" (borrow $x')) (result u32)))
751     (export $x "x" (type $x'))
752     (export "[constructor]x"
753       (func $ctor)
754       (func (param "y" (own $y)) (result (own $x))))
755     (export "[method]x.foo"
756       (func $foo)
757       (func (param "self" (borrow $x)) (result u32)))
758   )
759   (instance (export "b") (instantiate $b
760     (with "ctor" (func $b-x-ctor))
761     (with "foo" (func $b-x-foo))
762     (with "a-x" (type 0 "x"))
763     (with "b-x" (type $b-x))
764   ))
765 
766   ;; Create the `f` export which is a bare function
767   (func (export "f") (param "x1" (own $x)) (param "x2" (own $x)) (result (own $x))
768     (canon lift (core func $main "f")))
769 )
770             "#,
771         )?;
772 
773         let mut linker = Linker::new(&engine);
774         Resources::add_to_linker::<_, HasSelf<_>>(&mut linker, |f| f)?;
775         let mut store = Store::new(&engine, MyImports::default());
776         let i = Resources::instantiate(&mut store, &component, &linker)?;
777 
778         // call the root export `f` twice
779         let ret = i.call_f(&mut store, Resource::new_own(1), Resource::new_own(2))?;
780         assert_eq!(ret.rep(), 2);
781         assert_eq!(
782             mem::take(&mut store.data_mut().hostcalls),
783             [Hostcall::DropRootX(1)]
784         );
785         let ret = i.call_f(&mut store, Resource::new_own(3), Resource::new_own(4))?;
786         assert_eq!(ret.rep(), 4);
787         assert_eq!(
788             mem::take(&mut store.data_mut().hostcalls),
789             [Hostcall::DropRootX(3)]
790         );
791 
792         // interact with the `b` export
793         let b = i.b();
794         let b_x = b.x().call_constructor(&mut store, Resource::new_own(5))?;
795         assert_eq!(
796             mem::take(&mut store.data_mut().hostcalls),
797             [Hostcall::DropAX(5), Hostcall::NewA]
798         );
799         b.x().call_foo(&mut store, b_x)?;
800         assert_eq!(mem::take(&mut store.data_mut().hostcalls), []);
801         b_x.resource_drop(&mut store)?;
802         assert_eq!(
803             mem::take(&mut store.data_mut().hostcalls),
804             [Hostcall::DropAX(0)],
805         );
806         Ok(())
807     }
808 }
809 
810 mod unstable_import {
811     use super::*;
812     use wasmtime::component::HasSelf;
813 
814     wasmtime::component::bindgen!({
815         inline: "
816             package foo:foo;
817 
818             @unstable(feature = experimental-interface)
819             interface my-interface {
820                 @unstable(feature = experimental-function)
821                 my-function: func();
822             }
823 
824             world my-world {
825                 @unstable(feature = experimental-import)
826                 import my-interface;
827 
828                 export bar: func();
829             }
830         ",
831     });
832 
833     #[test]
834     fn run() -> Result<()> {
835         // In the example above, all features are required for `my-function` to be imported:
836         assert_success(
837             LinkOptions::default()
838                 .experimental_interface(true)
839                 .experimental_import(true)
840                 .experimental_function(true),
841         );
842 
843         // And every other incomplete combination should fail:
844         assert_failure(&LinkOptions::default());
845         assert_failure(LinkOptions::default().experimental_function(true));
846         assert_failure(LinkOptions::default().experimental_interface(true));
847         assert_failure(
848             LinkOptions::default()
849                 .experimental_interface(true)
850                 .experimental_function(true),
851         );
852         assert_failure(
853             LinkOptions::default()
854                 .experimental_interface(true)
855                 .experimental_import(true),
856         );
857         assert_failure(LinkOptions::default().experimental_import(true));
858         assert_failure(
859             LinkOptions::default()
860                 .experimental_import(true)
861                 .experimental_function(true),
862         );
863 
864         Ok(())
865     }
866 
867     fn assert_success(link_options: &LinkOptions) {
868         run_with_options(link_options).unwrap();
869     }
870     fn assert_failure(link_options: &LinkOptions) {
871         let err = run_with_options(link_options).unwrap_err().to_string();
872         assert_eq!(
873             err,
874             "component imports instance `foo:foo/my-interface`, but a matching implementation was not found in the linker"
875         );
876     }
877 
878     fn run_with_options(link_options: &LinkOptions) -> Result<()> {
879         let engine = engine();
880 
881         let component = Component::new(
882             &engine,
883             r#"
884                 (component
885                     (import "foo:foo/my-interface" (instance $i
886                         (export "my-function" (func))
887                     ))
888                     (core module $m
889                         (import "" "" (func))
890                         (export "" (func 0))
891                     )
892                     (core func $f (canon lower (func $i "my-function")))
893                     (core instance $r (instantiate $m
894                         (with "" (instance (export "" (func $f))))
895                     ))
896 
897                     (func $f (export "bar") (canon lift (core func $r "")))
898                 )
899             "#,
900         )?;
901 
902         #[derive(Default)]
903         struct MyHost;
904 
905         impl foo::foo::my_interface::Host for MyHost {
906             fn my_function(&mut self) {}
907         }
908 
909         let mut linker = Linker::new(&engine);
910         MyWorld::add_to_linker::<_, HasSelf<_>>(&mut linker, link_options, |h| h)?;
911         let mut store = Store::new(&engine, MyHost::default());
912         let one_import = MyWorld::instantiate(&mut store, &component, &linker)?;
913         one_import.call_bar(&mut store)?;
914         Ok(())
915     }
916 }
917