ERR/E4.2: value-carrying -> (int, !) main wrapper

Extends the failable-main entry-point wrapper to a value-carrying main.
`main :: () -> (int, !)` now exits the integer value on success (truncated
to u8, like a plain integer main) and reports the header + trace to stderr
+ exits 1 on an escaping error (same reporter as the pure `-> !` form).

- lower.zig validateMainSignature: accept a 2-field `{int, error_set}`
  tuple return (set needs_trace_runtime) instead of rejecting it. Multi-
  value `-> (T1, T2, !)` and non-integer value slots still reject — there's
  no single integer exit code to map them to (sharpened diagnostic).
- emit_llvm.zig: the `.ret` arm detects a value-carrying main (tuple ending
  in `.error_set`) and extracts `{value, tag}` (extractvalue 0/1) before
  calling emitFailableMainRet, now generalized to take an optional `value`
  (null → pure `-> !`, success exits 0; present → success exits the value).
  C reporter unchanged.

All E4.2 entry-point shapes (void / int / `-> !` / `-> (int, !)`) now done.
examples/245-failable-main-value.sx (exit 64); 239 comment refreshed.
This commit is contained in:
agra
2026-06-01 10:00:03 +03:00
parent 210cf91e37
commit e898effb4b
7 changed files with 78 additions and 29 deletions

View File

@@ -397,9 +397,19 @@ pub const Lowering = struct {
self.needs_trace_runtime = true;
return;
}
// `-> (T..., !)` — a multi-slot tuple return; not yet wired.
// `-> (T, !)` — value-carrying failable. Accepted only for a single
// **integer** value slot (`{int, error_set}`): the wrapper extracts
// the value + tag from the returned tuple, exits `value as u8` on
// success / reports + exits 1 on error. Multi-value `-> (T1, T2, !)`
// or a non-integer value slot stays rejected — there's no single
// integer exit code to map it to.
const ti = self.module.types.get(rt);
if (ti == .tuple and ti.tuple.fields.len == 2 and self.isIntEx(ti.tuple.fields[0])) {
self.needs_trace_runtime = true;
return;
}
if (self.diagnostics) |diags| {
diags.addFmt(.err, if (fd.return_type) |rtn| rtn.span else null, "a value-carrying failable `main` (`-> (T, !)`) is not yet supported — its multi-slot return ABI-mismatches the entry-point call; use `-> !` (no value) or a non-failable integer return, or absorb errors with `catch`", .{});
diags.addFmt(.err, if (fd.return_type) |rtn| rtn.span else null, "a value-carrying failable `main` must be `-> (int, !)` (one integer value slot); got '{s}'. Use `-> !` (no value), `-> (int, !)`, or a non-failable integer return", .{self.formatTypeName(rt)});
}
return;
}