stage2 Sema: Resolve source locations of @TypeOf parameters

This commit is contained in:
joachimschmidt557 2021-06-23 23:52:46 +08:00
parent 0bef271e75
commit fcdc5c6b3c
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
2 changed files with 62 additions and 11 deletions

View File

@ -1516,7 +1516,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| {
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, null);
if (var_is_mut) {
try sema.validateVarType(block, ty_src, final_elem_ty);
}
@ -2123,7 +2123,7 @@ fn analyzeBlockBody(
// 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.
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, null);
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
child_block.instructions.items.len);
sema.air_instructions.items(.data)[merges.block_inst] = .{ .ty_pl = .{
@ -4768,7 +4768,7 @@ fn zirBitwise(
const rhs_ty = sema.typeOf(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, null);
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
@ -4914,7 +4914,7 @@ fn analyzeArithmetic(
}
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, null);
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
@ -5223,7 +5223,7 @@ fn analyzeCmp(
return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
}
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, null);
if (!resolved_type.isSelfComparable(is_equality_cmp)) {
return sema.mod.fail(&block.base, src, "{s} operator not allowed for type '{}'", .{
@tagName(op), resolved_type,
@ -5433,7 +5433,7 @@ fn zirTypeofPeer(
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, extra.data.src_node);
return sema.addType(result_type);
}
@ -8324,11 +8324,42 @@ fn wrapErrorUnion(
}
}
fn resolveTypeOfArgSrcLoc(
gpa: *Allocator,
decl: *Decl,
typeof_builtin_call_node_offset: i32,
candidates: usize,
candidate_i: usize,
) LazySrcLoc {
@setCold(true);
if (candidates <= 2) {
switch (candidate_i) {
0 => return LazySrcLoc{ .node_offset_builtin_call_arg0 = typeof_builtin_call_node_offset },
1 => return LazySrcLoc{ .node_offset_builtin_call_arg1 = typeof_builtin_call_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(typeof_builtin_call_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] };
}
fn resolvePeerTypes(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
instructions: []Air.Inst.Ref,
typeof_builtin_call_node_offset: ?i32,
) !Type {
if (instructions.len == 0)
return Type.initTag(.noreturn);
@ -8339,7 +8370,8 @@ fn resolvePeerTypes(
const target = sema.mod.getTarget();
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 chosen_ty = sema.typeOf(chosen);
if (candidate_ty.eql(chosen_ty))
@ -8348,12 +8380,14 @@ fn resolvePeerTypes(
continue;
if (chosen_ty.zigTypeTag() == .NoReturn) {
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
}
if (candidate_ty.zigTypeTag() == .Undefined)
continue;
if (chosen_ty.zigTypeTag() == .Undefined) {
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
}
if (chosen_ty.isInt() and
@ -8362,18 +8396,21 @@ fn resolvePeerTypes(
{
if (chosen_ty.intInfo(target).bits < candidate_ty.intInfo(target).bits) {
chosen = candidate;
chosen_i = candidate_i + 1;
}
continue;
}
if (chosen_ty.isFloat() and candidate_ty.isFloat()) {
if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
chosen = candidate;
chosen_i = candidate_i + 1;
}
continue;
}
if (chosen_ty.zigTypeTag() == .ComptimeInt and candidate_ty.isInt()) {
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
}
@ -8383,6 +8420,7 @@ fn resolvePeerTypes(
if (chosen_ty.zigTypeTag() == .ComptimeFloat and candidate_ty.isFloat()) {
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
}
@ -8395,15 +8433,24 @@ fn resolvePeerTypes(
}
if (chosen_ty.zigTypeTag() == .EnumLiteral and candidate_ty.zigTypeTag() == .Enum) {
chosen = candidate;
chosen_i = candidate_i + 1;
continue;
}
// At this point, we hit a compile error. If the call to
// resolvePeerTypes originated from the @TypeOf builtin, we
// need to recover the source locations
const msg = msg: {
const msg = try sema.mod.errMsg(&block.base, src, "incompatible types: '{}' and '{}'", .{ chosen_ty, candidate_ty });
errdefer msg.destroy(sema.gpa);
// TODO add error notes
// try sema.mod.errNote(&block.base, chosen.src, msg, "type '{}' here", .{chosen_ty});
// try sema.mod.errNote(&block.base, candidate.src, msg, "type '{}' here", .{candidate_ty});
// TODO add error notes for other scenarios
if (typeof_builtin_call_node_offset) |node_offset| {
const chosen_src = resolveTypeOfArgSrcLoc(sema.gpa, block.src_decl, node_offset, instructions.len, chosen_i);
const candidate_src = resolveTypeOfArgSrcLoc(sema.gpa, block.src_decl, node_offset, instructions.len, candidate_i + 1);
try sema.mod.errNote(&block.base, chosen_src, msg, "type '{}' here", .{chosen_ty});
try sema.mod.errNote(&block.base, candidate_src, msg, "type '{}' here", .{candidate_ty});
}
break :msg msg;
};
return sema.mod.failWithOwnedErrorMsg(&block.base, msg);

View File

@ -288,7 +288,11 @@ pub fn addCases(ctx: *TestContext) !void {
\\pub fn main() void {
\\ _ = @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",
});
}
{