@@ -45,14 +45,26 @@ fn remote_pkg(name: &str) -> String {
4545}
4646
4747/// The version of github.com/bytecodealliance/go-pkg that's being used
48- const REMOTE_PKG_VERSION : & str = "v0.2.2 " ;
48+ const REMOTE_PKG_VERSION : & str = "v0.2.3 " ;
4949
5050/// If a user specifies the `pkg_name` flag, the required version for the
5151/// shared remote package isn't recorded. This enables downstream users to retrieve the version programmatically.
5252pub fn remote_pkg_version ( ) -> String {
5353 format ! ( "go.bytecodealliance.org/pkg {REMOTE_PKG_VERSION}" )
5454}
5555
56+ /// Appends `_` to `name` if it collides with a Go keyword.
57+ /// Source: https://go.dev/ref/spec#Keywords
58+ fn escape_go_keyword ( name : String ) -> String {
59+ match name. as_str ( ) {
60+ "break" | "case" | "chan" | "const" | "continue" | "default" | "defer" | "else"
61+ | "fallthrough" | "for" | "func" | "go" | "goto" | "if" | "import" | "interface"
62+ | "map" | "package" | "range" | "return" | "select" | "struct" | "switch" | "type"
63+ | "var" => format ! ( "{name}_" ) ,
64+ _ => name,
65+ }
66+ }
67+
5668#[ derive( Default , Debug , Copy , Clone ) ]
5769pub enum Format {
5870 #[ default]
@@ -225,6 +237,8 @@ struct Go {
225237 types : HashSet < ( String , TypeId ) > ,
226238 resources : HashMap < TypeId , Direction > ,
227239 futures_and_streams : HashMap < ( TypeId , bool ) , Option < WorldKey > > ,
240+ // Tracks which `future`/`stream` declarations have already been generated.
241+ generated_futures_and_streams : HashSet < FutureStreamDedup > ,
228242}
229243
230244impl Go {
@@ -571,16 +585,16 @@ func wasm_{kind}_drop_writable_{snake}(handle int32)
571585{lower}
572586
573587var wasm_{kind}_vtable_{snake} = witTypes.{upper_kind}Vtable[{payload}]{{
574- {size},
575- {align},
576- wasm_{kind}_read_{snake},
577- wasm_{kind}_write_{snake},
578- nil,
579- nil,
580- wasm_{kind}_drop_readable_{snake},
581- wasm_{kind}_drop_writable_{snake},
582- {lift_name},
583- {lower_name},
588+ Size: {size},
589+ Align: {align},
590+ Read: wasm_{kind}_read_{snake},
591+ Write: wasm_{kind}_write_{snake},
592+ CancelRead: nil,
593+ CancelWrite: nil,
594+ DropReadable: wasm_{kind}_drop_readable_{snake},
595+ DropWritable: wasm_{kind}_drop_writable_{snake},
596+ Lift: {lift_name},
597+ Lower: {lower_name},
584598}}
585599
586600func Make{upper_kind}{camel}() (*witTypes.{upper_kind}Writer[{payload}], *witTypes.{upper_kind}Reader[{payload}]) {{
@@ -1062,7 +1076,7 @@ impl Go {
10621076 func. params
10631077 . iter ( )
10641078 . skip ( if has_self { 1 } else { 0 } )
1065- . map ( |Param { name, .. } | name. to_lower_camel_case ( ) ) ,
1079+ . map ( |Param { name, .. } | escape_go_keyword ( name. to_lower_camel_case ( ) ) ) ,
10661080 )
10671081 . collect :: < Vec < _ > > ( ) ;
10681082
@@ -1422,7 +1436,7 @@ func wasm_export_{name}({params}) {results} {{
14221436 . iter ( )
14231437 . skip ( if has_self { 1 } else { 0 } )
14241438 . map ( |Param { name, ty, .. } | {
1425- let name = name. to_lower_camel_case ( ) ;
1439+ let name = escape_go_keyword ( name. to_lower_camel_case ( ) ) ;
14261440 let ty = self . type_name ( resolve, * ty, interface, in_import, imports) ;
14271441 format ! ( "{prefix}{name} {ty}" )
14281442 } )
@@ -1488,6 +1502,36 @@ func wasm_export_{name}({params}) {results} {{
14881502 if let hash_map:: Entry :: Vacant ( e) = self . futures_and_streams . entry ( ( ty, exported) ) {
14891503 e. insert ( interface. cloned ( ) ) ;
14901504
1505+ let name = self . go_package_name ( resolve, interface) ;
1506+
1507+ // Distinct `future`/`stream` types may share a
1508+ // payload type (e.g. when one payload is a type alias of the
1509+ // other, or when two anonymous payloads are structurally
1510+ // identical). Since the names of the generated declarations
1511+ // are derived from the payload type, generating code for each
1512+ // of them would produce duplicate declarations, so dedupe on
1513+ // the mangled payload name instead.
1514+ let kind = match & resolve. types [ ty] . kind {
1515+ TypeDefKind :: Future ( _) => "future" ,
1516+ TypeDefKind :: Stream ( _) => "stream" ,
1517+ _ => unreachable ! ( ) ,
1518+ } ;
1519+ let snake = payload_type
1520+ . map ( |ty| self . mangle_name ( resolve, ty, interface) )
1521+ . unwrap_or_else ( || "unit" . into ( ) ) ;
1522+
1523+ if !self
1524+ . generated_futures_and_streams
1525+ . insert ( FutureStreamDedup {
1526+ in_import,
1527+ is_exported : exported,
1528+ pkg_name : name. clone ( ) ,
1529+ mangled_name : format ! ( "{kind}_{snake}" ) ,
1530+ } )
1531+ {
1532+ continue ;
1533+ }
1534+
14911535 let data = self . future_or_stream (
14921536 resolve,
14931537 ty,
@@ -1498,7 +1542,6 @@ func wasm_export_{name}({params}) {results} {{
14981542 & func. name ,
14991543 ) ;
15001544
1501- let name = self . go_package_name ( resolve, interface) ;
15021545 if in_import || !exported {
15031546 & mut self . interfaces
15041547 } else {
@@ -1525,7 +1568,7 @@ func wasm_export_{name}({params}) {results} {{
15251568 }
15261569
15271570 fn go_package_name ( & self , resolve : & Resolve , interface : Option < & WorldKey > ) -> String {
1528- match interface {
1571+ let name = match interface {
15291572 Some ( WorldKey :: Name ( name) ) => name. to_snake_case ( ) ,
15301573 Some ( WorldKey :: Interface ( id) ) => {
15311574 let interface = & resolve. interfaces [ * id] ;
@@ -1550,7 +1593,9 @@ func wasm_export_{name}({params}) {results} {{
15501593 format ! ( "{namespace}_{package}_{version}{interface}" )
15511594 }
15521595 None => "wit_world" . into ( ) ,
1553- }
1596+ } ;
1597+
1598+ escape_go_keyword ( name)
15541599 }
15551600
15561601 fn func_name (
@@ -1897,11 +1942,16 @@ for index := 0; index < int({length}); index++ {{
18971942 self . generator . tuples . insert ( count) ;
18981943 self . imports . insert ( remote_pkg ( "types" ) ) ;
18991944
1900- let results = ( 0 ..count)
1945+ let names = ( 0 ..count)
19011946 . map ( |_| self . locals . tmp ( "result" ) )
1947+ . collect :: < Vec < _ > > ( ) ;
1948+ let bindings = names. join ( ", " ) ;
1949+ let fields = names
1950+ . iter ( )
1951+ . enumerate ( )
1952+ . map ( |( idx, name) | format ! ( "F{idx}: {name}" ) )
19021953 . collect :: < Vec < _ > > ( )
19031954 . join ( ", " ) ;
1904-
19051955 let types = tuple
19061956 . types
19071957 . iter ( )
@@ -1911,8 +1961,8 @@ for index := 0; index < int({length}); index++ {{
19111961
19121962 uwriteln ! (
19131963 self . src,
1914- "{results } := {call}
1915- {result} := witTypes.Tuple{count}[{types}]{{{results }}}"
1964+ "{bindings } := {call}
1965+ {result} := witTypes.Tuple{count}[{types}]{{{fields }}}"
19161966 ) ;
19171967 } else {
19181968 uwriteln ! ( self . src, "{result} := {call}" ) ;
@@ -2088,7 +2138,12 @@ if {value} {{
20882138 . map ( |& ty| self . type_name ( resolve, ty) )
20892139 . collect :: < Vec < _ > > ( )
20902140 . join ( ", " ) ;
2091- let fields = operands. join ( ", " ) ;
2141+ let fields = operands
2142+ . iter ( )
2143+ . enumerate ( )
2144+ . map ( |( idx, val) | format ! ( "F{idx}: {val}" ) )
2145+ . collect :: < Vec < String > > ( )
2146+ . join ( ", " ) ;
20922147 self . imports . insert ( remote_pkg ( "types" ) ) ;
20932148 results. push ( format ! ( "witTypes.Tuple{count}[{types}]{{{fields}}}" ) ) ;
20942149 }
@@ -2108,9 +2163,15 @@ if {value} {{
21082163 results. push ( format ! ( "({op}).{field}" ) ) ;
21092164 }
21102165 }
2111- Instruction :: RecordLift { ty, .. } => {
2166+ Instruction :: RecordLift { record , ty, .. } => {
21122167 let name = self . type_name ( resolve, Type :: Id ( * ty) ) ;
2113- let fields = operands. join ( ", " ) ;
2168+ let fields = record
2169+ . fields
2170+ . iter ( )
2171+ . zip ( operands. iter ( ) )
2172+ . map ( |( field, op) | format ! ( "{}: {op}" , field. name. to_upper_camel_case( ) ) )
2173+ . collect :: < Vec < _ > > ( )
2174+ . join ( ", " ) ;
21142175 results. push ( format ! ( "{name}{{{fields}}}" ) ) ;
21152176 }
21162177 Instruction :: OptionLower {
@@ -3286,3 +3347,11 @@ fn maybe_gofmt<'a>(format: Format, code: &'a [u8]) -> Cow<'a, [u8]> {
32863347 Cow :: Borrowed ( code)
32873348 } )
32883349}
3350+
3351+ #[ derive( Eq , PartialEq , Hash ) ]
3352+ struct FutureStreamDedup {
3353+ in_import : bool ,
3354+ is_exported : bool ,
3355+ pkg_name : String ,
3356+ mangled_name : String ,
3357+ }
0 commit comments