Wado

WEP: Literal Spread (..base)

Context

Wado has no way to build a { … } literal from an existing value. Rewriting one field of a struct forces listing every other field; building a map from another map, or composing a payload from several field sets, has the same boilerplate. Wado's { … } literal already covers three shapes — named structs, anonymous structs (synthesized from field shape, auto-Serialize), and key-value collections via KeyValueLiteralBuilder — so the fix should serve all three with one rule.

Decision

Add a ..base spread member to { … } literals, following JS spread rather than Rust's Functional Record Update.

Model: a literal is a left-to-right sequence of members — explicit k: v or ..base. Members are applied in source order, last write wins. Every subexpression is evaluated once, in source order; precedence is independent of evaluation.

One rule governs everything — a dead-write check:

A member is an error iff every field/key it contributes is also contributed by a later member (it is fully shadowed).

This is decidable only when field sets are statically known, which is exactly what makes the three cases differ without any per-case special rule:

Which mode applies follows the existing anonymous-vs-named literal split: an expected nominal type (A { … }, let x: A = { … }) constrains every ..base to that type; an inferred literal synthesizes the union.

Standalone ..base (no overriding members) is an error: under value semantics it is just a deep copy of base, which base itself already is.

Type rules: in a nominal literal, each ..base must be the literal's type (generic args unifiable) and participates in type-argument inference like an explicit member. In an anonymous literal, spreads may differ and drive the union. Field reads via a spread obey the same read-reachability as base.f, so ..base cannot pull a private field across a module boundary.

Consequences