Commit be1b231206
Changed files (3)
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.
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);
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.