wcc/check: #24-sib reject array-payload tagged-union construction, both stages
Constructing an array-typed payload into a tagged-union variant silently dropped it (cstage MOVQ $0 -> returns 0; wwstage match-loud only). Reject the construct when the selected variant chases to TY_ARRAY (target TY_TAGGED, non-tagged source). tagged-struct/slice/scalar/str variants and the array TYPE-decl stay legal. Faithful array-into-box block-store deferred (#6). test/wcc/834 (new) + Makefile.
This commit is contained in:
@@ -125,6 +125,39 @@ variant_present(Tparam *head, Type *vt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tagged_array_variant — #5/#60: when `src` is boxed into the tagged
|
||||
* union `dst`, return the variant `src` selects IFF that variant chases
|
||||
* to TY_ARRAY, else NULL. The array-payload box is unwired in cgen: the
|
||||
* widen emitter zero-fills the slot at box materialization (a silent
|
||||
* MOVQ $0 payload drop), so the construct must be rejected at the
|
||||
* checker until the faithful array-block-store lands (deferred task #6).
|
||||
* The tagged TYPE-decl with an array variant stays legal — test 944
|
||||
* declares (void|size|[5]size) and only boxes the narrow `size` variant
|
||||
* — only the array-variant CONSTRUCTION is refused. Mirrors the
|
||||
* concrete->tagged variant select in type_assignable (type.c:324-343)
|
||||
* so the variant chosen here is the one the box would materialize. */
|
||||
static Type *
|
||||
tagged_array_variant(Type *dst, Type *src)
|
||||
{
|
||||
if (dst == NULL || src == NULL) return NULL;
|
||||
Type *du = type_chase_named(dst);
|
||||
Type *su = type_chase_named(src);
|
||||
if (du == NULL || du->kind != TY_TAGGED) return NULL;
|
||||
if (su && su->kind == TY_TAGGED) return NULL; /* tagged->tagged */
|
||||
for (Tparam *p = du->params; p; p = p->next) {
|
||||
Type *pu = type_chase_named(p->type);
|
||||
if (pu && pu->kind == TY_TAGGED) {
|
||||
if (type_eq(p->type, src)) return NULL;
|
||||
continue;
|
||||
}
|
||||
if (type_assignable(p->type, src)) {
|
||||
if (pu && pu->kind == TY_ARRAY) return p->type;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* match_yield_type — walk a match arm's body looking for the type
|
||||
* of its first `yield expr;` statement. Returns NULL if no yield
|
||||
* was found. Doesn't descend into nested match bodies — each match
|
||||
@@ -2356,6 +2389,11 @@ clet(Checker *c, Node *n)
|
||||
!assignable_addrfn(c, declared, n->rhs))
|
||||
err(c, n->pos, "init %s not assignable to declared %s",
|
||||
type_name(c->a, initt), type_name(c->a, declared));
|
||||
/* #5/#60: reject boxing an array payload into a tagged variant. */
|
||||
if (declared && initt && initt != ty_err &&
|
||||
tagged_array_variant(declared, initt))
|
||||
err(c, n->pos, "array-typed tagged-union variant "
|
||||
"construction unwired — reject (task #5 / #60)");
|
||||
/* #104 fold-2: `let x: f32 = 1.0` — narrow the init literal to f32. */
|
||||
coerce_floatlit(n->rhs, declared);
|
||||
/* #258: `let s: []T = arr` borrows the array as a full slice. */
|
||||
@@ -2399,6 +2437,11 @@ cstmt(Checker *c, Node *n)
|
||||
&& !assignable_addrfn(c, c->ret, n->lhs))
|
||||
err(c, n->pos, "return %s not assignable to %s",
|
||||
type_name(c->a, rt), type_name(c->a, c->ret));
|
||||
/* #5/#60: reject returning an array payload into a tagged variant. */
|
||||
else if (c->ret != ty_void && rt != ty_err && c->ret != ty_err &&
|
||||
tagged_array_variant(c->ret, rt))
|
||||
err(c, n->pos, "array-typed tagged-union variant "
|
||||
"construction unwired — reject (task #5 / #60)");
|
||||
/* #104 fold-2: `fn g() f32 = { return 1.0; }` — narrow to f32. */
|
||||
coerce_floatlit(n->lhs, c->ret);
|
||||
/* #258: `return arr` borrows the array as a full slice.
|
||||
|
||||
Reference in New Issue
Block a user