wcc: stamp N_IDENT-callee destructure bindings in checker (#121)
resolvewalk N_MLET arm distributes the N_IDENT-callee rhs return-tuple element types onto unannotated bindings (the A-narrow slice). Byte-id- neutral — cgen still classifies structurally, stamps inert until the exprfloatkind collapse. N_DOT-callee destructure deferred to #16/#17. Prereq for the #121 collapse (commits 2/3).
This commit is contained in:
@@ -381,6 +381,56 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
|
||||
// `let (a, b) = call();` / `let a, b = call();` — destructure
|
||||
// bindings. #121 (Package B, A-narrow): distribute the callee's
|
||||
// tuple return-type element types onto the un-annotated bindings so
|
||||
// later references stamp n.type_, matching cgen's structural binding-
|
||||
// type classifier (cgmlet's rettupleof→localadd path). This closes
|
||||
// the unstamped-float-destructure gap that the exprfloatkind collapse
|
||||
// (commit 2's bridge) needs: without it a `let (f,i)=mk()` f64 binding
|
||||
// reads stamp nil → would disagree with the structural f64.
|
||||
//
|
||||
// GUARD bare N_IDENT callee only: exprtype's N_CALL N_DOT arm is the
|
||||
// shelved #16/#17 cross-module-shadow gap (check.ww:2250-2253), so a
|
||||
// module-qualified callee resolves to the wrong/nil return type —
|
||||
// stamping off it would be worse than the nil it replaces. Bare same-
|
||||
// module callees resolve correctly today. Faithful to harec
|
||||
// create_unpack_bindings (ref/harec/src/check.c:1354-1416) and the
|
||||
// cstage twin (cmd/wcc/check.c:1912 N_MLET, which uses cexpr ungated);
|
||||
// narrowed to N_IDENT pending #16/#17. Annotated bindings keep their
|
||||
// own type. Mirrors the N_FORRANGE binding-install shape above; the
|
||||
// bindings would otherwise install (unstamped) via the generic N_LET
|
||||
// walk, so this early return must register them itself.
|
||||
if (k == nkind.N_MLET) {
|
||||
if (n.rhs != nil) { resolvewalk(c, n.rhs); };
|
||||
let pt: *node = nil;
|
||||
if (n.rhs != nil) { if (n.rhs.kind == nkind.N_CALL) {
|
||||
let callee: *node = n.rhs.lhs;
|
||||
if (callee != nil) { if (callee.kind == nkind.N_IDENT) {
|
||||
// `rt` would shadow the imported lib/rt module
|
||||
// (checkmoduleshadow errors); `rty` avoids it.
|
||||
let rty: *node = exprtype(c, n.rhs, nil);
|
||||
if (rty != nil) { if (rty.kind == nkind.N_TTUPLE) {
|
||||
pt = rty.list;
|
||||
}; };
|
||||
}; };
|
||||
}; };
|
||||
let l: *node = n.list;
|
||||
for (l != nil) {
|
||||
if (l.lhs == nil) {
|
||||
if (pt != nil) { l.lhs = pt.lhs; };
|
||||
};
|
||||
let bnm: str = l.str;
|
||||
if (bnm.len > 0) {
|
||||
checkmoduleshadow(c, bnm, "let");
|
||||
scopedefine(c.cur, bnm, skind.SK_VAR, nil, l);
|
||||
};
|
||||
l = l.next;
|
||||
if (pt != nil) { pt = pt.next; };
|
||||
};
|
||||
return;
|
||||
};
|
||||
|
||||
if (k == nkind.N_DOT) {
|
||||
// Walk only the base; the .field name is a member, not a
|
||||
// free identifier.
|
||||
|
||||
Reference in New Issue
Block a user