check: reject an untyped array-literal borrow into a union slice variant (#18)
This commit is contained in:
@@ -4856,6 +4856,26 @@ fn isassignable(c: *checker, dst: *syntax.node, src: *syntax.node, confident: *b
|
||||
// qualleaf bridge). Pre-c3 the collision was ALSO accepted (call-arg
|
||||
// ran no check; let/return short-circuited on the scalar variant) — c3
|
||||
// is NEUTRAL on it.
|
||||
// #18: an ARRAY src reaching here means NO slice/array variant
|
||||
// matched by element type — the loop above confident-rejects a
|
||||
// [N]T-vs-[]U element mismatch and returns true on an exact match,
|
||||
// so an array surviving to here matches nothing. An array's only
|
||||
// legal tagged path is an exact-element slice variant (#17 desugar)
|
||||
// or an array variant (#5/#60), both decided confidently in the
|
||||
// loop. The shape-lenient leg below exists for nominal-lossy cross-
|
||||
// module ptr/struct identity (#10/#66/#37); arrays never have it
|
||||
// (element identity is structural, fully AST-known). So a [N]T here
|
||||
// is a CONFIDENT reject — mirror cstage type_assignable's concrete→
|
||||
// tagged arm returning 0 (cmd/wcc/type.c:344) and harec
|
||||
// tagged_select_subtype (no unique assignable member, ref/harec/src/
|
||||
// types.c:702 + the STORAGE_SLICE to_secondary==from_secondary gate
|
||||
// :1097). Without this an untyped-int arrlit return (`[10,20,30]`
|
||||
// defaults to [3]int) shape-matched the `e` (i32) variant (both
|
||||
// tagshape 0) → conf=false → checkretassign bailed before
|
||||
// rejectarrlitborrow = silent accept (wwstage-only, cs≠ww).
|
||||
if (su.kind == syntax.nkind.N_TARRAY) {
|
||||
return false; // *confident already true on this path
|
||||
};
|
||||
if (su.kind != syntax.nkind.N_TNAME) {
|
||||
let ss: i32 = tagshape(su);
|
||||
let sp: *syntax.node = du.list;
|
||||
@@ -5613,6 +5633,20 @@ fn rejectarrlitborrow(c: *checker, dsttn: *syntax.node, val: *syntax.node) bool
|
||||
// variant so the reject sees through the union. An N_ARRLIT can only
|
||||
// target a slice variant; an array-typed variant is the #5/#60 reject
|
||||
// upstream; full non-let support is #33. Twin of cstage #13 arm.
|
||||
//
|
||||
// #20 RETAINED DIVERGENCE (benign, rule-7 tracked, NEVER silent): this
|
||||
// chase is UNGATED — it picks the first slice variant whatever the
|
||||
// arrlit's element type. cstage's reject_arrlit_borrow gates the same
|
||||
// chase on type_assignable (cmd/wcc/check.c reject_arrlit_borrow), so
|
||||
// for an UNTYPED arrlit whose element matches NO variant (#18: [3]int
|
||||
// into ([]i32|e)) cstage DECLINES the chase → rejects purely at the
|
||||
// assignability layer ("not assignable"). wwstage emits "not assignable"
|
||||
// too (errnotassign, checkretassign) and THEN this extra "cannot borrow
|
||||
// as a slice". Both stages reject the SAME SET — no decision/asm
|
||||
// divergence (a reject emits no .s; rule-10 is asm-only). The exact-
|
||||
// parity port (gate this chase on isassignable, mirroring cstage) is
|
||||
// task #20; it touches this shared #13/#17/#18 chokepoint, so it is its
|
||||
// own commit.
|
||||
if (du.kind == syntax.nkind.N_TTAGGED) {
|
||||
let v: *syntax.node = du.list;
|
||||
for (v != nil) {
|
||||
|
||||
21
test/wcc/data/arrlit_slice_reject_union_untyped/case.ww
Normal file
21
test/wcc/data/arrlit_slice_reject_union_untyped/case.ww
Normal file
@@ -0,0 +1,21 @@
|
||||
//ww:error "not assignable"
|
||||
// #18 carrier: an UNTYPED-int array literal returned into a tagged-union SLICE
|
||||
// success variant ([]i32 | e). The literal defaults to [3]int, which is NOT
|
||||
// assignable to any variant ([]i32 wants i32 elements; e is i32), so BOTH stages
|
||||
// must REJECT at the assignability layer — harec tagged_select_subtype needs a
|
||||
// UNIQUE assignable member and the STORAGE_SLICE arm requires element identity
|
||||
// (ref/harec/src/types.c:702 + :1097). cstage rejects via type_assignable
|
||||
// returning 0 (cmd/wcc/type.c:344); wwstage's isassignable previously shape-
|
||||
// matched [3]int against the `e` (i32) scalar variant (both tagshape 0) and went
|
||||
// LENIENT (confident=false), so checkretassign short-circuited before the borrow
|
||||
// gate and SILENTLY ACCEPTED — a wwstage-only miscompile (cs≠ww). The fix makes
|
||||
// an array src with no element-matching variant a CONFIDENT reject in isassignable.
|
||||
// Sibling of #13 (the TYPED-literal leg, rejected by the borrow gate after it
|
||||
// passes assignability) and distinct from #17 (a legal array VARIABLE coercion).
|
||||
package main;
|
||||
type e = !i32;
|
||||
fn mk() ([]i32 | e) = { return [10, 20, 30]; };
|
||||
export fn main() i32 = {
|
||||
let s: []i32 = mk()!;
|
||||
return s[0];
|
||||
};
|
||||
Reference in New Issue
Block a user