wcc: #5 F1 promote type_chase_named + transitive-peel acceptance align-cs-up
Promote type_chase_named from cmd/w6c/cgen.c (static) to cmd/wcc/type.c (exported via ww.h) and re-route every checker single-NAMED-peel through it: check.c's ~28 inline ternaries + 3 ad-hoc loops, type.c's assignability/untyped/borrow/opaque peels. type_eq's nominal identity (check.c:114) and the resolve machinery guards stay untouched. The re-route IS the acceptance align-up — cstage loud-rejected alias shapes wwstage accepts AND runs Hare-right (F0 census, harec dealiases at every consumer): - #54 binop alias-vs-base: unify_arith gains the harec type_promote arm (ref/harec/src/check.c:1083-1105) — one-sided alias + dealias-equal promotes to the ALIAS side; alias-vs-alias stays rejected. - alias-cond family: if/for/&&/||/! chase-then-bool (harec check.c:2141/2515/3229/3572). assert stays loud (F0 2a symmetric). - #70 field access through 2-level alias chains (ken c3_chain3). - assignability through the full chain (harec types.c:989-996 dealias-both): return/init/assign legs, F0 8b idx/slice walls. - alias-of-ptr deref (harec types.c:19-22 type_dereference). The widening reaches cgen arms whose own single peels then misbehaved — both classes are closed IN THIS COMMIT so no intermediate state ships a loud->silent flip (bisect no-silent invariant): - index family: the 8b acceptance hit ptr-load base + esz=1 (SEGV / prefix-luck) — idx_eff + the N_INDEX read / index-write / &base[i] / N_SLICE (expr + call-arg) / N_FORRANGE / aggarg_srcaddr-index / castsrcprim-dot / match-field base classifies chase. - kind classifiers (ken #61-root-verify v3 find): a 2-level f64 alias param reached cg_isfloat's single peel and classified INT — silent wrong-register-class. cg_isfloat / type_isf32 / fld_isfloat / type_isstr / type_isslice chase. ken's v3 row is pinned with credit. Bootstrap asm is byte-identical before/after (w6c on every main.combined.ww cmp-equal vs a pristine738d7f4scratch; 989 lib_byteid pins unchanged): 2-level chains were checker-walled pre-F1, so no previously-accepted program changes shape. test: 944_alias_accept_run (20 rows): acceptance graduations pinned runtime + byte-id both stages; idx/slice/range/slice-param rows cs-only until the wwstage #60 esz family lands (F2 batch 1); cs-only harec-parity loud pin for alias-vs-alias binop; assert stays-loud row; ken-v3 + f64/str/slice kind rows. Mutation-checked at738d7f4. reviewer-F1 fold — the same invariant, outside the F0 census: this commit ADMITS 2+-level alias slice/str/aggregate types in STRUCT FIELD position, therefore this commit must keep them correct-or-loud. The cgen FIELD-TYPE gates single-peeled, so the slice/str 3-word arms fell to word0-only scalar tails — accept-and-corrupt, ww correct, every shape loud at the pristine base. Chased (probe-proven, byte-id graduations): single-dot field store + via-ptr twin, struct-lit fill, chained store-walk LEAF (the #71 walk chases hops, not leaves), chained-ptr-field store, single-dot / via-ptr / chained-walk field reads (clobber-probed — word0 reads luck-passed on stale BX/CX). The six unprobed sibling gates (indexed-elem store/read, ptr-chain read, heap fill, tuple-elem read, static emit) hard-error via fld_alias_tripwire on a 2+-level alias over an aggregate base, citing task #73 (the family's scheduled chase); <=1-level and scalar bases never fire — zero behavior change for any pre-#5-legal program (five selfhost mains cmp-identical vs the pristine738d7f4scratch). test: 944 +11 rows (9 K_RUN byte-id, wholeread K_RUN_CS [#60 ww half + pre-existing 1-level read-spine divergence], #73 tripwire K_BUILDERR_CS pin); 1-level controls per gate in /tmp/revF1.
This commit is contained in:
148
cmd/wcc/check.c
148
cmd/wcc/check.c
@@ -344,7 +344,7 @@ addrfn_ptr_matches(Type *ptr, Type *fnty)
|
||||
{
|
||||
if (ptr == NULL || ptr->kind != TY_PTR) return 0;
|
||||
Type *ref = ptr->sub;
|
||||
if (ref && ref->kind == TY_NAMED) ref = ref->under;
|
||||
ref = type_chase_named(ref);
|
||||
if (ref == NULL || ref->kind != TY_FN) return 0;
|
||||
return type_eq(ref, fnty);
|
||||
}
|
||||
@@ -377,7 +377,7 @@ assignable_addrfn(Checker *c, Type *dst, Node *rhs)
|
||||
if (s == NULL || s->kind != SK_FN) return 0;
|
||||
Type *fnty = s->type;
|
||||
if (fnty == NULL || fnty->kind != TY_FN) return 0;
|
||||
Type *du = (dst->kind == TY_NAMED) ? dst->under : dst;
|
||||
Type *du = type_chase_named(dst);
|
||||
if (du == NULL) return 0;
|
||||
if (du->kind == TY_PTR) return addrfn_ptr_matches(du, fnty);
|
||||
if (du->kind == TY_TAGGED) {
|
||||
@@ -408,7 +408,7 @@ static int
|
||||
arrlit_init_fits(Checker *c, Type *dt, Node *rhs)
|
||||
{
|
||||
if (rhs == NULL || rhs->kind != N_ARRLIT) return 0;
|
||||
Type *u = (dt && dt->kind == TY_NAMED) ? dt->under : dt;
|
||||
Type *u = type_chase_named(dt);
|
||||
/* #25: a SLICE target is admitted via the same per-element coercion
|
||||
* as the array path — the #258 borrow demands an exact element
|
||||
* type_eq, which an arrlit's self-stamped [N]<default> can't meet for
|
||||
@@ -417,7 +417,7 @@ arrlit_init_fits(Checker *c, Type *dt, Node *rhs)
|
||||
if (u == NULL || (u->kind != TY_ARRAY && u->kind != TY_SLICE))
|
||||
return 0;
|
||||
Type *et = u->sub;
|
||||
Type *eu = (et && et->kind == TY_NAMED) ? et->under : et;
|
||||
Type *eu = type_chase_named(et);
|
||||
u64 count = 0;
|
||||
for (Node *e = rhs->list; e; e = e->next) {
|
||||
if (e->kind == N_FIELD && e->str
|
||||
@@ -705,8 +705,7 @@ resolve_type(Checker *c, Node *n)
|
||||
* the checker-says-8/cgen-does-16 split behind the
|
||||
* packed-tuple miscompile family (#32/#33/#48). */
|
||||
if (tp->type) {
|
||||
Type *eu = tp->type->kind == TY_NAMED
|
||||
? tp->type->under : tp->type;
|
||||
Type *eu = type_chase_named(tp->type);
|
||||
if (eu && (eu->kind == TY_STR
|
||||
|| eu->kind == TY_SLICE
|
||||
|| eu->kind == TY_TAGGED))
|
||||
@@ -753,8 +752,7 @@ resolve_type(Checker *c, Node *n)
|
||||
* (possibly NAMED) inner tagged union into the
|
||||
* enclosing union — matches Hare's parse-time
|
||||
* unwrap flag on each tagged_type entry. */
|
||||
Type *vu = spread && vt && vt->kind == TY_NAMED
|
||||
? vt->under : vt;
|
||||
Type *vu = spread ? type_chase_named(vt) : vt;
|
||||
if (vu && vu->kind == TY_TAGGED &&
|
||||
(spread || vt->kind == TY_TAGGED)) {
|
||||
for (Tparam *src = vu->params; src; src = src->next) {
|
||||
@@ -885,7 +883,7 @@ resolve_type(Checker *c, Node *n)
|
||||
/* embed (anonymous struct or bare-name): the inner type
|
||||
* must be a struct; its fields are promoted to the outer
|
||||
* scope with offsets shifted by the embed base. */
|
||||
Type *inner = (ft && ft->kind == TY_NAMED) ? ft->under : ft;
|
||||
Type *inner = type_chase_named(ft);
|
||||
if (inner == NULL || inner->kind != TY_STRUCT) {
|
||||
err(c, f->pos, "embedded type must be a struct");
|
||||
off += ft ? ft->size : 0;
|
||||
@@ -982,6 +980,27 @@ unify_arith(Checker *c, Pos p, Type *a, Type *b)
|
||||
if (type_isuntyped(a) && type_assignable(b, a)) return b;
|
||||
if (type_isuntyped(b) && type_assignable(a, b)) return a;
|
||||
if (type_eq(a, b)) return a;
|
||||
/* One-sided alias vs its (transitive) base promotes to the ALIAS
|
||||
* side; alias vs DIFFERENT alias stays rejected even when the
|
||||
* bases agree. Mirrors harec type_promote (ref/harec/src/check.c:
|
||||
* 1083-1105: ALIAS+ALIAS → NULL, then dealias-equal → the alias
|
||||
* operand). wwstage accepts these shapes and runs them on the
|
||||
* chased width (F0 m1_binop/m1_binop2, ww runtime-correct).
|
||||
*
|
||||
* ERROR axis guard: `type invalid = !i32` must NOT promote against
|
||||
* a plain i32 — type_eq ignores iserror (primitives compare by
|
||||
* kind), but harec interns flags into DISTINCT types, so flagged-
|
||||
* vs-unflagged never reaches type_promote's dealias-equal arm. The
|
||||
* #246 loud (strconv.invalid != i32, pinned by 949_errtype_compare
|
||||
* on BOTH stages) rides this reject. */
|
||||
{
|
||||
Type *da = type_chase_named(a);
|
||||
Type *db = type_chase_named(b);
|
||||
if (!(a->kind == TY_NAMED && b->kind == TY_NAMED) &&
|
||||
da && db && da->iserror == db->iserror &&
|
||||
type_eq(da, db))
|
||||
return (a->kind == TY_NAMED) ? a : b;
|
||||
}
|
||||
return err(c, p, "operands have differing types %s and %s",
|
||||
type_name(c->a, a), type_name(c->a, b));
|
||||
}
|
||||
@@ -1017,9 +1036,7 @@ coerce_floatlit(Node *n, Type *target)
|
||||
return;
|
||||
/* Chase the full alias chain (wwstage resolvealias does the same), so
|
||||
* a doubly-aliased f32 target stamps in both stages or neither. */
|
||||
Type *u = target;
|
||||
while (u && u->kind == TY_NAMED)
|
||||
u = u->under;
|
||||
Type *u = type_chase_named(target);
|
||||
if (u == NULL || u->kind != TY_F32)
|
||||
return;
|
||||
if (n->kind == N_FLOATLIT && n->type == ty_untyped_float)
|
||||
@@ -1054,7 +1071,7 @@ static int
|
||||
reject_arrlit_borrow(Checker *c, Type *dst, Node *expr)
|
||||
{
|
||||
if (expr == NULL || expr->kind != N_ARRLIT) return 0;
|
||||
Type *du = (dst && dst->kind == TY_NAMED) ? dst->under : dst;
|
||||
Type *du = type_chase_named(dst);
|
||||
if (du == NULL || du->kind != TY_SLICE) return 0;
|
||||
err(c, expr->pos, "array literal cannot borrow as a slice here; "
|
||||
"bind it to a `let` first");
|
||||
@@ -1066,9 +1083,8 @@ desugar_arrayslice(Checker *c, Type *dst, Node *expr)
|
||||
{
|
||||
if (dst == NULL || expr == NULL || expr->type == NULL)
|
||||
return;
|
||||
Type *du = (dst->kind == TY_NAMED) ? dst->under : dst;
|
||||
Type *su = (expr->type->kind == TY_NAMED) ? expr->type->under
|
||||
: expr->type;
|
||||
Type *du = type_chase_named(dst);
|
||||
Type *su = type_chase_named(expr->type);
|
||||
if (du == NULL || su == NULL ||
|
||||
du->kind != TY_SLICE || su->kind != TY_ARRAY)
|
||||
return;
|
||||
@@ -1119,12 +1135,18 @@ cbinop(Checker *c, Node *n)
|
||||
err(c, n->pos, "ordered comparison on non-numeric");
|
||||
(void)unify_arith(c, n->pos, l, r);
|
||||
return ty_bool;
|
||||
case TK_AND: case TK_OR:
|
||||
if (!(l == ty_bool || l == ty_untyped_bool || l == ty_err))
|
||||
case TK_AND: case TK_OR: {
|
||||
/* Bool-ness through the alias chain — harec dealiases at the
|
||||
* logical-binop consumer (ref/harec/src/check.c:3229); ww
|
||||
* accepts + runs the alias-bool operand (F0 m2_andor). */
|
||||
Type *lu = type_chase_named(l);
|
||||
Type *ru = type_chase_named(r);
|
||||
if (!(lu == ty_bool || lu == ty_untyped_bool || l == ty_err))
|
||||
err(c, n->pos, "left of %s is not bool", tokname(n->op));
|
||||
if (!(r == ty_bool || r == ty_untyped_bool || r == ty_err))
|
||||
if (!(ru == ty_bool || ru == ty_untyped_bool || r == ty_err))
|
||||
err(c, n->pos, "right of %s is not bool", tokname(n->op));
|
||||
return ty_bool;
|
||||
}
|
||||
default:
|
||||
return err(c, n->pos, "unsupported binary op %s", tokname(n->op));
|
||||
}
|
||||
@@ -1139,20 +1161,28 @@ cunop(Checker *c, Node *n)
|
||||
if (!type_isnum(t))
|
||||
return err(c, n->pos, "%s on non-numeric", tokname(n->op));
|
||||
return t;
|
||||
case TK_NOT:
|
||||
if (!(t == ty_bool || t == ty_untyped_bool || t == ty_err))
|
||||
case TK_NOT: {
|
||||
/* harec dealiases at the `!` consumer (ref/harec/src/check.c:
|
||||
* 3572); ww accepts + runs the alias-bool operand (F0 m2_bang). */
|
||||
Type *u = type_chase_named(t);
|
||||
if (!(u == ty_bool || u == ty_untyped_bool || t == ty_err))
|
||||
err(c, n->pos, "! on non-bool");
|
||||
return ty_bool;
|
||||
}
|
||||
case TK_TILDE:
|
||||
if (!type_isint(t))
|
||||
return err(c, n->pos, "~ on non-integer");
|
||||
return t;
|
||||
case TK_STAR: /* deref */
|
||||
case TK_STAR: { /* deref */
|
||||
if (t == ty_err) return ty_err;
|
||||
if (t->kind != TY_PTR)
|
||||
/* harec type_dereference dealiases the operand (ref/harec/src/
|
||||
* types.c:19-22); wwstage unoptype TK_STAR resolvealias-chases. */
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_PTR)
|
||||
return err(c, n->pos, "cannot deref non-pointer %s",
|
||||
type_name(c->a, t));
|
||||
return t->sub;
|
||||
return u->sub;
|
||||
}
|
||||
case TK_AMP: /* address-of */
|
||||
/* Slice/str pseudo-fields .len/.cap surface as i32 but live
|
||||
* in 8B-aligned slots in the header (ptr@0, len@8, cap@16).
|
||||
@@ -1165,9 +1195,9 @@ cunop(Checker *c, Node *n)
|
||||
(strcmp(n->lhs->str, "len") == 0 ||
|
||||
strcmp(n->lhs->str, "cap") == 0)) {
|
||||
Type *bt = n->lhs->lhs->type;
|
||||
Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
Type *bu = type_chase_named(bt);
|
||||
if (bu && bu->kind == TY_PTR) bu = bu->sub;
|
||||
if (bu && bu->kind == TY_NAMED) bu = bu->under;
|
||||
bu = type_chase_named(bu);
|
||||
if (bu && (bu->kind == TY_SLICE || bu->kind == TY_STR))
|
||||
return type_ptr(c->a, ty_i64);
|
||||
}
|
||||
@@ -1269,8 +1299,7 @@ cexpr(Checker *c, Node *n)
|
||||
* (named) enum type itself, so bitwise ops between
|
||||
* members yield the same enum type via type_eq. */
|
||||
if (ms && ms->kind == SK_TYPE && ms->type) {
|
||||
Type *u = (ms->type->kind == TY_NAMED)
|
||||
? ms->type->under : ms->type;
|
||||
Type *u = type_chase_named(ms->type);
|
||||
if (u && u->kind == TY_ENUM) {
|
||||
for (Tfield *f = u->fields; f; f = f->next) {
|
||||
if (f->name && n->str &&
|
||||
@@ -1295,9 +1324,9 @@ cexpr(Checker *c, Node *n)
|
||||
}
|
||||
Type *base = cexpr(c, n->lhs);
|
||||
if (base == NULL || base == ty_err) return n->type = ty_err;
|
||||
Type *u = (base->kind == TY_NAMED) ? base->under : base;
|
||||
Type *u = type_chase_named(base);
|
||||
if (u && u->kind == TY_PTR) u = u->sub;
|
||||
if (u && u->kind == TY_NAMED) u = u->under;
|
||||
u = type_chase_named(u);
|
||||
/* Enum member access via a qualified base, e.g. `os.whence.CUR`.
|
||||
* The inner N_DOT resolved through SK_USE → the SK_TYPE sym's
|
||||
* named type. Fold the outer access to the member literal. */
|
||||
@@ -1364,7 +1393,7 @@ cexpr(Checker *c, Node *n)
|
||||
if (idx != ty_err && !type_isint(idx))
|
||||
err(c, n->pos, "index must be integer");
|
||||
if (base == ty_err) return n->type = ty_err;
|
||||
Type *u = (base->kind == TY_NAMED) ? base->under : base;
|
||||
Type *u = type_chase_named(base);
|
||||
if (u && (u->kind == TY_SLICE || u->kind == TY_ARRAY)) {
|
||||
/* #108(b): indexing needs the element size; `[]opaque`
|
||||
* is a legal (sized) header but its element is unsized.
|
||||
@@ -1447,9 +1476,9 @@ cexpr(Checker *c, Node *n)
|
||||
n->list->kind == N_DOT) {
|
||||
Node *dot = n->list;
|
||||
Type *bt = cexpr(c, dot->lhs);
|
||||
Type *u = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
|
||||
Type *u = type_chase_named(bt);
|
||||
if (u && u->kind == TY_PTR) u = u->sub;
|
||||
if (u && u->kind == TY_NAMED) u = u->under;
|
||||
u = type_chase_named(u);
|
||||
u64 off = 0;
|
||||
int found = 0;
|
||||
if (u && u->kind == TY_STRUCT) {
|
||||
@@ -1544,8 +1573,7 @@ cexpr(Checker *c, Node *n)
|
||||
err(c, n->pos, "delete: operand must be an indexing or slicing expression");
|
||||
else {
|
||||
Type *bt = d->lhs ? d->lhs->type : NULL;
|
||||
while (bt && bt->kind == TY_NAMED)
|
||||
bt = bt->under;
|
||||
bt = type_chase_named(bt);
|
||||
/* harec check.c:2024 wording; a
|
||||
* fixed-size [N]T base and a str
|
||||
* base land here. */
|
||||
@@ -1583,8 +1611,7 @@ cexpr(Checker *c, Node *n)
|
||||
err(c, n->pos, "insert: operand must be an indexing expression xs[i]");
|
||||
else {
|
||||
Type *bt = d->lhs ? d->lhs->type : NULL;
|
||||
while (bt && bt->kind == TY_NAMED)
|
||||
bt = bt->under;
|
||||
bt = type_chase_named(bt);
|
||||
/* harec check.c:807 wording; a
|
||||
* fixed-size [N]T base lands here. */
|
||||
if (bt == NULL || bt->kind != TY_SLICE)
|
||||
@@ -1696,7 +1723,7 @@ cexpr(Checker *c, Node *n)
|
||||
(void)cexpr(c, a);
|
||||
return n->type = ty_err;
|
||||
}
|
||||
Type *u = (ft->kind == TY_NAMED) ? ft->under : ft;
|
||||
Type *u = type_chase_named(ft);
|
||||
if (u == NULL || u->kind != TY_FN)
|
||||
return n->type = err(c, n->pos, "calling non-function %s",
|
||||
type_name(c->a, ft));
|
||||
@@ -1794,7 +1821,7 @@ cexpr(Checker *c, Node *n)
|
||||
} else {
|
||||
t = resolve_type(c, n->lhs);
|
||||
}
|
||||
Type *u = (t && t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
for (Node *f = n->list; f; f = f->next) {
|
||||
Type *vt = cexpr(c, f->lhs);
|
||||
if (u && u->kind == TY_STRUCT) {
|
||||
@@ -1837,7 +1864,7 @@ cexpr(Checker *c, Node *n)
|
||||
Type *base = cexpr(c, n->lhs);
|
||||
if (n->rhs) (void)cexpr(c, n->rhs);
|
||||
if (n->cond) (void)cexpr(c, n->cond);
|
||||
Type *u = (base && base->kind == TY_NAMED) ? base->under : base;
|
||||
Type *u = type_chase_named(base);
|
||||
if (u && u->kind == TY_ARRAY)
|
||||
return n->type = type_slice(c->a, u->sub);
|
||||
if (u && u->kind == TY_SLICE)
|
||||
@@ -1856,14 +1883,14 @@ cexpr(Checker *c, Node *n)
|
||||
}
|
||||
case N_RECV: {
|
||||
Type *t = cexpr(c, n->lhs);
|
||||
Type *u = (t && t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
if (u && u->kind == TY_CHAN) return n->type = u->sub;
|
||||
return n->type = err(c, n->pos, "<- expects chan, got %s",
|
||||
type_name(c->a, t));
|
||||
}
|
||||
case N_MATCH: {
|
||||
Type *st = cexpr(c, n->lhs);
|
||||
Type *u = (st && st->kind == TY_NAMED) ? st->under : st;
|
||||
Type *u = type_chase_named(st);
|
||||
if (u == NULL || u->kind != TY_TAGGED) {
|
||||
return n->type = err(c, n->pos,
|
||||
"match on non-tagged-union %s", type_name(c->a, st));
|
||||
@@ -1968,13 +1995,13 @@ cexpr(Checker *c, Node *n)
|
||||
* whether the expression returns bool (is) or the variant
|
||||
* itself (as). */
|
||||
if (n->rhs) n->rhs->type = vt;
|
||||
Type *u = (t && t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
/* Enum ↔ integer cast: `enumval as intT` or `int as enumT`.
|
||||
* Reinterpret-only — the storage shape is already integer, so
|
||||
* cgen treats the cast as a no-op (the value lives in the same
|
||||
* register). The `is` form is rejected; enums aren't sums. */
|
||||
Type *uu = u;
|
||||
Type *vu = (vt && vt->kind == TY_NAMED) ? vt->under : vt;
|
||||
Type *vu = type_chase_named(vt);
|
||||
int lhs_enum = uu && uu->kind == TY_ENUM;
|
||||
int rhs_enum = vu && vu->kind == TY_ENUM;
|
||||
if (n->kind == N_TYPEASSERT && (lhs_enum || rhs_enum) &&
|
||||
@@ -2012,7 +2039,7 @@ cexpr(Checker *c, Node *n)
|
||||
}
|
||||
case N_TRYPROP: case N_TRYUNW: {
|
||||
Type *t = cexpr(c, n->lhs);
|
||||
Type *u = (t && t->kind == TY_NAMED) ? t->under : t;
|
||||
Type *u = type_chase_named(t);
|
||||
if (u == NULL || u->kind != TY_TAGGED) {
|
||||
return n->type = err(c, n->pos,
|
||||
"%s on non-tagged-union %s",
|
||||
@@ -2049,7 +2076,7 @@ cexpr(Checker *c, Node *n)
|
||||
}
|
||||
if (n->kind == N_TRYPROP && has_errors) {
|
||||
Type *r = c->ret;
|
||||
Type *ru = (r && r->kind == TY_NAMED) ? r->under : r;
|
||||
Type *ru = type_chase_named(r);
|
||||
if (ru == NULL || ru->kind != TY_TAGGED) {
|
||||
err(c, n->pos,
|
||||
"?: enclosing function must return a tagged "
|
||||
@@ -2097,8 +2124,7 @@ cexpr(Checker *c, Node *n)
|
||||
tp->type = cexpr(c, e);
|
||||
Type *ed = type_default(tp->type);
|
||||
if (ed && ed->align > al) al = ed->align;
|
||||
Type *eu = (ed && ed->kind == TY_NAMED)
|
||||
? ed->under : ed;
|
||||
Type *eu = type_chase_named(ed);
|
||||
if (eu && (eu->kind == TY_STR || eu->kind == TY_SLICE
|
||||
|| eu->kind == TY_TAGGED))
|
||||
sz += (eu->size + 7) & ~(u64)7;
|
||||
@@ -2154,9 +2180,7 @@ clet(Checker *c, Node *n)
|
||||
* init) can't infer its length — that is a loud error, never a
|
||||
* silent zero-length array (rule 7, #7). */
|
||||
if (declared && declared->kind == TY_ARRAY && declared->alen == 0) {
|
||||
Type *iu = initt
|
||||
? ((initt->kind == TY_NAMED) ? initt->under : initt)
|
||||
: NULL;
|
||||
Type *iu = type_chase_named(initt);
|
||||
if (iu && iu->kind == TY_ARRAY)
|
||||
declared = type_array(c->a, declared->sub, iu->alen);
|
||||
else
|
||||
@@ -2195,8 +2219,7 @@ clet(Checker *c, Node *n)
|
||||
}
|
||||
}
|
||||
if (has_arr_repeat && declared) {
|
||||
Type *du = (declared->kind == TY_NAMED) ? declared->under
|
||||
: declared;
|
||||
Type *du = type_chase_named(declared);
|
||||
if (du && du->kind == TY_ARRAY)
|
||||
has_arr_repeat = 0;
|
||||
}
|
||||
@@ -2303,7 +2326,11 @@ cstmt(Checker *c, Node *n)
|
||||
}
|
||||
case N_IF: {
|
||||
Type *ct = cexpr(c, n->cond);
|
||||
if (ct != ty_err && ct != ty_bool && ct != ty_untyped_bool)
|
||||
/* harec dealiases at the if-cond consumer (ref/harec/src/
|
||||
* check.c:2141); ww accepts + runs alias-bool (F0 m2_if).
|
||||
* assert stays UN-chased — both stages loud there (F0 2a). */
|
||||
Type *cu = type_chase_named(ct);
|
||||
if (ct != ty_err && cu != ty_bool && cu != ty_untyped_bool)
|
||||
err(c, n->pos, "if condition must be bool, got %s",
|
||||
type_name(c->a, ct));
|
||||
cstmt(c, n->body);
|
||||
@@ -2315,14 +2342,14 @@ cstmt(Checker *c, Node *n)
|
||||
c->cur = newscope(c->a, saved);
|
||||
c->loops++;
|
||||
Type *st = cexpr(c, n->lhs);
|
||||
Type *u = (st && st->kind == TY_NAMED) ? st->under : st;
|
||||
Type *u = type_chase_named(st);
|
||||
Type *elem = NULL;
|
||||
if (u && (u->kind == TY_SLICE || u->kind == TY_ARRAY)) elem = u->sub;
|
||||
else if (u && u->kind == TY_STR) elem = ty_u8;
|
||||
else err(c, n->pos, "for-range needs slice/array/str");
|
||||
if (n->list != NULL) {
|
||||
/* tuple destructure: each name binds to a tuple field */
|
||||
Type *etu = (elem && elem->kind == TY_NAMED) ? elem->under : elem;
|
||||
Type *etu = type_chase_named(elem);
|
||||
Tparam *tp = (etu && etu->kind == TY_TUPLE) ? etu->params : NULL;
|
||||
for (Node *nm = n->list; nm; nm = nm->next) {
|
||||
Type *ft = tp ? tp->type : ty_err;
|
||||
@@ -2355,7 +2382,10 @@ cstmt(Checker *c, Node *n)
|
||||
if (n->lhs) cstmt(c, n->lhs); /* init may be a let or expr */
|
||||
if (n->cond) {
|
||||
Type *ct = cexpr(c, n->cond);
|
||||
if (ct != ty_err && ct != ty_bool && ct != ty_untyped_bool)
|
||||
/* harec dealiases at the loop-cond consumer (ref/
|
||||
* harec/src/check.c:2515); F0 m2_while. */
|
||||
Type *cu = type_chase_named(ct);
|
||||
if (ct != ty_err && cu != ty_bool && cu != ty_untyped_bool)
|
||||
err(c, n->pos, "for condition must be bool, got %s",
|
||||
type_name(c->a, ct));
|
||||
}
|
||||
@@ -2855,9 +2885,7 @@ check_file(Checker *c, Node *file)
|
||||
* the right `.len`. */
|
||||
if (d->type && d->type->kind == TY_ARRAY
|
||||
&& d->type->alen == 0) {
|
||||
Type *iu = rt
|
||||
? ((rt->kind == TY_NAMED) ? rt->under : rt)
|
||||
: NULL;
|
||||
Type *iu = type_chase_named(rt);
|
||||
if (iu && iu->kind == TY_ARRAY) {
|
||||
d->type = type_array(c->a,
|
||||
d->type->sub, iu->alen);
|
||||
|
||||
Reference in New Issue
Block a user