writeonce/tests/corpus/run/lang-switch-arm-drop/fixture.wo
shoney.arickathil 0df9b4fe31 feat(compiler): iteration 5 Tasks 1-4 — modules, language surface, switch, typedef records + enum variants
- Modules: `use`/`pub`, directory-as-module, per-module symbol resolution (a
  flat first-wins merge silently ran the wrong `pub fn` body), six reserved
  stdlib namespaces typed UNKNOWN-BUT-RESERVED.
- Surface: `and`/`or` (own precedence tier, short-circuit, Bool-only), `${}`
  interpolation desugared at parse time, `const`, break/continue with
  drop-correct exits, do-while, inline-fn rejection.
- switch expr/stmt: required `default` over scalars/Text, arm unification,
  EQ/EQS+JZ lowering, per-arm drop scopes with N-way JOIN-DROP; `default`
  sorted last by a shared lowering order (textual order made arms dead).
- typedef records: structural, same shape = one class entry; `?name: T`
  nullable-by-shape; emit_ctor fills omitted defaults; `type` as field name.
- Enum variants: all-bare unions = int ordinals; any-payload = one class
  entry per variant, tag IS the header class_id (no header field, no format
  bump); exhaustive switch without `default`; arity checked both directions.
- Payload escape modeled as move-out (pointer-kind fields only — a scalar
  escape is a copy); caller reaps owned heap temps passed by borrow: two
  unbounded LSan-blind leaks, 10.5 MB -> 1.5 MB flat over 300k iterations.
- Fixed en route, each with a RED repro: dead E209 builtin-arg check and
  `int_to_text` missing from both types.ml builtin tables (both segfaulted
  wovm), multi-file phantom double-report, emit_ctor's field temp clobbering
  dst in tail position (pre-existing), warnings swallowed without an error.
- Two fenced VM builtins: `int_to_text` (13), `variant_tag` (14).
- 14+565 unit (was 14+401), corpus 71 (was 32) plain and under wovm_asan,
  wovm-test + cli_smoke green. Log-watcher 307 -> 93 diagnostics (85 E101 /
  4 E207 / 1 E208 / 3 W202); the 5 non-E101 residuals await Task 7 grammar.
2026-08-12 14:40:07 +02:00

166 lines
3.9 KiB
Text

-- haxe-parity Task 3: `switch` arm-local drop correctness. `Big` has
-- 130 Int fields (the same runtime/test malloc-path trick
-- tests/corpus/run/lang-break-owned-drop/fixture.wo already uses:
-- field_cnt*8 bytes exceeds the arena's 1024-byte size-class ceiling,
-- so a missed DROP is a hard ASan leak, not a silent, unobservable
-- miss). `big` is created inside `case 1:` only (i == 1, one of three
-- loop iterations), never moved, never returned -- this is the DROP
-- under test: owner.ml's `analyze_switch` must record a DScope drop
-- for it at that ARM's own end (the switch's own drop-scope contract,
-- not the enclosing `while`'s), and emit.ml's `emit_switch` must
-- actually place it there. Proven under `runtime/build/wovm_asan`
-- (task-3-report.md has the RED/GREEN evidence: RED was a real bug
-- this fixture itself found, not a hypothetical -- a statement-position
-- switch's own placeholder `dst` register collided with `big`'s own
-- register, so the arm's trailing `print_int(big.f0)` silently
-- overwrote `big`'s only reference before the DROP ran); this
-- fixture's own oop-e2e.sh check (plain wovm) pins the *output*, not
-- the leak-freedom -- the two are complementary, not redundant.
class Big {
f0: Int
f1: Int
f2: Int
f3: Int
f4: Int
f5: Int
f6: Int
f7: Int
f8: Int
f9: Int
f10: Int
f11: Int
f12: Int
f13: Int
f14: Int
f15: Int
f16: Int
f17: Int
f18: Int
f19: Int
f20: Int
f21: Int
f22: Int
f23: Int
f24: Int
f25: Int
f26: Int
f27: Int
f28: Int
f29: Int
f30: Int
f31: Int
f32: Int
f33: Int
f34: Int
f35: Int
f36: Int
f37: Int
f38: Int
f39: Int
f40: Int
f41: Int
f42: Int
f43: Int
f44: Int
f45: Int
f46: Int
f47: Int
f48: Int
f49: Int
f50: Int
f51: Int
f52: Int
f53: Int
f54: Int
f55: Int
f56: Int
f57: Int
f58: Int
f59: Int
f60: Int
f61: Int
f62: Int
f63: Int
f64: Int
f65: Int
f66: Int
f67: Int
f68: Int
f69: Int
f70: Int
f71: Int
f72: Int
f73: Int
f74: Int
f75: Int
f76: Int
f77: Int
f78: Int
f79: Int
f80: Int
f81: Int
f82: Int
f83: Int
f84: Int
f85: Int
f86: Int
f87: Int
f88: Int
f89: Int
f90: Int
f91: Int
f92: Int
f93: Int
f94: Int
f95: Int
f96: Int
f97: Int
f98: Int
f99: Int
f100: Int
f101: Int
f102: Int
f103: Int
f104: Int
f105: Int
f106: Int
f107: Int
f108: Int
f109: Int
f110: Int
f111: Int
f112: Int
f113: Int
f114: Int
f115: Int
f116: Int
f117: Int
f118: Int
f119: Int
f120: Int
f121: Int
f122: Int
f123: Int
f124: Int
f125: Int
f126: Int
f127: Int
f128: Int
f129: Int
}
fn main() -> Int {
let i = 0;
while i < 3 {
switch i {
case 1:
let big = Big { f0: 1, f1: 1, f2: 1, f3: 1, f4: 1, f5: 1, f6: 1, f7: 1, f8: 1, f9: 1, f10: 1, f11: 1, f12: 1, f13: 1, f14: 1, f15: 1, f16: 1, f17: 1, f18: 1, f19: 1, f20: 1, f21: 1, f22: 1, f23: 1, f24: 1, f25: 1, f26: 1, f27: 1, f28: 1, f29: 1, f30: 1, f31: 1, f32: 1, f33: 1, f34: 1, f35: 1, f36: 1, f37: 1, f38: 1, f39: 1, f40: 1, f41: 1, f42: 1, f43: 1, f44: 1, f45: 1, f46: 1, f47: 1, f48: 1, f49: 1, f50: 1, f51: 1, f52: 1, f53: 1, f54: 1, f55: 1, f56: 1, f57: 1, f58: 1, f59: 1, f60: 1, f61: 1, f62: 1, f63: 1, f64: 1, f65: 1, f66: 1, f67: 1, f68: 1, f69: 1, f70: 1, f71: 1, f72: 1, f73: 1, f74: 1, f75: 1, f76: 1, f77: 1, f78: 1, f79: 1, f80: 1, f81: 1, f82: 1, f83: 1, f84: 1, f85: 1, f86: 1, f87: 1, f88: 1, f89: 1, f90: 1, f91: 1, f92: 1, f93: 1, f94: 1, f95: 1, f96: 1, f97: 1, f98: 1, f99: 1, f100: 1, f101: 1, f102: 1, f103: 1, f104: 1, f105: 1, f106: 1, f107: 1, f108: 1, f109: 1, f110: 1, f111: 1, f112: 1, f113: 1, f114: 1, f115: 1, f116: 1, f117: 1, f118: 1, f119: 1, f120: 1, f121: 1, f122: 1, f123: 1, f124: 1, f125: 1, f126: 1, f127: 1, f128: 1, f129: 1 };
print_int(big.f0);
default:
print("skip");
}
i = i + 1;
}
print("done");
return 0;
}