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