authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-30 16:05:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-30 16:17:59-07:00
log507dc1f2e7fac212e79f152e557cbec98a3c30e9
tree34b057caf8ebadef2d199af39b1b44fca48c1a23
parent84039a57e4684e8df10e657bb76c6acb3fb89238

stage2: fix hashing and comparison design flaw with Value

* `Value.toType` accepts a buffer parameter instead of an allocator parameter and can no longer fail. * Module: remove the unused `mod: *Module` parameter from various functions. * `Value.compare` now accepts a `Type` parameter which indicates the type of both operands. There is also a `Value.compareHetero` which accepts only Value parameters and supports comparing mixed types. Likewise, `Value.eql` requires a `Type` parameter. * `Value.hash` is removed; instead the hash map context structs now have a `ty: Type` field, and the hash function lives there, where it has access to a Value's Type when it computes a hash. - This allowed the hash function to be greatly simplified and sound in the sense that the same Values, even with different representations, always hash to the same thing. * Sema: Fix source location of zirCmp when an operand is runtime known but needs to be comptime known. * Remove unused target parameter from `Value.floatCast`.

6 files changed, 229 insertions(+), 442 deletions(-)

src/Air.zig+2-1
......@@ -503,7 +503,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
503503pub fn getRefType(air: Air, ref: Air.Inst.Ref) Type {
504504 const ref_int = @enumToInt(ref);
505505 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
506 return Air.Inst.Ref.typed_value_map[ref_int].val.toType(undefined) catch unreachable;
506 var buffer: Value.ToTypeBuffer = undefined;
507 return Air.Inst.Ref.typed_value_map[ref_int].val.toType(&buffer);
507508 }
508509 const inst_index = ref_int - Air.Inst.Ref.typed_value_map.len;
509510 const air_tags = air.instructions.items(.tag);
src/Module.zig+2-9
......@@ -4299,7 +4299,6 @@ pub fn simplePtrType(
42994299}
43004300
43014301pub fn ptrType(
4302 mod: *Module,
43034302 arena: *Allocator,
43044303 elem_ty: Type,
43054304 sentinel: ?Value,
......@@ -4311,7 +4310,6 @@ pub fn ptrType(
43114310 @"volatile": bool,
43124311 size: std.builtin.TypeInfo.Pointer.Size,
43134312) Allocator.Error!Type {
4314 _ = mod;
43154313 assert(host_size == 0 or bit_offset < host_size * 8);
43164314
43174315 // TODO check if type can be represented by simplePtrType
......@@ -4328,8 +4326,7 @@ pub fn ptrType(
43284326 });
43294327}
43304328
4331pub fn optionalType(mod: *Module, arena: *Allocator, child_type: Type) Allocator.Error!Type {
4332 _ = mod;
4329pub fn optionalType(arena: *Allocator, child_type: Type) Allocator.Error!Type {
43334330 switch (child_type.tag()) {
43344331 .single_const_pointer => return Type.Tag.optional_single_const_pointer.create(
43354332 arena,
......@@ -4344,16 +4341,14 @@ pub fn optionalType(mod: *Module, arena: *Allocator, child_type: Type) Allocator
43444341}
43454342
43464343pub fn arrayType(
4347 mod: *Module,
43484344 arena: *Allocator,
43494345 len: u64,
43504346 sentinel: ?Value,
43514347 elem_type: Type,
43524348) Allocator.Error!Type {
4353 _ = mod;
43544349 if (elem_type.eql(Type.initTag(.u8))) {
43554350 if (sentinel) |some| {
4356 if (some.eql(Value.initTag(.zero))) {
4351 if (some.eql(Value.initTag(.zero), elem_type)) {
43574352 return Type.Tag.array_u8_sentinel_0.create(arena, len);
43584353 }
43594354 } else {
......@@ -4376,12 +4371,10 @@ pub fn arrayType(
43764371}
43774372
43784373pub fn errorUnionType(
4379 mod: *Module,
43804374 arena: *Allocator,
43814375 error_set: Type,
43824376 payload: Type,
43834377) Allocator.Error!Type {
4384 _ = mod;
43854378 assert(error_set.zigTypeTag() == .ErrorSet);
43864379 if (error_set.eql(Type.initTag(.anyerror)) and payload.eql(Type.initTag(.void))) {
43874380 return Type.initTag(.anyerror_void_error_union);
src/RangeSet.zig+15-8
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const Order = std.math.Order;
3const Type = @import("type.zig").Type;
34const Value = @import("value.zig").Value;
45const RangeSet = @This();
56const SwitchProngSrc = @import("Module.zig").SwitchProngSrc;
......@@ -22,9 +23,15 @@ pub fn deinit(self: *RangeSet) void {
2223 self.ranges.deinit();
2324}
2425
25pub fn add(self: *RangeSet, first: Value, last: Value, src: SwitchProngSrc) !?SwitchProngSrc {
26pub fn add(
27 self: *RangeSet,
28 first: Value,
29 last: Value,
30 ty: Type,
31 src: SwitchProngSrc,
32) !?SwitchProngSrc {
2633 for (self.ranges.items) |range| {
27 if (last.compare(.gte, range.first) and first.compare(.lte, range.last)) {
34 if (last.compare(.gte, range.first, ty) and first.compare(.lte, range.last, ty)) {
2835 return range.src; // They overlap.
2936 }
3037 }
......@@ -37,18 +44,18 @@ pub fn add(self: *RangeSet, first: Value, last: Value, src: SwitchProngSrc) !?Sw
3744}
3845
3946/// Assumes a and b do not overlap
40fn lessThan(_: void, a: Range, b: Range) bool {
41 return a.first.compare(.lt, b.first);
47fn lessThan(ty: Type, a: Range, b: Range) bool {
48 return a.first.compare(.lt, b.first, ty);
4249}
4350
44pub fn spans(self: *RangeSet, first: Value, last: Value) !bool {
51pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool {
4552 if (self.ranges.items.len == 0)
4653 return false;
4754
48 std.sort.sort(Range, self.ranges.items, {}, lessThan);
55 std.sort.sort(Range, self.ranges.items, ty, lessThan);
4956
50 if (!self.ranges.items[0].first.eql(first) or
51 !self.ranges.items[self.ranges.items.len - 1].last.eql(last))
57 if (!self.ranges.items[0].first.eql(first, ty) or
58 !self.ranges.items[self.ranges.items.len - 1].last.eql(last, ty))
5259 {
5360 return false;
5461 }
src/Sema.zig+75-59
......@@ -634,7 +634,9 @@ fn analyzeAsType(
634634 const wanted_type = Type.initTag(.@"type");
635635 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
636636 const val = try sema.resolveConstValue(block, src, coerced_inst);
637 return val.toType(sema.arena);
637 var buffer: Value.ToTypeBuffer = undefined;
638 const ty = val.toType(&buffer);
639 return ty.copy(sema.arena);
638640}
639641
640642/// May return Value Tags: `variable`, `undef`.
......@@ -1022,7 +1024,9 @@ fn zirEnumDecl(
10221024 if (bag != 0) break true;
10231025 } else false;
10241026 if (any_values) {
1025 try enum_obj.values.ensureCapacity(&new_decl_arena.allocator, fields_len);
1027 try enum_obj.values.ensureTotalCapacityContext(&new_decl_arena.allocator, fields_len, .{
1028 .ty = tag_ty,
1029 });
10261030 }
10271031
10281032 {
......@@ -1100,10 +1104,10 @@ fn zirEnumDecl(
11001104 // that points to this default value expression rather than the struct.
11011105 // But only resolve the source location if we need to emit a compile error.
11021106 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref)).val;
1103 enum_obj.values.putAssumeCapacityNoClobber(tag_val, {});
1107 enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = tag_ty });
11041108 } else if (any_values) {
11051109 const tag_val = try Value.Tag.int_u64.create(&new_decl_arena.allocator, field_i);
1106 enum_obj.values.putAssumeCapacityNoClobber(tag_val, {});
1110 enum_obj.values.putAssumeCapacityNoClobberContext(tag_val, {}, .{ .ty = tag_ty });
11071111 }
11081112 }
11091113
......@@ -2516,7 +2520,7 @@ fn zirOptionalType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compi
25162520 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
25172521 const src = inst_data.src();
25182522 const child_type = try sema.resolveType(block, src, inst_data.operand);
2519 const opt_type = try sema.mod.optionalType(sema.arena, child_type);
2523 const opt_type = try Module.optionalType(sema.arena, child_type);
25202524
25212525 return sema.addType(opt_type);
25222526}
......@@ -2547,11 +2551,10 @@ fn zirArrayType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
25472551 const tracy = trace(@src());
25482552 defer tracy.end();
25492553
2550 // TODO these should be lazily evaluated
25512554 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
25522555 const len = try sema.resolveInstConst(block, .unneeded, bin_inst.lhs);
25532556 const elem_type = try sema.resolveType(block, .unneeded, bin_inst.rhs);
2554 const array_ty = try sema.mod.arrayType(sema.arena, len.val.toUnsignedInt(), null, elem_type);
2557 const array_ty = try Module.arrayType(sema.arena, len.val.toUnsignedInt(), null, elem_type);
25552558
25562559 return sema.addType(array_ty);
25572560}
......@@ -2560,13 +2563,12 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index)
25602563 const tracy = trace(@src());
25612564 defer tracy.end();
25622565
2563 // TODO these should be lazily evaluated
25642566 const inst_data = sema.code.instructions.items(.data)[inst].array_type_sentinel;
25652567 const len = try sema.resolveInstConst(block, .unneeded, inst_data.len);
25662568 const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
25672569 const sentinel = try sema.resolveInstConst(block, .unneeded, extra.sentinel);
25682570 const elem_type = try sema.resolveType(block, .unneeded, extra.elem_type);
2569 const array_ty = try sema.mod.arrayType(sema.arena, len.val.toUnsignedInt(), sentinel.val, elem_type);
2571 const array_ty = try Module.arrayType(sema.arena, len.val.toUnsignedInt(), sentinel.val, elem_type);
25702572
25712573 return sema.addType(array_ty);
25722574}
......@@ -2599,7 +2601,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Com
25992601 error_union.elemType(),
26002602 });
26012603 }
2602 const err_union_ty = try sema.mod.errorUnionType(sema.arena, error_union, payload);
2604 const err_union_ty = try Module.errorUnionType(sema.arena, error_union, payload);
26032605 return sema.addType(err_union_ty);
26042606}
26052607
......@@ -3890,6 +3892,7 @@ fn analyzeSwitch(
38903892 block,
38913893 &range_set,
38923894 item_ref,
3895 operand_ty,
38933896 src_node_offset,
38943897 .{ .scalar = scalar_i },
38953898 );
......@@ -3912,6 +3915,7 @@ fn analyzeSwitch(
39123915 block,
39133916 &range_set,
39143917 item_ref,
3918 operand_ty,
39153919 src_node_offset,
39163920 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
39173921 );
......@@ -3929,6 +3933,7 @@ fn analyzeSwitch(
39293933 &range_set,
39303934 item_first,
39313935 item_last,
3936 operand_ty,
39323937 src_node_offset,
39333938 .{ .range = .{ .prong = multi_i, .item = range_i } },
39343939 );
......@@ -3945,7 +3950,7 @@ fn analyzeSwitch(
39453950
39463951 const min_int = try operand_ty.minInt(&arena, mod.getTarget());
39473952 const max_int = try operand_ty.maxInt(&arena, mod.getTarget());
3948 if (try range_set.spans(min_int, max_int)) {
3953 if (try range_set.spans(min_int, max_int, operand_ty)) {
39493954 if (special_prong == .@"else") {
39503955 return mod.fail(
39513956 &block.base,
......@@ -4050,7 +4055,7 @@ fn analyzeSwitch(
40504055 );
40514056 }
40524057
4053 var seen_values = ValueSrcMap.init(gpa);
4058 var seen_values = ValueSrcMap.initContext(gpa, .{ .ty = operand_ty });
40544059 defer seen_values.deinit();
40554060
40564061 var extra_index: usize = special.end;
......@@ -4161,7 +4166,7 @@ fn analyzeSwitch(
41614166 const item = sema.resolveInst(item_ref);
41624167 // Validation above ensured these will succeed.
41634168 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
4164 if (operand_val.eql(item_val)) {
4169 if (operand_val.eql(item_val, operand_ty)) {
41654170 return sema.resolveBlockBody(block, src, &child_block, body, merges);
41664171 }
41674172 }
......@@ -4183,7 +4188,7 @@ fn analyzeSwitch(
41834188 const item = sema.resolveInst(item_ref);
41844189 // Validation above ensured these will succeed.
41854190 const item_val = sema.resolveConstValue(&child_block, .unneeded, item) catch unreachable;
4186 if (operand_val.eql(item_val)) {
4191 if (operand_val.eql(item_val, operand_ty)) {
41874192 return sema.resolveBlockBody(block, src, &child_block, body, merges);
41884193 }
41894194 }
......@@ -4198,8 +4203,8 @@ fn analyzeSwitch(
41984203 // Validation above ensured these will succeed.
41994204 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first) catch unreachable;
42004205 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last) catch unreachable;
4201 if (Value.compare(operand_val, .gte, first_tv.val) and
4202 Value.compare(operand_val, .lte, last_tv.val))
4206 if (Value.compare(operand_val, .gte, first_tv.val, operand_ty) and
4207 Value.compare(operand_val, .lte, last_tv.val, operand_ty))
42034208 {
42044209 return sema.resolveBlockBody(block, src, &child_block, body, merges);
42054210 }
......@@ -4450,12 +4455,13 @@ fn validateSwitchRange(
44504455 range_set: *RangeSet,
44514456 first_ref: Zir.Inst.Ref,
44524457 last_ref: Zir.Inst.Ref,
4458 operand_ty: Type,
44534459 src_node_offset: i32,
44544460 switch_prong_src: Module.SwitchProngSrc,
44554461) CompileError!void {
44564462 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
44574463 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
4458 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
4464 const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src);
44594465 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
44604466}
44614467
......@@ -4464,11 +4470,12 @@ fn validateSwitchItem(
44644470 block: *Scope.Block,
44654471 range_set: *RangeSet,
44664472 item_ref: Zir.Inst.Ref,
4473 operand_ty: Type,
44674474 src_node_offset: i32,
44684475 switch_prong_src: Module.SwitchProngSrc,
44694476) CompileError!void {
44704477 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
4471 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
4478 const maybe_prev_src = try range_set.add(item_val, item_val, operand_ty, switch_prong_src);
44724479 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
44734480}
44744481
......@@ -5137,20 +5144,26 @@ fn zirCmp(
51375144 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
51385145 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
51395146
5140 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
5141 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
5142 if (lhs_val.isUndef() or rhs_val.isUndef()) {
5143 return sema.addConstUndef(resolved_type);
5144 }
5145 if (lhs_val.compare(op, rhs_val)) {
5146 return Air.Inst.Ref.bool_true;
5147 const runtime_src: LazySrcLoc = src: {
5148 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
5149 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
5150 if (lhs_val.isUndef() or rhs_val.isUndef()) {
5151 return sema.addConstUndef(resolved_type);
5152 }
5153 if (lhs_val.compare(op, rhs_val, resolved_type)) {
5154 return Air.Inst.Ref.bool_true;
5155 } else {
5156 return Air.Inst.Ref.bool_false;
5157 }
51475158 } else {
5148 return Air.Inst.Ref.bool_false;
5159 break :src rhs_src;
51495160 }
5161 } else {
5162 break :src lhs_src;
51505163 }
5151 }
5164 };
5165 try sema.requireRuntimeBlock(block, runtime_src);
51525166
5153 try sema.requireRuntimeBlock(block, src);
51545167 const tag: Air.Inst.Tag = switch (op) {
51555168 .lt => .cmp_lt,
51565169 .lte => .cmp_lte,
......@@ -5626,7 +5639,7 @@ fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
56265639
56275640 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple;
56285641 const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type);
5629 const ty = try sema.mod.ptrType(
5642 const ty = try Module.ptrType(
56305643 sema.arena,
56315644 elem_type,
56325645 null,
......@@ -5680,7 +5693,7 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
56805693
56815694 const elem_type = try sema.resolveType(block, .unneeded, extra.data.elem_type);
56825695
5683 const ty = try sema.mod.ptrType(
5696 const ty = try Module.ptrType(
56845697 sema.arena,
56855698 elem_type,
56865699 sentinel,
......@@ -6569,7 +6582,7 @@ fn panicWithMsg(
65696582 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
65706583 const ptr_stack_trace_ty = try Module.simplePtrType(arena, stack_trace_ty, true, .One);
65716584 const null_stack_trace = try sema.addConstant(
6572 try mod.optionalType(arena, ptr_stack_trace_ty),
6585 try Module.optionalType(arena, ptr_stack_trace_ty),
65736586 Value.initTag(.null_value),
65746587 );
65756588 const args = try arena.create([2]Air.Inst.Ref);
......@@ -6713,7 +6726,8 @@ fn fieldVal(
67136726 },
67146727 .Type => {
67156728 const val = (try sema.resolveDefinedValue(block, object_src, object)).?;
6716 const child_type = try val.toType(arena);
6729 var to_type_buffer: Value.ToTypeBuffer = undefined;
6730 const child_type = val.toType(&to_type_buffer);
67176731 switch (child_type.zigTypeTag()) {
67186732 .ErrorSet => {
67196733 // TODO resolve inferred error sets
......@@ -6733,7 +6747,7 @@ fn fieldVal(
67336747 } else (try mod.getErrorValue(field_name)).key;
67346748
67356749 return sema.addConstant(
6736 child_type,
6750 try child_type.copy(arena),
67376751 try Value.Tag.@"error".create(arena, .{ .name = name }),
67386752 );
67396753 },
......@@ -6781,7 +6795,7 @@ fn fieldVal(
67816795 };
67826796 const field_index_u32 = @intCast(u32, field_index);
67836797 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
6784 return sema.addConstant(child_type, enum_val);
6798 return sema.addConstant(try child_type.copy(arena), enum_val);
67856799 },
67866800 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
67876801 }
......@@ -6805,7 +6819,6 @@ fn fieldPtr(
68056819 // in `fieldVal`. This function takes a pointer and returns a pointer.
68066820
68076821 const mod = sema.mod;
6808 const arena = sema.arena;
68096822 const object_ptr_src = src; // TODO better source location
68106823 const object_ptr_ty = sema.typeOf(object_ptr);
68116824 const object_ty = switch (object_ptr_ty.zigTypeTag()) {
......@@ -6887,7 +6900,8 @@ fn fieldPtr(
68876900 _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr);
68886901 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
68896902 const val = (sema.resolveDefinedValue(block, src, result) catch unreachable).?;
6890 const child_type = try val.toType(arena);
6903 var to_type_buffer: Value.ToTypeBuffer = undefined;
6904 const child_type = val.toType(&to_type_buffer);
68916905 switch (child_type.zigTypeTag()) {
68926906 .ErrorSet => {
68936907 // TODO resolve inferred error sets
......@@ -6902,15 +6916,14 @@ fn fieldPtr(
69026916 }
69036917 }
69046918 return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
6905 field_name,
6906 child_type,
6919 field_name, child_type,
69076920 });
69086921 } else (try mod.getErrorValue(field_name)).key;
69096922
69106923 var anon_decl = try block.startAnonDecl();
69116924 defer anon_decl.deinit();
69126925 return sema.analyzeDeclRef(try anon_decl.finish(
6913 child_type,
6926 try child_type.copy(anon_decl.arena()),
69146927 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
69156928 ));
69166929 },
......@@ -6960,7 +6973,7 @@ fn fieldPtr(
69606973 var anon_decl = try block.startAnonDecl();
69616974 defer anon_decl.deinit();
69626975 return sema.analyzeDeclRef(try anon_decl.finish(
6963 child_type,
6976 try child_type.copy(anon_decl.arena()),
69646977 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
69656978 ));
69666979 },
......@@ -7352,7 +7365,7 @@ fn coerce(
73527365
73537366 if (src_sentinel) |src_s| {
73547367 if (dst_sentinel) |dst_s| {
7355 if (src_s.eql(dst_s)) {
7368 if (src_s.eql(dst_s, dst_elem_type)) {
73567369 return sema.coerceArrayPtrToMany(block, dest_type, inst, inst_src);
73577370 }
73587371 }
......@@ -7474,7 +7487,7 @@ fn coerceNum(
74747487 }
74757488 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
74767489 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
7477 const res = val.floatCast(sema.arena, dest_type, target) catch |err| switch (err) {
7490 const res = val.floatCast(sema.arena, dest_type) catch |err| switch (err) {
74787491 error.Overflow => return sema.mod.fail(
74797492 &block.base,
74807493 inst_src,
......@@ -7813,12 +7826,12 @@ fn analyzeSlice(
78137826 array_type.sentinel()
78147827 else
78157828 slice_sentinel;
7816 return_elem_type = try sema.mod.arrayType(sema.arena, len, array_sentinel, elem_type);
7829 return_elem_type = try Module.arrayType(sema.arena, len, array_sentinel, elem_type);
78177830 return_ptr_size = .One;
78187831 }
78197832 }
78207833 }
7821 const return_type = try sema.mod.ptrType(
7834 const return_type = try Module.ptrType(
78227835 sema.arena,
78237836 return_elem_type,
78247837 if (end_opt == .none) slice_sentinel else null,
......@@ -7858,39 +7871,42 @@ fn cmpNumeric(
78587871 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
78597872 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
78607873 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
7861 lhs_ty.arrayLen(),
7862 rhs_ty.arrayLen(),
7874 lhs_ty.arrayLen(), rhs_ty.arrayLen(),
78637875 });
78647876 }
78657877 return sema.mod.fail(&block.base, src, "TODO implement support for vectors in cmpNumeric", .{});
78667878 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
78677879 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
7868 lhs_ty,
7869 rhs_ty,
7880 lhs_ty, rhs_ty,
78707881 });
78717882 }
78727883
7873 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
7874 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
7875 if (lhs_val.isUndef() or rhs_val.isUndef()) {
7876 return sema.addConstUndef(Type.initTag(.bool));
7877 }
7878 if (Value.compare(lhs_val, op, rhs_val)) {
7879 return Air.Inst.Ref.bool_true;
7884 const runtime_src: LazySrcLoc = src: {
7885 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
7886 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
7887 if (lhs_val.isUndef() or rhs_val.isUndef()) {
7888 return sema.addConstUndef(Type.initTag(.bool));
7889 }
7890 if (Value.compareHetero(lhs_val, op, rhs_val)) {
7891 return Air.Inst.Ref.bool_true;
7892 } else {
7893 return Air.Inst.Ref.bool_false;
7894 }
78807895 } else {
7881 return Air.Inst.Ref.bool_false;
7896 break :src rhs_src;
78827897 }
7898 } else {
7899 break :src lhs_src;
78837900 }
7884 }
7901 };
78857902
78867903 // TODO handle comparisons against lazy zero values
78877904 // Some values can be compared against zero without being runtime known or without forcing
78887905 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
78897906 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
78907907 // of this function if we don't need to.
7908 try sema.requireRuntimeBlock(block, runtime_src);
78917909
7892 // It must be a runtime comparison.
7893 try sema.requireRuntimeBlock(block, src);
78947910 // For floats, emit a float comparison instruction.
78957911 const lhs_is_float = switch (lhs_ty_tag) {
78967912 .Float, .ComptimeFloat => true,
src/type.zig+30-13
......@@ -426,7 +426,7 @@ pub const Type = extern union {
426426 const sentinel_b = info_b.sentinel;
427427 if (sentinel_a) |sa| {
428428 if (sentinel_b) |sb| {
429 if (!sa.eql(sb))
429 if (!sa.eql(sb, info_a.pointee_type))
430430 return false;
431431 } else {
432432 return false;
......@@ -455,13 +455,14 @@ pub const Type = extern union {
455455 .Array, .Vector => {
456456 if (a.arrayLen() != b.arrayLen())
457457 return false;
458 if (!a.elemType().eql(b.elemType()))
458 const elem_ty = a.elemType();
459 if (!elem_ty.eql(b.elemType()))
459460 return false;
460461 const sentinel_a = a.sentinel();
461462 const sentinel_b = b.sentinel();
462463 if (sentinel_a) |sa| {
463464 if (sentinel_b) |sb| {
464 return sa.eql(sb);
465 return sa.eql(sb, elem_ty);
465466 } else {
466467 return false;
467468 }
......@@ -2744,29 +2745,37 @@ pub const Type = extern union {
27442745 return @as(usize, payload.data);
27452746 }
27462747 const S = struct {
2747 fn fieldWithRange(int_val: Value, end: usize) ?usize {
2748 fn fieldWithRange(int_ty: Type, int_val: Value, end: usize) ?usize {
27482749 if (int_val.compareWithZero(.lt)) return null;
27492750 var end_payload: Value.Payload.U64 = .{
27502751 .base = .{ .tag = .int_u64 },
27512752 .data = end,
27522753 };
27532754 const end_val = Value.initPayload(&end_payload.base);
2754 if (int_val.compare(.gte, end_val)) return null;
2755 if (int_val.compare(.gte, end_val, int_ty)) return null;
27552756 return @intCast(usize, int_val.toUnsignedInt());
27562757 }
27572758 };
27582759 switch (ty.tag()) {
27592760 .enum_full, .enum_nonexhaustive => {
27602761 const enum_full = ty.cast(Payload.EnumFull).?.data;
2762 const tag_ty = enum_full.tag_ty;
27612763 if (enum_full.values.count() == 0) {
2762 return S.fieldWithRange(enum_tag, enum_full.fields.count());
2764 return S.fieldWithRange(tag_ty, enum_tag, enum_full.fields.count());
27632765 } else {
2764 return enum_full.values.getIndex(enum_tag);
2766 return enum_full.values.getIndexContext(enum_tag, .{ .ty = tag_ty });
27652767 }
27662768 },
27672769 .enum_simple => {
27682770 const enum_simple = ty.castTag(.enum_simple).?.data;
2769 return S.fieldWithRange(enum_tag, enum_simple.fields.count());
2771 const fields_len = enum_simple.fields.count();
2772 const bits = std.math.log2_int_ceil(usize, fields_len);
2773 var buffer: Payload.Bits = .{
2774 .base = .{ .tag = .int_unsigned },
2775 .data = bits,
2776 };
2777 const tag_ty = Type.initPayload(&buffer.base);
2778 return S.fieldWithRange(tag_ty, enum_tag, fields_len);
27702779 },
27712780 .atomic_ordering,
27722781 .atomic_rmw_op,
......@@ -2875,14 +2884,14 @@ pub const Type = extern union {
28752884 /// Asserts the type is an enum.
28762885 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
28772886 const S = struct {
2878 fn intInRange(int_val: Value, end: usize) bool {
2887 fn intInRange(tag_ty: Type, int_val: Value, end: usize) bool {
28792888 if (int_val.compareWithZero(.lt)) return false;
28802889 var end_payload: Value.Payload.U64 = .{
28812890 .base = .{ .tag = .int_u64 },
28822891 .data = end,
28832892 };
28842893 const end_val = Value.initPayload(&end_payload.base);
2885 if (int_val.compare(.gte, end_val)) return false;
2894 if (int_val.compare(.gte, end_val, tag_ty)) return false;
28862895 return true;
28872896 }
28882897 };
......@@ -2890,15 +2899,23 @@ pub const Type = extern union {
28902899 .enum_nonexhaustive => return int.intFitsInType(ty, target),
28912900 .enum_full => {
28922901 const enum_full = ty.castTag(.enum_full).?.data;
2902 const tag_ty = enum_full.tag_ty;
28932903 if (enum_full.values.count() == 0) {
2894 return S.intInRange(int, enum_full.fields.count());
2904 return S.intInRange(tag_ty, int, enum_full.fields.count());
28952905 } else {
2896 return enum_full.values.contains(int);
2906 return enum_full.values.containsContext(int, .{ .ty = tag_ty });
28972907 }
28982908 },
28992909 .enum_simple => {
29002910 const enum_simple = ty.castTag(.enum_simple).?.data;
2901 return S.intInRange(int, enum_simple.fields.count());
2911 const fields_len = enum_simple.fields.count();
2912 const bits = std.math.log2_int_ceil(usize, fields_len);
2913 var buffer: Payload.Bits = .{
2914 .base = .{ .tag = .int_unsigned },
2915 .data = bits,
2916 };
2917 const tag_ty = Type.initPayload(&buffer.base);
2918 return S.intInRange(tag_ty, int, fields_len);
29022919 },
29032920 .atomic_ordering,
29042921 .atomic_rmw_op,
src/value.zig+105-352
......@@ -653,8 +653,10 @@ pub const Value = extern union {
653653 unreachable;
654654 }
655655
656 pub const ToTypeBuffer = Type.Payload.Bits;
657
656658 /// Asserts that the value is representable as a type.
657 pub fn toType(self: Value, allocator: *Allocator) !Type {
659 pub fn toType(self: Value, buffer: *ToTypeBuffer) Type {
658660 return switch (self.tag()) {
659661 .ty => self.castTag(.ty).?.data,
660662 .u1_type => Type.initTag(.u1),
......@@ -714,14 +716,13 @@ pub const Value = extern union {
714716
715717 .int_type => {
716718 const payload = self.castTag(.int_type).?.data;
717 const new = try allocator.create(Type.Payload.Bits);
718 new.* = .{
719 buffer.* = .{
719720 .base = .{
720721 .tag = if (payload.signed) .int_signed else .int_unsigned,
721722 },
722723 .data = payload.bits,
723724 };
724 return Type.initPayload(&new.base);
725 return Type.initPayload(&buffer.base);
725726 },
726727
727728 .undef,
......@@ -958,9 +959,8 @@ pub const Value = extern union {
958959
959960 /// Converts an integer or a float to a float.
960961 /// Returns `error.Overflow` if the value does not fit in the new type.
961 pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value {
962 _ = target;
963 switch (ty.tag()) {
962 pub fn floatCast(self: Value, allocator: *Allocator, dest_ty: Type) !Value {
963 switch (dest_ty.tag()) {
964964 .f16 => {
965965 @panic("TODO add __trunctfhf2 to compiler-rt");
966966 //const res = try Value.Tag.float_16.create(allocator, self.toFloat(f16));
......@@ -970,13 +970,13 @@ pub const Value = extern union {
970970 },
971971 .f32 => {
972972 const res = try Value.Tag.float_32.create(allocator, self.toFloat(f32));
973 if (!self.eql(res))
973 if (!self.eql(res, dest_ty))
974974 return error.Overflow;
975975 return res;
976976 },
977977 .f64 => {
978978 const res = try Value.Tag.float_64.create(allocator, self.toFloat(f64));
979 if (!self.eql(res))
979 if (!self.eql(res, dest_ty))
980980 return error.Overflow;
981981 return res;
982982 },
......@@ -1083,12 +1083,18 @@ pub const Value = extern union {
10831083 return lhs_bigint.order(rhs_bigint);
10841084 }
10851085
1086 /// Asserts the value is comparable.
1087 pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {
1086 /// Asserts the value is comparable. Does not take a type parameter because it supports
1087 /// comparisons between heterogeneous types.
1088 pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {
1089 return order(lhs, rhs).compare(op);
1090 }
1091
1092 /// Asserts the value is comparable. Both operands have type `ty`.
1093 pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool {
10881094 return switch (op) {
1089 .eq => lhs.eql(rhs),
1090 .neq => !lhs.eql(rhs),
1091 else => order(lhs, rhs).compare(op),
1095 .eq => lhs.eql(rhs, ty),
1096 .neq => !lhs.eql(rhs, ty),
1097 else => compareHetero(lhs, op, rhs),
10921098 };
10931099 }
10941100
......@@ -1097,11 +1103,11 @@ pub const Value = extern union {
10971103 return orderAgainstZero(lhs).compare(op);
10981104 }
10991105
1100 /// TODO we can't compare value equality without also knowing the type to treat
1101 /// the values as
1102 pub fn eql(a: Value, b: Value) bool {
1106 pub fn eql(a: Value, b: Value, ty: Type) bool {
11031107 const a_tag = a.tag();
11041108 const b_tag = b.tag();
1109 assert(a_tag != .undef);
1110 assert(b_tag != .undef);
11051111 if (a_tag == b_tag) {
11061112 switch (a_tag) {
11071113 .void_value, .null_value => return true,
......@@ -1118,230 +1124,106 @@ pub const Value = extern union {
11181124 else => {},
11191125 }
11201126 }
1121 if (a.isType() and b.isType()) {
1122 // 128 bytes should be enough to hold both types
1123 var buf: [128]u8 = undefined;
1124 var fib = std.heap.FixedBufferAllocator.init(&buf);
1125 const a_type = a.toType(&fib.allocator) catch unreachable;
1126 const b_type = b.toType(&fib.allocator) catch unreachable;
1127 if (ty.zigTypeTag() == .Type) {
1128 var buf_a: ToTypeBuffer = undefined;
1129 var buf_b: ToTypeBuffer = undefined;
1130 const a_type = a.toType(&buf_a);
1131 const b_type = b.toType(&buf_b);
11271132 return a_type.eql(b_type);
11281133 }
11291134 return order(a, b).compare(.eq);
11301135 }
11311136
1132 pub fn hash_u32(self: Value) u32 {
1133 return @truncate(u32, self.hash());
1134 }
1135
1136 /// TODO we can't hash without also knowing the type of the value.
1137 /// we have to hash as if there were a canonical value memory layout.
1138 pub fn hash(self: Value) u64 {
1139 var hasher = std.hash.Wyhash.init(0);
1137 pub const ArrayHashContext = struct {
1138 ty: Type,
11401139
1141 switch (self.tag()) {
1142 .u1_type,
1143 .u8_type,
1144 .i8_type,
1145 .u16_type,
1146 .i16_type,
1147 .u32_type,
1148 .i32_type,
1149 .u64_type,
1150 .i64_type,
1151 .u128_type,
1152 .i128_type,
1153 .usize_type,
1154 .isize_type,
1155 .c_short_type,
1156 .c_ushort_type,
1157 .c_int_type,
1158 .c_uint_type,
1159 .c_long_type,
1160 .c_ulong_type,
1161 .c_longlong_type,
1162 .c_ulonglong_type,
1163 .c_longdouble_type,
1164 .f16_type,
1165 .f32_type,
1166 .f64_type,
1167 .f128_type,
1168 .c_void_type,
1169 .bool_type,
1170 .void_type,
1171 .type_type,
1172 .anyerror_type,
1173 .comptime_int_type,
1174 .comptime_float_type,
1175 .noreturn_type,
1176 .null_type,
1177 .undefined_type,
1178 .fn_noreturn_no_args_type,
1179 .fn_void_no_args_type,
1180 .fn_naked_noreturn_no_args_type,
1181 .fn_ccc_void_no_args_type,
1182 .single_const_pointer_to_comptime_int_type,
1183 .anyframe_type,
1184 .const_slice_u8_type,
1185 .enum_literal_type,
1186 .ty,
1187 .abi_align_default,
1188 => {
1189 // Directly return Type.hash, toType can only fail for .int_type.
1190 var allocator = std.heap.FixedBufferAllocator.init(&[_]u8{});
1191 return (self.toType(&allocator.allocator) catch unreachable).hash();
1192 },
1193 .int_type => {
1194 const payload = self.castTag(.int_type).?.data;
1195 var int_payload = Type.Payload.Bits{
1196 .base = .{
1197 .tag = if (payload.signed) .int_signed else .int_unsigned,
1198 },
1199 .data = payload.bits,
1200 };
1201 return Type.initPayload(&int_payload.base).hash();
1202 },
1140 pub fn hash(self: @This(), v: Value) u32 {
1141 const other_context: HashContext = .{ .ty = self.ty };
1142 return @truncate(u32, other_context.hash(v));
1143 }
1144 pub fn eql(self: @This(), a: Value, b: Value) bool {
1145 return a.eql(b, self.ty);
1146 }
1147 };
12031148
1204 .empty_struct_value,
1205 .empty_array,
1206 => {},
1149 pub const HashContext = struct {
1150 ty: Type,
12071151
1208 .undef,
1209 .null_value,
1210 .void_value,
1211 .unreachable_value,
1212 => std.hash.autoHash(&hasher, self.tag()),
1152 pub fn hash(self: @This(), v: Value) u64 {
1153 var hasher = std.hash.Wyhash.init(0);
12131154
1214 .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),
1215 .one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),
1155 switch (self.ty.zigTypeTag()) {
1156 .BoundFn => unreachable, // TODO remove this from the language
12161157
1217 .float_16, .float_32, .float_64, .float_128 => {
1218 @panic("TODO implement Value.hash for floats");
1219 },
1158 .Void,
1159 .NoReturn,
1160 .Undefined,
1161 .Null,
1162 => {},
12201163
1221 .enum_literal => {
1222 const payload = self.castTag(.enum_literal).?;
1223 hasher.update(payload.data);
1224 },
1225 .enum_field_index => {
1226 const payload = self.castTag(.enum_field_index).?;
1227 std.hash.autoHash(&hasher, payload.data);
1228 },
1229 .bytes => {
1230 const payload = self.castTag(.bytes).?;
1231 hasher.update(payload.data);
1232 },
1233 .repeated => {
1234 @panic("TODO Value.hash for repeated");
1235 },
1236 .array => {
1237 @panic("TODO Value.hash for array");
1238 },
1239 .slice => {
1240 @panic("TODO Value.hash for slice");
1241 },
1242 .eu_payload_ptr => {
1243 @panic("TODO Value.hash for eu_payload_ptr");
1244 },
1245 .int_u64 => {
1246 const payload = self.castTag(.int_u64).?;
1247 std.hash.autoHash(&hasher, payload.data);
1248 },
1249 .int_i64 => {
1250 const payload = self.castTag(.int_i64).?;
1251 std.hash.autoHash(&hasher, payload.data);
1252 },
1253 .comptime_alloc => {
1254 const payload = self.castTag(.comptime_alloc).?;
1255 std.hash.autoHash(&hasher, payload.data.val.hash());
1256 },
1257 .int_big_positive, .int_big_negative => {
1258 var space: BigIntSpace = undefined;
1259 const big = self.toBigInt(&space);
1260 if (big.limbs.len == 1) {
1261 // handle like {u,i}64 to ensure same hash as with Int{i,u}64
1262 if (big.positive) {
1263 std.hash.autoHash(&hasher, @as(u64, big.limbs[0]));
1264 } else {
1265 std.hash.autoHash(&hasher, @as(u64, @bitCast(usize, -@bitCast(isize, big.limbs[0]))));
1266 }
1267 } else {
1164 .Type => {
1165 var buf: ToTypeBuffer = undefined;
1166 return v.toType(&buf).hash();
1167 },
1168 .Bool => {
1169 std.hash.autoHash(&hasher, v.toBool());
1170 },
1171 .Int, .ComptimeInt => {
1172 var space: BigIntSpace = undefined;
1173 const big = v.toBigInt(&space);
12681174 std.hash.autoHash(&hasher, big.positive);
12691175 for (big.limbs) |limb| {
12701176 std.hash.autoHash(&hasher, limb);
12711177 }
1272 }
1273 },
1274 .elem_ptr => {
1275 const payload = self.castTag(.elem_ptr).?.data;
1276 std.hash.autoHash(&hasher, payload.array_ptr.hash());
1277 std.hash.autoHash(&hasher, payload.index);
1278 },
1279 .field_ptr => {
1280 const payload = self.castTag(.field_ptr).?.data;
1281 std.hash.autoHash(&hasher, payload.container_ptr.hash());
1282 std.hash.autoHash(&hasher, payload.field_index);
1283 },
1284 .decl_ref => {
1285 const decl = self.castTag(.decl_ref).?.data;
1286 std.hash.autoHash(&hasher, decl);
1287 },
1288 .function => {
1289 const func = self.castTag(.function).?.data;
1290 std.hash.autoHash(&hasher, func);
1291 },
1292 .extern_fn => {
1293 const decl = self.castTag(.extern_fn).?.data;
1294 std.hash.autoHash(&hasher, decl);
1295 },
1296 .variable => {
1297 const variable = self.castTag(.variable).?.data;
1298 std.hash.autoHash(&hasher, variable);
1299 },
1300 .@"error" => {
1301 const payload = self.castTag(.@"error").?.data;
1302 hasher.update(payload.name);
1303 },
1304 .error_union => {
1305 const payload = self.castTag(.error_union).?.data;
1306 std.hash.autoHash(&hasher, payload.hash());
1307 },
1308 .inferred_alloc => unreachable,
1309
1310 .manyptr_u8_type,
1311 .manyptr_const_u8_type,
1312 .atomic_ordering_type,
1313 .atomic_rmw_op_type,
1314 .calling_convention_type,
1315 .float_mode_type,
1316 .reduce_op_type,
1317 .call_options_type,
1318 .export_options_type,
1319 .extern_options_type,
1320 .@"struct",
1321 .@"union",
1322 => @panic("TODO this hash function looks pretty broken. audit it"),
1178 },
1179 .Float, .ComptimeFloat => {
1180 @panic("TODO implement hashing float values");
1181 },
1182 .Pointer => {
1183 @panic("TODO implement hashing pointer values");
1184 },
1185 .Array, .Vector => {
1186 @panic("TODO implement hashing array/vector values");
1187 },
1188 .Struct => {
1189 @panic("TODO implement hashing struct values");
1190 },
1191 .Optional => {
1192 @panic("TODO implement hashing optional values");
1193 },
1194 .ErrorUnion => {
1195 @panic("TODO implement hashing error union values");
1196 },
1197 .ErrorSet => {
1198 @panic("TODO implement hashing error set values");
1199 },
1200 .Enum => {
1201 @panic("TODO implement hashing enum values");
1202 },
1203 .Union => {
1204 @panic("TODO implement hashing union values");
1205 },
1206 .Fn => {
1207 @panic("TODO implement hashing function values");
1208 },
1209 .Opaque => {
1210 @panic("TODO implement hashing opaque values");
1211 },
1212 .Frame => {
1213 @panic("TODO implement hashing frame values");
1214 },
1215 .AnyFrame => {
1216 @panic("TODO implement hashing anyframe values");
1217 },
1218 .EnumLiteral => {
1219 @panic("TODO implement hashing enum literal values");
1220 },
1221 }
1222 return hasher.final();
13231223 }
1324 return hasher.final();
1325 }
13261224
1327 pub const ArrayHashContext = struct {
1328 pub fn hash(self: @This(), v: Value) u32 {
1329 _ = self;
1330 return v.hash_u32();
1331 }
1332 pub fn eql(self: @This(), a: Value, b: Value) bool {
1333 _ = self;
1334 return a.eql(b);
1335 }
1336 };
1337 pub const HashContext = struct {
1338 pub fn hash(self: @This(), v: Value) u64 {
1339 _ = self;
1340 return v.hash();
1341 }
13421225 pub fn eql(self: @This(), a: Value, b: Value) bool {
1343 _ = self;
1344 return a.eql(b);
1226 return a.eql(b, self.ty);
13451227 }
13461228 };
13471229
......@@ -1508,111 +1390,6 @@ pub const Value = extern union {
15081390 };
15091391 }
15101392
1511 /// Valid for all types. Asserts the value is not undefined.
1512 /// TODO this function is a code smell and should be deleted
1513 fn isType(self: Value) bool {
1514 return switch (self.tag()) {
1515 .ty,
1516 .int_type,
1517 .u1_type,
1518 .u8_type,
1519 .i8_type,
1520 .u16_type,
1521 .i16_type,
1522 .u32_type,
1523 .i32_type,
1524 .u64_type,
1525 .i64_type,
1526 .u128_type,
1527 .i128_type,
1528 .usize_type,
1529 .isize_type,
1530 .c_short_type,
1531 .c_ushort_type,
1532 .c_int_type,
1533 .c_uint_type,
1534 .c_long_type,
1535 .c_ulong_type,
1536 .c_longlong_type,
1537 .c_ulonglong_type,
1538 .c_longdouble_type,
1539 .f16_type,
1540 .f32_type,
1541 .f64_type,
1542 .f128_type,
1543 .c_void_type,
1544 .bool_type,
1545 .void_type,
1546 .type_type,
1547 .anyerror_type,
1548 .comptime_int_type,
1549 .comptime_float_type,
1550 .noreturn_type,
1551 .null_type,
1552 .undefined_type,
1553 .fn_noreturn_no_args_type,
1554 .fn_void_no_args_type,
1555 .fn_naked_noreturn_no_args_type,
1556 .fn_ccc_void_no_args_type,
1557 .single_const_pointer_to_comptime_int_type,
1558 .anyframe_type,
1559 .const_slice_u8_type,
1560 .enum_literal_type,
1561 .manyptr_u8_type,
1562 .manyptr_const_u8_type,
1563 .atomic_ordering_type,
1564 .atomic_rmw_op_type,
1565 .calling_convention_type,
1566 .float_mode_type,
1567 .reduce_op_type,
1568 .call_options_type,
1569 .export_options_type,
1570 .extern_options_type,
1571 => true,
1572
1573 .zero,
1574 .one,
1575 .empty_array,
1576 .bool_true,
1577 .bool_false,
1578 .function,
1579 .extern_fn,
1580 .variable,
1581 .int_u64,
1582 .int_i64,
1583 .int_big_positive,
1584 .int_big_negative,
1585 .comptime_alloc,
1586 .decl_ref,
1587 .elem_ptr,
1588 .field_ptr,
1589 .bytes,
1590 .repeated,
1591 .array,
1592 .slice,
1593 .float_16,
1594 .float_32,
1595 .float_64,
1596 .float_128,
1597 .void_value,
1598 .enum_literal,
1599 .enum_field_index,
1600 .@"error",
1601 .error_union,
1602 .empty_struct_value,
1603 .@"struct",
1604 .@"union",
1605 .null_value,
1606 .abi_align_default,
1607 .eu_payload_ptr,
1608 => false,
1609
1610 .undef => unreachable,
1611 .unreachable_value => unreachable,
1612 .inferred_alloc => unreachable,
1613 };
1614 }
1615
16161393 /// This type is not copyable since it may contain pointers to its inner data.
16171394 pub const Payload = struct {
16181395 tag: Tag,
......@@ -1806,27 +1583,3 @@ pub const Value = extern union {
18061583 limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb,
18071584 };
18081585};
1809
1810test "hash same value different representation" {
1811 const zero_1 = Value.initTag(.zero);
1812 var payload_1 = Value.Payload.U64{
1813 .base = .{ .tag = .int_u64 },
1814 .data = 0,
1815 };
1816 const zero_2 = Value.initPayload(&payload_1.base);
1817 try std.testing.expectEqual(zero_1.hash(), zero_2.hash());
1818
1819 var payload_2 = Value.Payload.I64{
1820 .base = .{ .tag = .int_i64 },
1821 .data = 0,
1822 };
1823 const zero_3 = Value.initPayload(&payload_2.base);
1824 try std.testing.expectEqual(zero_2.hash(), zero_3.hash());
1825
1826 var payload_3 = Value.Payload.BigInt{
1827 .base = .{ .tag = .int_big_negative },
1828 .data = &[_]std.math.big.Limb{0},
1829 };
1830 const zero_4 = Value.initPayload(&payload_3.base);
1831 try std.testing.expectEqual(zero_3.hash(), zero_4.hash());
1832}