InternPool: add optional values
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 },
|
||||
} }) },
|
||||
} });
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
16
src/type.zig
16
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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user