@@ -710,6 +710,187 @@ mod variant_error {
710710 }
711711}
712712
713+ mod multiple_interfaces_error {
714+ use super :: * ;
715+ use exports:: foo;
716+ use inline:: inline:: imports;
717+ use inline:: inline:: types;
718+
719+ wasmtime:: component:: bindgen!( {
720+ inline: "
721+ package inline:inline
722+ interface types {
723+ enum e1 { a, b, c }
724+ enum-error: func(a: float64) -> result<float64, e1>
725+ }
726+ interface imports {
727+ use types.{e1}
728+ enum-error: func(a: float64) -> result<float64, e1>
729+ }
730+ world result-playground {
731+ import imports
732+ export foo: interface {
733+ enum e1 { a, b, c }
734+ enum-error: func(a: float64) -> result<float64, e1>
735+ }
736+ }" ,
737+ trappable_error_type: { "inline:inline/types" :: e1: TrappableE1 }
738+ } ) ;
739+
740+ #[ test]
741+ fn run ( ) -> Result < ( ) , Error > {
742+ let engine = engine ( ) ;
743+ // NOTE: this component doesn't make use of a types import, and relies instead on
744+ // subtyping.
745+ let component = Component :: new (
746+ & engine,
747+ format ! (
748+ r#"
749+ (component
750+ (type $err' (enum "a" "b" "c"))
751+ (import (interface "inline:inline/imports") (instance $i
752+ (export $e1 "e1" (type (eq $err')))
753+ (export "enum-error" (func (param "a" float64) (result (result float64 (error $e1)))))
754+ ))
755+ (core module $libc
756+ (memory (export "memory") 1)
757+ {REALLOC_AND_FREE}
758+ )
759+ (core instance $libc (instantiate $libc))
760+ (core module $m
761+ (import "" "core_enum_error" (func $f (param f64 i32)))
762+ (import "libc" "memory" (memory 0))
763+ (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
764+ (func (export "core_enum_error_export") (param f64) (result i32)
765+ (local $retptr i32)
766+ (local.set $retptr
767+ (call $realloc
768+ (i32.const 0)
769+ (i32.const 0)
770+ (i32.const 4)
771+ (i32.const 16)))
772+ (call $f (local.get 0) (local.get $retptr))
773+ (local.get $retptr)
774+ )
775+ )
776+ (core func $core_enum_error
777+ (canon lower (func $i "enum-error") (memory $libc "memory") (realloc (func $libc "realloc")))
778+ )
779+ (core instance $i (instantiate $m
780+ (with "" (instance (export "core_enum_error" (func $core_enum_error))))
781+ (with "libc" (instance $libc))
782+ ))
783+ (func $f_enum_error
784+ (param "a" float64)
785+ (result (result float64 (error $err')))
786+ (canon lift (core func $i "core_enum_error_export") (memory $libc "memory"))
787+ )
788+
789+ (component $nested
790+ (import "f-err" (type $err (eq $err')))
791+ (import "f" (func $f (param "a" float64) (result (result float64 (error $err)))))
792+ (export $err2 "err" (type $err'))
793+ (export "enum-error" (func $f) (func (param "a" float64) (result (result float64 (error $err2)))))
794+ )
795+
796+ (instance $n (instantiate $nested
797+ (with "f-err" (type $err'))
798+ (with "f" (func $f_enum_error))
799+ ))
800+ (export "foo" (instance $n))
801+ )
802+ "#
803+ ) ,
804+ ) ?;
805+
806+ // You can create concrete trap types which make it all the way out to the
807+ // host caller, via downcast_ref below.
808+ #[ derive( Debug ) ]
809+ struct MyTrap ;
810+
811+ impl std:: fmt:: Display for MyTrap {
812+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
813+ write ! ( f, "{:?}" , self )
814+ }
815+ }
816+ impl std:: error:: Error for MyTrap { }
817+
818+ // It is possible to define From impls that target these generated trappable
819+ // types. This allows you to integrate libraries with other error types, or
820+ // use your own more descriptive error types, and use ? to convert them at
821+ // their throw site.
822+ impl From < MyTrap > for types:: TrappableE1 {
823+ fn from ( t : MyTrap ) -> types:: TrappableE1 {
824+ types:: TrappableE1 :: trap ( anyhow ! ( t) )
825+ }
826+ }
827+
828+ #[ derive( Default ) ]
829+ struct MyImports { }
830+
831+ impl types:: Host for MyImports {
832+ fn enum_error ( & mut self , a : f64 ) -> Result < f64 , types:: TrappableE1 > {
833+ if a == 0.0 {
834+ Ok ( a)
835+ } else if a == 1.0 {
836+ Err ( imports:: E1 :: A ) ?
837+ } else {
838+ Err ( MyTrap ) ?
839+ }
840+ }
841+ }
842+
843+ impl imports:: Host for MyImports {
844+ fn enum_error ( & mut self , a : f64 ) -> Result < f64 , types:: TrappableE1 > {
845+ if a == 0.0 {
846+ Ok ( a)
847+ } else if a == 1.0 {
848+ Err ( imports:: E1 :: A ) ?
849+ } else {
850+ Err ( MyTrap ) ?
851+ }
852+ }
853+ }
854+
855+ let mut linker = Linker :: new ( & engine) ;
856+ imports:: add_to_linker ( & mut linker, |f : & mut MyImports | f) ?;
857+
858+ let mut store = Store :: new ( & engine, MyImports :: default ( ) ) ;
859+ let ( results, _) = ResultPlayground :: instantiate ( & mut store, & component, & linker) ?;
860+
861+ assert_eq ! (
862+ results
863+ . foo( )
864+ . call_enum_error( & mut store, 0.0 )
865+ . expect( "no trap" )
866+ . expect( "no error returned" ) ,
867+ 0.0
868+ ) ;
869+
870+ let e = results
871+ . foo ( )
872+ . call_enum_error ( & mut store, 1.0 )
873+ . expect ( "no trap" )
874+ . err ( )
875+ . expect ( "error returned" ) ;
876+ assert_eq ! ( e, foo:: E1 :: A ) ;
877+
878+ let e = results
879+ . foo ( )
880+ . call_enum_error ( & mut store, 2.0 )
881+ . err ( )
882+ . expect ( "trap" ) ;
883+ assert_eq ! (
884+ format!( "{}" , e. source( ) . expect( "trap message is stored in source" ) ) ,
885+ "MyTrap"
886+ ) ;
887+ e. downcast_ref :: < MyTrap > ( )
888+ . expect ( "downcast trap to concrete MyTrap type" ) ;
889+
890+ Ok ( ( ) )
891+ }
892+ }
893+
713894mod with_remapping {
714895 use super :: * ;
715896
0 commit comments