InternPool: add optional values

This commit is contained in:
Andrew Kelley
2023-05-08 13:00:21 -07:00
parent 68b95a39b1
commit e94a81c951
5 changed files with 122 additions and 45 deletions

View File

@@ -55,7 +55,8 @@ pub const Key = union(enum) {
lib_name: u32,
},
int: Key.Int,
ptr: Key.Ptr,
ptr: Ptr,
opt: Opt,
enum_tag: struct {
ty: Index,
tag: BigIntConst,
@@ -151,6 +152,13 @@ pub const Key = union(enum) {
};
};
/// `null` is represented by the `val` field being `none`.
pub const Opt = struct {
ty: Index,
/// This could be `none`, indicating the optional is `null`.
val: Index,
};
pub fn hash32(key: Key) u32 {
return @truncate(u32, key.hash64());
}
@@ -175,6 +183,7 @@ pub const Key = union(enum) {
.simple_type,
.simple_value,
.extern_func,
.opt,
=> |info| std.hash.autoHash(hasher, info),
.int => |int| {
@@ -257,6 +266,10 @@ pub const Key = union(enum) {
const b_info = b.extern_func;
return std.meta.eql(a_info, b_info);
},
.opt => |a_info| {
const b_info = b.opt;
return std.meta.eql(a_info, b_info);
},
.ptr => |a_info| {
const b_info = b.ptr;
@@ -343,6 +356,7 @@ pub const Key = union(enum) {
inline .ptr,
.int,
.opt,
.extern_func,
.enum_tag,
=> |x| return x.ty,
@@ -771,7 +785,15 @@ pub const Tag = enum(u8) {
simple_internal,
/// A pointer to an integer value.
/// data is extra index of PtrInt, which contains the type and address.
/// Only pointer types are allowed to have this encoding. Optional types must use
/// `opt_payload` or `opt_null`.
ptr_int,
/// An optional value that is non-null.
/// data is Index of the payload value.
opt_payload,
/// An optional value that is null.
/// data is Index of the payload type.
opt_null,
/// Type: u8
/// data is integer value
int_u8,
@@ -1129,6 +1151,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.fields_len = 0,
} },
},
.opt_null => .{ .opt = .{
.ty = @intToEnum(Index, data),
.val = .none,
} },
.opt_payload => .{ .opt = .{
.ty = indexToKey(ip, @intToEnum(Index, data)).typeOf(),
.val = @intToEnum(Index, data),
} },
.ptr_int => {
const info = ip.extraData(PtrInt, data);
return .{ .ptr = .{
@@ -1321,6 +1351,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
},
},
.opt => |opt| {
assert(opt.ty != .none);
ip.items.appendAssumeCapacity(if (opt.val == .none) .{
.tag = .opt_null,
.data = @enumToInt(opt.ty),
} else .{
.tag = .opt_payload,
.data = @enumToInt(opt.val),
});
},
.int => |int| b: {
switch (int.ty) {
.none => unreachable,
@@ -1342,62 +1383,51 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
},
.u16_type => switch (int.storage) {
.big_int => |big_int| {
if (big_int.to(u32)) |casted| {
ip.items.appendAssumeCapacity(.{
.tag = .int_u16,
.data = casted,
});
break :b;
} else |_| {}
ip.items.appendAssumeCapacity(.{
.tag = .int_u16,
.data = big_int.to(u16) catch unreachable,
});
break :b;
},
inline .u64, .i64 => |x| {
if (std.math.cast(u32, x)) |casted| {
ip.items.appendAssumeCapacity(.{
.tag = .int_u16,
.data = casted,
});
break :b;
}
ip.items.appendAssumeCapacity(.{
.tag = .int_u16,
.data = @intCast(u16, x),
});
break :b;
},
},
.u32_type => switch (int.storage) {
.big_int => |big_int| {
if (big_int.to(u32)) |casted| {
ip.items.appendAssumeCapacity(.{
.tag = .int_u32,
.data = casted,
});
break :b;
} else |_| {}
ip.items.appendAssumeCapacity(.{
.tag = .int_u32,
.data = big_int.to(u32) catch unreachable,
});
break :b;
},
inline .u64, .i64 => |x| {
if (std.math.cast(u32, x)) |casted| {
ip.items.appendAssumeCapacity(.{
.tag = .int_u32,
.data = casted,
});
break :b;
}
ip.items.appendAssumeCapacity(.{
.tag = .int_u32,
.data = @intCast(u32, x),
});
break :b;
},
},
.i32_type => switch (int.storage) {
.big_int => |big_int| {
if (big_int.to(i32)) |casted| {
ip.items.appendAssumeCapacity(.{
.tag = .int_i32,
.data = @bitCast(u32, casted),
});
break :b;
} else |_| {}
const casted = big_int.to(i32) catch unreachable;
ip.items.appendAssumeCapacity(.{
.tag = .int_i32,
.data = @bitCast(u32, casted),
});
break :b;
},
inline .u64, .i64 => |x| {
if (std.math.cast(i32, x)) |casted| {
ip.items.appendAssumeCapacity(.{
.tag = .int_i32,
.data = @bitCast(u32, casted),
});
break :b;
}
ip.items.appendAssumeCapacity(.{
.tag = .int_i32,
.data = @bitCast(u32, @intCast(i32, x)),
});
break :b;
},
},
.usize_type => switch (int.storage) {
@@ -1798,6 +1828,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
.simple_value => 0,
.simple_internal => 0,
.ptr_int => @sizeOf(PtrInt),
.opt_null => 0,
.opt_payload => 0,
.int_u8 => 0,
.int_u16 => 0,
.int_u32 => 0,

View File

@@ -6887,12 +6887,32 @@ pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
return ptrType(mod, .{ .elem_type = child_type.ip_index, .is_const = true });
}
/// Supports optionals in addition to pointers.
pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
if (ty.isPtrLikeOptional(mod)) {
const i = try intern(mod, .{ .opt = .{
.ty = ty.ip_index,
.val = try intern(mod, .{ .ptr = .{
.ty = ty.childType(mod).ip_index,
.addr = .{ .int = try intern(mod, .{ .int = .{
.ty = .usize_type,
.storage = .{ .u64 = x },
} }) },
} }),
} });
return i.toValue();
} else {
return ptrIntValue_ptronly(mod, ty, x);
}
}
/// Supports only pointers. See `ptrIntValue` for pointer-like optional support.
pub fn ptrIntValue_ptronly(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
assert(ty.zigTypeTag(mod) == .Pointer);
const i = try intern(mod, .{ .ptr = .{
.ty = ty.ip_index,
.addr = .{ .int = try intern(mod, .{ .int = .{
.ty = ty.ip_index,
.ty = .usize_type,
.storage = .{ .u64 = x },
} }) },
} });

View File

@@ -31684,6 +31684,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
};
@@ -33207,6 +33208,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
}
@@ -33776,6 +33778,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
};

View File

@@ -146,6 +146,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
.simple_value => unreachable,
},
@@ -1574,10 +1575,13 @@ pub const Type = struct {
.simple_type => |s| return writer.writeAll(@tagName(s)),
.struct_type => @panic("TODO"),
.union_type => @panic("TODO"),
// values, not types
.simple_value => unreachable,
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
}
@@ -1850,6 +1854,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
}
@@ -1961,6 +1966,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
};
@@ -2362,6 +2368,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
}
@@ -2776,6 +2783,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
}
@@ -2946,6 +2954,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
};
@@ -3803,6 +3812,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
};
@@ -4178,6 +4188,7 @@ pub const Type = struct {
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.opt => unreachable,
.enum_tag => unreachable,
},
};
@@ -4339,11 +4350,14 @@ pub const Type = struct {
},
.struct_type => @panic("TODO"),
.union_type => @panic("TODO"),
// values, not types
.simple_value => unreachable,
.extern_func => unreachable,
.int => unreachable,
.ptr => unreachable,
.enum_tag => unreachable, // it's a value, not a type
.opt => unreachable,
.enum_tag => unreachable,
},
};
}

View File

@@ -2336,6 +2336,14 @@ pub const Value = struct {
// The value is runtime-known and shouldn't affect the hash.
if (val.isRuntimeValue()) return;
if (val.ip_index != .none) {
// The InternPool data structure hashes based on Key to make interned objects
// unique. An Index can be treated simply as u32 value for the
// purpose of Type/Value hashing and equality.
std.hash.autoHash(hasher, val.ip_index);
return;
}
switch (ty.zigTypeTag(mod)) {
.Opaque => unreachable, // Cannot hash opaque types
.Void,