diff --git a/examples/215-ref-capture-value-arg-diagnostic.sx b/examples/215-ref-capture-value-arg-diagnostic.sx new file mode 100644 index 0000000..3ffd40f --- /dev/null +++ b/examples/215-ref-capture-value-arg-diagnostic.sx @@ -0,0 +1,18 @@ +// A by-reference loop capture (`for xs: (*m)`) binds `m` to a `*T`. +// Passing it where a `T` value is expected used to slip through to the +// LLVM verifier ("Call parameter type does not match function signature"). +// The compiler now reports it at the call site with a fix-it: write `m.*`. + +#import "modules/std.sx"; + +Move :: struct { flag: s64; } + +take :: (m: Move) -> s64 { return m.flag; } + +main :: () -> s32 { + moves : [2]Move = .[ Move.{ flag = 1 }, Move.{ flag = 2 } ]; + for moves: (*m) { + take(m); + } + return 0; +} diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 7f89f09..99e54a4 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -6569,6 +6569,23 @@ pub const Lowering = struct { } } } + // A by-reference loop capture (`for xs: (*m)`) binds `m` to a `*T`. + // Passing it where a `T` value is expected used to slip through as a + // type-mismatched call that only LLVM's verifier rejected; report it + // here with a fix-it instead. + if (ai < param_types.len and arg.data == .identifier) { + if (self.refCapturePointee(arg)) |pointee| { + if (pointee == param_types[ai]) { + if (self.diagnostics) |d| { + const nm = arg.data.identifier.name; + const tn = self.formatTypeName(pointee); + const fix = std.fmt.allocPrint(self.alloc, "{s}.*", .{nm}) catch nm; + const pid = d.addFmtId(.err, arg.span, "by-reference loop capture '{s}' has type '*{s}', but '{s}' is expected here", .{ nm, tn, tn }); + d.addHelpFmt(pid, arg.span, fix, "dereference it to pass the value: `{s}`", .{fix}); + } + } + } + } const val = self.lowerExpr(arg); self.target_type = saved_target; args.append(self.alloc, val) catch unreachable; diff --git a/tests/expected/215-ref-capture-value-arg-diagnostic.exit b/tests/expected/215-ref-capture-value-arg-diagnostic.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/expected/215-ref-capture-value-arg-diagnostic.exit @@ -0,0 +1 @@ +1 diff --git a/tests/expected/215-ref-capture-value-arg-diagnostic.txt b/tests/expected/215-ref-capture-value-arg-diagnostic.txt new file mode 100644 index 0000000..6aa3ad8 --- /dev/null +++ b/tests/expected/215-ref-capture-value-arg-diagnostic.txt @@ -0,0 +1,10 @@ +error: by-reference loop capture 'm' has type '*Move', but 'Move' is expected here + --> /Users/agra/projects/sx/examples/215-ref-capture-value-arg-diagnostic.sx:15:14 + | +15 | take(m); + | ^ + +help: dereference it to pass the value: `m.*` + | +15 | m.* + | ^