cmd+selfhost+test: relax alloc-slice element-type pin via LHS retype
`alloc([], n)` synthesizes ([]u8 | nomem) at expression level — that's fine, since the slice form only legitimately appears in let-init position where the LHS carries the real element type. In clet, after type-checking the rhs, peel any N_TRYPROP/N_TRYUNW wrapper, match the alloc-slice AST shape with the same-module shadow gate (from #23), and retype the call's tagged return to ([]T | nomem) where T is the declared LHS element. Then assignability sees []T vs []T and accepts. Cgen N_LET shortcut gains a viatryprop arm next to the existing viatryunw — on rt_alloc returning null, emits the tagged-return nomem propagation (MOVQ $nidx, AX; epilogue) instead of exit(1). nidx comes from cg_tag_for_variant on the enclosing fn's return type, matching the existing TRYPROP propret path. Wwstage mirrors all four hunks (check.ww + cgenstmt.ww). Promotes the previously-silent conf=false skip into a confident accept. Unblocks #6 (dupall) and lays the path for #4/#7. Byte-identity holds modulo the pre-existing #44 alloc/rt_alloc symbol divergence.
This commit is contained in:
@@ -6366,15 +6366,22 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
*
|
||||
* Task #30 graduated the builtin to `([]T | nomem)`. The let
|
||||
* declares a bare `[]T`, so the canonical idiom wraps in `!`
|
||||
* to abort on OOM; walk into the N_TRYUNW to keep the
|
||||
* direct-store fast path. */
|
||||
* (abort on OOM) or `?` (propagate nomem to the enclosing
|
||||
* fn's tagged return). Task #45 extends the shortcut to also
|
||||
* match N_TRYPROP and emit the propret pattern. */
|
||||
{
|
||||
Node *call = NULL;
|
||||
int via_tryunw = 0;
|
||||
int via_tryprop = 0;
|
||||
if (n->rhs && n->rhs->kind == N_TRYUNW && n->rhs->lhs
|
||||
&& n->rhs->lhs->kind == N_CALL) {
|
||||
call = n->rhs->lhs;
|
||||
via_tryunw = 1;
|
||||
} else if (n->rhs && n->rhs->kind == N_TRYPROP
|
||||
&& n->rhs->lhs
|
||||
&& n->rhs->lhs->kind == N_CALL) {
|
||||
call = n->rhs->lhs;
|
||||
via_tryprop = 1;
|
||||
}
|
||||
if (call && lu && lu->kind == TY_SLICE && sz == 24
|
||||
&& call->lhs && call->lhs->kind == N_IDENT
|
||||
@@ -6401,6 +6408,23 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
ins2(c, A_MOVQ, aimm(60), areg(D_AX));
|
||||
ins0(c, A_SYSCALL);
|
||||
label(c, ok);
|
||||
} else if (via_tryprop) {
|
||||
/* #45: null = nomem; propagate to the
|
||||
* enclosing fn's tagged return. AX = tag
|
||||
* of nomem variant in cg_ret_type; epilogue
|
||||
* RETs to caller. */
|
||||
char *ok = mklabel(c, "tryprop_ok");
|
||||
ins2(c, A_CMPQ, aimm(0), areg(D_AX));
|
||||
ins1(c, A_JNE, abranch(ok));
|
||||
Type *r = cg_ret_type;
|
||||
if (r && r->kind == TY_NAMED) r = r->under;
|
||||
int nidx = cg_tag_for_variant(r, ty_nomem);
|
||||
if (nidx < 0) nidx = 1;
|
||||
ins2(c, A_MOVQ, aimm(nidx), areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_BP), areg(D_SP));
|
||||
ins1(c, A_POPQ, areg(D_BP));
|
||||
ins0(c, A_RET);
|
||||
label(c, ok);
|
||||
}
|
||||
ins1(c, A_POPQ, areg(D_BX)); /* count */
|
||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off + 0));
|
||||
|
||||
@@ -1494,6 +1494,48 @@ clet(Checker *c, Node *n)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* #45: alloc([], n) defers element type to the let-init context
|
||||
* (Hare-style). cexpr's alloc-slice branch synthesizes
|
||||
* ([]u8 | nomem) with no LHS context; when the let declares []T,
|
||||
* retype the inner call (and any ?/! wrapper) to ([]T | nomem) /
|
||||
* []T so the assignability check below succeeds for any T. cgen
|
||||
* already drives element size from declared->sub at the N_LET
|
||||
* shortcut (cmd/w6c/cgen.c). */
|
||||
if (declared && declared->kind == TY_SLICE && declared->sub
|
||||
&& declared->sub != ty_u8 && n->rhs) {
|
||||
Node *wrap = NULL;
|
||||
Node *call = n->rhs;
|
||||
if (call->kind == N_TRYPROP || call->kind == N_TRYUNW) {
|
||||
wrap = call;
|
||||
call = call->lhs;
|
||||
}
|
||||
if (call && call->kind == N_CALL && call->lhs
|
||||
&& call->lhs->kind == N_IDENT
|
||||
&& call->lhs->type == ty_err
|
||||
&& call->lhs->str
|
||||
&& strcmp(call->lhs->str, "alloc") == 0
|
||||
&& call->list && call->list->kind == N_ARRLIT
|
||||
&& call->list->list == NULL
|
||||
&& call->list->next
|
||||
&& call->list->next->next == NULL) {
|
||||
Type *st = type_slice(c->a, declared->sub);
|
||||
Type *tt = newtype(c->a, TY_TAGGED);
|
||||
Tparam *vs = amalloc(c->a, sizeof *vs);
|
||||
Tparam *ve = amalloc(c->a, sizeof *ve);
|
||||
vs->type = st; vs->next = ve;
|
||||
ve->type = ty_nomem; ve->next = NULL;
|
||||
tt->params = vs;
|
||||
tt->size = 32;
|
||||
tt->align = 8;
|
||||
call->type = tt;
|
||||
if (wrap) {
|
||||
wrap->type = st;
|
||||
initt = st;
|
||||
} else {
|
||||
initt = tt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (declared && initt && initt != ty_err && !has_arr_repeat &&
|
||||
!type_assignable(declared, initt))
|
||||
err(c, n->pos, "init %s not assignable to declared %s",
|
||||
|
||||
Reference in New Issue
Block a user