You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The resolution logic lives in `try_resolve_callback()` in `interface_emitter.mbt`, which checks both direct callbacks (`type_registry.get_callback_def()`) and typedef→callback chains (`type_registry.resolve_typedef_to_callback()`).
135
+
121
136
### FromJsAny Pattern
122
137
123
138
Every generated type (`#external` interfaces, dictionaries, callbacks, typedefs, namespaces) gets a `FromJsAny` impl via `ImplFromJsAny` in the `Emit` enum. Enums get a custom impl using `from_unchecked(String)`. This enables type-safe `JsPromise[T]` resolution on wasm-gc.
@@ -220,6 +235,7 @@ Quick reference for MoonBit patterns that differ from Rust/OCaml and cause frequ
220
235
-**Private types**: Use `priv enum` / `priv struct` for types not in the public API; the compiler warns if you forget `priv`
221
236
-**`///|` doc comments**: Required before every top-level declaration (function, type, let binding); `moon fmt` adds them automatically
222
237
-**Enum constructors in expressions**: Can omit the type prefix when the expected type is known from context (e.g., `HasArg("x")` instead of `ArgMatch::HasArg("x")` when the field type is `ArgMatch`)
238
+
-**Guard clauses**: `guard expr is Pattern(x) else { return None }` for early returns from pattern matching on Option/enum types. Preferred over nested `match` when extracting a single variant.
-**Test helpers**: Define shared helpers (like `make_arg`, `setup_emitter`) at the top of `_wbtest.mbt` files to reduce boilerplate. The emit package has `setup_test` in `emit_wbtest.mbt`.
244
260
-**Multi-target output**: Use `mbt_code_gen_multi(emits)` which returns `{ shared, js_ffi, wasm_ffi }` — always assert all three fields to catch regressions in both JS and wasm-gc output.
261
+
-**Type predicates**: Use `ArgMbtType` methods (`is_string()`, `is_enum()`, `is_dictionary()`) — not standalone functions.
245
262
246
263
## wasm-gc Known Issues
247
264
@@ -253,9 +270,9 @@ All examples compile for both js and wasm-gc targets except `fetch-async` (requi
253
270
254
271
**`JsValue::null()` defaults on non-nullable types (resolved)**: On wasm-gc, `JsValue::null()` returns `externref` (nullable), but string-typed aliases like `CSSOMString = String` map to `(ref extern)` (non-nullable). The MoonBit compiler generates a default-value thunk returning `(ref extern)` that internally calls the nullable `JsNull::null` import — this fails `wasm-tools validate`. The code generator in `method_args()` (`interface_emitter.mbt`) now strips `JsValue::null()` defaults for `Primitive(_)`, `Enum(_)`, **and `Other(_)`** types (the last catches type aliases). The parameter becomes a plain optional and `opt_to_js` sends `undefined` when absent. Use `make validate-wasm` after `make build-examples` to catch these issues early — it runs in <2 seconds vs 14+ seconds for Playwright.
255
272
256
-
**`externref` vs `(ref extern)` nullability on wasm-gc (resolved)**: On wasm-gc, `JsValue` maps to `externref` (nullable) and `JsAny`/`String` maps to `(ref extern)` (non-nullable). MoonBit's `unsafe_cast()` generates no wasm instructions — it cannot change nullability. To convert `externref` → `(ref extern)`, use the `jsvalue_to_jsany()` helper (defined in `base.mbt/js_value_wasm.mbt`) which uses the `String?` unwrap trick to emit `ref.as_non_null`. This is needed when passing JsValue results to `FromJsAny::from_js_any()` for primitive type conversions (Bool, Int, Double). See dictionary getter code in `emit.mbt` (`render_dictionary_getter_shared`). For `#external` types returned from wasm FFI imports, the pattern is: declare the FFI as returning `JsValue` (externref), then `.unsafe_cast()` to the target type (see `js_object_wasm.mbt` for an example).
273
+
**`externref` vs `(ref extern)` nullability on wasm-gc (resolved)**: On wasm-gc, `JsValue` maps to `externref` (nullable) and `JsAny`/`String` maps to `(ref extern)` (non-nullable). MoonBit's `unsafe_cast()` generates no wasm instructions — it cannot change nullability. To convert `externref` → `(ref extern)`, use the `jsvalue_to_jsany()` helper (defined in `base.mbt/js_value_wasm.mbt`) which uses the `String?` unwrap trick to emit `ref.as_non_null`. This is needed when passing JsValue results to `FromJsAny::from_js_any()` for primitive type conversions (Bool, Int, Double). The `JsValue::to_option_prim()` helper in `base.mbt/js_value.mbt` encapsulates this pattern for nullable returns. For `#external` types returned from wasm FFI imports, the pattern is: declare the FFI as returning `JsValue` (externref), then `.unsafe_cast()` to the target type (see `js_object_wasm.mbt` for an example).
257
274
258
-
**`unsigned long long` (UInt64) properties on wasm-gc (resolved)**: The JS runtime code generator now wraps return values of `LongLong`, `UnsignedLongLong`, and `Bigint` types with `BigInt()` in generated getters and methods (e.g., `get_version: (obj) => BigInt(obj.version)`). The `is_bigint_type` helper in `emit_js_runtime.mbt` detects these types and the `is_bigint` parameter on `emit_js_getter`/`emit_js_method`/`emit_js_namespace_getter`/`emit_js_namespace_method` controls wrapping.
275
+
**`unsigned long long` (UInt64) properties on wasm-gc (resolved)**: The JS runtime code generator now wraps return values of `LongLong`, `UnsignedLongLong`, and `Bigint` types with `BigInt()` in generated getters and methods (e.g., `get_version: (obj) => BigInt(obj.version)`). The `is_bigint_type` helper in `emit_js_runtime.mbt` detects these types and the `is_bigint` parameter on `emit_js_getter`/`emit_js_method` controls wrapping. Namespace methods/getters reuse these same functions with `is_static=true`.
259
276
260
277
## Pending: remove default_value from code generation (branch `remove-default-value`)
0 commit comments