// lit_str_pseudo_test — the string-LITERAL `.len` / `.ptr` pseudo-field, // migrated from test/wcc/801_litstr_pseudo_run.c (#14). cstage was wrong, // wwstage correct (a rule-10 divergence): `"hi".len` returned the POINTER — a // string literal is TY_UNTYPED_STR (not TY_STR), so it missed the typed str // pseudo-field gate in cgen.c's N_DOT and fell to `cgexpr(lhs)` (AX=.ptr) // without the BX->AX len shuffle that wwstage's cgdot catch-all already did. // byte-id was BLIND: no bootstrap source uses literal `.len` (devs hardcoded // the lengths). The fix aligns cstage UP — the N_DOT fallback emits `MOVQ BX,AX` // for `.len`; `.ptr` already returned AX. The str-VARIABLE `.len` was a control. package lit_str_pseudo_test; fn slen(s: str) i32 = { return s.len: i32; }; @test fn lit_len() void = { assert("hello".len: i32 == 5); }; @test fn lit_len_empty_multibyte() void = { // "" is 0 bytes; "héllo\n" is 7 bytes (h, é=2 UTF-8 bytes, l, l, o, \n) — // a ptr would not read 7, so this guards a .ptr/.len confusion. assert("".len: i32 == 0); assert("héllo\n".len: i32 == 7); }; @test fn lit_ptr_deref() void = { // .ptr still points at the bytes (first byte == 'h'), proving the fix left // .ptr untouched; then .len == 5. let p: *u8 = "hello".ptr; assert(*p == 'h'); assert("hello".len: i32 == 5); }; @test fn lit_arg_passthrough() void = { // callee-side .len on a literal passed as a str arg — the real-world shape // (os.write(1, lit.ptr, lit.len)) that surfaced #14. assert(slen("abcdef") == 6); assert("abcdef".len: i32 == 6); };