Commit e94a81c951
Changed files (5)
src/InternPool.zig
@@ -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,
src/Module.zig
@@ -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 },
} }) },
} });
src/Sema.zig
@@ -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,
},
};
src/type.zig
@@ -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,
},
};
}
src/value.zig
@@ -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,