Found while reviewing #197. The struct constructor validates only arity at runtime, never field types, and the setter validates nothing. The analyser rejects direct ill-typed calls (P("str") is a compile error), but any Any-typed path bypasses it:
struct P { x: Int }
let ctors = [P];
let p = ctors[0]("not an int"); // constructs successfully
// p.x now holds a String in an Int-typed field
The same applies to Any-mediated setter calls. Code the analyser statically resolved under the assumption p.x: Int then fails later at an unrelated site with a confusing error.
Suggested direction
The constructor and setter closures (ndc_vm/src/value/function.rs) already capture Rc<StructInfo> and check arity; they could check the argument values against info.fields the same way. Worth deciding together with the planned subtyping rework, since "does this value fit this StaticType" is exactly the relation being reworked there (e.g. #191, and the deferred Option/None assignability).
🤖
Found while reviewing #197. The struct constructor validates only arity at runtime, never field types, and the setter validates nothing. The analyser rejects direct ill-typed calls (
P("str")is a compile error), but anyAny-typed path bypasses it:The same applies to
Any-mediated setter calls. Code the analyser statically resolved under the assumptionp.x: Intthen fails later at an unrelated site with a confusing error.Suggested direction
The constructor and setter closures (
ndc_vm/src/value/function.rs) already captureRc<StructInfo>and check arity; they could check the argument values againstinfo.fieldsthe same way. Worth deciding together with the planned subtyping rework, since "does this value fit thisStaticType" is exactly the relation being reworked there (e.g. #191, and the deferredOption/Noneassignability).🤖