From 5dbe12ca5723939c03c6346483f1a75ea0a0edcf Mon Sep 17 00:00:00 2001 From: agra Date: Thu, 28 May 2026 12:19:12 +0300 Subject: [PATCH] =?UTF-8?q?ffi=20M5.A.next.4B.B:=20compile=5Ferror=20intri?= =?UTF-8?q?nsic=20=E2=80=94=20make-green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New reflection-builtin arm in `tryLowerReflectionCall` for `compile_error(msg)`. Resolves the string literal at lower time, emits a focused diagnostic at the call site's span via `self.diagnostics.addFmt(.err, ...)`, and returns a void-typed constant so the call expression can sit in any statement position. Three error shapes: - Zero args → "compile_error requires a string argument". - Non-string-literal arg → "compile_error argument must be a string literal" (we need the message text at lower time; runtime expressions can't be reported as compile errors). - Valid literal → the literal text is the error message verbatim. `examples/187-compile-error.sx` flips green (the `unresolved` diagnostic from the lock-in commit becomes the focused `intentional compile error from #run`). 221/221. --- src/ir/lower.zig | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 6f7e42a..589bcef 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -8966,6 +8966,28 @@ pub const Lowering = struct { } return self.builder.constBool(false); } + if (std.mem.eql(u8, name, "compile_error")) { + // compile_error(msg) — raise a build-time diagnostic at + // the call site. The argument must be a string literal so + // the message text is available at lower time. Returns a + // void-typed const (the call site is consumed for its + // side effect, not its value). + if (self.diagnostics) |diags| { + if (c.args.len < 1) { + diags.addFmt(.err, c.callee.span, "compile_error requires a string argument", .{}); + } else if (c.args[0].data == .string_literal) { + const lit = c.args[0].data.string_literal; + const msg = if (lit.is_raw) + lit.raw + else + unescape.unescapeString(self.alloc, lit.raw) catch lit.raw; + diags.addFmt(.err, c.callee.span, "{s}", .{msg}); + } else { + diags.addFmt(.err, c.callee.span, "compile_error argument must be a string literal", .{}); + } + } + return self.builder.constInt(0, .void); + } if (std.mem.eql(u8, name, "field_name")) { // field_name(T, i) → field_name_get instruction if (c.args.len < 2) return self.builder.constString(self.module.types.internString(""));