Skip to content

Commit 521a246

Browse files
committed
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.
2 parents a3b667a + 40017af commit 521a246

7 files changed

Lines changed: 76 additions & 9 deletions

File tree

.sources/VERSIONS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ chain-fusion-signer v0.4.0
5757
papi v0.1.1 168bc9d
5858
ic-pub-key v1.0.1 f89fa55
5959
icp-cli v1.1.0 fe4af7c
60-
motoko v1.13.0 cd63c2e
60+
motoko v1.14.1 58c3239
6161
motoko-core v2.4.0 cd37dbf
6262
cdk-rs ic-cdk v0.20.1 / ic-cdk-timers v1.0.0 / ic-cdk-executor v2.0.0 317f55c
6363
candid 2025-12-18 # candid v0.10.20, didc v0.5.4 2e4a2cf

.sources/motoko

Submodule motoko updated 48 files

docs/guides/authentication/internet-identity.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ To keep principals consistent across your own custom domains, configure **altern
569569
}
570570
```
571571
572-
A maximum of 10 alternative origins can be listed. No trailing slashes or paths.
572+
A maximum of 100 alternative origins can be listed. No trailing slashes or paths.
573573
574574
2. **Configure the asset canister** to serve the `.well-known` directory. Add an `.ic-assets.json5` in your frontend source:
575575

docs/languages/motoko/fundamentals/implicit-parameters.md

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ The compiler searches for implicit arguments in the following order, stopping at
191191
1. Local values in the current scope.
192192
2. Module fields (e.g., `Array.compare<T>`).
193193
3. Fields of unimported modules (requires `--implicit-package`).
194-
3. **Structural**: structural combiners (`__record`, `__tuple` convention) applied to record or 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):
195195
1. Local values in the current scope.
196196
2. Module fields.
197197
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
230230

231231
### Structural derivation
232232

233-
When an implicit is needed for a **record or 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.
234234

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:
236236

237237
| Parameter name | Combiner type | Implicit argument type | Description |
238238
|----------------|----------------------------|------------------------------------------|------------------------------------------------|
239239
| `__record` | `[(Text, () -> E)] -> R` | `Rec -> R` or `(Rec, Rec) -> R` | Record: one or two records, arity from implicit|
240240
| `__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)`|
242242

243243
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.
244244

@@ -381,6 +381,42 @@ func inspect<T>(x : T, describe : (implicit : T -> Text)) : Text = describe(x);
381381
assert inspect(("hello", 42 : Nat)) == "(hello, 42)";
382382
```
383383

384+
#### Variant derivation (`__variant`)
385+
386+
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);
413+
414+
type Shape = { #circle : Nat; #named : Text };
415+
assert inspect<Shape>(#named "hi") == "#named(hi)";
416+
```
417+
418+
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+
384420
#### Disambiguation: binary vs unary when both `__record` and `__tuple` are in scope
385421

386422
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:

docs/languages/motoko/reference/changelog.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,37 @@ sidebar:
88

99
# Motoko compiler changelog
1010

11+
## 1.14.1 (2026-08-17)
12+
13+
* motoko (`moc`)
14+
15+
* improvement: RTS weak reference interaction with the incremental GC: weak
16+
reference reads now go through a load barrier (#6296).
17+
18+
* bugfix: when decoding a Candid `blob` or `text`, bound the claimed length (#6311).
19+
20+
## 1.14.0 (2026-08-11)
21+
22+
* motoko (`moc`)
23+
24+
* feat: Structural implicit derivation now supports variants via the `__variant` combiner (`(Text, () -> E) -> R`).
25+
The synthesized wrapper switches on the active case and applies the combiner to its `(tag, payload thunk)`,
26+
deriving operations like serialization for any variant whose case payloads have instances (#6192).
27+
28+
* feat: the default maximum for stable memory (`--max-stable-pages`) is now 100 GiB
29+
(was 4 GiB), raising the default ceiling for the `Region` library.
30+
Override with `--max-stable-pages <n>` as before (#6279).
31+
32+
* bugfix: implement the new Candid subtyping rule `service <actortype> <: principal`
33+
(dfinity/candid#748): service references now decode at type `Principal`, both when
34+
decoded directly and in deferred subtype checks on function references (#6275).
35+
36+
* bugfix: a `class` in expression position lowered to unit instead of its
37+
constructor (#6291).
38+
39+
* bugfix: a self tail call whose argument is a tuple-returning expression
40+
crashed the compiler (or miscompiled, with the IR check off) (#6292).
41+
1142
## 1.13.0 (2026-08-03)
1243

1344
* motoko (`moc`)

docs/languages/motoko/reference/compiler-ref.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ You can use the following options with the `moc` command.
5656
| `--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. |
5757
| `--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.|
5858
| `--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). |
6060
| `-no-system-api` | Disables system API imports. |
6161
| `-no-timer` | Disables timer API imports and hides timer primitives. |
6262
| `-o <file>` | Specifies the output file. |

docs/languages/motoko/reference/language-manual.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2396,7 +2396,7 @@ the expanded function call expression `<parenthetical>? <exp1> <T0,…​,Tn>? <
23962396
23972397
- `__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.
23982398
- `__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.
24002400
24012401
The call expression `<exp1> <T0,…​,Tn>? <exp2>` evaluates `<exp1>` to a result `r1`. If `r1` is `trap`, then the result is `trap`.
24022402

0 commit comments

Comments
 (0)