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
Merge origin/main into docs/guides-authentication-ii-app-metadata
main had already synced the II spec to release-2026-08-14 (#345), so
.sources/VERSIONS conflicted on the internetidentity line. Resolved to
release-2026-08-21 (4c934d1f), the newer pin, and reran
npm run sync:ii-spec so the generated files come from that pin rather
than from a text merge of two generated versions.
main also merged #349, which raised the alternative origins limit in the
guide; that line auto-merged and is unaffected by this branch.
Copy file name to clipboardExpand all lines: docs/languages/motoko/fundamentals/implicit-parameters.md
+40-4Lines changed: 40 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -191,7 +191,7 @@ The compiler searches for implicit arguments in the following order, stopping at
191
191
1. Local values in the current scope.
192
192
2. Module fields (e.g., `Array.compare<T>`).
193
193
3. Fields of unimported modules (requires `--implicit-package`).
194
-
3.**Structural**: structural combiners (`__record`, `__tuple`convention) applied to recordor tuple types (see [Structural derivation](#structural-derivation) below):
194
+
3.**Structural**: structural combiners (`__record`, `__tuple`, `__variant`convention) applied to record, tuple, or variant types (see [Structural derivation](#structural-derivation) below):
195
195
1. Local values in the current scope.
196
196
2. Module fields.
197
197
3. Fields of unimported modules (requires `--implicit-package`).
@@ -230,15 +230,15 @@ When derivation is attempted but fails (for example, because an inner implicit c
230
230
231
231
### Structural derivation
232
232
233
-
When an implicit is needed for a **recordor tuple type**, the compiler can synthesize it automatically using a *structural combiner*: a function whose single parameter name begins with `__` and encodes the structural decomposition kind. Structural combiners must not have implicit parameters.
233
+
When an implicit is needed for a **record, tuple, or variant type**, the compiler can synthesize it automatically using a *structural combiner*: a function whose single parameter name begins with `__` and encodes the structural decomposition kind. Structural combiners must not have implicit parameters.
234
234
235
-
Two structural kinds are supported, distinguished by the combiner's parameter name:
235
+
Three structural kinds are supported, distinguished by the combiner's parameter name:
236
236
237
237
| Parameter name | Combiner type | Implicit argument type | Description |
|`__record`|`[(Text, () -> E)] -> R`|`Rec -> R` or `(Rec, Rec) -> R`| Record: one or two records, arity from implicit|
240
240
|`__tuple`|`[() -> E] -> R`|`(A, B, ...) -> R` or `((A,B,...), (A,B,...)) -> R` (≥ 2 elements) | Tuple: one implicit per element |
241
-
|`__variant`|: |: | Reserved for future extension |
241
+
|`__variant`|`(Text, () -> E) -> R`|`Var -> R`| Variant: the active case `(tag, payload thunk)`|
242
242
243
243
Each per-field/element result is wrapped in a **thunk** (`() -> E`), giving the combiner full control over evaluation order. Combiners that need all values (like serialization) simply call every thunk. Combiners that can short-circuit (like comparison) can stop early: remaining thunks are never evaluated.
244
244
@@ -381,6 +381,42 @@ func inspect<T>(x : T, describe : (implicit : T -> Text)) : Text = describe(x);
When the compiler is looking for an implicit of type `Var -> R` where `Var` is a variant type `{ #t1 : T1; ...; #tn : Tn }`, it searches for a structural combiner whose parameter is named `__variant` and has type `(Text, () -> E) -> R`.
387
+
388
+
Unlike a record or tuple, a variant value is exactly **one** of its cases at runtime. The compiler synthesizes a wrapper that switches on the active case and applies the combiner once to its `(tag, payload thunk)`:
389
+
390
+
```
391
+
func($v) {
392
+
combiner(switch ($v) {
393
+
case (#t1 x) ("t1", func() { inst1(x) });
394
+
...
395
+
case (#tn x) ("tn", func() { instn(x) });
396
+
})
397
+
}
398
+
```
399
+
400
+
Each per-case implicit has type `Ti -> E`, resolved by the same search label. A no-payload case `#t` has payload type `()`, so it needs a `() -> E` instance: the same rule that applies to every component type of a record or tuple.
401
+
402
+
```motoko
403
+
// __variant combiner: serialise the active case as "#tag(payload)".
404
+
func show(__variant : (Text, () -> Text)) : Text {
405
+
let (tag, payload) = __variant;
406
+
"#" # tag # "(" # payload() # ")"
407
+
};
408
+
409
+
module TextShow { public func show(self : Text) : Text = self };
410
+
module NatShow { public func show(self : Nat) : Text = debug_show self };
411
+
412
+
func inspect<T>(x : T, show : (implicit : T -> Text)) : Text = show(x);
Only the unary form (`Var -> R`) is supported. Binary operations over variants (`(Var, Var) -> R`, e.g. `compare`) are not derived structurally, because the two values may be in different cases; write such combiners explicitly.
419
+
384
420
#### Disambiguation: binary vs unary when both `__record` and `__tuple` are in scope
385
421
386
422
Having `__record` and `__tuple` combiners in scope simultaneously is safe: the compiler picks the right path by inspecting the **number of arguments** in the implicit argument's function type. The dispatch depends on where the tuple appears in the source, not on what the type expands to:
Copy file name to clipboardExpand all lines: docs/languages/motoko/reference/compiler-ref.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -56,7 +56,7 @@ You can use the following options with the `moc` command.
56
56
|`--implicit-derivation-depth <n>`| Maximum recursion depth for [implicit](../fundamentals/implicit-parameters.md) argument derivation (default 100). Raise if a complex derivation is rejected as depth-limited. |
57
57
|`--legacy-persistence`| Use legacy (classical) persistence. This also enables the usage of --copying-gc, --compacting-gc, and --generational-gc. Deprecated in favor of the new enhanced orthogonal persistence, which is default. Legacy persistence will be removed in the future.|
58
58
|`--map`| Outputs a JavaScript source map. |
59
-
|`--max-stable-pages <n>`| Set maximum number of pages available for library `ExperimentStableMemory.mo`(default 65536). |
59
+
|`--max-stable-pages <n>`| Set maximum number of pages available to stable memory via the `Region` library (default 1638400, i.e. 100 GiB). |
60
60
|`-no-system-api`| Disables system API imports. |
61
61
|`-no-timer`| Disables timer API imports and hides timer primitives. |
Copy file name to clipboardExpand all lines: docs/languages/motoko/reference/language-manual.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2396,7 +2396,7 @@ the expanded function call expression `<parenthetical>? <exp1> <T0,…,Tn>? <
2396
2396
2397
2397
- `__record` (parameter type `[(Text, () -> E)] -> R`): handles both unary holes (`SomeRecord -> R`) and binary holes (`(SomeRecord, SomeRecord) -> R` where both args are the same record type). For a unary hole it synthesizes `func($r) { combiner([("f", func() = inst($r.f)), ...]) }` with per-field implicits `FieldType -> E`. For a binary hole it synthesizes `func($r1, $r2) { combiner([("f", func() = inst($r1.f, $r2.f)), ...]) }` with per-field implicits `(FieldType, FieldType) -> E`. Per-field thunks let the combiner short-circuit (e.g. comparison). The arity is determined by the hole type, not the combiner.
2398
2398
- `__tuple` (parameter type `[() -> E] -> R`): handles both unary holes (`(A, B, ...) -> R` with at least two elements) and binary holes (`((A, B, ...), (A, B, ...)) -> R` where both args are the same tuple type with ≥ 2 elements). For a unary hole it synthesizes `func($t) { combiner([func() = inst0($t.0), func() = inst1($t.1), ...]) }` with per-element implicits `ElemType_i -> E`. For a binary hole it synthesizes `func($t1, $t2) { combiner([func() = inst0($t1.0, $t2.0), ...]) }` with per-element implicits `(ElemType_i, ElemType_i) -> E`. Tuples with fewer than two elements are not synthesized: single-element tuples reduce to the element type, and unit `()` is treated as a scalar.
2399
-
- `__variant` is reserved for future extension.
2399
+
- `__variant` (parameter type `(Text, () -> E) -> R`): handles unary holes (`SomeVariant -> R`) only. Since a variant value is exactly one of its cases, it synthesizes `func($v) { combiner(switch $v { case (#t x) ("t", func() = inst(x)); ... }) }` with per-case implicits `CaseType -> E`. Binary holes (`(SomeVariant, SomeVariant) -> R`) are not synthesized, since the two values may inhabit different cases.
2400
2400
2401
2401
The call expression `<exp1> <T0,…,Tn>? <exp2>` evaluates `<exp1>` to a result `r1`. If `r1` is `trap`, then the result is `trap`.
0 commit comments