diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index efe13f8d..6e53ff4f 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -8271,10 +8271,36 @@ fn unoptype(c: *checker, e: *node) *node = { return nil; }; +// indexresult — derive the result tnode of an N_INDEX expression. +// Mirrors cstage cmd/wcc/check.c:870-894. Slice/array → elem; str → +// u8; `*[N]T` decays to T (pointer-to-array); `*[]T` does NOT decay +// (yields []T via the generic *U → U fallback — Hare-faithful, a +// pointer-to-slice is a 1D array of slices, not of T); generic *T → T. +fn indexresult(c: *checker, e: *node) *node = { + let basetn: *node = exprtype(c, e.lhs, nil); + let _idx: *node = exprtype(c, e.rhs, nil); + let u: *node = resolvealias(c, unwrapbang(basetn)); + if (u == nil) { return nil; }; + if (u.kind == nkind.N_TSLICE) { return u.lhs; }; + if (u.kind == nkind.N_TARRAY) { return u.lhs; }; + if (u.kind == nkind.N_TNAME) { + if (streq(u.str, "str")) { return mktname(c, "u8"); }; + }; + if (u.kind == nkind.N_TPTR) { + let inner: *node = u.lhs; + let iu: *node = resolvealias(c, unwrapbang(inner)); + if (iu != nil && iu.kind == nkind.N_TARRAY) { + return iu.lhs; + }; + return inner; + }; + return nil; +}; + // exprtype — best-effort type-AST inference for an expression // node. Handles literals, identifiers, calls, casts, binary/unary -// ops; returns nil for shapes we don't statically know (struct -// field access into non-primitive types, etc). +// ops, indexing; returns nil for shapes we don't statically know +// (struct field access into non-primitive types, etc). // `hint`: optional declared-type AST passed by the caller (let // target, assign target). nil = "no hint, derive from self". Threaded // for use by A.6.1's STRUCTLIT/ARRLIT arms which can't self-type and @@ -8361,6 +8387,11 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { e.type_ = tinfofornode(c, tn): *void; return tn; }; + if (k == nkind.N_INDEX) { + let tn: *node = indexresult(c, e); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; if (k == nkind.N_CAST) { // `expr: T` — explicit cast; the type expr is e.rhs. Mirrors // cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`. diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index d89e8be2..dac8091b 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -1339,10 +1339,36 @@ fn unoptype(c: *checker, e: *node) *node = { return nil; }; +// indexresult — derive the result tnode of an N_INDEX expression. +// Mirrors cstage cmd/wcc/check.c:870-894. Slice/array → elem; str → +// u8; `*[N]T` decays to T (pointer-to-array); `*[]T` does NOT decay +// (yields []T via the generic *U → U fallback — Hare-faithful, a +// pointer-to-slice is a 1D array of slices, not of T); generic *T → T. +fn indexresult(c: *checker, e: *node) *node = { + let basetn: *node = exprtype(c, e.lhs, nil); + let _idx: *node = exprtype(c, e.rhs, nil); + let u: *node = resolvealias(c, unwrapbang(basetn)); + if (u == nil) { return nil; }; + if (u.kind == nkind.N_TSLICE) { return u.lhs; }; + if (u.kind == nkind.N_TARRAY) { return u.lhs; }; + if (u.kind == nkind.N_TNAME) { + if (streq(u.str, "str")) { return mktname(c, "u8"); }; + }; + if (u.kind == nkind.N_TPTR) { + let inner: *node = u.lhs; + let iu: *node = resolvealias(c, unwrapbang(inner)); + if (iu != nil && iu.kind == nkind.N_TARRAY) { + return iu.lhs; + }; + return inner; + }; + return nil; +}; + // exprtype — best-effort type-AST inference for an expression // node. Handles literals, identifiers, calls, casts, binary/unary -// ops; returns nil for shapes we don't statically know (struct -// field access into non-primitive types, etc). +// ops, indexing; returns nil for shapes we don't statically know +// (struct field access into non-primitive types, etc). // `hint`: optional declared-type AST passed by the caller (let // target, assign target). nil = "no hint, derive from self". Threaded // for use by A.6.1's STRUCTLIT/ARRLIT arms which can't self-type and @@ -1429,6 +1455,11 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { e.type_ = tinfofornode(c, tn): *void; return tn; }; + if (k == nkind.N_INDEX) { + let tn: *node = indexresult(c, e); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; if (k == nkind.N_CAST) { // `expr: T` — explicit cast; the type expr is e.rhs. Mirrors // cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`. diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index ed0b2568..0ce9f343 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -8271,10 +8271,36 @@ fn unoptype(c: *checker, e: *node) *node = { return nil; }; +// indexresult — derive the result tnode of an N_INDEX expression. +// Mirrors cstage cmd/wcc/check.c:870-894. Slice/array → elem; str → +// u8; `*[N]T` decays to T (pointer-to-array); `*[]T` does NOT decay +// (yields []T via the generic *U → U fallback — Hare-faithful, a +// pointer-to-slice is a 1D array of slices, not of T); generic *T → T. +fn indexresult(c: *checker, e: *node) *node = { + let basetn: *node = exprtype(c, e.lhs, nil); + let _idx: *node = exprtype(c, e.rhs, nil); + let u: *node = resolvealias(c, unwrapbang(basetn)); + if (u == nil) { return nil; }; + if (u.kind == nkind.N_TSLICE) { return u.lhs; }; + if (u.kind == nkind.N_TARRAY) { return u.lhs; }; + if (u.kind == nkind.N_TNAME) { + if (streq(u.str, "str")) { return mktname(c, "u8"); }; + }; + if (u.kind == nkind.N_TPTR) { + let inner: *node = u.lhs; + let iu: *node = resolvealias(c, unwrapbang(inner)); + if (iu != nil && iu.kind == nkind.N_TARRAY) { + return iu.lhs; + }; + return inner; + }; + return nil; +}; + // exprtype — best-effort type-AST inference for an expression // node. Handles literals, identifiers, calls, casts, binary/unary -// ops; returns nil for shapes we don't statically know (struct -// field access into non-primitive types, etc). +// ops, indexing; returns nil for shapes we don't statically know +// (struct field access into non-primitive types, etc). // `hint`: optional declared-type AST passed by the caller (let // target, assign target). nil = "no hint, derive from self". Threaded // for use by A.6.1's STRUCTLIT/ARRLIT arms which can't self-type and @@ -8361,6 +8387,11 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { e.type_ = tinfofornode(c, tn): *void; return tn; }; + if (k == nkind.N_INDEX) { + let tn: *node = indexresult(c, e); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; if (k == nkind.N_CAST) { // `expr: T` — explicit cast; the type expr is e.rhs. Mirrors // cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`.