ERR/E5.1: lambda-specific raise-not-failable hint
A closure literal whose body raises but is annotated non-failable (or has no ! in its return) now gets a lambda-specific diagnostic telling the user to declare the failable return explicitly, instead of the generic "raise is only valid inside a failable function". Failability is never inferred for a lambda, so a raising lambda with no ! is a hard error that should point at the fix. New in_lambda_body flag (save/restore for nesting) set around the lambda body lowering in lowerLambda; diagRaiseNotFailable branches on it. Top-level functions keep the generic message. Test: 1043-errors-lambda-raise-annotation-hint.sx.
This commit is contained in:
@@ -135,6 +135,7 @@ pub const Lowering = struct {
|
||||
current_match_tags: ?[]const u64 = null, // type tags for current match arm (for runtime dispatch)
|
||||
force_block_value: bool = false, // set by lowerBlockValue to extract if-else values
|
||||
block_terminated: bool = false, // set when constant-folded if emits a return/br into current block
|
||||
in_lambda_body: bool = false, // true while lowering a closure-literal body; sharpens the `raise`-not-failable diagnostic (ERR E5.1: tell the user to annotate `-> (T, !)`)
|
||||
defer_stack: std.ArrayList(CleanupEntry) = std.ArrayList(CleanupEntry).empty, // block-scoped defer + onfail cleanup stack
|
||||
func_defer_base: usize = 0, // defer stack base for current function (lowerReturn drains to this)
|
||||
global_names: std.StringHashMap(GlobalInfo) = std.StringHashMap(GlobalInfo).init(std.heap.page_allocator), // #run global name → GlobalId
|
||||
@@ -7867,7 +7868,12 @@ pub const Lowering = struct {
|
||||
lambda_scope.put(p.name, .{ .ref = slot, .ty = pty, .is_alloca = true });
|
||||
}
|
||||
|
||||
// Lower body — capture last expression as return value
|
||||
// Lower body — capture last expression as return value. The
|
||||
// `in_lambda_body` flag scopes the lambda-specific `raise`-not-failable
|
||||
// hint; save/restore so a lambda nested inside a regular function (or a
|
||||
// lambda inside a lambda) restores the enclosing context.
|
||||
const saved_in_lambda = self.in_lambda_body;
|
||||
self.in_lambda_body = true;
|
||||
if (ret_ty != .void) {
|
||||
if (self.lowerBlockValue(lam.body)) |val| {
|
||||
if (!self.currentBlockHasTerminator()) {
|
||||
@@ -7886,6 +7892,7 @@ pub const Lowering = struct {
|
||||
} else {
|
||||
self.lowerBlock(lam.body);
|
||||
}
|
||||
self.in_lambda_body = saved_in_lambda;
|
||||
self.ensureTerminator(ret_ty);
|
||||
self.builder.finalize();
|
||||
|
||||
@@ -15839,7 +15846,11 @@ pub const Lowering = struct {
|
||||
|
||||
fn diagRaiseNotFailable(self: *Lowering, span: ast.Span) void {
|
||||
if (self.diagnostics) |diags| {
|
||||
diags.addFmt(.err, span, "`raise` is only valid inside a failable function (a return type with `!` or `!Named`)", .{});
|
||||
if (self.in_lambda_body) {
|
||||
diags.addFmt(.err, span, "lambda body raises; declare its return type explicitly with `-> (T, !)` or `-> (T, !Named)`", .{});
|
||||
} else {
|
||||
diags.addFmt(.err, span, "`raise` is only valid inside a failable function (a return type with `!` or `!Named`)", .{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user