test(compiler): unit helpers run inference; retarget borrow-escape fixture

Wire Gcinfer.infer into runner.ml's owner_str/emit_str so the unit tests
classify GC-ness identically to the driver (prerequisite for removing @gc: its
tests read the golden .wo through the library).

That exposed owner-err/borrow-escape.wo, which tested WO-E304 on *class*
escapes — now legally demand-promoted. Retargeted it to CONTAINER (`multi Text`)
escapes, which are owned and never promoted, so it still exercises the three
WO-E304 shapes (stored-in-field, returned, moved-to-take). Assertion positions
+ golden re-blessed.

Verified: woc-test 566/0, test_diag 14/0, oop-e2e 79/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
shoney.arickathil 2026-08-18 19:10:39 +02:00
parent c301d1acb1
commit 023233895c
3 changed files with 25 additions and 22 deletions

View file

@ -1,19 +1,19 @@
owner-err/borrow-escape.wo:9:16: error WO-E304: borrow of `other` cannot be stored in `self.box` — borrows cannot outlive their scope
self.box = other
^
owner-err/borrow-escape.wo:9:18: error WO-E304: borrow of `other` cannot be stored in `self.items` — borrows cannot outlive their scope
self.items = other
^
owner-err/borrow-escape.wo:8:12: `other` is borrowed here — declare it `take other: T` to pass ownership in
fn adopt(other: Box) {
fn adopt(other: multi Text) {
^
owner-err/borrow-escape.wo:18:10: error WO-E304: borrow of `h.box` escapes `leak` — borrows cannot outlive their scope
return h.box
owner-err/borrow-escape.wo:18:10: error WO-E304: borrow of `h.items` escapes `leak` — borrows cannot outlive their scope
return h.items
^
owner-err/borrow-escape.wo:17:9: `h` is borrowed here — declare it `take h: T` to pass ownership in
fn leak(h: Holder) -> Box {
fn leak(h: Holder) -> multi Text {
^
owner-err/borrow-escape.wo:22:15: error WO-E304: borrow of `h.box` cannot be passed to `take b` — borrows cannot outlive their scope
return keep(h.box)
owner-err/borrow-escape.wo:22:15: error WO-E304: borrow of `h.items` cannot be passed to `take b` — borrows cannot outlive their scope
return keep(h.items)
^
owner-err/borrow-escape.wo:21:10: `h` is borrowed here — declare it `take h: T` to pass ownership in
fn stash(h: Holder) -> Int {

View file

@ -1,23 +1,23 @@
class Box {
n: Int
}
-- Iteration 7b: WO-E304 borrow escapes, using CONTAINER values (`multi Text`).
-- A class value that escapes is demand-promoted to traced, so the illustrative
-- escapes must be containers, which are owned and never promoted. Mirrors the
-- run/borrow-escape-return corpus case (a class escape, now legal).
class Holder {
box: Box
items: multi Text
fn adopt(other: Box) {
self.box = other
fn adopt(other: multi Text) {
self.items = other
}
}
fn keep(take b: Box) -> Int {
fn keep(take b: multi Text) -> Int {
return 0
}
fn leak(h: Holder) -> Box {
return h.box
fn leak(h: Holder) -> multi Text {
return h.items
}
fn stash(h: Holder) -> Int {
return keep(h.box)
return keep(h.items)
}

View file

@ -39,6 +39,7 @@ module Parser = Woc_lib.Parser
module Dump = Woc_lib.Dump
module Types = Woc_lib.Types
module Owner = Woc_lib.Owner
module Gcinfer = Woc_lib.Gcinfer
module Emit = Woc_lib.Emit
module Disasm = Woc_lib.Disasm
@ -1807,6 +1808,7 @@ let owner_str ~file src =
let toks = Lexer.tokenize collector ~file src in
let prog = Parser.parse collector ~file toks in
let syms, () = Types.typecheck ~file prog collector in
let syms = Gcinfer.infer [ (file, prog) ] syms in
let tables = Owner.analyze ~file prog syms collector in
(tables, collector)
@ -1819,6 +1821,7 @@ let emit_str ~file src =
let toks = Lexer.tokenize collector ~file src in
let prog = Parser.parse collector ~file toks in
let syms, () = Types.typecheck ~file prog collector in
let syms = Gcinfer.infer [ (file, prog) ] syms in
let tables = Owner.analyze ~file prog syms collector in
(* Single-file helper (every golden fixture is one file): its own
module is "." and that module's own symbols are exactly `syms` —
@ -1929,7 +1932,7 @@ let () =
field, returned, moved out to a `take` parameter. *)
match owner_err_fixture "borrow-escape" with
| [ store; ret; take ] ->
check_site "borrow-escape (stored in a field)" ~code:"WO-E304" ~line:9 ~col:16 ~rel_line:8
check_site "borrow-escape (stored in a field)" ~code:"WO-E304" ~line:9 ~col:18 ~rel_line:8
~rel_col:12 store;
check_site "borrow-escape (returned)" ~code:"WO-E304" ~line:18 ~col:10 ~rel_line:17 ~rel_col:9
ret;
@ -1937,7 +1940,7 @@ let () =
~rel_line:21 ~rel_col:10 take;
(* spec section 6's own wording for this diagnostic *)
check "borrow-escape: names the place and the function it escapes"
(Option.is_some (find_substring ~needle:"borrow of `h.box` escapes `leak`" ret.Diag.message))
(Option.is_some (find_substring ~needle:"borrow of `h.items` escapes `leak`" ret.Diag.message))
| ds ->
check_eq "borrow-escape: exactly three ownership errors" ~expected:3 ~actual:(List.length ds)
string_of_int