stage2: rework Type Payload layout

Add `Type.castTag` and note that it is preferable to call than
`Type.cast`. This matches other abstractions in the codebase.

Added a convenience function `Type.Tag.create` which really cleans up
the callsites of creating `Type` objects.

`Type` payloads can now share types. This is in preparation for another
improvement that I want to do.
This commit is contained in:
Andrew Kelley
2020-12-30 19:57:11 -07:00
parent 2622575fde
commit 133da8692e
8 changed files with 432 additions and 403 deletions

View File

@@ -562,7 +562,7 @@ pub const Scope = struct {
pub fn deinit(self: *Container, gpa: *Allocator) void {
self.decls.deinit(gpa);
// TODO either Container of File should have an arena for sub_file_path and ty
gpa.destroy(self.ty.cast(Type.Payload.EmptyStruct).?);
gpa.destroy(self.ty.castTag(.empty_struct).?);
gpa.free(self.file_scope.sub_file_path);
self.* = undefined;
}
@@ -2528,12 +2528,11 @@ pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []
}
// TODO Scope.Container arena for ty and sub_file_path
const struct_payload = try self.gpa.create(Type.Payload.EmptyStruct);
errdefer self.gpa.destroy(struct_payload);
const file_scope = try self.gpa.create(Scope.File);
errdefer self.gpa.destroy(file_scope);
const struct_ty = try Type.Tag.empty_struct.create(self.gpa, &file_scope.root_container);
errdefer self.gpa.destroy(struct_ty.castTag(.empty_struct).?);
struct_payload.* = .{ .scope = &file_scope.root_container };
file_scope.* = .{
.sub_file_path = resolved_path,
.source = .{ .unloaded = {} },
@@ -2543,7 +2542,7 @@ pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []
.root_container = .{
.file_scope = file_scope,
.decls = .{},
.ty = Type.initPayload(&struct_payload.base),
.ty = struct_ty,
},
};
self.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
@@ -2564,7 +2563,7 @@ pub fn cmpNumeric(
lhs: *Inst,
rhs: *Inst,
op: std.math.CompareOperator,
) !*Inst {
) InnerError!*Inst {
assert(lhs.ty.isNumeric());
assert(rhs.ty.isNumeric());
@@ -2738,15 +2737,14 @@ fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*In
}
fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
if (signed) {
const int_payload = try scope.arena().create(Type.Payload.IntSigned);
int_payload.* = .{ .bits = bits };
return Type.initPayload(&int_payload.base);
} else {
const int_payload = try scope.arena().create(Type.Payload.IntUnsigned);
int_payload.* = .{ .bits = bits };
return Type.initPayload(&int_payload.base);
}
const int_payload = try scope.arena().create(Type.Payload.Bits);
int_payload.* = .{
.base = .{
.tag = if (signed) .int_signed else .int_unsigned,
},
.data = bits,
};
return Type.initPayload(&int_payload.base);
}
pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {
@@ -2829,7 +2827,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
// T to ?T
if (dest_type.zigTypeTag() == .Optional) {
var buf: Type.Payload.PointerSimple = undefined;
var buf: Type.Payload.ElemType = undefined;
const child_type = dest_type.optionalChild(&buf);
if (child_type.eql(inst.ty)) {
return self.wrapOptional(scope, dest_type, inst);
@@ -3225,7 +3223,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu
// TODO stage1 type inference bug
const T = Type.Tag;
const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
const type_payload = try scope.arena().create(Type.Payload.ElemType);
type_payload.* = .{
.base = .{
.tag = switch (size) {
@@ -3235,7 +3233,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu
.Slice => if (mutable) T.mut_slice else T.const_slice,
},
},
.pointee_type = elem_ty,
.data = elem_ty,
};
return Type.initPayload(&type_payload.base);
}
@@ -3257,8 +3255,7 @@ pub fn ptrType(
assert(host_size == 0 or bit_offset < host_size * 8);
// TODO check if type can be represented by simplePtrType
const type_payload = try scope.arena().create(Type.Payload.Pointer);
type_payload.* = .{
return Type.Tag.pointer.create(scope.arena(), .{
.pointee_type = elem_ty,
.sentinel = sentinel,
.@"align" = @"align",
@@ -3268,95 +3265,73 @@ pub fn ptrType(
.mutable = mutable,
.@"volatile" = @"volatile",
.size = size,
};
return Type.initPayload(&type_payload.base);
}
pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
return Type.initPayload(switch (child_type.tag()) {
.single_const_pointer => blk: {
const payload = try scope.arena().create(Type.Payload.PointerSimple);
payload.* = .{
.base = .{ .tag = .optional_single_const_pointer },
.pointee_type = child_type.elemType(),
};
break :blk &payload.base;
},
.single_mut_pointer => blk: {
const payload = try scope.arena().create(Type.Payload.PointerSimple);
payload.* = .{
.base = .{ .tag = .optional_single_mut_pointer },
.pointee_type = child_type.elemType(),
};
break :blk &payload.base;
},
else => blk: {
const payload = try scope.arena().create(Type.Payload.Optional);
payload.* = .{
.child_type = child_type,
};
break :blk &payload.base;
},
});
}
pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type {
pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
switch (child_type.tag()) {
.single_const_pointer => return Type.Tag.optional_single_const_pointer.create(
scope.arena(),
child_type.elemType(),
),
.single_mut_pointer => return Type.Tag.optional_single_mut_pointer.create(
scope.arena(),
child_type.elemType(),
),
else => return Type.Tag.optional.create(scope.arena(), child_type),
}
}
pub fn arrayType(
self: *Module,
scope: *Scope,
len: u64,
sentinel: ?Value,
elem_type: Type,
) Allocator.Error!Type {
if (elem_type.eql(Type.initTag(.u8))) {
if (sentinel) |some| {
if (some.eql(Value.initTag(.zero))) {
const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
payload.* = .{
.len = len,
};
return Type.initPayload(&payload.base);
return Type.Tag.array_u8_sentinel_0.create(scope.arena(), len);
}
} else {
const payload = try scope.arena().create(Type.Payload.Array_u8);
payload.* = .{
.len = len,
};
return Type.initPayload(&payload.base);
return Type.Tag.array_u8.create(scope.arena(), len);
}
}
if (sentinel) |some| {
const payload = try scope.arena().create(Type.Payload.ArraySentinel);
payload.* = .{
return Type.Tag.array_sentinel.create(scope.arena(), .{
.len = len,
.sentinel = some,
.elem_type = elem_type,
};
return Type.initPayload(&payload.base);
});
}
const payload = try scope.arena().create(Type.Payload.Array);
payload.* = .{
return Type.Tag.array.create(scope.arena(), .{
.len = len,
.elem_type = elem_type,
};
return Type.initPayload(&payload.base);
});
}
pub fn errorUnionType(self: *Module, scope: *Scope, error_set: Type, payload: Type) Allocator.Error!Type {
pub fn errorUnionType(
self: *Module,
scope: *Scope,
error_set: Type,
payload: Type,
) Allocator.Error!Type {
assert(error_set.zigTypeTag() == .ErrorSet);
if (error_set.eql(Type.initTag(.anyerror)) and payload.eql(Type.initTag(.void))) {
return Type.initTag(.anyerror_void_error_union);
}
const result = try scope.arena().create(Type.Payload.ErrorUnion);
result.* = .{
return Type.Tag.error_union.create(scope.arena(), .{
.error_set = error_set,
.payload = payload,
};
return Type.initPayload(&result.base);
});
}
pub fn anyframeType(self: *Module, scope: *Scope, return_type: Type) Allocator.Error!Type {
const result = try scope.arena().create(Type.Payload.AnyFrame);
result.* = .{
.return_type = return_type,
};
return Type.initPayload(&result.base);
return Type.Tag.anyframe_T.create(scope.arena(), return_type);
}
pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {