writeonce/tests/corpus/run/interp-borrowed-field/fixture.wo
shoney.arickathil ed29ccadbc fix(compiler): return of a Text interp of a place handed out the borrow
- emit_return's place test matched only bare Ident/Field/Index, so
  `return "${p.content}"` (p a loop borrow) returned the part's own
  string; the caller's eventual drop freed it under the container —
  arena corruption surfacing two requests later (multipart slice)
- the return test now sees through Interp exactly as copy_place_text
  does (is_borrowed_value_t, container reads excluded); bare
  Ident/Field/Index behavior at return unchanged
- interp-borrowed-field fixture grows the return flavor (fn first),
  50 iterations exact
- gates: oop-e2e 89/0 (ASan stage), woc-test green

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 03:32:31 +02:00

44 lines
1.1 KiB
Text

-- probe: Text interpolation of a borrowed field inside a loop.
-- If the interpolation segment drops the field it only borrows, repeated
-- calls corrupt the arena and the third-ish call crashes in release.
class Row {
method: Text
}
class Tab {
rows: multi Row
fn scan() -> Text {
let out = "";
for r in self.rows {
if out == "" { out = "${r.method}"; } else { out = "${out}, ${r.method}"; }
}
return out;
}
-- the RETURN flavor: an interpolation of a borrowed field handed straight
-- to the caller must be the caller's own copy, not the row's string
fn first() -> Text {
for r in self.rows {
return "${r.method}";
}
return "";
}
}
fn main() -> Int {
let t = Tab { rows: [] };
push(t.rows, Row { method: "GET" });
push(t.rows, Row { method: "POST" });
let i = 0;
while i < 50 {
let s = t.scan();
if s != "GET, POST" { print("bad: ${s} at ${i}"); return 1; }
let h = t.first();
if h != "GET" { print("bad first: ${h} at ${i}"); return 1; }
i = i + 1;
}
print("ok");
return 0;
}