| author | |
| committer | |
| log | 94e98bfe80033439382bff22bcab02aaaa580dc5 |
| tree | cb8b5e94a0a32e9b7eeb2c401ef0732db0d7dace |
| parent | aa4332fb0e5f46657c8c41a3971150b642be1c19 |
| signature |
9 files changed, 254 insertions(+), 46 deletions(-)
src/Air/print.zig+1-1| ... | @@ -363,7 +363,7 @@ const Writer = struct { | ... | @@ -363,7 +363,7 @@ const Writer = struct { |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | fn writeType(w: *Writer, s: *std.Io.Writer, ty: Type) !void { | 365 | fn writeType(w: *Writer, s: *std.Io.Writer, ty: Type) !void { |
| 366 | return ty.print(s, w.pt); | 366 | return ty.print(s, w.pt, null); |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | fn writeTy(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void { | 369 | fn writeTy(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void { |
src/Sema.zig+36-27| ... | @@ -2447,19 +2447,6 @@ fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, t | ... | @@ -2447,19 +2447,6 @@ fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, t |
| 2447 | }); | 2447 | }); |
| 2448 | } | 2448 | } |
| 2449 | 2449 | ||
| 2450 | fn failWithErrorSetCodeMissing( | ||
| 2451 | sema: *Sema, | ||
| 2452 | block: *Block, | ||
| 2453 | src: LazySrcLoc, | ||
| 2454 | dest_err_set_ty: Type, | ||
| 2455 | src_err_set_ty: Type, | ||
| 2456 | ) CompileError { | ||
| 2457 | const pt = sema.pt; | ||
| 2458 | return sema.fail(block, src, "expected type '{f}', found type '{f}'", .{ | ||
| 2459 | dest_err_set_ty.fmt(pt), src_err_set_ty.fmt(pt), | ||
| 2460 | }); | ||
| 2461 | } | ||
| 2462 | |||
| 2463 | pub fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: ?usize) CompileError { | 2450 | pub fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: ?usize) CompileError { |
| 2464 | const pt = sema.pt; | 2451 | const pt = sema.pt; |
| 2465 | return sema.failWithOwnedErrorMsg(block, msg: { | 2452 | return sema.failWithOwnedErrorMsg(block, msg: { |
| ... | @@ -2619,6 +2606,26 @@ pub fn errMsg( | ... | @@ -2619,6 +2606,26 @@ pub fn errMsg( |
| 2619 | return Zcu.ErrorMsg.create(sema.gpa, src, format, args); | 2606 | return Zcu.ErrorMsg.create(sema.gpa, src, format, args); |
| 2620 | } | 2607 | } |
| 2621 | 2608 | ||
| 2609 | fn typeMismatchErrMsg(sema: *Sema, src: LazySrcLoc, expected: Type, found: Type) Allocator.Error!*Zcu.ErrorMsg { | ||
| 2610 | const pt = sema.pt; | ||
| 2611 | var cmp: Type.Comparison = try .init(&.{ expected, found }, pt); | ||
| 2612 | defer cmp.deinit(pt); | ||
| 2613 | |||
| 2614 | const msg = try sema.errMsg(src, "expected type '{f}', found '{f}'", .{ | ||
| 2615 | cmp.fmtType(expected, pt), | ||
| 2616 | cmp.fmtType(found, pt), | ||
| 2617 | }); | ||
| 2618 | errdefer msg.destroy(sema.gpa); | ||
| 2619 | |||
| 2620 | for (cmp.type_dedupe_cache.keys(), cmp.type_dedupe_cache.values()) |ty, value| { | ||
| 2621 | if (value == .dont_dedupe) continue; | ||
| 2622 | const placeholder = value.dedupe; | ||
| 2623 | try sema.errNote(src, msg, "{f} = {f}", .{ placeholder, ty.fmt(pt) }); | ||
| 2624 | } | ||
| 2625 | |||
| 2626 | return msg; | ||
| 2627 | } | ||
| 2628 | |||
| 2622 | pub fn fail( | 2629 | pub fn fail( |
| 2623 | sema: *Sema, | 2630 | sema: *Sema, |
| 2624 | block: *Block, | 2631 | block: *Block, |
| ... | @@ -2635,6 +2642,14 @@ pub fn fail( | ... | @@ -2635,6 +2642,14 @@ pub fn fail( |
| 2635 | return sema.failWithOwnedErrorMsg(block, err_msg); | 2642 | return sema.failWithOwnedErrorMsg(block, err_msg); |
| 2636 | } | 2643 | } |
| 2637 | 2644 | ||
| 2645 | fn failWithTypeMismatch(sema: *Sema, block: *Block, src: LazySrcLoc, expected: Type, found: Type) CompileError { | ||
| 2646 | const err_msg = try sema.typeMismatchErrMsg(src, expected, found); | ||
| 2647 | errdefer err_msg.destroy(sema.gpa); | ||
| 2648 | try addDeclaredHereNote(sema, err_msg, expected); | ||
| 2649 | try addDeclaredHereNote(sema, err_msg, found); | ||
| 2650 | return sema.failWithOwnedErrorMsg(block, err_msg); | ||
| 2651 | } | ||
| 2652 | |||
| 2638 | pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) error{ AnalysisFail, OutOfMemory } { | 2653 | pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg) error{ AnalysisFail, OutOfMemory } { |
| 2639 | @branchHint(.cold); | 2654 | @branchHint(.cold); |
| 2640 | const gpa = sema.gpa; | 2655 | const gpa = sema.gpa; |
| ... | @@ -22933,7 +22948,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -22933,7 +22948,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 22933 | const operand_is_vector = operand_ty.zigTypeTag(zcu) == .vector; | 22948 | const operand_is_vector = operand_ty.zigTypeTag(zcu) == .vector; |
| 22934 | const dest_is_vector = dest_ty.zigTypeTag(zcu) == .vector; | 22949 | const dest_is_vector = dest_ty.zigTypeTag(zcu) == .vector; |
| 22935 | if (operand_is_vector != dest_is_vector) { | 22950 | if (operand_is_vector != dest_is_vector) { |
| 22936 | return sema.fail(block, operand_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }); | 22951 | return sema.failWithTypeMismatch(block, operand_src, dest_ty, operand_ty); |
| 22937 | } | 22952 | } |
| 22938 | 22953 | ||
| 22939 | if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_int) { | 22954 | if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_int) { |
| ... | @@ -29167,7 +29182,7 @@ fn coerceExtra( | ... | @@ -29167,7 +29182,7 @@ fn coerceExtra( |
| 29167 | } | 29182 | } |
| 29168 | 29183 | ||
| 29169 | const msg = msg: { | 29184 | const msg = msg: { |
| 29170 | const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) }); | 29185 | const msg = try sema.typeMismatchErrMsg(inst_src, dest_ty, inst_ty); |
| 29171 | errdefer msg.destroy(sema.gpa); | 29186 | errdefer msg.destroy(sema.gpa); |
| 29172 | 29187 | ||
| 29173 | if (!can_coerce_to) { | 29188 | if (!can_coerce_to) { |
| ... | @@ -30780,9 +30795,7 @@ fn coerceEnumToUnion( | ... | @@ -30780,9 +30795,7 @@ fn coerceEnumToUnion( |
| 30780 | 30795 | ||
| 30781 | const tag_ty = union_ty.unionTagType(zcu) orelse { | 30796 | const tag_ty = union_ty.unionTagType(zcu) orelse { |
| 30782 | const msg = msg: { | 30797 | const msg = msg: { |
| 30783 | const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ | 30798 | const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty); |
| 30784 | union_ty.fmt(pt), inst_ty.fmt(pt), | ||
| 30785 | }); | ||
| 30786 | errdefer msg.destroy(sema.gpa); | 30799 | errdefer msg.destroy(sema.gpa); |
| 30787 | try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{}); | 30800 | try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{}); |
| 30788 | try sema.addDeclaredHereNote(msg, union_ty); | 30801 | try sema.addDeclaredHereNote(msg, union_ty); |
| ... | @@ -30933,9 +30946,7 @@ fn coerceArrayLike( | ... | @@ -30933,9 +30946,7 @@ fn coerceArrayLike( |
| 30933 | const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(zcu)); | 30946 | const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(zcu)); |
| 30934 | if (dest_len != inst_len) { | 30947 | if (dest_len != inst_len) { |
| 30935 | const msg = msg: { | 30948 | const msg = msg: { |
| 30936 | const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ | 30949 | const msg = try sema.typeMismatchErrMsg(inst_src, dest_ty, inst_ty); |
| 30937 | dest_ty.fmt(pt), inst_ty.fmt(pt), | ||
| 30938 | }); | ||
| 30939 | errdefer msg.destroy(sema.gpa); | 30950 | errdefer msg.destroy(sema.gpa); |
| 30940 | try sema.errNote(dest_ty_src, msg, "destination has length {d}", .{dest_len}); | 30951 | try sema.errNote(dest_ty_src, msg, "destination has length {d}", .{dest_len}); |
| 30941 | try sema.errNote(inst_src, msg, "source has length {d}", .{inst_len}); | 30952 | try sema.errNote(inst_src, msg, "source has length {d}", .{inst_len}); |
| ... | @@ -31018,9 +31029,7 @@ fn coerceTupleToArray( | ... | @@ -31018,9 +31029,7 @@ fn coerceTupleToArray( |
| 31018 | 31029 | ||
| 31019 | if (dest_len != inst_len) { | 31030 | if (dest_len != inst_len) { |
| 31020 | const msg = msg: { | 31031 | const msg = msg: { |
| 31021 | const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ | 31032 | const msg = try sema.typeMismatchErrMsg(inst_src, dest_ty, inst_ty); |
| 31022 | dest_ty.fmt(pt), inst_ty.fmt(pt), | ||
| 31023 | }); | ||
| 31024 | errdefer msg.destroy(sema.gpa); | 31033 | errdefer msg.destroy(sema.gpa); |
| 31025 | try sema.errNote(dest_ty_src, msg, "destination has length {d}", .{dest_len}); | 31034 | try sema.errNote(dest_ty_src, msg, "destination has length {d}", .{dest_len}); |
| 31026 | try sema.errNote(inst_src, msg, "source has length {d}", .{inst_len}); | 31035 | try sema.errNote(inst_src, msg, "source has length {d}", .{inst_len}); |
| ... | @@ -32719,12 +32728,12 @@ fn wrapErrorUnionSet( | ... | @@ -32719,12 +32728,12 @@ fn wrapErrorUnionSet( |
| 32719 | break :ok; | 32728 | break :ok; |
| 32720 | }, | 32729 | }, |
| 32721 | } | 32730 | } |
| 32722 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); | 32731 | return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty); |
| 32723 | }, | 32732 | }, |
| 32724 | else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) { | 32733 | else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) { |
| 32725 | .error_set_type => |error_set_type| ok: { | 32734 | .error_set_type => |error_set_type| ok: { |
| 32726 | if (error_set_type.nameIndex(ip, expected_name) != null) break :ok; | 32735 | if (error_set_type.nameIndex(ip, expected_name) != null) break :ok; |
| 32727 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); | 32736 | return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty); |
| 32728 | }, | 32737 | }, |
| 32729 | .inferred_error_set_type => |func_index| ok: { | 32738 | .inferred_error_set_type => |func_index| ok: { |
| 32730 | // We carefully do this in an order that avoids unnecessarily | 32739 | // We carefully do this in an order that avoids unnecessarily |
| ... | @@ -32740,7 +32749,7 @@ fn wrapErrorUnionSet( | ... | @@ -32740,7 +32749,7 @@ fn wrapErrorUnionSet( |
| 32740 | }, | 32749 | }, |
| 32741 | } | 32750 | } |
| 32742 | 32751 | ||
| 32743 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); | 32752 | return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty); |
| 32744 | }, | 32753 | }, |
| 32745 | else => unreachable, | 32754 | else => unreachable, |
| 32746 | }, | 32755 | }, |
src/Type.zig+192-13| ... | @@ -141,7 +141,7 @@ const Format = struct { | ... | @@ -141,7 +141,7 @@ const Format = struct { |
| 141 | pt: Zcu.PerThread, | 141 | pt: Zcu.PerThread, |
| 142 | 142 | ||
| 143 | fn default(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void { | 143 | fn default(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void { |
| 144 | return print(f.ty, writer, f.pt); | 144 | return print(f.ty, writer, f.pt, null); |
| 145 | } | 145 | } |
| 146 | }; | 146 | }; |
| 147 | 147 | ||
| ... | @@ -157,7 +157,17 @@ pub fn dump(start_type: Type, writer: *std.Io.Writer) std.Io.Writer.Error!void { | ... | @@ -157,7 +157,17 @@ pub fn dump(start_type: Type, writer: *std.Io.Writer) std.Io.Writer.Error!void { |
| 157 | 157 | ||
| 158 | /// Prints a name suitable for `@typeName`. | 158 | /// Prints a name suitable for `@typeName`. |
| 159 | /// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels. | 159 | /// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels. |
| 160 | pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer.Error!void { | 160 | pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Comparison) std.Io.Writer.Error!void { |
| 161 | if (ctx) |c| { | ||
| 162 | const should_dedupe = shouldDedupeType(ty, c, pt) catch |err| switch (err) { | ||
| 163 | error.OutOfMemory => return error.WriteFailed, | ||
| 164 | }; | ||
| 165 | switch (should_dedupe) { | ||
| 166 | .dont_dedupe => {}, | ||
| 167 | .dedupe => |placeholder| return placeholder.format(writer), | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 161 | const zcu = pt.zcu; | 171 | const zcu = pt.zcu; |
| 162 | const ip = &zcu.intern_pool; | 172 | const ip = &zcu.intern_pool; |
| 163 | switch (ip.indexToKey(ty.toIntern())) { | 173 | switch (ip.indexToKey(ty.toIntern())) { |
| ... | @@ -209,39 +219,39 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. | ... | @@ -209,39 +219,39 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. |
| 209 | if (info.flags.is_const) try writer.writeAll("const "); | 219 | if (info.flags.is_const) try writer.writeAll("const "); |
| 210 | if (info.flags.is_volatile) try writer.writeAll("volatile "); | 220 | if (info.flags.is_volatile) try writer.writeAll("volatile "); |
| 211 | 221 | ||
| 212 | try print(Type.fromInterned(info.child), writer, pt); | 222 | try print(Type.fromInterned(info.child), writer, pt, ctx); |
| 213 | return; | 223 | return; |
| 214 | }, | 224 | }, |
| 215 | .array_type => |array_type| { | 225 | .array_type => |array_type| { |
| 216 | if (array_type.sentinel == .none) { | 226 | if (array_type.sentinel == .none) { |
| 217 | try writer.print("[{d}]", .{array_type.len}); | 227 | try writer.print("[{d}]", .{array_type.len}); |
| 218 | try print(Type.fromInterned(array_type.child), writer, pt); | 228 | try print(Type.fromInterned(array_type.child), writer, pt, ctx); |
| 219 | } else { | 229 | } else { |
| 220 | try writer.print("[{d}:{f}]", .{ | 230 | try writer.print("[{d}:{f}]", .{ |
| 221 | array_type.len, | 231 | array_type.len, |
| 222 | Value.fromInterned(array_type.sentinel).fmtValue(pt), | 232 | Value.fromInterned(array_type.sentinel).fmtValue(pt), |
| 223 | }); | 233 | }); |
| 224 | try print(Type.fromInterned(array_type.child), writer, pt); | 234 | try print(Type.fromInterned(array_type.child), writer, pt, ctx); |
| 225 | } | 235 | } |
| 226 | return; | 236 | return; |
| 227 | }, | 237 | }, |
| 228 | .vector_type => |vector_type| { | 238 | .vector_type => |vector_type| { |
| 229 | try writer.print("@Vector({d}, ", .{vector_type.len}); | 239 | try writer.print("@Vector({d}, ", .{vector_type.len}); |
| 230 | try print(Type.fromInterned(vector_type.child), writer, pt); | 240 | try print(Type.fromInterned(vector_type.child), writer, pt, ctx); |
| 231 | try writer.writeAll(")"); | 241 | try writer.writeAll(")"); |
| 232 | return; | 242 | return; |
| 233 | }, | 243 | }, |
| 234 | .opt_type => |child| { | 244 | .opt_type => |child| { |
| 235 | try writer.writeByte('?'); | 245 | try writer.writeByte('?'); |
| 236 | return print(Type.fromInterned(child), writer, pt); | 246 | return print(Type.fromInterned(child), writer, pt, ctx); |
| 237 | }, | 247 | }, |
| 238 | .error_union_type => |error_union_type| { | 248 | .error_union_type => |error_union_type| { |
| 239 | try print(Type.fromInterned(error_union_type.error_set_type), writer, pt); | 249 | try print(Type.fromInterned(error_union_type.error_set_type), writer, pt, ctx); |
| 240 | try writer.writeByte('!'); | 250 | try writer.writeByte('!'); |
| 241 | if (error_union_type.payload_type == .generic_poison_type) { | 251 | if (error_union_type.payload_type == .generic_poison_type) { |
| 242 | try writer.writeAll("anytype"); | 252 | try writer.writeAll("anytype"); |
| 243 | } else { | 253 | } else { |
| 244 | try print(Type.fromInterned(error_union_type.payload_type), writer, pt); | 254 | try print(Type.fromInterned(error_union_type.payload_type), writer, pt, ctx); |
| 245 | } | 255 | } |
| 246 | return; | 256 | return; |
| 247 | }, | 257 | }, |
| ... | @@ -323,7 +333,7 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. | ... | @@ -323,7 +333,7 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. |
| 323 | for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, val, i| { | 333 | for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, val, i| { |
| 324 | try writer.writeAll(if (i == 0) " " else ", "); | 334 | try writer.writeAll(if (i == 0) " " else ", "); |
| 325 | if (val != .none) try writer.writeAll("comptime "); | 335 | if (val != .none) try writer.writeAll("comptime "); |
| 326 | try print(Type.fromInterned(field_ty), writer, pt); | 336 | try print(Type.fromInterned(field_ty), writer, pt, ctx); |
| 327 | if (val != .none) try writer.print(" = {f}", .{Value.fromInterned(val).fmtValue(pt)}); | 337 | if (val != .none) try writer.print(" = {f}", .{Value.fromInterned(val).fmtValue(pt)}); |
| 328 | } | 338 | } |
| 329 | try writer.writeAll(" }"); | 339 | try writer.writeAll(" }"); |
| ... | @@ -360,7 +370,7 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. | ... | @@ -360,7 +370,7 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. |
| 360 | if (param_ty == .generic_poison_type) { | 370 | if (param_ty == .generic_poison_type) { |
| 361 | try writer.writeAll("anytype"); | 371 | try writer.writeAll("anytype"); |
| 362 | } else { | 372 | } else { |
| 363 | try print(Type.fromInterned(param_ty), writer, pt); | 373 | try print(Type.fromInterned(param_ty), writer, pt, ctx); |
| 364 | } | 374 | } |
| 365 | } | 375 | } |
| 366 | if (fn_info.is_var_args) { | 376 | if (fn_info.is_var_args) { |
| ... | @@ -387,13 +397,13 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. | ... | @@ -387,13 +397,13 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread) std.Io.Writer. |
| 387 | if (fn_info.return_type == .generic_poison_type) { | 397 | if (fn_info.return_type == .generic_poison_type) { |
| 388 | try writer.writeAll("anytype"); | 398 | try writer.writeAll("anytype"); |
| 389 | } else { | 399 | } else { |
| 390 | try print(Type.fromInterned(fn_info.return_type), writer, pt); | 400 | try print(Type.fromInterned(fn_info.return_type), writer, pt, ctx); |
| 391 | } | 401 | } |
| 392 | }, | 402 | }, |
| 393 | .anyframe_type => |child| { | 403 | .anyframe_type => |child| { |
| 394 | if (child == .none) return writer.writeAll("anyframe"); | 404 | if (child == .none) return writer.writeAll("anyframe"); |
| 395 | try writer.writeAll("anyframe->"); | 405 | try writer.writeAll("anyframe->"); |
| 396 | return print(Type.fromInterned(child), writer, pt); | 406 | return print(Type.fromInterned(child), writer, pt, ctx); |
| 397 | }, | 407 | }, |
| 398 | 408 | ||
| 399 | // values, not types | 409 | // values, not types |
| ... | @@ -4046,6 +4056,175 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool { | ... | @@ -4046,6 +4056,175 @@ pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool { |
| 4046 | return null; | 4056 | return null; |
| 4047 | } | 4057 | } |
| 4048 | 4058 | ||
| 4059 | /// Recursively walks the type and marks for each subtype how many times it has been seen | ||
| 4060 | fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void { | ||
| 4061 | const zcu = pt.zcu; | ||
| 4062 | const ip = &zcu.intern_pool; | ||
| 4063 | |||
| 4064 | const gop = try visited.getOrPut(zcu.gpa, ty); | ||
| 4065 | if (gop.found_existing) { | ||
| 4066 | gop.value_ptr.* += 1; | ||
| 4067 | } else { | ||
| 4068 | gop.value_ptr.* = 1; | ||
| 4069 | } | ||
| 4070 | |||
| 4071 | switch (ip.indexToKey(ty.toIntern())) { | ||
| 4072 | .ptr_type => try collectSubtypes(Type.fromInterned(ty.ptrInfo(zcu).child), pt, visited), | ||
| 4073 | .array_type => |array_type| try collectSubtypes(Type.fromInterned(array_type.child), pt, visited), | ||
| 4074 | .vector_type => |vector_type| try collectSubtypes(Type.fromInterned(vector_type.child), pt, visited), | ||
| 4075 | .opt_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited), | ||
| 4076 | .error_union_type => |error_union_type| { | ||
| 4077 | try collectSubtypes(Type.fromInterned(error_union_type.error_set_type), pt, visited); | ||
| 4078 | if (error_union_type.payload_type != .generic_poison_type) { | ||
| 4079 | try collectSubtypes(Type.fromInterned(error_union_type.payload_type), pt, visited); | ||
| 4080 | } | ||
| 4081 | }, | ||
| 4082 | .tuple_type => |tuple| { | ||
| 4083 | for (tuple.types.get(ip)) |field_ty| { | ||
| 4084 | try collectSubtypes(Type.fromInterned(field_ty), pt, visited); | ||
| 4085 | } | ||
| 4086 | }, | ||
| 4087 | .func_type => |fn_info| { | ||
| 4088 | const param_types = fn_info.param_types.get(&zcu.intern_pool); | ||
| 4089 | for (param_types) |param_ty| { | ||
| 4090 | if (param_ty != .generic_poison_type) { | ||
| 4091 | try collectSubtypes(Type.fromInterned(param_ty), pt, visited); | ||
| 4092 | } | ||
| 4093 | } | ||
| 4094 | |||
| 4095 | if (fn_info.return_type != .generic_poison_type) { | ||
| 4096 | try collectSubtypes(Type.fromInterned(fn_info.return_type), pt, visited); | ||
| 4097 | } | ||
| 4098 | }, | ||
| 4099 | .anyframe_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited), | ||
| 4100 | |||
| 4101 | // leaf types | ||
| 4102 | .undef, | ||
| 4103 | .inferred_error_set_type, | ||
| 4104 | .error_set_type, | ||
| 4105 | .struct_type, | ||
| 4106 | .union_type, | ||
| 4107 | .opaque_type, | ||
| 4108 | .enum_type, | ||
| 4109 | .simple_type, | ||
| 4110 | .int_type, | ||
| 4111 | => {}, | ||
| 4112 | |||
| 4113 | // values, not types | ||
| 4114 | .simple_value, | ||
| 4115 | .variable, | ||
| 4116 | .@"extern", | ||
| 4117 | .func, | ||
| 4118 | .int, | ||
| 4119 | .err, | ||
| 4120 | .error_union, | ||
| 4121 | .enum_literal, | ||
| 4122 | .enum_tag, | ||
| 4123 | .empty_enum_value, | ||
| 4124 | .float, | ||
| 4125 | .ptr, | ||
| 4126 | .slice, | ||
| 4127 | .opt, | ||
| 4128 | .aggregate, | ||
| 4129 | .un, | ||
| 4130 | // memoization, not types | ||
| 4131 | .memoized_call, | ||
| 4132 | => unreachable, | ||
| 4133 | } | ||
| 4134 | } | ||
| 4135 | |||
| 4136 | fn shouldDedupeType(ty: Type, ctx: *Comparison, pt: Zcu.PerThread) error{OutOfMemory}!Comparison.DedupeEntry { | ||
| 4137 | if (ctx.type_occurrences.get(ty)) |occ| { | ||
| 4138 | if (ctx.type_dedupe_cache.get(ty)) |cached| { | ||
| 4139 | return cached; | ||
| 4140 | } | ||
| 4141 | |||
| 4142 | var discarding: std.Io.Writer.Discarding = .init(&.{}); | ||
| 4143 | |||
| 4144 | print(ty, &discarding.writer, pt, null) catch | ||
| 4145 | unreachable; // we are writing into a discarding writer, it should never fail | ||
| 4146 | |||
| 4147 | const type_len: i32 = @intCast(discarding.count); | ||
| 4148 | |||
| 4149 | const placeholder_len: i32 = 3; | ||
| 4150 | const min_saved_bytes: i32 = 10; | ||
| 4151 | |||
| 4152 | const saved_bytes = (type_len - placeholder_len) * (occ - 1); | ||
| 4153 | const max_placeholders = 7; // T to Z | ||
| 4154 | const should_dedupe = saved_bytes >= min_saved_bytes and ctx.placeholder_index < max_placeholders; | ||
| 4155 | |||
| 4156 | const entry: Comparison.DedupeEntry = if (should_dedupe) b: { | ||
| 4157 | ctx.placeholder_index += 1; | ||
| 4158 | break :b .{ .dedupe = .{ .index = ctx.placeholder_index - 1 } }; | ||
| 4159 | } else .dont_dedupe; | ||
| 4160 | |||
| 4161 | try ctx.type_dedupe_cache.put(pt.zcu.gpa, ty, entry); | ||
| 4162 | |||
| 4163 | return entry; | ||
| 4164 | } else { | ||
| 4165 | return .{ .dont_dedupe = {} }; | ||
| 4166 | } | ||
| 4167 | } | ||
| 4168 | |||
| 4169 | /// The comparison recursively walks all types given and notes how many times | ||
| 4170 | /// each subtype occurs. It then while recursively printing decides for each | ||
| 4171 | /// subtype whether to print the type inline or create a placeholder based on | ||
| 4172 | /// the subtype length and number of occurences. Placeholders are then found by | ||
| 4173 | /// iterating `type_dedupe_cache` which caches the inline/placeholder decisions. | ||
| 4174 | pub const Comparison = struct { | ||
| 4175 | type_occurrences: std.AutoArrayHashMapUnmanaged(Type, u16), | ||
| 4176 | type_dedupe_cache: std.AutoArrayHashMapUnmanaged(Type, DedupeEntry), | ||
| 4177 | placeholder_index: u8, | ||
| 4178 | |||
| 4179 | pub const Placeholder = struct { | ||
| 4180 | index: u8, | ||
| 4181 | |||
| 4182 | pub fn format(p: Placeholder, writer: *std.Io.Writer) error{WriteFailed}!void { | ||
| 4183 | return writer.print("<{c}>", .{p.index + 'T'}); | ||
| 4184 | } | ||
| 4185 | }; | ||
| 4186 | |||
| 4187 | pub const DedupeEntry = union(enum) { | ||
| 4188 | dont_dedupe: void, | ||
| 4189 | dedupe: Placeholder, | ||
| 4190 | }; | ||
| 4191 | |||
| 4192 | pub fn init(types: []const Type, pt: Zcu.PerThread) error{OutOfMemory}!Comparison { | ||
| 4193 | var cmp: Comparison = .{ | ||
| 4194 | .type_occurrences = .empty, | ||
| 4195 | .type_dedupe_cache = .empty, | ||
| 4196 | .placeholder_index = 0, | ||
| 4197 | }; | ||
| 4198 | |||
| 4199 | errdefer cmp.deinit(pt); | ||
| 4200 | |||
| 4201 | for (types) |ty| { | ||
| 4202 | try collectSubtypes(ty, pt, &cmp.type_occurrences); | ||
| 4203 | } | ||
| 4204 | |||
| 4205 | return cmp; | ||
| 4206 | } | ||
| 4207 | |||
| 4208 | pub fn deinit(cmp: *Comparison, pt: Zcu.PerThread) void { | ||
| 4209 | const gpa = pt.zcu.gpa; | ||
| 4210 | cmp.type_occurrences.deinit(gpa); | ||
| 4211 | cmp.type_dedupe_cache.deinit(gpa); | ||
| 4212 | } | ||
| 4213 | |||
| 4214 | pub fn fmtType(ctx: *Comparison, ty: Type, pt: Zcu.PerThread) Comparison.Formatter { | ||
| 4215 | return .{ .ty = ty, .ctx = ctx, .pt = pt }; | ||
| 4216 | } | ||
| 4217 | pub const Formatter = struct { | ||
| 4218 | ty: Type, | ||
| 4219 | ctx: *Comparison, | ||
| 4220 | pt: Zcu.PerThread, | ||
| 4221 | |||
| 4222 | pub fn format(self: Comparison.Formatter, writer: anytype) error{WriteFailed}!void { | ||
| 4223 | print(self.ty, writer, self.pt, self.ctx) catch return error.WriteFailed; | ||
| 4224 | } | ||
| 4225 | }; | ||
| 4226 | }; | ||
| 4227 | |||
| 4049 | pub const @"u1": Type = .{ .ip_index = .u1_type }; | 4228 | pub const @"u1": Type = .{ .ip_index = .u1_type }; |
| 4050 | pub const @"u8": Type = .{ .ip_index = .u8_type }; | 4229 | pub const @"u8": Type = .{ .ip_index = .u8_type }; |
| 4051 | pub const @"u16": Type = .{ .ip_index = .u16_type }; | 4230 | pub const @"u16": Type = .{ .ip_index = .u16_type }; |
src/codegen/llvm.zig+1-1| ... | @@ -2697,7 +2697,7 @@ pub const Object = struct { | ... | @@ -2697,7 +2697,7 @@ pub const Object = struct { |
| 2697 | fn allocTypeName(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error![:0]const u8 { | 2697 | fn allocTypeName(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error![:0]const u8 { |
| 2698 | var aw: std.Io.Writer.Allocating = .init(o.gpa); | 2698 | var aw: std.Io.Writer.Allocating = .init(o.gpa); |
| 2699 | defer aw.deinit(); | 2699 | defer aw.deinit(); |
| 2700 | ty.print(&aw.writer, pt) catch |err| switch (err) { | 2700 | ty.print(&aw.writer, pt, null) catch |err| switch (err) { |
| 2701 | error.WriteFailed => return error.OutOfMemory, | 2701 | error.WriteFailed => return error.OutOfMemory, |
| 2702 | }; | 2702 | }; |
| 2703 | return aw.toOwnedSliceSentinel(0); | 2703 | return aw.toOwnedSliceSentinel(0); |
src/codegen/spirv/CodeGen.zig+1-1| ... | @@ -1213,7 +1213,7 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 { | ... | @@ -1213,7 +1213,7 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 { |
| 1213 | const gpa = cg.module.gpa; | 1213 | const gpa = cg.module.gpa; |
| 1214 | var aw: std.Io.Writer.Allocating = .init(gpa); | 1214 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1215 | defer aw.deinit(); | 1215 | defer aw.deinit(); |
| 1216 | ty.print(&aw.writer, cg.pt) catch |err| switch (err) { | 1216 | ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) { |
| 1217 | error.WriteFailed => return error.OutOfMemory, | 1217 | error.WriteFailed => return error.OutOfMemory, |
| 1218 | }; | 1218 | }; |
| 1219 | return try aw.toOwnedSlice(); | 1219 | return try aw.toOwnedSlice(); |
src/print_value.zig+1-1| ... | @@ -66,7 +66,7 @@ pub fn print( | ... | @@ -66,7 +66,7 @@ pub fn print( |
| 66 | .func_type, | 66 | .func_type, |
| 67 | .error_set_type, | 67 | .error_set_type, |
| 68 | .inferred_error_set_type, | 68 | .inferred_error_set_type, |
| 69 | => try Type.print(val.toType(), writer, pt), | 69 | => try Type.print(val.toType(), writer, pt, null), |
| 70 | .undef => try writer.writeAll("undefined"), | 70 | .undef => try writer.writeAll("undefined"), |
| 71 | .simple_value => |simple_value| switch (simple_value) { | 71 | .simple_value => |simple_value| switch (simple_value) { |
| 72 | .void => try writer.writeAll("{}"), | 72 | .void => try writer.writeAll("{}"), |
test/cases/compile_errors/pointer_attributes_checked_when_coercing_pointer_to_anon_literal.zig+2-1| ... | @@ -16,7 +16,8 @@ comptime { | ... | @@ -16,7 +16,8 @@ comptime { |
| 16 | // | 16 | // |
| 17 | // :2:29: error: expected type '[][]const u8', found '*const [2][]const u8' | 17 | // :2:29: error: expected type '[][]const u8', found '*const [2][]const u8' |
| 18 | // :2:29: note: cast discards const qualifier | 18 | // :2:29: note: cast discards const qualifier |
| 19 | // :6:31: error: expected type '*[2][]const u8', found '*const [2][]const u8' | 19 | // :6:31: error: expected type '*<T>', found '*const <T>' |
| 20 | // :6:31: note: <T> = [2][]const u8 | ||
| 20 | // :6:31: note: cast discards const qualifier | 21 | // :6:31: note: cast discards const qualifier |
| 21 | // :11:19: error: expected type '*tmp.S', found '*const tmp.S' | 22 | // :11:19: error: expected type '*tmp.S', found '*const tmp.S' |
| 22 | // :11:19: note: cast discards const qualifier | 23 | // :11:19: note: cast discards const qualifier |
test/cases/compile_errors/type_dedupe.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const SomeVeryLongName = struct {}; | ||
| 2 | |||
| 3 | fn foo(a: *SomeVeryLongName) void { | ||
| 4 | _ = a; | ||
| 5 | } | ||
| 6 | |||
| 7 | export fn entry() void { | ||
| 8 | const a: SomeVeryLongName = .{}; | ||
| 9 | |||
| 10 | foo(a); | ||
| 11 | } | ||
| 12 | |||
| 13 | // error | ||
| 14 | // | ||
| 15 | // :10:9: error: expected type '*<T>', found '<T>' | ||
| 16 | // :10:9: note: <T> = tmp.SomeVeryLongName | ||
| 17 | // :1:26: note: struct declared here | ||
| 18 | // :3:11: note: parameter type declared here | ||
test/cases/compile_errors/type_mismatch_with_tuple_concatenation.zig+2-1| ... | @@ -5,4 +5,5 @@ export fn entry() void { | ... | @@ -5,4 +5,5 @@ export fn entry() void { |
| 5 | 5 | ||
| 6 | // error | 6 | // error |
| 7 | // | 7 | // |
| 8 | // :3:11: error: expected type '@TypeOf(.{})', found 'struct { comptime comptime_int = 1, comptime comptime_int = 2, comptime comptime_int = 3 }' | 8 | // :3:11: error: expected type '@TypeOf(.{})', found 'struct { comptime <T> = 1, comptime <T> = 2, comptime <T> = 3 }' |
| 9 | // :3:11: note: <T> = comptime_int |