| author | |
| committer | |
| log | be1b23120648dff5e23d67b089c10b479564bffd |
| tree | 79e455747856a29c096ee4f5e5ef61e7186b57c2 |
| parent | 9584feae5f27a8b987975d8fe8242e2169098a75 |
3 files changed, 84 insertions(+), 30 deletions(-)
src/InternPool.zig+41-4| ... | @@ -1517,6 +1517,8 @@ pub const Tag = enum(u8) { | ... | @@ -1517,6 +1517,8 @@ pub const Tag = enum(u8) { |
| 1517 | /// 0. name: NullTerminatedString for each names_len | 1517 | /// 0. name: NullTerminatedString for each names_len |
| 1518 | pub const ErrorSet = struct { | 1518 | pub const ErrorSet = struct { |
| 1519 | names_len: u32, | 1519 | names_len: u32, |
| 1520 | /// Maps error names to declaration index. | ||
| 1521 | names_map: MapIndex, | ||
| 1520 | }; | 1522 | }; |
| 1521 | 1523 | ||
| 1522 | /// Trailing: | 1524 | /// Trailing: |
| ... | @@ -2024,6 +2026,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -2024,6 +2026,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2024 | const names = ip.extra.items[error_set.end..][0..names_len]; | 2026 | const names = ip.extra.items[error_set.end..][0..names_len]; |
| 2025 | return .{ .error_set_type = .{ | 2027 | return .{ .error_set_type = .{ |
| 2026 | .names = @ptrCast([]const NullTerminatedString, names), | 2028 | .names = @ptrCast([]const NullTerminatedString, names), |
| 2029 | .names_map = error_set.data.names_map.toOptional(), | ||
| 2027 | } }; | 2030 | } }; |
| 2028 | }, | 2031 | }, |
| 2029 | .type_inferred_error_set => .{ | 2032 | .type_inferred_error_set => .{ |
| ... | @@ -2518,6 +2521,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2518,6 +2521,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2518 | .tag = .type_error_set, | 2521 | .tag = .type_error_set, |
| 2519 | .data = ip.addExtraAssumeCapacity(ErrorSet{ | 2522 | .data = ip.addExtraAssumeCapacity(ErrorSet{ |
| 2520 | .names_len = names_len, | 2523 | .names_len = names_len, |
| 2524 | .names_map = names_map, | ||
| 2521 | }), | 2525 | }), |
| 2522 | }); | 2526 | }); |
| 2523 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, error_set_type.names)); | 2527 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, error_set_type.names)); |
| ... | @@ -3605,15 +3609,34 @@ pub fn sliceLen(ip: InternPool, i: Index) Index { | ... | @@ -3605,15 +3609,34 @@ pub fn sliceLen(ip: InternPool, i: Index) Index { |
| 3605 | /// * int <=> int | 3609 | /// * int <=> int |
| 3606 | /// * int <=> enum | 3610 | /// * int <=> enum |
| 3607 | /// * ptr <=> ptr | 3611 | /// * ptr <=> ptr |
| 3612 | /// * null_value => opt | ||
| 3613 | /// * payload => opt | ||
| 3608 | pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index { | 3614 | pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index { |
| 3609 | if (ip.typeOf(val) == new_ty) return val; | 3615 | const old_ty = ip.typeOf(val); |
| 3616 | if (old_ty == new_ty) return val; | ||
| 3610 | switch (ip.indexToKey(val)) { | 3617 | switch (ip.indexToKey(val)) { |
| 3611 | .int => |int| switch (ip.indexToKey(new_ty)) { | 3618 | .int => |int| switch (ip.indexToKey(new_ty)) { |
| 3619 | .simple_type => |simple_type| switch (simple_type) { | ||
| 3620 | .usize, | ||
| 3621 | .isize, | ||
| 3622 | .c_char, | ||
| 3623 | .c_short, | ||
| 3624 | .c_ushort, | ||
| 3625 | .c_int, | ||
| 3626 | .c_uint, | ||
| 3627 | .c_long, | ||
| 3628 | .c_ulong, | ||
| 3629 | .c_longlong, | ||
| 3630 | .c_ulonglong, | ||
| 3631 | => return getCoercedInts(ip, gpa, int, new_ty), | ||
| 3632 | else => {}, | ||
| 3633 | }, | ||
| 3634 | .int_type => return getCoercedInts(ip, gpa, int, new_ty), | ||
| 3612 | .enum_type => return ip.get(gpa, .{ .enum_tag = .{ | 3635 | .enum_type => return ip.get(gpa, .{ .enum_tag = .{ |
| 3613 | .ty = new_ty, | 3636 | .ty = new_ty, |
| 3614 | .int = val, | 3637 | .int = val, |
| 3615 | } }), | 3638 | } }), |
| 3616 | else => return getCoercedInts(ip, gpa, int, new_ty), | 3639 | else => {}, |
| 3617 | }, | 3640 | }, |
| 3618 | .enum_tag => |enum_tag| { | 3641 | .enum_tag => |enum_tag| { |
| 3619 | // Assume new_ty is an integer type. | 3642 | // Assume new_ty is an integer type. |
| ... | @@ -3624,10 +3647,24 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al | ... | @@ -3624,10 +3647,24 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al |
| 3624 | .ty = new_ty, | 3647 | .ty = new_ty, |
| 3625 | .addr = ptr.addr, | 3648 | .addr = ptr.addr, |
| 3626 | } }), | 3649 | } }), |
| 3627 | else => unreachable, | 3650 | else => {}, |
| 3628 | }, | 3651 | }, |
| 3629 | else => unreachable, | 3652 | else => {}, |
| 3653 | } | ||
| 3654 | switch (ip.indexToKey(new_ty)) { | ||
| 3655 | .opt_type => |child_ty| switch (val) { | ||
| 3656 | .null_value => return ip.get(gpa, .{ .opt = .{ | ||
| 3657 | .ty = new_ty, | ||
| 3658 | .val = .none, | ||
| 3659 | } }), | ||
| 3660 | else => return ip.get(gpa, .{ .opt = .{ | ||
| 3661 | .ty = new_ty, | ||
| 3662 | .val = try ip.getCoerced(gpa, val, child_ty), | ||
| 3663 | } }), | ||
| 3664 | }, | ||
| 3665 | else => {}, | ||
| 3630 | } | 3666 | } |
| 3667 | unreachable; | ||
| 3631 | } | 3668 | } |
| 3632 | 3669 | ||
| 3633 | /// Asserts `val` has an integer type. | 3670 | /// Asserts `val` has an integer type. |
src/Sema.zig+10-9| ... | @@ -8480,13 +8480,10 @@ fn zirOptionalPayload( | ... | @@ -8480,13 +8480,10 @@ fn zirOptionalPayload( |
| 8480 | }; | 8480 | }; |
| 8481 | 8481 | ||
| 8482 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { | 8482 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 8483 | if (val.isNull(mod)) { | 8483 | return if (val.optionalValue(mod)) |payload| |
| 8484 | return sema.fail(block, src, "unable to unwrap null", .{}); | 8484 | sema.addConstant(result_ty, payload) |
| 8485 | } | 8485 | else |
| 8486 | if (val.castTag(.opt_payload)) |payload| { | 8486 | sema.fail(block, src, "unable to unwrap null", .{}); |
| 8487 | return sema.addConstant(result_ty, payload.data); | ||
| 8488 | } | ||
| 8489 | return sema.addConstant(result_ty, val); | ||
| 8490 | } | 8487 | } |
| 8491 | 8488 | ||
| 8492 | try sema.requireRuntimeBlock(block, src, null); | 8489 | try sema.requireRuntimeBlock(block, src, null); |
| ... | @@ -18929,7 +18926,7 @@ fn zirReify( | ... | @@ -18929,7 +18926,7 @@ fn zirReify( |
| 18929 | if (ptr_size == .One or ptr_size == .C) { | 18926 | if (ptr_size == .One or ptr_size == .C) { |
| 18930 | return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); | 18927 | return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); |
| 18931 | } | 18928 | } |
| 18932 | const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data; | 18929 | const sentinel_ptr_val = sentinel_val.optionalValue(mod).?; |
| 18933 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ | 18930 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 18934 | .@"addrspace" = .generic, | 18931 | .@"addrspace" = .generic, |
| 18935 | .pointee_type = elem_ty, | 18932 | .pointee_type = elem_ty, |
| ... | @@ -28807,7 +28804,11 @@ fn coerceCompatiblePtrs( | ... | @@ -28807,7 +28804,11 @@ fn coerceCompatiblePtrs( |
| 28807 | return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); | 28804 | return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); |
| 28808 | } | 28805 | } |
| 28809 | // The comptime Value representation is compatible with both types. | 28806 | // The comptime Value representation is compatible with both types. |
| 28810 | return sema.addConstant(dest_ty, val); | 28807 | return sema.addConstant(dest_ty, (try mod.intern_pool.getCoerced( |
| 28808 | mod.gpa, | ||
| 28809 | try val.intern(inst_ty, mod), | ||
| 28810 | dest_ty.ip_index, | ||
| 28811 | )).toValue()); | ||
| 28811 | } | 28812 | } |
| 28812 | try sema.requireRuntimeBlock(block, inst_src, null); | 28813 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28813 | const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod); | 28814 | const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod); |
src/value.zig+33-17| ... | @@ -718,18 +718,25 @@ pub const Value = struct { | ... | @@ -718,18 +718,25 @@ pub const Value = struct { |
| 718 | }, | 718 | }, |
| 719 | else => unreachable, | 719 | else => unreachable, |
| 720 | }; | 720 | }; |
| 721 | const enum_type = ip.indexToKey(ty.ip_index).enum_type; | 721 | return switch (ip.indexToKey(ty.ip_index)) { |
| 722 | if (enum_type.values.len != 0) { | 722 | // Assume it is already an integer and return it directly. |
| 723 | return enum_type.values[field_index].toValue(); | 723 | .simple_type, .int_type => val, |
| 724 | } else { | 724 | .enum_type => |enum_type| if (enum_type.values.len != 0) |
| 725 | // Field index and integer values are the same. | 725 | enum_type.values[field_index].toValue() |
| 726 | return mod.intValue(enum_type.tag_ty.toType(), field_index); | 726 | else // Field index and integer values are the same. |
| 727 | } | 727 | mod.intValue(enum_type.tag_ty.toType(), field_index), |
| 728 | else => unreachable, | ||
| 729 | }; | ||
| 728 | }, | 730 | }, |
| 729 | else => { | 731 | else => return switch (ip.indexToKey(ip.typeOf(val.ip_index))) { |
| 730 | const enum_type = ip.indexToKey(ip.typeOf(val.ip_index)).enum_type; | 732 | // Assume it is already an integer and return it directly. |
| 731 | const int = try ip.getCoerced(mod.gpa, val.ip_index, enum_type.tag_ty); | 733 | .simple_type, .int_type => val, |
| 732 | return int.toValue(); | 734 | .enum_type => |enum_type| (try ip.getCoerced( |
| 735 | mod.gpa, | ||
| 736 | val.ip_index, | ||
| 737 | enum_type.tag_ty, | ||
| 738 | )).toValue(), | ||
| 739 | else => unreachable, | ||
| 733 | }, | 740 | }, |
| 734 | } | 741 | } |
| 735 | } | 742 | } |
| ... | @@ -2906,7 +2913,7 @@ pub const Value = struct { | ... | @@ -2906,7 +2913,7 @@ pub const Value = struct { |
| 2906 | inline .u64, .i64 => |x| x == 0, | 2913 | inline .u64, .i64 => |x| x == 0, |
| 2907 | }, | 2914 | }, |
| 2908 | .opt => |opt| opt.val == .none, | 2915 | .opt => |opt| opt.val == .none, |
| 2909 | else => unreachable, | 2916 | else => false, |
| 2910 | }, | 2917 | }, |
| 2911 | }; | 2918 | }; |
| 2912 | } | 2919 | } |
| ... | @@ -2949,11 +2956,20 @@ pub const Value = struct { | ... | @@ -2949,11 +2956,20 @@ pub const Value = struct { |
| 2949 | 2956 | ||
| 2950 | /// Value of the optional, null if optional has no payload. | 2957 | /// Value of the optional, null if optional has no payload. |
| 2951 | pub fn optionalValue(val: Value, mod: *const Module) ?Value { | 2958 | pub fn optionalValue(val: Value, mod: *const Module) ?Value { |
| 2952 | if (val.isNull(mod)) return null; | 2959 | return switch (val.ip_index) { |
| 2953 | 2960 | .none => if (val.isNull(mod)) null | |
| 2954 | // Valid for optional representation to be the direct value | 2961 | // Valid for optional representation to be the direct value |
| 2955 | // and not use opt_payload. | 2962 | // and not use opt_payload. |
| 2956 | return if (val.castTag(.opt_payload)) |p| p.data else val; | 2963 | else if (val.castTag(.opt_payload)) |p| p.data else val, |
| 2964 | .null_value => null, | ||
| 2965 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | ||
| 2966 | .opt => |opt| switch (opt.val) { | ||
| 2967 | .none => null, | ||
| 2968 | else => opt.val.toValue(), | ||
| 2969 | }, | ||
| 2970 | else => unreachable, | ||
| 2971 | }, | ||
| 2972 | }; | ||
| 2957 | } | 2973 | } |
| 2958 | 2974 | ||
| 2959 | /// Valid for all types. Asserts the value is not undefined. | 2975 | /// Valid for all types. Asserts the value is not undefined. |