InternPool: add missing logic

This commit is contained in:
Jacob Young 2023-05-21 03:57:12 -04:00 committed by Andrew Kelley
parent 9584feae5f
commit be1b231206
3 changed files with 84 additions and 30 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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.