| ... | ... | @@ -1055,6 +1055,40 @@ pub const Value = extern union { |
| 1055 | 1055 | } |
| 1056 | 1056 | } |
| 1057 | 1057 | |
| 1058 | pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 { |
| 1059 | if (ty.zigTypeTag() == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(), mod); |
| 1060 | |
| 1061 | const field_index = switch (val.tag()) { |
| 1062 | .enum_field_index => val.castTag(.enum_field_index).?.data, |
| 1063 | .the_only_possible_value => blk: { |
| 1064 | assert(ty.enumFieldCount() == 1); |
| 1065 | break :blk 0; |
| 1066 | }, |
| 1067 | .enum_literal => return val.castTag(.enum_literal).?.data, |
| 1068 | else => field_index: { |
| 1069 | const values = switch (ty.tag()) { |
| 1070 | .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values, |
| 1071 | .enum_numbered => ty.castTag(.enum_numbered).?.data.values, |
| 1072 | .enum_simple => Module.EnumFull.ValueMap{}, |
| 1073 | else => unreachable, |
| 1074 | }; |
| 1075 | break :field_index if (values.entries.len == 0) |
| 1076 | // auto-numbered enum |
| 1077 | @intCast(u32, val.toUnsignedInt(mod.getTarget())) |
| 1078 | else |
| 1079 | @intCast(u32, values.getIndexContext(val, .{ .ty = ty, .mod = mod }).?); |
| 1080 | }, |
| 1081 | }; |
| 1082 | |
| 1083 | const fields = switch (ty.tag()) { |
| 1084 | .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.fields, |
| 1085 | .enum_numbered => ty.castTag(.enum_numbered).?.data.fields, |
| 1086 | .enum_simple => ty.castTag(.enum_simple).?.data.fields, |
| 1087 | else => unreachable, |
| 1088 | }; |
| 1089 | return fields.keys()[field_index]; |
| 1090 | } |
| 1091 | |
| 1058 | 1092 | /// Asserts the value is an integer. |
| 1059 | 1093 | pub fn toBigInt(val: Value, space: *BigIntSpace, target: Target) BigIntConst { |
| 1060 | 1094 | return val.toBigIntAdvanced(space, target, null) catch unreachable; |
| ... | ... | @@ -2211,7 +2245,7 @@ pub const Value = extern union { |
| 2211 | 2245 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, sema_kit); |
| 2212 | 2246 | }, |
| 2213 | 2247 | else => {}, |
| 2214 | | } else if (a_tag == .null_value or b_tag == .null_value) { |
| 2248 | } else if (b_tag == .null_value or b_tag == .@"error") { |
| 2215 | 2249 | return false; |
| 2216 | 2250 | } else if (a_tag == .undef or b_tag == .undef) { |
| 2217 | 2251 | return false; |
| ... | ... | @@ -2335,18 +2369,25 @@ pub const Value = extern union { |
| 2335 | 2369 | if (a_nan) return true; |
| 2336 | 2370 | return a_float == b_float; |
| 2337 | 2371 | }, |
| 2338 | | .Optional => { |
| 2339 | | if (a.tag() != .opt_payload and b.tag() == .opt_payload) { |
| 2340 | | var buffer: Payload.SubValue = .{ |
| 2341 | | .base = .{ .tag = .opt_payload }, |
| 2342 | | .data = a, |
| 2343 | | }; |
| 2344 | | const opt_val = Value.initPayload(&buffer.base); |
| 2345 | | return eqlAdvanced(opt_val, ty, b, ty, mod, sema_kit); |
| 2346 | | } |
| 2372 | .Optional => if (a_tag != .null_value and b_tag == .opt_payload) { |
| 2373 | var sub_pl: Payload.SubValue = .{ |
| 2374 | .base = .{ .tag = b.tag() }, |
| 2375 | .data = a, |
| 2376 | }; |
| 2377 | const sub_val = Value.initPayload(&sub_pl.base); |
| 2378 | return eqlAdvanced(sub_val, ty, b, ty, mod, sema_kit); |
| 2379 | }, |
| 2380 | .ErrorUnion => if (a_tag != .@"error" and b_tag == .eu_payload) { |
| 2381 | var sub_pl: Payload.SubValue = .{ |
| 2382 | .base = .{ .tag = b.tag() }, |
| 2383 | .data = a, |
| 2384 | }; |
| 2385 | const sub_val = Value.initPayload(&sub_pl.base); |
| 2386 | return eqlAdvanced(sub_val, ty, b, ty, mod, sema_kit); |
| 2347 | 2387 | }, |
| 2348 | 2388 | else => {}, |
| 2349 | 2389 | } |
| 2390 | if (a_tag == .null_value or a_tag == .@"error") return false; |
| 2350 | 2391 | return (try orderAdvanced(a, b, target, sema_kit)).compare(.eq); |
| 2351 | 2392 | } |
| 2352 | 2393 | |
| ... | ... | @@ -2436,7 +2477,7 @@ pub const Value = extern union { |
| 2436 | 2477 | const sub_ty = ty.optionalChild(&buffer); |
| 2437 | 2478 | sub_val.hash(sub_ty, hasher, mod); |
| 2438 | 2479 | } else { |
| 2439 | | std.hash.autoHash(hasher, false); // non-null |
| 2480 | std.hash.autoHash(hasher, false); // null |
| 2440 | 2481 | } |
| 2441 | 2482 | }, |
| 2442 | 2483 | .ErrorUnion => { |
| ... | ... | @@ -2474,8 +2515,8 @@ pub const Value = extern union { |
| 2474 | 2515 | union_obj.val.hash(active_field_ty, hasher, mod); |
| 2475 | 2516 | }, |
| 2476 | 2517 | .Fn => { |
| 2477 | | // Note that his hashes the *Fn/*ExternFn rather than the *Decl. This is |
| 2478 | | // to differentiate function bodies from function pointers. |
| 2518 | // Note that this hashes the *Fn/*ExternFn rather than the *Decl. |
| 2519 | // This is to differentiate function bodies from function pointers. |
| 2479 | 2520 | // This is currently redundant since we already hash the zig type tag |
| 2480 | 2521 | // at the top of this function. |
| 2481 | 2522 | if (val.castTag(.function)) |func| { |
| ... | ... | @@ -2497,6 +2538,64 @@ pub const Value = extern union { |
| 2497 | 2538 | } |
| 2498 | 2539 | } |
| 2499 | 2540 | |
| 2541 | /// This is a more conservative hash function that produces equal hashes for values |
| 2542 | /// that can coerce into each other. |
| 2543 | /// This function is used by hash maps and so treats floating-point NaNs as equal |
| 2544 | /// to each other, and not equal to other floating-point values. |
| 2545 | pub fn hashUncoerced(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void { |
| 2546 | if (val.isUndef()) return; |
| 2547 | // The value is runtime-known and shouldn't affect the hash. |
| 2548 | if (val.tag() == .runtime_value) return; |
| 2549 | |
| 2550 | switch (ty.zigTypeTag()) { |
| 2551 | .BoundFn => unreachable, // TODO remove this from the language |
| 2552 | .Opaque => unreachable, // Cannot hash opaque types |
| 2553 | .Void, |
| 2554 | .NoReturn, |
| 2555 | .Undefined, |
| 2556 | .Null, |
| 2557 | .Struct, // It sure would be nice to do something clever with structs. |
| 2558 | => |zig_type_tag| std.hash.autoHash(hasher, zig_type_tag), |
| 2559 | .Type => { |
| 2560 | var buf: ToTypeBuffer = undefined; |
| 2561 | val.toType(&buf).hashWithHasher(hasher, mod); |
| 2562 | }, |
| 2563 | .Float, .ComptimeFloat => std.hash.autoHash(hasher, @bitCast(u128, val.toFloat(f128))), |
| 2564 | .Bool, .Int, .ComptimeInt, .Pointer, .Fn => switch (val.tag()) { |
| 2565 | .slice => val.castTag(.slice).?.data.ptr.hashPtr(hasher, mod.getTarget()), |
| 2566 | else => val.hashPtr(hasher, mod.getTarget()), |
| 2567 | }, |
| 2568 | .Array, .Vector => { |
| 2569 | const len = ty.arrayLen(); |
| 2570 | const elem_ty = ty.childType(); |
| 2571 | var index: usize = 0; |
| 2572 | var elem_value_buf: ElemValueBuffer = undefined; |
| 2573 | while (index < len) : (index += 1) { |
| 2574 | const elem_val = val.elemValueBuffer(mod, index, &elem_value_buf); |
| 2575 | elem_val.hashUncoerced(elem_ty, hasher, mod); |
| 2576 | } |
| 2577 | }, |
| 2578 | .Optional => if (val.castTag(.opt_payload)) |payload| { |
| 2579 | var buf: Type.Payload.ElemType = undefined; |
| 2580 | const child_ty = ty.optionalChild(&buf); |
| 2581 | payload.data.hashUncoerced(child_ty, hasher, mod); |
| 2582 | } else std.hash.autoHash(hasher, std.builtin.TypeId.Null), |
| 2583 | .ErrorSet, .ErrorUnion => if (val.getError()) |err| hasher.update(err) else { |
| 2584 | const pl_ty = ty.errorUnionPayload(); |
| 2585 | val.castTag(.eu_payload).?.data.hashUncoerced(pl_ty, hasher, mod); |
| 2586 | }, |
| 2587 | .Enum, .EnumLiteral, .Union => { |
| 2588 | hasher.update(val.tagName(ty, mod)); |
| 2589 | if (val.cast(Payload.Union)) |union_obj| { |
| 2590 | const active_field_ty = ty.unionFieldType(union_obj.data.tag, mod); |
| 2591 | union_obj.data.val.hashUncoerced(active_field_ty, hasher, mod); |
| 2592 | } else std.hash.autoHash(hasher, std.builtin.TypeId.Void); |
| 2593 | }, |
| 2594 | .Frame => @panic("TODO implement hashing frame values"), |
| 2595 | .AnyFrame => @panic("TODO implement hashing anyframe values"), |
| 2596 | } |
| 2597 | } |
| 2598 | |
| 2500 | 2599 | pub const ArrayHashContext = struct { |
| 2501 | 2600 | ty: Type, |
| 2502 | 2601 | mod: *Module, |