diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c2492c5..a96adb28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), - [#306](https://github.com/bytecodealliance/go-modules/issues/306): do not emit incompatible version feature gates when serializing WIT. For example, if a world with version `0.1.0` *includes* a world from another package with a `@since(version = 0.2.0)` feature gate, then strip that feature gate when serializing to WIT if the version is greater than the world’s package version. - [#350](https://github.com/bytecodealliance/go-modules/issues/350): correctly align `record` size to the highest alignment of its fields, per [specification](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#element-size). - +- [#352](https://github.com/bytecodealliance/go-modules/issues/352): do not use `tuple` types as data shape for `variant` or `result` types, as they may contain a `bool` or not be packed. ## [v0.6.2] — 2025-03-16 diff --git a/testdata/issues/issue352.wit b/testdata/issues/issue352.wit new file mode 100644 index 00000000..09f3a430 --- /dev/null +++ b/testdata/issues/issue352.wit @@ -0,0 +1,9 @@ +package issues:issue352; + +world w { + import i; +} + +interface i { + type a = result, s16>; +} diff --git a/testdata/issues/issue352.wit.json b/testdata/issues/issue352.wit.json new file mode 100644 index 00000000..5f5ae73b --- /dev/null +++ b/testdata/issues/issue352.wit.json @@ -0,0 +1,64 @@ +{ + "worlds": [ + { + "name": "w", + "imports": { + "interface-0": { + "interface": { + "id": 0 + } + } + }, + "exports": {}, + "package": 0 + } + ], + "interfaces": [ + { + "name": "i", + "types": { + "a": 1 + }, + "functions": {}, + "package": 0 + } + ], + "types": [ + { + "name": null, + "kind": { + "tuple": { + "types": [ + "bool", + "bool", + "bool" + ] + } + }, + "owner": null + }, + { + "name": "a", + "kind": { + "result": { + "ok": 0, + "err": "s16" + } + }, + "owner": { + "interface": 0 + } + } + ], + "packages": [ + { + "name": "issues:issue352", + "interfaces": { + "i": 0 + }, + "worlds": { + "w": 0 + } + } + ] +} \ No newline at end of file diff --git a/testdata/issues/issue352.wit.json.golden.wit b/testdata/issues/issue352.wit.json.golden.wit new file mode 100644 index 00000000..ff1dcdd1 --- /dev/null +++ b/testdata/issues/issue352.wit.json.golden.wit @@ -0,0 +1,9 @@ +package issues:issue352; + +interface i { + type a = result, s16>; +} + +world w { + import i; +} diff --git a/tests/generated/wasi/sockets/v0.2.0/network/abi.go b/tests/generated/wasi/sockets/v0.2.0/network/abi.go index a088bd1d..248787ae 100644 --- a/tests/generated/wasi/sockets/v0.2.0/network/abi.go +++ b/tests/generated/wasi/sockets/v0.2.0/network/abi.go @@ -7,6 +7,12 @@ import ( "unsafe" ) +// IPv6AddressShape is used for storage in variant or result types. +type IPv6AddressShape struct { + _ cm.HostLayout + shape [unsafe.Sizeof(IPv6Address{})]byte +} + // IPv6SocketAddressShape is used for storage in variant or result types. type IPv6SocketAddressShape struct { _ cm.HostLayout diff --git a/tests/generated/wasi/sockets/v0.2.0/network/network.wit.go b/tests/generated/wasi/sockets/v0.2.0/network/network.wit.go index a37b5b9a..ff1fbfc3 100644 --- a/tests/generated/wasi/sockets/v0.2.0/network/network.wit.go +++ b/tests/generated/wasi/sockets/v0.2.0/network/network.wit.go @@ -250,7 +250,7 @@ type IPv6Address [8]uint16 // ipv4(ipv4-address), // ipv6(ipv6-address), // } -type IPAddress cm.Variant[uint8, IPv6Address, IPv6Address] +type IPAddress cm.Variant[uint8, IPv6AddressShape, IPv6Address] // IPAddressIPv4 returns a [IPAddress] of case "ipv4". func IPAddressIPv4(data IPv4Address) IPAddress { diff --git a/wit/bindgen/generator.go b/wit/bindgen/generator.go index 5ddb5875..cb52900a 100644 --- a/wit/bindgen/generator.go +++ b/wit/bindgen/generator.go @@ -1032,8 +1032,8 @@ func (g *generator) typeDefShape(file *gen.File, dir wit.Direction, t *wit.TypeD case wit.Type: return g.typeShape(file, dir, kind) case *wit.Variant: - if kind.Enum() != nil { - // Variants that can be represented as an enum do not need a custom shape. + if len(kind.Types()) == 0 { + // Variants without associated types do not need a custom shape. return g.typeRep(file, dir, t) } case *wit.Result: @@ -1041,11 +1041,6 @@ func (g *generator) typeDefShape(file *gen.File, dir wit.Direction, t *wit.TypeD // Results without associated types do not need a custom shape. return g.typeRep(file, dir, t) } - case *wit.Tuple: - if kind.Type() != nil { - // Monotypic tuples have a packed memory layout. - return g.typeRep(file, dir, t) - } case *wit.Enum, *wit.Flags, *wit.List, *wit.Resource, *wit.Own, *wit.Borrow, *wit.Stream, *wit.Future: // Certain types do not need custom type shapes: