w6c+cgen: len() over indexed str/slice element extracts .len (fix #19)

`len(xs[i])` over a [N]str/[]str (and []T slice) element returned the
element's .ptr, not its length, on BOTH stages (shared gap, not rule-10):
the len() builtin had no N_INDEX arm, so it fell to the bare-cgexpr
fallback, where the N_INDEX str/slice load (cgslicehdr) leaves AX=.ptr,
BX=.len, CX=.cap — and len() returned AX (the ptr) as the length.

Add an N_INDEX arm gated on a (TY_SLICE||TY_STR) element in both stages:
cgexpr the element, then MOVQ BX,AX to shuffle the len word into the
result reg — the same shape as the #14 .len pseudo-field fix. Byte-id
neutral (no bootstrap source uses len(indexed-element)); regenerated
w6c + wwdump combined.ww. New 802_lenidx_run pins runtime + cs==ww.
This commit is contained in:
2026-06-03 11:56:16 +09:00
parent 58c8f4be02
commit 6b67655eca
6 changed files with 280 additions and 0 deletions

View File

@@ -370,6 +370,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_xmod_valglobal_dot_run \
$(BIN)/test_len_strglobal_run \
$(BIN)/test_litstr_pseudo_run \
$(BIN)/test_lenidx_run \
$(BIN)/test_tuple_sret_callee \
$(BIN)/test_tuple_sret_receive_run \
$(BIN)/test_struct_tuple_field_slot \
@@ -886,6 +887,14 @@ $(BIN)/test_litstr_pseudo_run: test/wcc/801_litstr_pseudo_run.c \
$(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
# #19: len() over an INDEXED str/slice element (`len(xs[i])`) returned the
# element's .ptr, not its length (cstage == wwstage, shared gap). Runtime
# (cstage build+run) + cs==ww byte-id, both dimensions per row.
$(BIN)/test_lenidx_run: test/wcc/802_lenidx_run.c \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
# #10 Fold A (wide tuple-return / sret, CALLEE side): an over-cap tuple
# return (> 4 GP or > 2 SSE eightbytes) now compiles via sret instead of
# loud-stopping at the SEND. Compile + cs==ww byte-id only — the receive