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