-
Notifications
You must be signed in to change notification settings - Fork 20
Incorrect code is generated for option<borrow<resource>> in some records #394
Description
Summary
wit-bindgen-go generates incorrect lift functions when a record containing option<borrow<resource>> is defined in one interface and used as a function parameter in another interface. The lift function incorrectly returns cm.Option[cm.Rep] instead of cm.Option[ResourceType], causing a type mismatch compilation error.
Environment
- wit-bindgen-go: Latest from
go.bytecodealliance.org/cmd/wit-bindgen-go(as of 2025年10月15日) - go-modules: commit
55a8715 - Go: 1.23+
- TinyGo: 0.34.0 (wasip2 target)
Minimal Reproduction
WIT Definition
package my:test@0.1.0; interface protocol { use wasi:io/streams@0.2.3.{output-stream}; record client-context { output: option<borrow<output-stream>>, } } interface tools { use protocol.{client-context}; do-something: func(ctx: client-context); } world test { export tools; }
Generated Code (Incorrect)
File: my/test/protocol/protocol.wit.go
type ClientContext struct { _ cm.HostLayout `json:"-"` Output cm.Option[OutputStream] `json:"output"` }
File: my/test/tools/abi.go
func lift_OptionBorrowOutputStream(f0 uint32, f1 uint32) (v cm.Option[cm.Rep]) { if f0 == 0 { return } return (cm.Option[cm.Rep])(cm.Some[cm.Rep](cm.Reinterpret[cm.Rep]((uint32)(f1)))) } func lift_ClientContext(f0 uint32, f1 uint32) (v protocol.ClientContext) { v.Output = lift_OptionBorrowOutputStream(f0, f1) // ❌ Type mismatch! return }
Compilation Error
my/test/tools/abi.go:18:13: cannot use lift_OptionBorrowOutputStream(f0, f1)
(value of struct type cm.Option[cm.Rep]) as cm.Option[protocol.OutputStream]
value in assignment
Expected Behavior
The lift function should return the concrete resource type, not cm.Rep:
func lift_OptionBorrowOutputStream(f0 uint32, f1 uint32) (v cm.Option[protocol.OutputStream]) { if f0 == 0 { return } return (cm.Option[protocol.OutputStream])(cm.Some[protocol.OutputStream]( cm.Reinterpret[protocol.OutputStream]((uint32)(f1)))) }
Analysis
The bug occurs due to cross-interface type resolution:
- Within same package (
option<borrow<resource>>in same interface): ✅ Generates correctly - Cross-package record fields (
borrow<resource>without option): ✅ Generates correctly - Cross-package with option wrapper (
option<borrow<resource>>): ❌ Bug triggered
The codegen correctly handles:
- Function parameters with
option<borrow<resource>>→cm.Option[cm.Rep] - Record fields with
borrow<resource>→ResourceType
But fails when combining both patterns in a cross-interface scenario.
Impact
This bug affects the wasmcp MCP framework where ClientContext (defined in wasmcp:mcp/protocol) contains output: option<borrow<output-stream>> and is used across multiple capability interfaces.
Example: wasmcp:mcp/tools-capability interface uses client-context from the protocol interface:
interface protocol { record client-context { identity-claims: option<string>, session-id: option<string>, output: option<borrow<output-stream>>, } }
interface tools-capability { use protocol.{client-context, ...}; list-tools: func(request: list-tools-request, client: client-context) -> list-tools-result; call-tool: func(request: call-tool-request, client: client-context) -> option<call-tool-result>; }
This prevents building any Go-based MCP tools capability using wit-bindgen-go.
Workaround
The only current workaround is to manually patch the generated abi.go file after each generation:
-func lift_OptionBorrowOutputStream(f0 uint32, f1 uint32) (v cm.Option[cm.Rep]) { +func lift_OptionBorrowOutputStream(f0 uint32, f1 uint32) (v cm.Option[protocol.OutputStream]) { if f0 == 0 { return } - return (cm.Option[cm.Rep])(cm.Some[cm.Rep](cm.Reinterpret[cm.Rep]((uint32)(f1)))) + return (cm.Option[protocol.OutputStream])(cm.Some[protocol.OutputStream]( + cm.Reinterpret[protocol.OutputStream]((uint32)(f1)))) }
This is fragile and breaks on every regeneration.