selfhost/cmd/wcc: stamp N_DOT struct/pseudo/tuple in exprtype (A.6.1.5b)

Port cstage cmd/wcc/check.c:833-866 stamp cases to exprtype's
N_DOT arm. Three sub-cases append to the A.6.1.5a basetn-walk
block, all pure type_ annotations — none mutate e.kind:

  - Pseudo-fields .len / .cap / .ptr on slice / str / array
    (cstage L833-842). `len` and `cap` stamp i32; `ptr` synthesises
    an N_TPTR over the element (u8 for str, bu.lhs else).
  - Struct field walk on N_TSTRUCT (cstage L843-849) — match
    N_TFIELD by name, return f.lhs and stamp.
  - Tuple positional access `t.0`, `t.1`, … on N_TTUPLE
    (cstage L850-866). fldnumidx (cgenutil SSoT for decimal-only
    parsing) yields the index; walk bu.list .next idx times.

Two divergences from cstage, documented inline:
  - Wwstage carries str as N_TNAME("str") (no dedicated N_TSTR);
    the pseudo-field guard tests the trio shape directly.
  - Wwstage falls through to nil on struct/tuple miss instead
    of erroring (lenient policy per scruttype L656).

Cumulative N_DOT arm now ~162 LOC, under Rob's 250-LOC tripwire.
No new helpers; fldnumidx reused. #56 mod.fn() parser-rep stays
parked.

Phase 1 A.6 step 5b of ~8 — closes Hare's access_field surface
(ref/hare/hare/ast/expr.ha:7-38). Cgenutil's paired walker still
derives the same shapes; A.6.3 collapses those onto these stamps.

Verified 132/132 incl. 995_self_rebuild byte-identity.
This commit is contained in:
2026-05-21 19:08:02 +09:00
parent 894d966707
commit aa73e73013
3 changed files with 174 additions and 0 deletions

View File

@@ -8638,6 +8638,64 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
m = m.next;
};
}; };
// A.6.1.5b stamp cases — mirror cstage check.c:833-866. Pure
// type-AST stamps; never rewrite e.kind. Lenient on misses
// (cstage errors); falls through to nil under scruttype L656.
//
// Pseudo-fields .len/.cap/.ptr on slice/str/array. Cstage
// L833-842. `str` lives as N_TNAME("str") in wwstage — no
// dedicated N_TSTR kind — so test the trio shape here.
if (bu != nil) {
let isstr: bool = (bu.kind == nkind.N_TNAME) && streq(bu.str, "str");
if (bu.kind == nkind.N_TSLICE || bu.kind == nkind.N_TARRAY || isstr) {
if (streq(e.str, "len")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(e.str, "cap")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(e.str, "ptr")) {
let elem: *node = bu.lhs;
if (isstr) { elem = mktname(c, "u8"); };
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
pp.lhs = elem;
e.type_ = tinfofornode(c, pp): *void;
return pp;
};
};
};
// Struct field walk. Cstage L843-849 errors on missing field.
if (bu != nil) { if (bu.kind == nkind.N_TSTRUCT) {
let f: *node = bu.list;
for (f != nil) {
if (f.kind == nkind.N_TFIELD) { if (streq(f.str, e.str)) {
e.type_ = tinfofornode(c, f.lhs): *void;
return f.lhs;
}; };
f = f.next;
};
}; };
// Tuple positional access `t.0`, `t.1`, …. Cstage L850-866
// errors on non-numeric / out-of-range; wwstage falls
// through. fldnumidx (cgenutil) returns -1 on non-digit.
if (bu != nil) { if (bu.kind == nkind.N_TTUPLE) {
let idx: i32 = fldnumidx(e.str);
if (idx >= 0) {
let p: *node = bu.list;
for (idx > 0 && p != nil) {
p = p.next;
idx -= 1;
};
if (p != nil) {
e.type_ = tinfofornode(c, p): *void;
return p;
};
};
}; };
};
return nil;
};

View File

