mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #9166 from joachimschmidt557/stage2
stage2 Sema: Add error notes to unresolvable peer types
This commit is contained in:
commit
a0670e748e
3 changed files with 105 additions and 11 deletions
|
|
@ -4399,6 +4399,57 @@ pub const SwitchProngSrc = union(enum) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const PeerTypeCandidateSrc = union(enum) {
|
||||||
|
/// Do not print out error notes for candidate sources
|
||||||
|
none: void,
|
||||||
|
/// When we want to know the the src of candidate i, look up at
|
||||||
|
/// index i in this slice
|
||||||
|
override: []LazySrcLoc,
|
||||||
|
/// resolvePeerTypes originates from a @TypeOf(...) call
|
||||||
|
typeof_builtin_call_node_offset: i32,
|
||||||
|
|
||||||
|
pub fn resolve(
|
||||||
|
self: PeerTypeCandidateSrc,
|
||||||
|
gpa: *Allocator,
|
||||||
|
decl: *Decl,
|
||||||
|
candidates: usize,
|
||||||
|
candidate_i: usize,
|
||||||
|
) ?LazySrcLoc {
|
||||||
|
@setCold(true);
|
||||||
|
|
||||||
|
switch (self) {
|
||||||
|
.none => {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
.override => |candidate_srcs| {
|
||||||
|
return candidate_srcs[candidate_i];
|
||||||
|
},
|
||||||
|
.typeof_builtin_call_node_offset => |node_offset| {
|
||||||
|
if (candidates <= 2) {
|
||||||
|
switch (candidate_i) {
|
||||||
|
0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = node_offset },
|
||||||
|
1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = node_offset },
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tree = decl.namespace.file_scope.getTree(gpa) catch |err| {
|
||||||
|
// In this case we emit a warning + a less precise source location.
|
||||||
|
log.warn("unable to load {s}: {s}", .{
|
||||||
|
decl.namespace.file_scope.sub_file_path, @errorName(err),
|
||||||
|
});
|
||||||
|
return LazySrcLoc{ .node_offset = 0 };
|
||||||
|
};
|
||||||
|
const node = decl.relativeToNodeIndex(node_offset);
|
||||||
|
const node_datas = tree.nodes.items(.data);
|
||||||
|
const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
|
||||||
|
|
||||||
|
return LazySrcLoc{ .node_abs = params[candidate_i] };
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void {
|
pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
|
||||||
53
src/Sema.zig
53
src/Sema.zig
|
|
@ -1496,7 +1496,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
|
||||||
|
|
||||||
if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| {
|
if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| {
|
||||||
const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
|
const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
|
||||||
const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list);
|
const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
|
||||||
if (var_is_mut) {
|
if (var_is_mut) {
|
||||||
try sema.validateVarType(block, ty_src, final_elem_ty);
|
try sema.validateVarType(block, ty_src, final_elem_ty);
|
||||||
}
|
}
|
||||||
|
|
@ -2103,7 +2103,7 @@ fn analyzeBlockBody(
|
||||||
// Need to set the type and emit the Block instruction. This allows machine code generation
|
// Need to set the type and emit the Block instruction. This allows machine code generation
|
||||||
// to emit a jump instruction to after the block when it encounters the break.
|
// to emit a jump instruction to after the block when it encounters the break.
|
||||||
try parent_block.instructions.append(gpa, merges.block_inst);
|
try parent_block.instructions.append(gpa, merges.block_inst);
|
||||||
const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items);
|
const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);
|
||||||
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
|
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
|
||||||
child_block.instructions.items.len);
|
child_block.instructions.items.len);
|
||||||
sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{
|
sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{
|
||||||
|
|
@ -5325,7 +5325,7 @@ fn zirBitwise(
|
||||||
const rhs_ty = sema.typeOf(rhs);
|
const rhs_ty = sema.typeOf(rhs);
|
||||||
|
|
||||||
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
|
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
|
||||||
const resolved_type = try sema.resolvePeerTypes(block, src, instructions);
|
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
|
||||||
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
|
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
|
||||||
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
|
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
|
||||||
|
|
||||||
|
|
@ -5506,7 +5506,7 @@ fn analyzeArithmetic(
|
||||||
};
|
};
|
||||||
|
|
||||||
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
|
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
|
||||||
const resolved_type = try sema.resolvePeerTypes(block, src, instructions);
|
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
|
||||||
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
|
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
|
||||||
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
|
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
|
||||||
|
|
||||||
|
|
@ -5817,7 +5817,7 @@ fn analyzeCmp(
|
||||||
return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
|
return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
|
||||||
}
|
}
|
||||||
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
|
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
|
||||||
const resolved_type = try sema.resolvePeerTypes(block, src, instructions);
|
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
|
||||||
if (!resolved_type.isSelfComparable(is_equality_cmp)) {
|
if (!resolved_type.isSelfComparable(is_equality_cmp)) {
|
||||||
return sema.mod.fail(&block.base, src, "{s} operator not allowed for type '{}'", .{
|
return sema.mod.fail(&block.base, src, "{s} operator not allowed for type '{}'", .{
|
||||||
@tagName(op), resolved_type,
|
@tagName(op), resolved_type,
|
||||||
|
|
@ -6027,7 +6027,7 @@ fn zirTypeofPeer(
|
||||||
inst_list[i] = sema.resolveInst(arg_ref);
|
inst_list[i] = sema.resolveInst(arg_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result_type = try sema.resolvePeerTypes(block, src, inst_list);
|
const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node });
|
||||||
return sema.addType(result_type);
|
return sema.addType(result_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8966,6 +8966,7 @@ fn resolvePeerTypes(
|
||||||
block: *Scope.Block,
|
block: *Scope.Block,
|
||||||
src: LazySrcLoc,
|
src: LazySrcLoc,
|
||||||
instructions: []Air.Inst.Ref,
|
instructions: []Air.Inst.Ref,
|
||||||
|
candidate_srcs: Module.PeerTypeCandidateSrc,
|
||||||
) !Type {
|
) !Type {
|
||||||
if (instructions.len == 0)
|
if (instructions.len == 0)
|
||||||
return Type.initTag(.noreturn);
|
return Type.initTag(.noreturn);
|
||||||
|
|
@ -8976,7 +8977,8 @@ fn resolvePeerTypes(
|
||||||
const target = sema.mod.getTarget();
|
const target = sema.mod.getTarget();
|
||||||
|
|
||||||
var chosen = instructions[0];
|
var chosen = instructions[0];
|
||||||
for (instructions[1..]) |candidate| {
|
var chosen_i: usize = 0;
|
||||||
|
for (instructions[1..]) |candidate, candidate_i| {
|
||||||
const candidate_ty = sema.typeOf(candidate);
|
const candidate_ty = sema.typeOf(candidate);
|
||||||
const chosen_ty = sema.typeOf(chosen);
|
const chosen_ty = sema.typeOf(chosen);
|
||||||
if (candidate_ty.eql(chosen_ty))
|
if (candidate_ty.eql(chosen_ty))
|
||||||
|
|
@ -8985,12 +8987,14 @@ fn resolvePeerTypes(
|
||||||
continue;
|
continue;
|
||||||
if (chosen_ty.zigTypeTag() == .NoReturn) {
|
if (chosen_ty.zigTypeTag() == .NoReturn) {
|
||||||
chosen = candidate;
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (candidate_ty.zigTypeTag() == .Undefined)
|
if (candidate_ty.zigTypeTag() == .Undefined)
|
||||||
continue;
|
continue;
|
||||||
if (chosen_ty.zigTypeTag() == .Undefined) {
|
if (chosen_ty.zigTypeTag() == .Undefined) {
|
||||||
chosen = candidate;
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (chosen_ty.isInt() and
|
if (chosen_ty.isInt() and
|
||||||
|
|
@ -8999,18 +9003,21 @@ fn resolvePeerTypes(
|
||||||
{
|
{
|
||||||
if (chosen_ty.intInfo(target).bits < candidate_ty.intInfo(target).bits) {
|
if (chosen_ty.intInfo(target).bits < candidate_ty.intInfo(target).bits) {
|
||||||
chosen = candidate;
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (chosen_ty.isFloat() and candidate_ty.isFloat()) {
|
if (chosen_ty.isFloat() and candidate_ty.isFloat()) {
|
||||||
if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
|
if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
|
||||||
chosen = candidate;
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chosen_ty.zigTypeTag() == .ComptimeInt and candidate_ty.isInt()) {
|
if (chosen_ty.zigTypeTag() == .ComptimeInt and candidate_ty.isInt()) {
|
||||||
chosen = candidate;
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9020,6 +9027,7 @@ fn resolvePeerTypes(
|
||||||
|
|
||||||
if (chosen_ty.zigTypeTag() == .ComptimeFloat and candidate_ty.isFloat()) {
|
if (chosen_ty.zigTypeTag() == .ComptimeFloat and candidate_ty.isFloat()) {
|
||||||
chosen = candidate;
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9032,11 +9040,38 @@ fn resolvePeerTypes(
|
||||||
}
|
}
|
||||||
if (chosen_ty.zigTypeTag() == .EnumLiteral and candidate_ty.zigTypeTag() == .Enum) {
|
if (chosen_ty.zigTypeTag() == .EnumLiteral and candidate_ty.zigTypeTag() == .Enum) {
|
||||||
chosen = candidate;
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO error notes pointing out each type
|
// At this point, we hit a compile error. We need to recover
|
||||||
return sema.mod.fail(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen_ty, candidate_ty });
|
// the source locations.
|
||||||
|
const chosen_src = candidate_srcs.resolve(
|
||||||
|
sema.gpa,
|
||||||
|
block.src_decl,
|
||||||
|
instructions.len,
|
||||||
|
chosen_i,
|
||||||
|
);
|
||||||
|
const candidate_src = candidate_srcs.resolve(
|
||||||
|
sema.gpa,
|
||||||
|
block.src_decl,
|
||||||
|
instructions.len,
|
||||||
|
candidate_i + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
const msg = msg: {
|
||||||
|
const msg = try sema.mod.errMsg(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen_ty, candidate_ty });
|
||||||
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
||||||
|
if (chosen_src) |src_loc|
|
||||||
|
try sema.mod.errNote(&block.base, src_loc, msg, "type '{}' here", .{chosen_ty});
|
||||||
|
|
||||||
|
if (candidate_src) |src_loc|
|
||||||
|
try sema.mod.errNote(&block.base, src_loc, msg, "type '{}' here", .{candidate_ty});
|
||||||
|
|
||||||
|
break :msg msg;
|
||||||
|
};
|
||||||
|
return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sema.typeOf(chosen);
|
return sema.typeOf(chosen);
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,11 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||||
\\pub fn main() void {
|
\\pub fn main() void {
|
||||||
\\ _ = @TypeOf(true, 1);
|
\\ _ = @TypeOf(true, 1);
|
||||||
\\}
|
\\}
|
||||||
, &[_][]const u8{":2:9: error: incompatible types: 'bool' and 'comptime_int'"});
|
, &[_][]const u8{
|
||||||
|
":2:9: error: incompatible types: 'bool' and 'comptime_int'",
|
||||||
|
":2:17: note: type 'bool' here",
|
||||||
|
":2:23: note: type 'comptime_int' here",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -1729,7 +1733,11 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||||
\\ const b = false;
|
\\ const b = false;
|
||||||
\\ _ = a & &b;
|
\\ _ = a & &b;
|
||||||
\\}
|
\\}
|
||||||
, &[_][]const u8{":4:11: error: incompatible types: 'bool' and '*const bool'"});
|
, &[_][]const u8{
|
||||||
|
":4:11: error: incompatible types: 'bool' and '*const bool'",
|
||||||
|
":4:9: note: type 'bool' here",
|
||||||
|
":4:13: note: type '*const bool' here",
|
||||||
|
});
|
||||||
|
|
||||||
case.addCompareOutput(
|
case.addCompareOutput(
|
||||||
\\pub fn main() void {
|
\\pub fn main() void {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue