- 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>
44 lines
1.1 KiB
Text
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;
|
|
}
|