@@ -1706,6 +1706,64 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
m = m.next;
};
}; };
// A.6.1.5b stamp cases — mirror cstage check.c:833-866. Pure
// type-AST stamps; never rewrite e.kind. Lenient on misses
// (cstage errors); falls through to nil under scruttype L656.
//
// Pseudo-fields .len/.cap/.ptr on slice/str/array. Cstage
// L833-842. `str` lives as N_TNAME("str") in wwstage — no
// dedicated N_TSTR kind — so test the trio shape here.
if (bu != nil) {
let isstr: bool = (bu.kind == nkind.N_TNAME) && streq(bu.str, "str");
if (bu.kind == nkind.N_TSLICE || bu.kind == nkind.N_TARRAY || isstr) {
if (streq(e.str, "len")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(e.str, "cap")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(e.str, "ptr")) {
let elem: *node = bu.lhs;
if (isstr) { elem = mktname(c, "u8"); };
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
pp.lhs = elem;
e.type_ = tinfofornode(c, pp): *void;
return pp;
};
};
};
// Struct field walk. Cstage L843-849 errors on missing field.
if (bu != nil) { if (bu.kind == nkind.N_TSTRUCT) {
let f: *node = bu.list;
for (f != nil) {
if (f.kind == nkind.N_TFIELD) { if (streq(f.str, e.str)) {
e.type_ = tinfofornode(c, f.lhs): *void;
return f.lhs;
}; };
f = f.next;
};
}; };
// Tuple positional access `t.0`, `t.1`, …. Cstage L850-866
// errors on non-numeric / out-of-range; wwstage falls
// through. fldnumidx (cgenutil) returns -1 on non-digit.
if (bu != nil) { if (bu.kind == nkind.N_TTUPLE) {
let idx: i32 = fldnumidx(e.str);
if (idx >= 0) {
let p: *node = bu.list;
for (idx > 0 && p != nil) {
p = p.next;
idx -= 1;
};
if (p != nil) {
e.type_ = tinfofornode(c, p): *void;
return p;
};
};
}; };
};
return nil;
};

View File

@@ -8638,6 +8638,64 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
m = m.next;
};
}; };
// A.6.1.5b stamp cases — mirror cstage check.c:833-866. Pure
// type-AST stamps; never rewrite e.kind. Lenient on misses
// (cstage errors); falls through to nil under scruttype L656.
//
// Pseudo-fields .len/.cap/.ptr on slice/str/array. Cstage
// L833-842. `str` lives as N_TNAME("str") in wwstage — no
// dedicated N_TSTR kind — so test the trio shape here.
if (bu != nil) {
let isstr: bool = (bu.kind == nkind.N_TNAME) && streq(bu.str, "str");
if (bu.kind == nkind.N_TSLICE || bu.kind == nkind.N_TARRAY || isstr) {
if (streq(e.str, "len")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(e.str, "cap")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(e.str, "ptr")) {
let elem: *node = bu.lhs;
if (isstr) { elem = mktname(c, "u8"); };
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
pp.lhs = elem;
e.type_ = tinfofornode(c, pp): *void;
return pp;
};
};
};
// Struct field walk. Cstage L843-849 errors on missing field.
if (bu != nil) { if (bu.kind == nkind.N_TSTRUCT) {
let f: *node = bu.list;
for (f != nil) {
if (f.kind == nkind.N_TFIELD) { if (streq(f.str, e.str)) {
e.type_ = tinfofornode(c, f.lhs): *void;
return f.lhs;
}; };
f = f.next;
};
}; };
// Tuple positional access `t.0`, `t.1`, …. Cstage L850-866
// errors on non-numeric / out-of-range; wwstage falls
// through. fldnumidx (cgenutil) returns -1 on non-digit.
if (bu != nil) { if (bu.kind == nkind.N_TTUPLE) {
let idx: i32 = fldnumidx(e.str);
if (idx >= 0) {
let p: *node = bu.list;
for (idx > 0 && p != nil) {
p = p.next;
idx -= 1;
};
if (p != nil) {
e.type_ = tinfofornode(c, p): *void;
return p;
};
};
}; };
};
return nil;
};