aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-07-10 16:51:10 +0300
committerVeikka Tuominen <git@vexu.eu>2022-07-10 23:47:56 +0300
commit34fe2b4f4be29efa8f4ba4b9f32b22373fdddc22 (patch)
tree8227137b718913e1997324cac2642e66375836bc /src/Sema.zig
parentb9f01bc39452042be1609b63f3066cfcac82f273 (diff)
downloadzig-34fe2b4f4be29efa8f4ba4b9f32b22373fdddc22.tar.gz
zig-34fe2b4f4be29efa8f4ba4b9f32b22373fdddc22.zip
Sema: prefer original error message in `coerce`
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig66
1 files changed, 55 insertions, 11 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 6f1259ed82..bb14943e22 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -19853,6 +19853,26 @@ fn coerce(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true) catch |err| switch (err) {
+ error.NotCoercible => unreachable,
+ else => |e| return e,
+ };
+}
+
+const CoersionError = CompileError || error{
+ /// When coerce is called recursively, this error should be returned instead of using `fail`
+ /// to ensure correct types in compile errors.
+ NotCoercible,
+};
+
+fn coerceExtra(
+ sema: *Sema,
+ block: *Block,
+ dest_ty_unresolved: Type,
+ inst: Air.Inst.Ref,
+ inst_src: LazySrcLoc,
+ report_err: bool,
+) CoersionError!Air.Inst.Ref {
switch (dest_ty_unresolved.tag()) {
.var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
.generic_poison => return inst,
@@ -19869,7 +19889,7 @@ fn coerce(
const arena = sema.arena;
const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
- const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
+ var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
if (in_memory_result == .ok) {
if (maybe_inst_val) |val| {
// Keep the comptime Value representation; take the new type.
@@ -19882,7 +19902,7 @@ fn coerce(
const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
switch (dest_ty.zigTypeTag()) {
- .Optional => {
+ .Optional => optional: {
// undefined sets the optional bit also to undefined.
if (is_undef) {
return sema.addConstUndef(dest_ty);
@@ -19903,10 +19923,19 @@ fn coerce(
// T to ?T
const child_type = try dest_ty.optionalChildAlloc(sema.arena);
- const intermediate = try sema.coerce(block, child_type, inst, inst_src);
- return sema.wrapOptional(block, dest_ty, intermediate, inst_src);
+ const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false) catch |err| switch (err) {
+ error.NotCoercible => {
+ if (in_memory_result == .no_match) {
+ // Try to give more useful notes
+ in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src);
+ }
+ break :optional;
+ },
+ else => |e| return e,
+ };
+ return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
},
- .Pointer => {
+ .Pointer => pointer: {
const dest_info = dest_ty.ptrInfo().data;
// Function body to function pointer.
@@ -20011,16 +20040,26 @@ fn coerce(
return sema.addConstant(dest_ty, Value.@"null");
},
.ComptimeInt => {
- const addr = try sema.coerce(block, Type.usize, inst, inst_src);
- return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
+ const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false) catch |err| switch (err) {
+ error.NotCoercible => break :pointer,
+ else => |e| return e,
+ };
+ return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
},
.Int => {
const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
.signed => Type.isize,
.unsigned => Type.usize,
};
- const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src);
- return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
+ const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false) catch |err| switch (err) {
+ error.NotCoercible => {
+ // Try to give more useful notes
+ in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src);
+ break :pointer;
+ },
+ else => |e| return e,
+ };
+ return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
},
.Pointer => p: {
const inst_info = inst_ty.ptrInfo().data;
@@ -20155,6 +20194,7 @@ fn coerce(
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
// comptime known integer to other number
if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
+ if (!report_err) return error.NotCoercible;
return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
}
return try sema.addConstant(dest_ty, val);
@@ -20356,6 +20396,8 @@ fn coerce(
return sema.addConstUndef(dest_ty);
}
+ if (!report_err) return error.NotCoercible;
+
const msg = msg: {
const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
errdefer msg.destroy(sema.gpa);
@@ -20534,8 +20576,10 @@ const InMemoryCoercionResult = union(enum) {
cur = pair.child;
},
.optional_shape => |pair| {
- try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ var buf_actual: Type.Payload.ElemType = undefined;
+ var buf_wanted: Type.Payload.ElemType = undefined;
+ try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
+ pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod),
});
break;
},