diff --git a/src/InternPool.zig b/src/InternPool.zig index 652a7ecdea..ecc7b7a383 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1517,6 +1517,8 @@ pub const Tag = enum(u8) { /// 0. name: NullTerminatedString for each names_len pub const ErrorSet = struct { names_len: u32, + /// Maps error names to declaration index. + names_map: MapIndex, }; /// Trailing: @@ -2024,6 +2026,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { const names = ip.extra.items[error_set.end..][0..names_len]; return .{ .error_set_type = .{ .names = @ptrCast([]const NullTerminatedString, names), + .names_map = error_set.data.names_map.toOptional(), } }; }, .type_inferred_error_set => .{ @@ -2518,6 +2521,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { .tag = .type_error_set, .data = ip.addExtraAssumeCapacity(ErrorSet{ .names_len = names_len, + .names_map = names_map, }), }); ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, error_set_type.names)); @@ -3605,15 +3609,34 @@ pub fn sliceLen(ip: InternPool, i: Index) Index { /// * int <=> int /// * int <=> enum /// * ptr <=> ptr +/// * null_value => opt +/// * payload => opt pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index { - if (ip.typeOf(val) == new_ty) return val; + const old_ty = ip.typeOf(val); + if (old_ty == new_ty) return val; switch (ip.indexToKey(val)) { .int => |int| switch (ip.indexToKey(new_ty)) { + .simple_type => |simple_type| switch (simple_type) { + .usize, + .isize, + .c_char, + .c_short, + .c_ushort, + .c_int, + .c_uint, + .c_long, + .c_ulong, + .c_longlong, + .c_ulonglong, + => return getCoercedInts(ip, gpa, int, new_ty), + else => {}, + }, + .int_type => return getCoercedInts(ip, gpa, int, new_ty), .enum_type => return ip.get(gpa, .{ .enum_tag = .{ .ty = new_ty, .int = val, } }), - else => return getCoercedInts(ip, gpa, int, new_ty), + else => {}, }, .enum_tag => |enum_tag| { // Assume new_ty is an integer type. @@ -3624,10 +3647,24 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al .ty = new_ty, .addr = ptr.addr, } }), - else => unreachable, + else => {}, }, - else => unreachable, + else => {}, } + switch (ip.indexToKey(new_ty)) { + .opt_type => |child_ty| switch (val) { + .null_value => return ip.get(gpa, .{ .opt = .{ + .ty = new_ty, + .val = .none, + } }), + else => return ip.get(gpa, .{ .opt = .{ + .ty = new_ty, + .val = try ip.getCoerced(gpa, val, child_ty), + } }), + }, + else => {}, + } + unreachable; } /// Asserts `val` has an integer type. diff --git a/src/Sema.zig b/src/Sema.zig index e109da79de..bc74e5b2db 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8480,13 +8480,10 @@ fn zirOptionalPayload( }; if (try sema.resolveDefinedValue(block, src, operand)) |val| { - if (val.isNull(mod)) { - return sema.fail(block, src, "unable to unwrap null", .{}); - } - if (val.castTag(.opt_payload)) |payload| { - return sema.addConstant(result_ty, payload.data); - } - return sema.addConstant(result_ty, val); + return if (val.optionalValue(mod)) |payload| + sema.addConstant(result_ty, payload) + else + sema.fail(block, src, "unable to unwrap null", .{}); } try sema.requireRuntimeBlock(block, src, null); @@ -18929,7 +18926,7 @@ fn zirReify( if (ptr_size == .One or ptr_size == .C) { return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); } - const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data; + const sentinel_ptr_val = sentinel_val.optionalValue(mod).?; const ptr_ty = try Type.ptr(sema.arena, mod, .{ .@"addrspace" = .generic, .pointee_type = elem_ty, @@ -28807,7 +28804,11 @@ fn coerceCompatiblePtrs( return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); } // The comptime Value representation is compatible with both types. - return sema.addConstant(dest_ty, val); + return sema.addConstant(dest_ty, (try mod.intern_pool.getCoerced( + mod.gpa, + try val.intern(inst_ty, mod), + dest_ty.ip_index, + )).toValue()); } try sema.requireRuntimeBlock(block, inst_src, null); const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod); diff --git a/src/value.zig b/src/value.zig index 5963b84b25..0277f0bdb2 100644 --- a/src/value.zig +++ b/src/value.zig @@ -718,18 +718,25 @@ pub const Value = struct { }, else => unreachable, }; - const enum_type = ip.indexToKey(ty.ip_index).enum_type; - if (enum_type.values.len != 0) { - return enum_type.values[field_index].toValue(); - } else { - // Field index and integer values are the same. - return mod.intValue(enum_type.tag_ty.toType(), field_index); - } + return switch (ip.indexToKey(ty.ip_index)) { + // Assume it is already an integer and return it directly. + .simple_type, .int_type => val, + .enum_type => |enum_type| if (enum_type.values.len != 0) + enum_type.values[field_index].toValue() + else // Field index and integer values are the same. + mod.intValue(enum_type.tag_ty.toType(), field_index), + else => unreachable, + }; }, - else => { - const enum_type = ip.indexToKey(ip.typeOf(val.ip_index)).enum_type; - const int = try ip.getCoerced(mod.gpa, val.ip_index, enum_type.tag_ty); - return int.toValue(); + else => return switch (ip.indexToKey(ip.typeOf(val.ip_index))) { + // Assume it is already an integer and return it directly. + .simple_type, .int_type => val, + .enum_type => |enum_type| (try ip.getCoerced( + mod.gpa, + val.ip_index, + enum_type.tag_ty, + )).toValue(), + else => unreachable, }, } } @@ -2906,7 +2913,7 @@ pub const Value = struct { inline .u64, .i64 => |x| x == 0, }, .opt => |opt| opt.val == .none, - else => unreachable, + else => false, }, }; } @@ -2949,11 +2956,20 @@ pub const Value = struct { /// Value of the optional, null if optional has no payload. pub fn optionalValue(val: Value, mod: *const Module) ?Value { - if (val.isNull(mod)) return null; - - // Valid for optional representation to be the direct value - // and not use opt_payload. - return if (val.castTag(.opt_payload)) |p| p.data else val; + return switch (val.ip_index) { + .none => if (val.isNull(mod)) null + // Valid for optional representation to be the direct value + // and not use opt_payload. + else if (val.castTag(.opt_payload)) |p| p.data else val, + .null_value => null, + else => switch (mod.intern_pool.indexToKey(val.ip_index)) { + .opt => |opt| switch (opt.val) { + .none => null, + else => opt.val.toValue(), + }, + else => unreachable, + }, + }; } /// Valid for all types. Asserts the value is not undefined.