authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-12 13:22:27-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-08-12 13:22:27-04:00
loga0670e748ec4914f7fc198422d0815e71e90a54f
tree4f32c8520102c445752ba882657fb7e9a67854c8
parent394d287778971c3d06fc401e688fc048cdf9860a
parent16c11988587ad78cd47ec571e1120c052abd47ed
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9166 from joachimschmidt557/stage2

stage2 Sema: Add error notes to unresolvable peer types

3 files changed, 105 insertions(+), 11 deletions(-)

src/Module.zig+51
...@@ -4399,6 +4399,57 @@ pub const SwitchProngSrc = union(enum) {...@@ -4399,6 +4399,57 @@ pub const SwitchProngSrc = union(enum) {
4399 }4399 }
4400};4400};
44014401
4402pub const PeerTypeCandidateSrc = union(enum) {
4403 /// Do not print out error notes for candidate sources
4404 none: void,
4405 /// When we want to know the the src of candidate i, look up at
4406 /// index i in this slice
4407 override: []LazySrcLoc,
4408 /// resolvePeerTypes originates from a @TypeOf(...) call
4409 typeof_builtin_call_node_offset: i32,
4410
4411 pub fn resolve(
4412 self: PeerTypeCandidateSrc,
4413 gpa: *Allocator,
4414 decl: *Decl,
4415 candidates: usize,
4416 candidate_i: usize,
4417 ) ?LazySrcLoc {
4418 @setCold(true);
4419
4420 switch (self) {
4421 .none => {
4422 return null;
4423 },
4424 .override => |candidate_srcs| {
4425 return candidate_srcs[candidate_i];
4426 },
4427 .typeof_builtin_call_node_offset => |node_offset| {
4428 if (candidates <= 2) {
4429 switch (candidate_i) {
4430 0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = node_offset },
4431 1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = node_offset },
4432 else => unreachable,
4433 }
4434 }
4435
4436 const tree = decl.namespace.file_scope.getTree(gpa) catch |err| {
4437 // In this case we emit a warning + a less precise source location.
4438 log.warn("unable to load {s}: {s}", .{
4439 decl.namespace.file_scope.sub_file_path, @errorName(err),
4440 });
4441 return LazySrcLoc{ .node_offset = 0 };
4442 };
4443 const node = decl.relativeToNodeIndex(node_offset);
4444 const node_datas = tree.nodes.items(.data);
4445 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
4446
4447 return LazySrcLoc{ .node_abs = params[candidate_i] };
4448 },
4449 }
4450 }
4451};
4452
4402pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void {4453pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void {
4403 const tracy = trace(@src());4454 const tracy = trace(@src());
4404 defer tracy.end();4455 defer tracy.end();
src/Sema.zig+44-9
...@@ -1496,7 +1496,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde...@@ -1496,7 +1496,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
14961496
1497 if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| {1497 if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| {
1498 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;1498 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
1499 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list);1499 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
1500 if (var_is_mut) {1500 if (var_is_mut) {
1501 try sema.validateVarType(block, ty_src, final_elem_ty);1501 try sema.validateVarType(block, ty_src, final_elem_ty);
1502 }1502 }
...@@ -2103,7 +2103,7 @@ fn analyzeBlockBody(...@@ -2103,7 +2103,7 @@ fn analyzeBlockBody(
2103 // Need to set the type and emit the Block instruction. This allows machine code generation2103 // Need to set the type and emit the Block instruction. This allows machine code generation
2104 // to emit a jump instruction to after the block when it encounters the break.2104 // to emit a jump instruction to after the block when it encounters the break.
2105 try parent_block.instructions.append(gpa, merges.block_inst);2105 try parent_block.instructions.append(gpa, merges.block_inst);
2106 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items);2106 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);
2107 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +2107 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
2108 child_block.instructions.items.len);2108 child_block.instructions.items.len);
2109 sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{2109 sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{
...@@ -5325,7 +5325,7 @@ fn zirBitwise(...@@ -5325,7 +5325,7 @@ fn zirBitwise(
5325 const rhs_ty = sema.typeOf(rhs);5325 const rhs_ty = sema.typeOf(rhs);
53265326
5327 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };5327 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
5328 const resolved_type = try sema.resolvePeerTypes(block, src, instructions);5328 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
5329 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);5329 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
5330 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);5330 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
53315331
...@@ -5506,7 +5506,7 @@ fn analyzeArithmetic(...@@ -5506,7 +5506,7 @@ fn analyzeArithmetic(
5506 };5506 };
55075507
5508 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };5508 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
5509 const resolved_type = try sema.resolvePeerTypes(block, src, instructions);5509 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
5510 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);5510 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
5511 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);5511 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
55125512
...@@ -5817,7 +5817,7 @@ fn analyzeCmp(...@@ -5817,7 +5817,7 @@ fn analyzeCmp(
5817 return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);5817 return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
5818 }5818 }
5819 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };5819 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
5820 const resolved_type = try sema.resolvePeerTypes(block, src, instructions);5820 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
5821 if (!resolved_type.isSelfComparable(is_equality_cmp)) {5821 if (!resolved_type.isSelfComparable(is_equality_cmp)) {
5822 return sema.mod.fail(&block.base, src, "{s} operator not allowed for type '{}'", .{5822 return sema.mod.fail(&block.base, src, "{s} operator not allowed for type '{}'", .{
5823 @tagName(op), resolved_type,5823 @tagName(op), resolved_type,
...@@ -6027,7 +6027,7 @@ fn zirTypeofPeer(...@@ -6027,7 +6027,7 @@ fn zirTypeofPeer(
6027 inst_list[i] = sema.resolveInst(arg_ref);6027 inst_list[i] = sema.resolveInst(arg_ref);
6028 }6028 }
60296029
6030 const result_type = try sema.resolvePeerTypes(block, src, inst_list);6030 const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node });
6031 return sema.addType(result_type);6031 return sema.addType(result_type);
6032}6032}
60336033
...@@ -8966,6 +8966,7 @@ fn resolvePeerTypes(...@@ -8966,6 +8966,7 @@ fn resolvePeerTypes(
8966 block: *Scope.Block,8966 block: *Scope.Block,
8967 src: LazySrcLoc,8967 src: LazySrcLoc,
8968 instructions: []Air.Inst.Ref,8968 instructions: []Air.Inst.Ref,
8969 candidate_srcs: Module.PeerTypeCandidateSrc,
8969) !Type {8970) !Type {
8970 if (instructions.len == 0)8971 if (instructions.len == 0)
8971 return Type.initTag(.noreturn);8972 return Type.initTag(.noreturn);
...@@ -8976,7 +8977,8 @@ fn resolvePeerTypes(...@@ -8976,7 +8977,8 @@ fn resolvePeerTypes(
8976 const target = sema.mod.getTarget();8977 const target = sema.mod.getTarget();
89778978
8978 var chosen = instructions[0];8979 var chosen = instructions[0];
8979 for (instructions[1..]) |candidate| {8980 var chosen_i: usize = 0;
8981 for (instructions[1..]) |candidate, candidate_i| {
8980 const candidate_ty = sema.typeOf(candidate);8982 const candidate_ty = sema.typeOf(candidate);
8981 const chosen_ty = sema.typeOf(chosen);8983 const chosen_ty = sema.typeOf(chosen);
8982 if (candidate_ty.eql(chosen_ty))8984 if (candidate_ty.eql(chosen_ty))
...@@ -8985,12 +8987,14 @@ fn resolvePeerTypes(...@@ -8985,12 +8987,14 @@ fn resolvePeerTypes(
8985 continue;8987 continue;
8986 if (chosen_ty.zigTypeTag() == .NoReturn) {8988 if (chosen_ty.zigTypeTag() == .NoReturn) {
8987 chosen = candidate;8989 chosen = candidate;
8990 chosen_i = candidate_i + 1;
8988 continue;8991 continue;
8989 }8992 }
8990 if (candidate_ty.zigTypeTag() == .Undefined)8993 if (candidate_ty.zigTypeTag() == .Undefined)
8991 continue;8994 continue;
8992 if (chosen_ty.zigTypeTag() == .Undefined) {8995 if (chosen_ty.zigTypeTag() == .Undefined) {
8993 chosen = candidate;8996 chosen = candidate;
8997 chosen_i = candidate_i + 1;
8994 continue;8998 continue;
8995 }8999 }
8996 if (chosen_ty.isInt() and9000 if (chosen_ty.isInt() and
...@@ -8999,18 +9003,21 @@ fn resolvePeerTypes(...@@ -8999,18 +9003,21 @@ fn resolvePeerTypes(
8999 {9003 {
9000 if (chosen_ty.intInfo(target).bits < candidate_ty.intInfo(target).bits) {9004 if (chosen_ty.intInfo(target).bits < candidate_ty.intInfo(target).bits) {
9001 chosen = candidate;9005 chosen = candidate;
9006 chosen_i = candidate_i + 1;
9002 }9007 }
9003 continue;9008 continue;
9004 }9009 }
9005 if (chosen_ty.isFloat() and candidate_ty.isFloat()) {9010 if (chosen_ty.isFloat() and candidate_ty.isFloat()) {
9006 if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {9011 if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
9007 chosen = candidate;9012 chosen = candidate;
9013 chosen_i = candidate_i + 1;
9008 }9014 }
9009 continue;9015 continue;
9010 }9016 }
90119017
9012 if (chosen_ty.zigTypeTag() == .ComptimeInt and candidate_ty.isInt()) {9018 if (chosen_ty.zigTypeTag() == .ComptimeInt and candidate_ty.isInt()) {
9013 chosen = candidate;9019 chosen = candidate;
9020 chosen_i = candidate_i + 1;
9014 continue;9021 continue;
9015 }9022 }
90169023
...@@ -9020,6 +9027,7 @@ fn resolvePeerTypes(...@@ -9020,6 +9027,7 @@ fn resolvePeerTypes(
90209027
9021 if (chosen_ty.zigTypeTag() == .ComptimeFloat and candidate_ty.isFloat()) {9028 if (chosen_ty.zigTypeTag() == .ComptimeFloat and candidate_ty.isFloat()) {
9022 chosen = candidate;9029 chosen = candidate;
9030 chosen_i = candidate_i + 1;
9023 continue;9031 continue;
9024 }9032 }
90259033
...@@ -9032,11 +9040,38 @@ fn resolvePeerTypes(...@@ -9032,11 +9040,38 @@ fn resolvePeerTypes(
9032 }9040 }
9033 if (chosen_ty.zigTypeTag() == .EnumLiteral and candidate_ty.zigTypeTag() == .Enum) {9041 if (chosen_ty.zigTypeTag() == .EnumLiteral and candidate_ty.zigTypeTag() == .Enum) {
9034 chosen = candidate;9042 chosen = candidate;
9043 chosen_i = candidate_i + 1;
9035 continue;9044 continue;
9036 }9045 }
90379046
9038 // TODO error notes pointing out each type9047 // At this point, we hit a compile error. We need to recover
9039 return sema.mod.fail(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen_ty, candidate_ty });9048 // the source locations.
9049 const chosen_src = candidate_srcs.resolve(
9050 sema.gpa,
9051 block.src_decl,
9052 instructions.len,
9053 chosen_i,
9054 );
9055 const candidate_src = candidate_srcs.resolve(
9056 sema.gpa,
9057 block.src_decl,
9058 instructions.len,
9059 candidate_i + 1,
9060 );
9061
9062 const msg = msg: {
9063 const msg = try sema.mod.errMsg(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen_ty, candidate_ty });
9064 errdefer msg.destroy(sema.gpa);
9065
9066 if (chosen_src) |src_loc|
9067 try sema.mod.errNote(&block.base, src_loc, msg, "type '{}' here", .{chosen_ty});
9068
9069 if (candidate_src) |src_loc|
9070 try sema.mod.errNote(&block.base, src_loc, msg, "type '{}' here", .{candidate_ty});
9071
9072 break :msg msg;
9073 };
9074 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
9040 }9075 }
90419076
9042 return sema.typeOf(chosen);9077 return sema.typeOf(chosen);
test/cases.zig+10-2
...@@ -288,7 +288,11 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -288,7 +288,11 @@ pub fn addCases(ctx: *TestContext) !void {
288 \\pub fn main() void {288 \\pub fn main() void {
289 \\ _ = @TypeOf(true, 1);289 \\ _ = @TypeOf(true, 1);
290 \\}290 \\}
291 , &[_][]const u8{":2:9: error: incompatible types: 'bool' and 'comptime_int'"});291 , &[_][]const u8{
292 ":2:9: error: incompatible types: 'bool' and 'comptime_int'",
293 ":2:17: note: type 'bool' here",
294 ":2:23: note: type 'comptime_int' here",
295 });
292 }296 }
293297
294 {298 {
...@@ -1729,7 +1733,11 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1729,7 +1733,11 @@ pub fn addCases(ctx: *TestContext) !void {
1729 \\ const b = false;1733 \\ const b = false;
1730 \\ _ = a & &b;1734 \\ _ = a & &b;
1731 \\}1735 \\}
1732 , &[_][]const u8{":4:11: error: incompatible types: 'bool' and '*const bool'"});1736 , &[_][]const u8{
1737 ":4:11: error: incompatible types: 'bool' and '*const bool'",
1738 ":4:9: note: type 'bool' here",
1739 ":4:13: note: type '*const bool' here",
1740 });
17331741
1734 case.addCompareOutput(1742 case.addCompareOutput(
1735 \\pub fn main() void {1743 \\pub fn main() void {