- 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.
193 lines
4.4 KiB
Text
193 lines
4.4 KiB
Text
-- haxe-parity Task 4: drop correctness around payload-binding switch
|
|
-- arms (lang-switch-arm-drop is the model). Everything here must hold
|
|
-- under runtime/build/wovm_asan, not just plain wovm:
|
|
-- 1. the subject (`ev`, an owned variant object) is dropped exactly
|
|
-- once, at its own scope end -- its per-variant class-table kinds
|
|
-- free the payload recursively (Log's CONCAT-built Text; Boxed's
|
|
-- embedded Big -- 130 Int fields, past the arena's 1024-byte
|
|
-- ceiling, so any miss is a hard ASan failure, not a silent one);
|
|
-- 2. `line`/`b`, the arms' payload bindings, are BORROWS of the
|
|
-- subject's fields -- never dropped by their arm, or the subject's
|
|
-- own drop double-frees;
|
|
-- 3. `big` (arm-local owned value in `case Log`) still gets its
|
|
-- ordinary arm-scope drop alongside the binding;
|
|
-- 4. `mk(2)`'s local Big is MOVED into `Boxed(big)` -- the variant
|
|
-- construction is a ctor-field escape (owner.ml), so the local
|
|
-- must NOT also drop at mk's return: that would double-free the
|
|
-- Big the variant object now owns;
|
|
-- 5. `w`, a variant object from a DIRECT construction (not through a
|
|
-- declared-return fn), is classified owned through the
|
|
-- construction itself and dropped at main's end.
|
|
type Ev = Tick | Log(line: Text) | Boxed(b: Big)
|
|
|
|
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 mk_big() -> Big {
|
|
return Big { f0: 1, f1: 2, f2: 3, 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 }
|
|
}
|
|
|
|
fn mk(n: Int) -> Ev {
|
|
if n == 1 { return Log("boot " .. int_to_text(n)) }
|
|
if n == 2 {
|
|
let big = mk_big();
|
|
return Boxed(big);
|
|
}
|
|
return Tick
|
|
}
|
|
|
|
fn main() -> Int {
|
|
let i = 0;
|
|
while i < 4 {
|
|
let ev = mk(i);
|
|
switch ev {
|
|
case Log(line):
|
|
let big = mk_big();
|
|
print_int(big.f0);
|
|
print(line);
|
|
case Boxed(b):
|
|
print_int(b.f1);
|
|
case Tick:
|
|
print("tick");
|
|
}
|
|
i = i + 1;
|
|
}
|
|
let w = Boxed(mk_big());
|
|
switch w {
|
|
case Boxed(b): print_int(b.f2);
|
|
case Log(line): print(line);
|
|
case Tick: print("tick");
|
|
}
|
|
print("done");
|
|
return 0;
|
|
}
|