@@ -135,6 +135,7 @@ pub struct CSharp {
135
135
needs_interop_string : bool ,
136
136
needs_export_return_area : bool ,
137
137
needs_rep_table : bool ,
138
+ needs_wit_exception : bool ,
138
139
interface_fragments : HashMap < String , InterfaceTypeAndFragments > ,
139
140
world_fragments : Vec < InterfaceFragment > ,
140
141
sizes : SizeAlign ,
@@ -515,6 +516,23 @@ impl WorldGenerator for CSharp {
515
516
)
516
517
}
517
518
519
+ if self . needs_wit_exception {
520
+ src. push_str (
521
+ r#"
522
+ public class WitException: Exception {
523
+ public object Value { get; }
524
+ public uint NestingLevel { get; }
525
+
526
+ public WitException(object v, uint level)
527
+ {
528
+ Value = v;
529
+ NestingLevel = level;
530
+ }
531
+ }
532
+ "# ,
533
+ )
534
+ }
535
+
518
536
// Declare a statically-allocated return area, if needed. We only do
519
537
// this for export bindings, because import bindings allocate their
520
538
// return-area on the stack.
@@ -929,14 +947,25 @@ impl InterfaceGenerator<'_> {
929
947
_ => unreachable ! ( ) ,
930
948
} ;
931
949
932
- let result_type = if let FunctionKind :: Constructor ( _) = & func. kind {
933
- String :: new ( )
950
+ let ( result_type, results ) = if let FunctionKind :: Constructor ( _) = & func. kind {
951
+ ( String :: new ( ) , Vec :: new ( ) )
934
952
} else {
935
953
match func. results . len ( ) {
936
- 0 => "void" . to_string ( ) ,
954
+ 0 => ( "void" . to_string ( ) , Vec :: new ( ) ) ,
937
955
1 => {
938
- let ty = func. results . iter_types ( ) . next ( ) . unwrap ( ) ;
939
- self . type_name_with_qualifier ( ty, true )
956
+ let ( payload, results) = payload_and_results (
957
+ self . resolve ,
958
+ * func. results . iter_types ( ) . next ( ) . unwrap ( ) ,
959
+ ) ;
960
+ (
961
+ if let Some ( ty) = payload {
962
+ self . gen . needs_result = true ;
963
+ self . type_name_with_qualifier ( & ty, true )
964
+ } else {
965
+ "void" . to_string ( )
966
+ } ,
967
+ results,
968
+ )
940
969
}
941
970
_ => {
942
971
let types = func
@@ -945,7 +974,7 @@ impl InterfaceGenerator<'_> {
945
974
. map ( |ty| self . type_name_with_qualifier ( ty, true ) )
946
975
. collect :: < Vec < _ > > ( )
947
976
. join ( ", " ) ;
948
- format ! ( "({})" , types)
977
+ ( format ! ( "({})" , types) , Vec :: new ( ) )
949
978
}
950
979
}
951
980
} ;
@@ -976,6 +1005,7 @@ impl InterfaceGenerator<'_> {
976
1005
}
977
1006
} )
978
1007
. collect ( ) ,
1008
+ results,
979
1009
) ;
980
1010
981
1011
abi:: call (
@@ -1055,11 +1085,44 @@ impl InterfaceGenerator<'_> {
1055
1085
1056
1086
let sig = self . resolve . wasm_signature ( AbiVariant :: GuestExport , func) ;
1057
1087
1088
+ let ( result_type, results) = if let FunctionKind :: Constructor ( _) = & func. kind {
1089
+ ( String :: new ( ) , Vec :: new ( ) )
1090
+ } else {
1091
+ match func. results . len ( ) {
1092
+ 0 => ( "void" . to_owned ( ) , Vec :: new ( ) ) ,
1093
+ 1 => {
1094
+ let ( payload, results) = payload_and_results (
1095
+ self . resolve ,
1096
+ * func. results . iter_types ( ) . next ( ) . unwrap ( ) ,
1097
+ ) ;
1098
+ (
1099
+ if let Some ( ty) = payload {
1100
+ self . gen . needs_result = true ;
1101
+ self . type_name ( & ty)
1102
+ } else {
1103
+ "void" . to_string ( )
1104
+ } ,
1105
+ results,
1106
+ )
1107
+ }
1108
+ _ => {
1109
+ let types = func
1110
+ . results
1111
+ . iter_types ( )
1112
+ . map ( |ty| self . type_name ( ty) )
1113
+ . collect :: < Vec < String > > ( )
1114
+ . join ( ", " ) ;
1115
+ ( format ! ( "({}) " , types) , Vec :: new ( ) )
1116
+ }
1117
+ }
1118
+ } ;
1119
+
1058
1120
let mut bindgen = FunctionBindgen :: new (
1059
1121
self ,
1060
1122
& func. item_name ( ) ,
1061
1123
& func. kind ,
1062
1124
( 0 ..sig. params . len ( ) ) . map ( |i| format ! ( "p{i}" ) ) . collect ( ) ,
1125
+ results,
1063
1126
) ;
1064
1127
1065
1128
abi:: call (
@@ -1087,24 +1150,6 @@ impl InterfaceGenerator<'_> {
1087
1150
_ => unreachable ! ( ) ,
1088
1151
} ;
1089
1152
1090
- let result_type = if let FunctionKind :: Constructor ( _) = & func. kind {
1091
- String :: new ( )
1092
- } else {
1093
- match func. results . len ( ) {
1094
- 0 => "void" . to_owned ( ) ,
1095
- 1 => self . type_name ( func. results . iter_types ( ) . next ( ) . unwrap ( ) ) ,
1096
- _ => {
1097
- let types = func
1098
- . results
1099
- . iter_types ( )
1100
- . map ( |ty| self . type_name ( ty) )
1101
- . collect :: < Vec < String > > ( )
1102
- . join ( ", " ) ;
1103
- format ! ( "({}) " , types)
1104
- }
1105
- }
1106
- } ;
1107
-
1108
1153
let wasm_params = sig
1109
1154
. params
1110
1155
. iter ( )
@@ -1507,8 +1552,18 @@ impl InterfaceGenerator<'_> {
1507
1552
} else {
1508
1553
match func. results . len ( ) {
1509
1554
0 => "void" . into ( ) ,
1510
- 1 => self
1511
- . type_name_with_qualifier ( func. results . iter_types ( ) . next ( ) . unwrap ( ) , qualifier) ,
1555
+ 1 => {
1556
+ let ( payload, _) = payload_and_results (
1557
+ self . resolve ,
1558
+ * func. results . iter_types ( ) . next ( ) . unwrap ( ) ,
1559
+ ) ;
1560
+ if let Some ( ty) = payload {
1561
+ self . gen . needs_result = true ;
1562
+ self . type_name_with_qualifier ( & ty, qualifier)
1563
+ } else {
1564
+ "void" . to_string ( )
1565
+ }
1566
+ }
1512
1567
count => {
1513
1568
self . gen . tuple_counts . insert ( count) ;
1514
1569
format ! (
@@ -1834,6 +1889,7 @@ struct FunctionBindgen<'a, 'b> {
1834
1889
func_name : & ' b str ,
1835
1890
kind : & ' b FunctionKind ,
1836
1891
params : Box < [ String ] > ,
1892
+ results : Vec < TypeId > ,
1837
1893
src : String ,
1838
1894
locals : Ns ,
1839
1895
block_storage : Vec < BlockStorage > ,
@@ -1853,6 +1909,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
1853
1909
func_name : & ' b str ,
1854
1910
kind : & ' b FunctionKind ,
1855
1911
params : Box < [ String ] > ,
1912
+ results : Vec < TypeId > ,
1856
1913
) -> FunctionBindgen < ' a , ' b > {
1857
1914
let mut locals = Ns :: default ( ) ;
1858
1915
// Ensure temporary variable names don't clash with parameter names:
@@ -1865,6 +1922,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
1865
1922
func_name,
1866
1923
kind,
1867
1924
params,
1925
+ results,
1868
1926
src : String :: new ( ) ,
1869
1927
locals,
1870
1928
block_storage : Vec :: new ( ) ,
@@ -2585,10 +2643,69 @@ impl Bindgen for FunctionBindgen<'_, '_> {
2585
2643
0 => uwriteln ! ( self . src, "{target}.{func_name}({oper});" ) ,
2586
2644
1 => {
2587
2645
let ret = self . locals . tmp ( "ret" ) ;
2646
+ let ty = self . gen . type_name_with_qualifier (
2647
+ func. results . iter_types ( ) . next ( ) . unwrap ( ) ,
2648
+ true
2649
+ ) ;
2650
+ uwriteln ! ( self . src, "{ty} {ret};" ) ;
2651
+ let mut cases = Vec :: with_capacity ( self . results . len ( ) ) ;
2652
+ let mut oks = Vec :: with_capacity ( self . results . len ( ) ) ;
2653
+ let mut payload_is_void = false ;
2654
+ for ( index, ty) in self . results . iter ( ) . enumerate ( ) {
2655
+ let TypeDefKind :: Result ( result) = & self . gen . resolve . types [ * ty] . kind else {
2656
+ unreachable ! ( ) ;
2657
+ } ;
2658
+ let err_ty = if let Some ( ty) = result. err {
2659
+ self . gen . type_name_with_qualifier ( & ty, true )
2660
+ } else {
2661
+ "None" . to_owned ( )
2662
+ } ;
2663
+ let ty = self . gen . type_name_with_qualifier ( & Type :: Id ( * ty) , true ) ;
2664
+ let head = oks. concat ( ) ;
2665
+ let tail = oks. iter ( ) . map ( |_| ")" ) . collect :: < Vec < _ > > ( ) . concat ( ) ;
2666
+ cases. push (
2667
+ format ! (
2668
+ "\
2669
+ case {index}: {{
2670
+ ret = {head}{ty}.err(({err_ty}) e.Value){tail};
2671
+ break;
2672
+ }}
2673
+ "
2674
+ )
2675
+ ) ;
2676
+ oks. push ( format ! ( "{ty}.ok(" ) ) ;
2677
+ payload_is_void = result. ok . is_none ( ) ;
2678
+ }
2679
+ if !self . results . is_empty ( ) {
2680
+ self . src . push_str ( "try {\n " ) ;
2681
+ }
2682
+ let head = oks. concat ( ) ;
2683
+ let tail = oks. iter ( ) . map ( |_| ")" ) . collect :: < Vec < _ > > ( ) . concat ( ) ;
2684
+ let val = if payload_is_void {
2685
+ uwriteln ! ( self . src, "{target}.{func_name}({oper});" ) ;
2686
+ "new None()" . to_owned ( )
2687
+ } else {
2688
+ format ! ( "{target}.{func_name}({oper})" )
2689
+ } ;
2588
2690
uwriteln ! (
2589
2691
self . src,
2590
- "var {ret} = {target}.{func_name}({oper}) ;"
2692
+ "{ret} = {head}{val}{tail} ;"
2591
2693
) ;
2694
+ if !self . results . is_empty ( ) {
2695
+ self . gen . gen . needs_wit_exception = true ;
2696
+ let cases = cases. join ( "\n " ) ;
2697
+ uwriteln ! (
2698
+ self . src,
2699
+ r#"}} catch (WitException e) {{
2700
+ switch (e.NestingLevel) {{
2701
+ {cases}
2702
+
2703
+ default: throw new ArgumentException($"invalid nesting level: {{e.NestingLevel}}");
2704
+ }}
2705
+ }}
2706
+ "#
2707
+ ) ;
2708
+ }
2592
2709
results. push ( ret) ;
2593
2710
}
2594
2711
_ => {
@@ -2626,17 +2743,51 @@ impl Bindgen for FunctionBindgen<'_, '_> {
2626
2743
if !matches ! ( ( self . gen . direction, self . kind) , ( Direction :: Import , FunctionKind :: Constructor ( _) ) ) {
2627
2744
match func. results . len ( ) {
2628
2745
0 => ( ) ,
2629
- 1 => uwriteln ! ( self . src, "return {};" , operands[ 0 ] ) ,
2746
+ 1 => {
2747
+ let mut payload_is_void = false ;
2748
+ let mut previous = operands[ 0 ] . clone ( ) ;
2749
+ let mut vars = Vec :: with_capacity ( self . results . len ( ) ) ;
2750
+ if let Direction :: Import = self . gen . direction {
2751
+ for ty in & self . results {
2752
+ vars. push ( previous. clone ( ) ) ;
2753
+ let tmp = self . locals . tmp ( "tmp" ) ;
2754
+ uwrite ! (
2755
+ self . src,
2756
+ "\
2757
+ if ({previous}.IsOk) {{
2758
+ var {tmp} = {previous}.AsOk;
2759
+ "
2760
+ ) ;
2761
+ previous = tmp;
2762
+ let TypeDefKind :: Result ( result) = & self . gen . resolve . types [ * ty] . kind else {
2763
+ unreachable ! ( ) ;
2764
+ } ;
2765
+ payload_is_void = result. ok . is_none ( ) ;
2766
+ }
2767
+ }
2768
+ uwriteln ! ( self . src, "return {};" , if payload_is_void { "" } else { & previous } ) ;
2769
+ for ( level, var) in vars. iter ( ) . enumerate ( ) . rev ( ) {
2770
+ self . gen . gen . needs_wit_exception = true ;
2771
+ uwrite ! (
2772
+ self . src,
2773
+ "\
2774
+ }} else {{
2775
+ throw new WitException({var}.AsErr, {level});
2776
+ }}
2777
+ "
2778
+ ) ;
2779
+ }
2780
+ }
2630
2781
_ => {
2631
2782
let results = operands. join ( ", " ) ;
2632
2783
uwriteln ! ( self . src, "return ({results});" )
2633
2784
}
2634
2785
}
2635
2786
2636
- // Close all the fixed blocks.
2637
- for _ in 0 ..self . fixed {
2638
- uwriteln ! ( self . src, "}}" ) ;
2639
- }
2787
+ // Close all the fixed blocks.
2788
+ for _ in 0 ..self . fixed {
2789
+ uwriteln ! ( self . src, "}}" ) ;
2790
+ }
2640
2791
}
2641
2792
}
2642
2793
@@ -3102,3 +3253,26 @@ fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId {
3102
3253
}
3103
3254
}
3104
3255
}
3256
+
3257
+ fn payload_and_results ( resolve : & Resolve , ty : Type ) -> ( Option < Type > , Vec < TypeId > ) {
3258
+ fn recurse ( resolve : & Resolve , ty : Type , results : & mut Vec < TypeId > ) -> Option < Type > {
3259
+ if let Type :: Id ( id) = ty {
3260
+ if let TypeDefKind :: Result ( result) = & resolve. types [ id] . kind {
3261
+ results. push ( id) ;
3262
+ if let Some ( ty) = result. ok {
3263
+ recurse ( resolve, ty, results)
3264
+ } else {
3265
+ None
3266
+ }
3267
+ } else {
3268
+ Some ( ty)
3269
+ }
3270
+ } else {
3271
+ Some ( ty)
3272
+ }
3273
+ }
3274
+
3275
+ let mut results = Vec :: new ( ) ;
3276
+ let payload = recurse ( resolve, ty, & mut results) ;
3277
+ ( payload, results)
3278
+ }
0 commit comments