@@ -216,3 +216,85 @@ fn main() -> Unit {
216216 never nests generics more than a handful of levels, and the item is rated LOW / non-correctness.
217217 The risk of regressing generics resolution was judged disproportionate to the benefit, so the fix
218218 is left for a dedicated change rather than bundled with the RSS-1…RSS-10 correctness fixes.
219+
220+ ---
221+
222+ ## Added during tinygrad-port work (2026-06-11)
223+
224+ ### RSS-12 — [ FIXED] — Nested generic type-arguments in method calls parsed as comparisons
225+ - ** Source:** ` crates/rsscript/src/syntax/parser.rs ` ` find_top_level_operator ` (~ :3031).
226+ - ` List.new<List<Int>>() ` , ` List.get<List<Int>>(...) ` , ` List.len<List<Int>>(...) ` all failed with
227+ RS0015 "unsupported syntax". The binary-operator splitter tracked ` angle_depth ` asymmetrically:
228+ it decremented on a nested inner ` > ` but never incremented on the nested inner ` < ` (the inner
229+ ` < ` of ` List<Int> ` is not a generic-open per ` is_generic_angle_open ` , which requires the matching
230+ ` > ` to be followed by ` . ` /` ( ` ), so ` angle_depth ` hit 0 one ` > ` early and the outer ` > ` was parsed
231+ as a ` Greater ` comparison → the call collapsed to ` Expr::Unknown ` .
232+ - ** Fix:** inside a generic argument list (` angle_depth > 0 ` ), also ` angle_depth += 1 ` on ` < ` . Inside
233+ a type-argument list ` < ` is unambiguously a nested generic open, never a comparison.
234+ - ** Verified:** ` List<List<Int>> ` build/index/len/param all parse, typecheck, and run.
235+
236+ ### RSS-13 — [ FIXED] — User sum payload-variant construction did not resolve/lower
237+ - Previously documented in fixtures as "user payload-variant construction is not yet executable":
238+ declaring and ` match ` ing payload variants worked, but constructing one (` ArgInt(value: 5) ` ,
239+ ` Shape.Circle(radius: 5) ` ) failed with RS0206 "does not resolve" / a backend "cannot find tuple
240+ variant" error.
241+ - ** Sources / fix (two sites):**
242+ 1 . ` crates/rsscript/src/hir.rs ` ` resolve_call ` (~ :762): also resolve a call as
243+ ` CallResolution::EnumVariant ` when ` self.sum_type_for_variant(name).is_some() ` (not only the
244+ builtins Ok/Err/Some/None). The reg-VM already lowered ` MakeVariant ` via ` sum_variant_fields ` .
245+ 2 . ` crates/rsscript/src/rust_lower/lowerer.rs ` constructor lowering (~ :2412): emit the qualified,
246+ struct-style form ` Enum::Variant { field: value, ... } ` (nullary: ` Enum::Variant ` ) for user sum
247+ variants, matching the lowered enum (whose payload variants use named fields), instead of the
248+ bare/tuple fall-through.
249+ - ** Verified:** construct + ` match ` /discriminate + extract (via owned/` take ` scrutinee) all run.
250+ - ** Known follow-up:** extracting a * Copy* payload (Int/Float) directly from a * borrowed* (` read ` )
251+ match still needs the binding deref'd (use an owned ` take ` /cloned scrutinee for now).
252+
253+ ### RSS-15 — [ ADDED] — Explicit, callable ` .clone() ` for ` derives(Clone) ` types
254+ - Previously only implicit clone existed (e.g. ` read ` args retained into a collection); there was no
255+ surface syntax to deep-copy a user value, and ` derives(Copy) ` on a sum is rejected. This blocked
256+ rebuilding immutable graph nodes (e.g. a UOp simplifier).
257+ - ** Added (kept implicit clone):**
258+ - ` hir.rs ` ` resolve_receiver_call ` : when no method candidate resolves and the method is ` clone ` ,
259+ synthesize a builtin sig ` (self: read T) -> fresh T ` so ` x.clone() ` resolves and types as ` T ` .
260+ - ` rust_lower/lowerer.rs ` receiver-call lowering: for a user struct/sum receiver, emit
261+ ` {receiver}.clone() ` (Rust's derived Clone = deep copy). Gated to user types so builtins
262+ (JSON/Map/List) keep their own clone lowering (` json_clone ` , …).
263+ - ` rust_lower/lowerer.rs ` ` lower_call_arg_for_expected_type ` : exclude ` clone ` from the
264+ "` read ` receiver-call result is re-borrowed" rule — ` .clone() ` yields an owned value, so passing
265+ it to a by-value param must not add ` & ` (was emitting ` &x.clone() ` into an owned param).
266+ - ** Verified:** clone of struct/sum/field; clone passed to a by-value param; whole rss suite green.
267+
268+ ### RSS-13 follow-ups — [ FIXED] — payload-variant construction is now typed & checked
269+ - (Audit found the initial RSS-13 resolved variant calls but did not type/check them.)
270+ - ** P1 type:** ` hir.rs ` ` infer_enum_variant_type ` now returns the variant's sum type for user variants
271+ (was only Some/Ok/Err), so ` Number(value: 5) ` has type ` Token ` and misuse (e.g. passing it to a
272+ ` read String ` param) is caught (RS0207) instead of emitting invalid Rust.
273+ - ** P1 check / no panic:** ` checks/calls.rs ` ` check_enum_variant_form ` validates user-variant
274+ construction against declared fields — unknown field name (RS0203), wrong arity (RS0203/RS0204) —
275+ so a malformed constructor (` Number(1, 2) ` , ` Number(bad: 5) ` ) is a checker error, not an
276+ out-of-bounds panic in the lowerer.
277+ - ** P2 field types:** ` rust_lower/lowerer.rs ` variant construction lowers each arg against its declared
278+ field type (mirroring struct ctors) and resolves fields by name bounds-safely. Note: once round-2
279+ value-type checking landed, ` Tiny(value: 1) ` with ` value: Int32 ` is * rejected* at check (RS0207, an
280+ ` Int ` literal is not ` Int32 ` ) — same as struct constructors; the field-type lowering applies to
281+ values that already have the field's type (e.g. an ` Int32 ` -typed binding), which lower without a cast.
282+
283+ ### RSS-13 follow-ups (round 2) — [ FIXED] — duplicate fields & field-value types
284+ - (Second audit: the round-1 variant checker tracked names/counts but not duplicates or value types.)
285+ - ** Exactly-once coverage:** ` check_enum_variant_form ` now tracks per-field coverage — duplicate field
286+ (RS0205), unknown field (RS0203), too many (RS0203), and any unfilled field (RS0204). So
287+ ` Both(left: 1, left: 2) ` reports duplicate ` left ` + missing ` right ` (was: passed check, then E0062).
288+ - ** Value types:** each variant field value is type-checked against its declared field type (reusing
289+ ` argument_type_matches ` + the JSON/Map/List literal acceptances, like binding-payload checks). So
290+ ` Number(value: "x") ` for ` value: Int ` reports RS0207 (was: passed check, then E0308).
291+
292+ ### RSS-15 / RSS-13 follow-ups (round 3) — [ FIXED] — clone gated on ` Clone ` ; variants are named-only
293+ - ** ` .clone() ` only for ` Clone ` -deriving types:** the synthesized clone previously resolved for * any*
294+ user type, so ` struct Boxy derives(Eq) ` passed ` check ` then failed Rust with E0599. Now ` Hir ` tracks
295+ ` clone_types ` (declared types whose derive list includes ` Clone ` ); ` resolve_receiver_call ` synthesizes
296+ ` clone ` only for those (non-user receivers keep prior behavior), and rust_lower emits ` .clone() ` only
297+ when ` type_derives_clone(root) ` . A declared type without ` Clone ` now reports RS0206 at check time.
298+ - ** Variants are named-field-only:** ` check_enum_variant_form ` rejects any unnamed payload arg
299+ (RS0201), matching the v0.6 spec (variants use the same named-field construction form as structs).
300+ ` Number(5) ` is now a checker error instead of lowering to ` Token::Number { value: 5i64 } ` .
0 commit comments