/
nv-lang
/
nova
Обзор
Документация
Войти
/
nv-lang
/
nova
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
std/src/encoding/serde/record_autoderive_test.nv
118 строк
5 KB
Evgeniy Golovin
fix(№111): прямая сериализация Vec[T] — check_satisfaction_against_methods распознаёт []T-блэнкет (D239); фикстуры round-trip
26 июл 2026, 22:06
26 июл 2026, 22:06
5d378a4
Код
Авторство
О чём код?
// Plan 180 Ф.2 — record auto-derive via #impl(Serialize + Deserialize). // No hand-written @serialize/.deserialize: the compiler synthesizes them. // Migrated from nova_tests/serde/autoderive.nv (Plan 182 Ф.2): the same // content compiled fine in-module (folder=one-CU, same as here) but hit a // cross-module CODEGEN-FAIL when consumed as an external-consumer fixture // (`str.from` unresolved under strict-mode mono) — living beside the module // avoids that import boundary entirely. module encoding.serde #impl(Serialize + Deserialize) type Addr value { ro city str, ro zip int } #impl(Serialize + Deserialize) type User value { ro name str ro age int ro addr Addr ro tags []str ro email Option[str] ro score f64 } test "auto-derive record round-trip (flat + nested + Vec + Option + float)" { ro u = User{ name: "alice", age: 30, addr: Addr{ city: "NYC", zip: 10001 }, tags: ["x", "y"], email: Some("a@b.c"), score: 3.14 } ro enc = json_encode(u)!! ro dec = json_decode[User](enc)!! assert(dec.name == "alice") assert(dec.age == 30) assert(dec.addr.city == "NYC") assert(dec.addr.zip == 10001) assert(dec.tags.len() == 2) assert(dec.tags[0] == "x") assert(dec.email == Some("a@b.c")) assert(dec.score == 3.14) } test "auto-derive with None + empty vec" { ro u = User{ name: "bob", age: 0, addr: Addr{ city: "", zip: 0 }, tags: [], email: None, score: -0.5 } ro dec = json_decode[User](json_encode(u)!!)!! assert(dec.email == None) assert(dec.tags.len() == 0) assert(dec.score == -0.5) } // Plan 221.1 №111 — `Vec[T Serialize]` as a unit of (de)serialization. // `VecWrapper.items` uses the EXPLICIT generic spelling `Vec[VecItem]` (as // opposed to `tags []str` above, which uses the `[]T` array-sugar spelling) // — both are the SAME receiver per D239, but the auto-derive synthesizer's // per-field `@items.serialize(s)?`/static `Vec[VecItem].deserialize(sub)?` // dispatched to serde.nv's `fn[T Serialize] []T @serialize[S Serializer]`/ // `fn[T Deserialize] []T.deserialize[D Deserializer]` container-conformance // blanket, registered under the LITERAL "[]T" method_table key (parser // spelling) — the checker's receiver-return-type resolution recognized the // `[]T`-sugar spelling (an Array TypeRef) but bailed on the explicit // `Vec[T]`-generic spelling (a Named TypeRef with a concrete type-arg), // ICE'ing `[P67-LEGACY] method call `.serialize` return type unknown` // (emit_c.rs) — a struct field with an explicit-generic Vec-of-serializable // element never compiled at all before this fix. #impl(Serialize + Deserialize) type VecItem value { ro name str, ro count int } #impl(Serialize + Deserialize) type VecWrapper value { ro items Vec[VecItem] } test "auto-derive record field with explicit Vec[T] generic spelling round-trip" { ro w = VecWrapper{ items: [VecItem{ name: "a", count: 1 }, VecItem{ name: "b", count: 2 }] } ro enc = json_encode(w)!! ro dec = json_decode[VecWrapper](enc)!! assert(dec.items.len() == 2) assert(dec.items[0].name == "a") assert(dec.items[0].count == 1) assert(dec.items[1].name == "b") assert(dec.items[1].count == 2) } test "auto-derive record field with explicit Vec[T] generic spelling — empty vec" { ro w = VecWrapper{ items: [] } ro dec = json_decode[VecWrapper](json_encode(w)!!)!! assert(dec.items.len() == 0) } // Direct (top-level, no struct wrapper) serialization of a BARE `Vec[T]` // value — the OTHER half of №111 ("иной краш-путь"): before this fix, ANY // direct `json_encode(vec)` call — regardless of `[]T`/`Vec[T]` spelling and // regardless of element type (verified: reproduced identically for a bare // `[]str`) — was REJECTED at the generic-bound check // (`json_encode[T Serialize]`) with "type `Vec` does not satisfy `Serialize` // bound", because that check consulted `method_table.get("Vec")` directly and // never considered the "[]T"-keyed container-conformance blanket at all. Fixed // by recursing into the element type when a matching slice-typevar blanket is // registered for the bound's required method(s). // // Decode direction NOT covered here: `json_decode[Vec[VecItem]](enc)` (a // direct top-level turbofish target, as opposed to a struct field's nested // `Vec[T].deserialize` call synthesized by the derive machinery, which DOES // work — see `VecWrapper` above) hits a SEPARATE, pre-existing mono- // collection gap (linker: `undefined symbol …_static_deserialize`), // element-independent (reproduces for `Vec[str]` too) and unmasked — not // introduced — by this fix (previously hidden behind the bound-check's false // rejection). Filed as a follow-up (see registry), out of №111's scope. test "direct top-level Vec[T] serialization (no enclosing struct)" { ro items = [VecItem{ name: "x", count: 10 }, VecItem{ name: "y", count: 20 }] ro enc = json_encode(items)!! assert(enc.starts_with("[")) assert(enc.ends_with("]")) assert(enc.contains("\"name\":\"x\"")) assert(enc.contains("\"count\":10")) assert(enc.contains("\"name\":\"y\"")) assert(enc.contains("\"count\":20")) }