Skip to content

Commit ec445fb

Browse files
schmeeVexu
authored andcommitted
Improve error messages for break type coercion
1 parent 8642770 commit ec445fb

9 files changed

+199
-67
lines changed

src/AstGen.zig

Lines changed: 133 additions & 36 deletions
Large diffs are not rendered by default.

src/Module.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5949,7 +5949,7 @@ pub const PeerTypeCandidateSrc = union(enum) {
59495949
none: void,
59505950
/// When we want to know the the src of candidate i, look up at
59515951
/// index i in this slice
5952-
override: []LazySrcLoc,
5952+
override: []?LazySrcLoc,
59535953
/// resolvePeerTypes originates from a @TypeOf(...) call
59545954
typeof_builtin_call_node_offset: i32,
59555955

src/Sema.zig

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,16 @@ pub const Block = struct {
349349
/// if we need to add type coercion at the end of block analysis.
350350
/// Same indexes, capacity, length as `results`.
351351
br_list: std.ArrayListUnmanaged(Air.Inst.Index),
352+
/// Keeps the source location of the rhs operand of the break instruction,
353+
/// to enable more precise compile errors.
354+
/// Same indexes, capacity, length as `results`.
355+
src_locs: std.ArrayListUnmanaged(?LazySrcLoc),
356+
357+
pub fn deinit(merges: *@This(), allocator: mem.Allocator) void {
358+
merges.results.deinit(allocator);
359+
merges.br_list.deinit(allocator);
360+
merges.src_locs.deinit(allocator);
361+
}
352362
};
353363

354364
/// For debugging purposes.
@@ -722,8 +732,7 @@ const LabeledBlock = struct {
722732

723733
fn destroy(lb: *LabeledBlock, gpa: Allocator) void {
724734
lb.block.instructions.deinit(gpa);
725-
lb.label.merges.results.deinit(gpa);
726-
lb.label.merges.br_list.deinit(gpa);
735+
lb.label.merges.deinit(gpa);
727736
gpa.destroy(lb);
728737
}
729738
};
@@ -777,8 +786,9 @@ fn analyzeBodyRuntimeBreak(sema: *Sema, block: *Block, body: []const Zir.Inst.In
777786
error.ComptimeBreak => {
778787
const zir_datas = sema.code.instructions.items(.data);
779788
const break_data = zir_datas[sema.comptime_break_inst].@"break";
789+
const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
780790
try sema.addRuntimeBreak(block, .{
781-
.block_inst = break_data.block_inst,
791+
.block_inst = extra.block_inst,
782792
.operand = break_data.operand,
783793
.inst = sema.comptime_break_inst,
784794
});
@@ -817,8 +827,9 @@ pub fn analyzeBodyBreak(
817827
sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn())
818828
return null;
819829
const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
830+
const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
820831
return BreakData{
821-
.block_inst = break_data.block_inst,
832+
.block_inst = extra.block_inst,
822833
.operand = break_data.operand,
823834
.inst = break_inst,
824835
};
@@ -5238,6 +5249,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
52385249
var label: Block.Label = .{
52395250
.zir_block = inst,
52405251
.merges = .{
5252+
.src_locs = .{},
52415253
.results = .{},
52425254
.br_list = .{},
52435255
.block_inst = block_inst,
@@ -5251,8 +5263,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
52515263
const merges = &child_block.label.?.merges;
52525264

52535265
defer child_block.instructions.deinit(gpa);
5254-
defer merges.results.deinit(gpa);
5255-
defer merges.br_list.deinit(gpa);
5266+
defer merges.deinit(gpa);
52565267

52575268
var loop_block = child_block.makeSubBlock();
52585269
defer loop_block.instructions.deinit(gpa);
@@ -5422,6 +5433,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
54225433
var label: Block.Label = .{
54235434
.zir_block = inst,
54245435
.merges = .{
5436+
.src_locs = .{},
54255437
.results = .{},
54265438
.br_list = .{},
54275439
.block_inst = block_inst,
@@ -5450,8 +5462,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
54505462
};
54515463

54525464
defer child_block.instructions.deinit(gpa);
5453-
defer label.merges.results.deinit(gpa);
5454-
defer label.merges.br_list.deinit(gpa);
5465+
defer label.merges.deinit(gpa);
54555466

54565467
return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges);
54575468
}
@@ -5480,7 +5491,8 @@ fn resolveBlockBody(
54805491

54815492
const break_inst = sema.comptime_break_inst;
54825493
const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
5483-
if (break_data.block_inst == body_inst) {
5494+
const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
5495+
if (extra.block_inst == body_inst) {
54845496
return try sema.resolveInst(break_data.operand);
54855497
} else {
54865498
return error.ComptimeBreak;
@@ -5533,7 +5545,7 @@ fn analyzeBlockBody(
55335545
// Need to set the type and emit the Block instruction. This allows machine code generation
55345546
// to emit a jump instruction to after the block when it encounters the break.
55355547
try parent_block.instructions.append(gpa, merges.block_inst);
5536-
const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);
5548+
const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items });
55375549
// TODO add note "missing else causes void value"
55385550

55395551
const type_src = src; // TODO: better source location
@@ -5842,14 +5854,20 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError
58425854
defer tracy.end();
58435855

58445856
const inst_data = sema.code.instructions.items(.data)[inst].@"break";
5857+
const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
58455858
const operand = try sema.resolveInst(inst_data.operand);
5846-
const zir_block = inst_data.block_inst;
5859+
const zir_block = extra.block_inst;
58475860

58485861
var block = start_block;
58495862
while (true) {
58505863
if (block.label) |label| {
58515864
if (label.zir_block == zir_block) {
58525865
const br_ref = try start_block.addBr(label.merges.block_inst, operand);
5866+
const src_loc = if (extra.operand_src_node != Zir.Inst.Break.no_src_node)
5867+
LazySrcLoc.nodeOffset(extra.operand_src_node)
5868+
else
5869+
null;
5870+
try label.merges.src_locs.append(sema.gpa, src_loc);
58535871
try label.merges.results.append(sema.gpa, operand);
58545872
try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
58555873
block.runtime_index.increment();
@@ -6643,6 +6661,7 @@ fn analyzeCall(
66436661
.func = null,
66446662
.comptime_result = undefined,
66456663
.merges = .{
6664+
.src_locs = .{},
66466665
.results = .{},
66476666
.br_list = .{},
66486667
.block_inst = block_inst,
@@ -6692,8 +6711,7 @@ fn analyzeCall(
66926711
const merges = &child_block.inlining.?.merges;
66936712

66946713
defer child_block.instructions.deinit(gpa);
6695-
defer merges.results.deinit(gpa);
6696-
defer merges.br_list.deinit(gpa);
6714+
defer merges.deinit(gpa);
66976715

66986716
// If it's a comptime function call, we need to memoize it as long as no external
66996717
// comptime memory is mutated.
@@ -10780,6 +10798,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1078010798
var label: Block.Label = .{
1078110799
.zir_block = inst,
1078210800
.merges = .{
10801+
.src_locs = .{},
1078310802
.results = .{},
1078410803
.br_list = .{},
1078510804
.block_inst = block_inst,
@@ -10807,8 +10826,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1080710826
};
1080810827
const merges = &child_block.label.?.merges;
1080910828
defer child_block.instructions.deinit(gpa);
10810-
defer merges.results.deinit(gpa);
10811-
defer merges.br_list.deinit(gpa);
10829+
defer merges.deinit(gpa);
1081210830

1081310831
if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| {
1081410832
var extra_index: usize = special.end;
@@ -12298,7 +12316,7 @@ fn zirBitwise(
1229812316
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
1229912317

1230012318
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
12301-
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
12319+
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
1230212320
const scalar_type = resolved_type.scalarType();
1230312321
const scalar_tag = scalar_type.zigTypeTag();
1230412322

@@ -12502,7 +12520,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1250212520
try trash_block.addBitCast(rhs_info.elem_type, .void_value),
1250312521
};
1250412522
break :t try sema.resolvePeerTypes(block, src, &instructions, .{
12505-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
12523+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1250612524
});
1250712525
};
1250812526

@@ -13002,7 +13020,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1300213020

1300313021
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1300413022
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
13005-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13023+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1300613024
});
1300713025

1300813026
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13162,7 +13180,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1316213180

1316313181
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1316413182
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
13165-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13183+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1316613184
});
1316713185

1316813186
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13325,7 +13343,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1332513343

1332613344
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1332713345
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
13328-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13346+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1332913347
});
1333013348

1333113349
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13441,7 +13459,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1344113459

1344213460
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1344313461
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
13444-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13462+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1344513463
});
1344613464

1344713465
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13683,7 +13701,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1368313701

1368413702
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1368513703
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
13686-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13704+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1368713705
});
1368813706

1368913707
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -13866,7 +13884,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1386613884

1386713885
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1386813886
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
13869-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13887+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1387013888
});
1387113889

