w6c+selfhost+lib: Hare-style variadic call sites
Param-decl `name: T...` (Tparam.variadic=1, type []T), call-site
gather of N args into a fresh `[N]T`, forward via `xs...`, full
selfhost mirror, and lib/fmt graduated to the Hare shape.
Frontend:
- parse: `T...` after a param's type stamps Node.op=TK_ELLIPSIS
and breaks out (variadic must be last).
- check: resolve_type N_TFN / build_fn_type wrap the param type
as []T and set tp->variadic. N_CALL accepts either a tail of
args assignable to T (gather) or a single `xs...` spread of
[]T (forward); both bypass the "too many args" check on the
variadic slot.
- type: type_eq compares Tparam.variadic.
Cgen (cstage):
- call site: when the callee has a variadic last param,
materialise the tail args into a frame-resident `[N]T` via
localoff, write a 24B slice descriptor (ptr,len,cap), and
splice a synthesised N_IDENT into args[] so the downstream
widen/eval/pop loops see one slice slot. Tagged-element types
route each store through cg_widen_tagged_store. Forwarding
skips gather: the N_SPREAD wrapper is replaced with its inner
slice expression. Empty form writes {nil,0,0}. args[] / widen[]
bump from 16 to 64 to accommodate Hare's mixed-arg printers.
Selfhost mirror:
- lib/ww/parse: `T...` mark on N_PARAM.op.
- cgen: varargseq counter on Cg; scanlocals reserves
@vararg_d_N + @vararg_sl_N per variadic call (seq recorded on
N_CALL.uval so cgcall picks the same names). cgcall does the
same gather/forward and N_IDENT splice. cgfnparams treats
variadic params as 24B slice slots via a synthesised TSLICE
tnode. pushargsrev skips the tagged-widen detection for
variadic params (effective type is []T, not tagged).
- rhstargetname now recognises N_TRUE/N_FALSE/N_RUNELIT and
typed N_INTLIT so the variant-tag lookup finds bool/rune/iN
variants instead of falling through to "first non-str" (which
misassigned tag 0 to bool in tagged unions like formattable).
lib/fmt graduated: print/println/fprint/fprintln/errorln/fatal
take `args: formattable...`. Bare `error` (no -ln) is skipped —
the leaf name collides with strconv's `type error = !(invalid |
overflow)` under the driver's flat namespace.
Tests: 5 new e2e rows (plain gather, zero-arg, tagged element,
forwarding, fmt.println end-to-end). lib/CLAUDE.md workaround
paragraph replaced with the Hare-shape description.
This commit is contained in:
@@ -404,7 +404,17 @@ resolve_type(Checker *c, Node *n)
|
||||
}
|
||||
Tparam *tp = amalloc(c->a, sizeof *tp);
|
||||
tp->name = p->str;
|
||||
tp->type = resolve_type(c, p->lhs);
|
||||
Type *pt = resolve_type(c, p->lhs);
|
||||
/* Hare-style `T...` (marked on the param node via
|
||||
* Node.op == TK_ELLIPSIS): the param's effective type
|
||||
* inside the callee is []T, and call sites either
|
||||
* gather N args of type T or forward an `xs...` slice. */
|
||||
if (p->op == TK_ELLIPSIS) {
|
||||
tp->variadic = 1;
|
||||
tp->type = type_slice(c->a, pt);
|
||||
} else {
|
||||
tp->type = pt;
|
||||
}
|
||||
if (head == NULL) head = tp;
|
||||
else tail->next = tp;
|
||||
tail = tp;
|
||||
@@ -962,12 +972,38 @@ cexpr(Checker *c, Node *n)
|
||||
err(c, n->pos, "too many arguments");
|
||||
continue;
|
||||
}
|
||||
/* Hare-style variadic param: every remaining arg either
|
||||
* - flows into the gather (assignable to element T), or
|
||||
* - is a single `xs...` spread of `[]T` (forwarding).
|
||||
* Don't advance p — the variadic slot absorbs the tail. */
|
||||
if (p->variadic) {
|
||||
Type *elem = (p->type && p->type->kind == TY_SLICE)
|
||||
? p->type->sub : ty_err;
|
||||
if (a->kind == N_SPREAD) {
|
||||
if (at != ty_err && p->type != ty_err &&
|
||||
!type_assignable(p->type, at))
|
||||
err(c, a->pos,
|
||||
"spread arg: %s not assignable to %s",
|
||||
type_name(c->a, at),
|
||||
type_name(c->a, p->type));
|
||||
if (a->next != NULL)
|
||||
err(c, a->pos,
|
||||
"spread arg must be the last");
|
||||
} else if (elem != ty_err && at != ty_err) {
|
||||
if (!type_assignable(elem, at))
|
||||
err(c, a->pos,
|
||||
"variadic arg: %s not assignable to %s",
|
||||
type_name(c->a, at),
|
||||
type_name(c->a, elem));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!type_assignable(p->type, at) && at != ty_err && p->type != ty_err)
|
||||
err(c, a->pos, "argument type %s not assignable to %s",
|
||||
type_name(c->a, at), type_name(c->a, p->type));
|
||||
p = p->next;
|
||||
}
|
||||
if (p != NULL)
|
||||
if (p != NULL && !p->variadic)
|
||||
err(c, n->pos, "not enough arguments");
|
||||
return n->type = u->ret ? u->ret : ty_void;
|
||||
}
|
||||
@@ -1514,7 +1550,14 @@ build_fn_type(Checker *c, Node *fn)
|
||||
}
|
||||
Tparam *tp = amalloc(c->a, sizeof *tp);
|
||||
tp->name = p->str;
|
||||
tp->type = resolve_type(c, p->lhs);
|
||||
Type *pt = resolve_type(c, p->lhs);
|
||||
/* Hare-style `T...` — see resolve_type N_TFN. */
|
||||
if (p->op == TK_ELLIPSIS) {
|
||||
tp->variadic = 1;
|
||||
tp->type = type_slice(c->a, pt);
|
||||
} else {
|
||||
tp->type = pt;
|
||||
}
|
||||
if (head == NULL) head = tp;
|
||||
else tail->next = tp;
|
||||
tail = tp;
|
||||
|
||||
Reference in New Issue
Block a user