@@ -762,7 +762,7 @@ struct IntrinsicJSFragment: Sendable {
762762 }
763763
764764 let innerFragment =
765- if wrappedType. optionalConvention == . stackABI {
765+ if wrappedType. optionalParameterUsesStackABI {
766766 try stackLowerFragment ( elementType: wrappedType)
767767 } else {
768768 try lowerParameter ( type: wrappedType)
@@ -779,7 +779,7 @@ struct IntrinsicJSFragment: Sendable {
779779 kind: JSOptionalKind ,
780780 innerFragment: IntrinsicJSFragment
781781 ) throws -> IntrinsicJSFragment {
782- let isStackConvention = wrappedType. optionalConvention == . stackABI
782+ let isStackConvention = wrappedType. optionalParameterUsesStackABI
783783
784784 return IntrinsicJSFragment (
785785 parameters: [ " value " ] ,
@@ -2696,6 +2696,24 @@ private extension BridgeType {
26962696 }
26972697 }
26982698
2699+ /// Whether an optional of this type pushes its payload onto the bridge stack
2700+ /// when passed as a *parameter*.
2701+ ///
2702+ /// This usually matches `optionalConvention == .stackABI`, but `jsObject`
2703+ /// optionals are the exception: their return values travel through the stack
2704+ /// while their parameters use the direct `(isSome, objId)` ABI, matching plain
2705+ /// `Optional<JSObject>` and exported `@JS class` parameters.
2706+ var optionalParameterUsesStackABI : Bool {
2707+ switch self {
2708+ case . jsObject:
2709+ return false
2710+ case . nullable( let wrapped, _) :
2711+ return wrapped. optionalParameterUsesStackABI
2712+ default :
2713+ return optionalConvention == . stackABI
2714+ }
2715+ }
2716+
26992717 var nilSentinel : NilSentinel {
27002718 switch self {
27012719 case . swiftProtocol:
0 commit comments