1387213890
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
@@ -13968,7 +13986,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1396813986

1396913987
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1397013988
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
13971-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13989+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1397213990
});
1397313991

1397413992
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
@@ -14081,7 +14099,7 @@ fn zirOverflowArithmetic(
1408114099
lhs_ty
1408214100
else
1408314101
try sema.resolvePeerTypes(block, src, instructions, .{
14084-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
14102+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1408514103
});
1408614104

1408714105
const rhs_dest_ty = if (zir_tag == .shl_with_overflow)
@@ -14312,7 +14330,7 @@ fn analyzeArithmetic(
1431214330

1431314331
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1431414332
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
14315-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
14333+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
1431614334
});
1431714335

1431814336
const is_vector = resolved_type.zigTypeTag() == .Vector;
@@ -15200,7 +15218,7 @@ fn analyzeCmp(
1520015218
return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src);
1520115219
}
1520215220
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
15203-
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
15221+
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
1520415222
if (!resolved_type.isSelfComparable(is_equality_cmp)) {
1520515223
return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{
1520615224
compareOperatorName(op), resolved_type.fmt(sema.mod),
@@ -17024,6 +17042,7 @@ fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !voi
1702417042
.label = .{
1702517043
.zir_block = break_data.block_inst,
1702617044
.merges = .{
17045+
.src_locs = .{},
1702717046
.results = .{},
1702817047
.br_list = .{},
1702917048
.block_inst = new_block_inst,
@@ -20605,7 +20624,7 @@ fn checkSimdBinOp(
2060520624
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
2060620625
var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null;
2060720626
const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
20608-
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
20627+
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
2060920628
});
2061020629
const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
2061120630
const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);

src/Zir.zig

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2603,8 +2603,8 @@ pub const Inst = struct {
26032603
}
26042604
},
26052605
@"break": struct {
2606-
block_inst: Index,
26072606
operand: Ref,
2607+
payload_index: u32,
26082608
},
26092609
switch_capture: struct {
26102610
switch_inst: Index,
@@ -2690,6 +2690,13 @@ pub const Inst = struct {
26902690
};
26912691
};
26922692

2693+
pub const Break = struct {
2694+
pub const no_src_node = std.math.maxInt(i32);
2695+
2696+
block_inst: Index,
2697+
operand_src_node: i32,
2698+
};
2699+
26932700
/// Trailing:
26942701
/// 0. Output for every outputs_len
26952702
/// 1. Input for every inputs_len

src/print_zir.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2321,8 +2321,9 @@ const Writer = struct {
23212321

23222322
fn writeBreak(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
23232323
const inst_data = self.code.instructions.items(.data)[inst].@"break";
2324+
const extra = self.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
23242325

2325-
try self.writeInstIndex(stream, inst_data.block_inst);
2326+
try self.writeInstIndex(stream, extra.block_inst);
23262327
try stream.writeAll(", ");
23272328
try self.writeInstRef(stream, inst_data.operand);
23282329
try stream.writeAll(")");

test/cases/compile_errors/incompatible sub-byte fields.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ export fn entry() void {
2525
// target=native
2626
//
2727
// :14:17: error: incompatible types: '*align(1:0:1) u2' and '*align(2:8:2) u2'
28+
// :15:14: note: type '*align(1:0:1) u2' here
29+
// :16:14: note: type '*align(2:8:2) u2' here

test/cases/compile_errors/missing_else_clause.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ export fn entry() void {
3131
// target=native
3232
//
3333
// :2:21: error: incompatible types: 'i32' and 'void'
34+
// :6:25: note: type 'i32' here
3435
// :6:15: error: incompatible types: 'i32' and 'void'
36+
// :2:31: note: type 'i32' here
3537
// :12:16: error: expected type 'tmp.h.T', found 'void'
3638
// :11:15: note: struct declared here
3739
// :18:9: error: incompatible types: 'void' and 'tmp.k.T'

test/cases/compile_errors/missing_result_type_for_phi_node.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ export fn entry() void {
1010
// target=native
1111
//
1212
// :5:11: error: incompatible types: 'void' and 'comptime_int'
13+
// :5:11: note: type 'void' here
14+
// :5:17: note: type 'comptime_int' here

test/cases/compile_errors/unused_value_in_switch_in_loop.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ export fn entry() void {
1212
// target=native
1313
//
1414
// :3:18: error: incompatible types: 'comptime_int' and 'void'
15+
// :4:14: note: type 'comptime_int' here
16+
// :5:16: note: type 'void' here

0 commit comments

Comments
 (0)