aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Module.zig54
-rw-r--r--src/astgen.zig177
-rw-r--r--src/type.zig142
-rw-r--r--src/type/Enum.zig55
-rw-r--r--src/type/Struct.zig56
-rw-r--r--src/type/Union.zig56
-rw-r--r--src/value.zig2
-rw-r--r--src/zir.zig108
-rw-r--r--src/zir_sema.zig8
9 files changed, 647 insertions, 11 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 9707e79e2a..8575c59f4c 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -460,7 +460,7 @@ pub const Scope = struct {
};
}
- /// Asserts the scope has a parent which is a ZIRModule, Contaienr or File and
+ /// Asserts the scope has a parent which is a ZIRModule, Container or File and
/// returns the sub_file_path field.
pub fn subFilePath(base: *Scope) []const u8 {
switch (base.tag) {
@@ -501,12 +501,12 @@ pub const Scope = struct {
}
}
- pub fn getOwnerPkg(base: *Scope) *Package {
+ pub fn getFileScope(base: *Scope) *Scope.File {
var cur = base;
while (true) {
cur = switch (cur.tag) {
- .container => return @fieldParentPtr(Container, "base", cur).file_scope.pkg,
- .file => return @fieldParentPtr(File, "base", cur).pkg,
+ .container => return @fieldParentPtr(Container, "base", cur).file_scope,
+ .file => return @fieldParentPtr(File, "base", cur),
.zir_module => unreachable, // TODO are zir modules allowed to import packages?
.gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,
.local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
@@ -582,7 +582,7 @@ pub const Scope = struct {
file_scope: *Scope.File,
/// Direct children of the file.
- decls: std.AutoArrayHashMapUnmanaged(*Decl, void),
+ decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
ty: Type,
pub fn deinit(self: *Container, gpa: *Allocator) void {
@@ -2464,6 +2464,48 @@ pub fn createAnonymousDecl(
return new_decl;
}
+pub fn createContainerDecl(
+ self: *Module,
+ scope: *Scope,
+ base_token: std.zig.ast.TokenIndex,
+ decl_arena: *std.heap.ArenaAllocator,
+ typed_value: TypedValue,
+) !*Decl {
+ const scope_decl = scope.decl().?;
+ const name = try self.getAnonTypeName(scope, base_token);
+ defer self.gpa.free(name);
+ const name_hash = scope.namespace().fullyQualifiedNameHash(name);
+ const src_hash: std.zig.SrcHash = undefined;
+ const new_decl = try self.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
+ const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
+
+ decl_arena_state.* = decl_arena.state;
+ new_decl.typed_value = .{
+ .most_recent = .{
+ .typed_value = typed_value,
+ .arena = decl_arena_state,
+ },
+ };
+ new_decl.analysis = .complete;
+ new_decl.generation = self.generation;
+
+ return new_decl;
+}
+
+fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
+ // TODO add namespaces, generic function signatrues
+ const tree = scope.tree();
+ const base_name = switch (tree.token_ids[base_token]) {
+ .Keyword_struct => "struct",
+ .Keyword_enum => "enum",
+ .Keyword_union => "union",
+ .Keyword_opaque => "opaque",
+ else => unreachable,
+ };
+ const loc = tree.tokenLocationLoc(0, tree.token_locs[base_token]);
+ return std.fmt.allocPrint(self.gpa, "{}:{}:{}", .{ base_name, loc.line, loc.column });
+}
+
fn getNextAnonNameIndex(self: *Module) usize {
return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
}
@@ -2645,7 +2687,7 @@ pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst,
}
pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []const u8) !*Scope.File {
- const cur_pkg = scope.getOwnerPkg();
+ const cur_pkg = scope.getFileScope().pkg;
const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
const found_pkg = cur_pkg.table.get(target_string);
diff --git a/src/astgen.zig b/src/astgen.zig
index 7f5d596dda..53503a0467 100644
--- a/src/astgen.zig
+++ b/src/astgen.zig
@@ -282,6 +282,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
.Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),
.OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?),
.Switch => return switchExpr(mod, scope, rl, node.castTag(.Switch).?),
+ .ContainerDecl => return containerDecl(mod, scope, rl, node.castTag(.ContainerDecl).?),
.Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
.Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
@@ -294,7 +295,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
.Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}),
.AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),
.FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
- .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
.Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),
}
}
@@ -856,6 +856,181 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si
return rlWrapPtr(mod, scope, rl, try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand));
}
+fn containerField(
+ mod: *Module,
+ scope: *Scope,
+ node: *ast.Node.ContainerField,
+) InnerError!*zir.Inst {
+ const tree = scope.tree();
+ const src = tree.token_locs[node.firstToken()].start;
+ const name = try mod.identifierTokenString(scope, node.name_token);
+
+ if (node.comptime_token == null and node.value_expr == null and node.align_expr == null) {
+ if (node.type_expr) |some| {
+ const ty = try typeExpr(mod, scope, some);
+ return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldTyped, .{
+ .bytes = name,
+ .ty = ty,
+ }, .{});
+ } else {
+ return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldNamed, .{
+ .bytes = name,
+ }, .{});
+ }
+ }
+
+ const ty = if (node.type_expr) |some| try typeExpr(mod, scope, some) else null;
+ const alignment = if (node.align_expr) |some| try expr(mod, scope, .none, some) else null;
+ const init = if (node.value_expr) |some| try expr(mod, scope, .none, some) else null;
+
+ return addZIRInst(mod, scope, src, zir.Inst.ContainerField, .{
+ .bytes = name,
+ }, .{
+ .ty = ty,
+ .init = init,
+ .alignment = alignment,
+ .is_comptime = node.comptime_token != null,
+ });
+}
+
+fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ContainerDecl) InnerError!*zir.Inst {
+ const tree = scope.tree();
+ const src = tree.token_locs[node.kind_token].start;
+
+ var gen_scope: Scope.GenZIR = .{
+ .parent = scope,
+ .decl = scope.decl().?,
+ .arena = scope.arena(),
+ .instructions = .{},
+ };
+ defer gen_scope.instructions.deinit(mod.gpa);
+
+ var fields = std.ArrayList(*zir.Inst).init(mod.gpa);
+ defer fields.deinit();
+
+ for (node.fieldsAndDecls()) |fd| {
+ if (fd.castTag(.ContainerField)) |f| {
+ try fields.append(try containerField(mod, &gen_scope.base, f));
+ }
+ }
+
+ var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
+ errdefer decl_arena.deinit();
+ const arena = &decl_arena.allocator;
+
+ var layout: std.builtin.TypeInfo.ContainerLayout = .Auto;
+ if (node.layout_token) |some| switch (tree.token_ids[some]) {
+ .Keyword_extern => layout = .Extern,
+ .Keyword_packed => layout = .Packed,
+ else => unreachable,
+ };
+
+ const container_type = switch (tree.token_ids[node.kind_token]) {
+ .Keyword_enum => blk: {
+ const tag_type: ?*zir.Inst = switch (node.init_arg_expr) {
+ .Type => |t| try typeExpr(mod, &gen_scope.base, t),
+ .None => null,
+ .Enum => unreachable,
+ };
+ const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.EnumType, .{
+ .fields = try arena.dupe(*zir.Inst, fields.items),
+ }, .{
+ .layout = layout,
+ .tag_type = tag_type,
+ });
+ const enum_type = try arena.create(Type.Payload.Enum);
+ enum_type.* = .{
+ .analysis = .{
+ .queued = .{
+ .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) },
+ .inst = inst,
+ },
+ },
+ .scope = .{
+ .file_scope = scope.getFileScope(),
+ .ty = Type.initPayload(&enum_type.base),
+ },
+ };
+ break :blk Type.initPayload(&enum_type.base);
+ },
+ .Keyword_struct => blk: {
+ assert(node.init_arg_expr == .None);
+ const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.StructType, .{
+ .fields = try arena.dupe(*zir.Inst, fields.items),
+ }, .{
+ .layout = layout,
+ });
+ const struct_type = try arena.create(Type.Payload.Struct);
+ struct_type.* = .{
+ .analysis = .{
+ .queued = .{
+ .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) },
+ .inst = inst,
+ },
+ },
+ .scope = .{
+ .file_scope = scope.getFileScope(),
+ .ty = Type.initPayload(&struct_type.base),
+ },
+ };
+ break :blk Type.initPayload(&struct_type.base);
+ },
+ .Keyword_union => blk: {
+ const init_inst = switch (node.init_arg_expr) {
+ .Enum => |e| if (e) |t| try typeExpr(mod, &gen_scope.base, t) else null,
+ .None => null,
+ .Type => |t| try typeExpr(mod, &gen_scope.base, t),
+ };
+ const init_kind: zir.Inst.UnionType.InitKind = switch (node.init_arg_expr) {
+ .Enum => .enum_type,
+ .None => .none,
+ .Type => .tag_type,
+ };
+ const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.UnionType, .{
+ .fields = try arena.dupe(*zir.Inst, fields.items),
+ }, .{
+ .layout = layout,
+ .init_kind = init_kind,
+ .init_inst = init_inst,
+ });
+ const union_type = try arena.create(Type.Payload.Union);
+ union_type.* = .{
+ .analysis = .{
+ .queued = .{
+ .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) },
+ .inst = inst,
+ },
+ },
+ .scope = .{
+ .file_scope = scope.getFileScope(),
+ .ty = Type.initPayload(&union_type.base),
+ },
+ };
+ break :blk Type.initPayload(&union_type.base);
+ },
+ .Keyword_opaque => blk: {
+ if (fields.items.len > 0) {
+ return mod.fail(scope, fields.items[0].src, "opaque types cannot have fields", .{});
+ }
+ const opaque_type = try arena.create(Type.Payload.Opaque);
+ opaque_type.* = .{
+ .scope = .{
+ .file_scope = scope.getFileScope(),
+ .ty = Type.initPayload(&opaque_type.base),
+ },
+ };
+ break :blk Type.initPayload(&opaque_type.base);
+ },
+ else => unreachable,
+ };
+ const val = try Value.Tag.ty.create(arena, container_type);
+ const decl = try mod.createContainerDecl(scope, node.kind_token, &decl_arena, .{
+ .ty = Type.initTag(.type),
+ .val = val,
+ });
+ return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}));
+}
+
fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
const tree = scope.tree();
const src = tree.token_locs[node.error_token].start;
diff --git a/src/type.zig b/src/type.zig
index 9e2cd321f0..be61f57c1d 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -49,7 +49,7 @@ pub const Type = extern union {
.c_longdouble,
=> return .Float,
- .c_void => return .Opaque,
+ .c_void, .@"opaque" => return .Opaque,
.bool => return .Bool,
.void => return .Void,
.type => return .Type,
@@ -92,7 +92,9 @@ pub const Type = extern union {
.anyframe_T, .@"anyframe" => return .AnyFrame,
- .empty_struct => return .Struct,
+ .@"struct", .empty_struct => return .Struct,
+ .@"enum" => return .Enum,
+ .@"union" => return .Union,
}
}
@@ -470,6 +472,11 @@ pub const Type = extern union {
.error_set => return self.copyPayloadShallow(allocator, Payload.Decl),
.error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
.empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
+
+ .@"enum" => return self.copyPayloadShallow(allocator, Payload.Enum),
+ .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
+ .@"union" => return self.copyPayloadShallow(allocator, Payload.Union),
+ .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
}
}
@@ -695,6 +702,11 @@ pub const Type = extern union {
},
.inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"),
.inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"),
+ // TODO use declaration name
+ .@"enum" => return out_stream.writeAll("enum {}"),
+ .@"struct" => return out_stream.writeAll("struct {}"),
+ .@"union" => return out_stream.writeAll("union {}"),
+ .@"opaque" => return out_stream.writeAll("opaque {}"),
}
unreachable;
}
@@ -803,6 +815,10 @@ pub const Type = extern union {
return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();
},
+ .@"enum" => @panic("TODO"),
+ .@"struct" => @panic("TODO"),
+ .@"union" => @panic("TODO"),
+
.c_void,
.void,
.type,
@@ -813,6 +829,7 @@ pub const Type = extern union {
.@"undefined",
.enum_literal,
.empty_struct,
+ .@"opaque",
=> false,
.inferred_alloc_const => unreachable,
@@ -924,6 +941,10 @@ pub const Type = extern union {
@panic("TODO abiAlignment error union");
},
+ .@"enum" => self.cast(Payload.Enum).?.abiAlignment(target),
+ .@"struct" => @panic("TODO"),
+ .@"union" => @panic("TODO"),
+
.c_void,
.void,
.type,
@@ -936,6 +957,7 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"opaque",
=> unreachable,
};
}
@@ -961,6 +983,7 @@ pub const Type = extern union {
.empty_struct => unreachable,
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
+ .@"opaque" => unreachable,
.u8,
.i8,
@@ -1067,6 +1090,10 @@ pub const Type = extern union {
}
@panic("TODO abiSize error union");
},
+
+ .@"enum" => @panic("TODO"),
+ .@"struct" => @panic("TODO"),
+ .@"union" => @panic("TODO"),
};
}
@@ -1134,6 +1161,10 @@ pub const Type = extern union {
.error_set,
.error_set_single,
.empty_struct,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.single_const_pointer,
@@ -1205,6 +1236,10 @@ pub const Type = extern union {
.error_set,
.error_set_single,
.empty_struct,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
.const_slice,
@@ -1297,6 +1332,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.const_slice,
@@ -1371,6 +1410,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.single_const_pointer,
@@ -1454,6 +1497,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.pointer => {
@@ -1532,6 +1579,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.pointer => {
@@ -1652,6 +1703,10 @@ pub const Type = extern union {
.empty_struct => unreachable,
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
+ .@"enum" => unreachable,
+ .@"struct" => unreachable,
+ .@"union" => unreachable,
+ .@"opaque" => unreachable,
.array => self.castTag(.array).?.data.elem_type,
.array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
@@ -1775,6 +1830,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
.array => self.castTag(.array).?.data.len,
@@ -1843,6 +1902,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
.single_const_pointer,
@@ -1928,6 +1991,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.int_signed,
@@ -2005,6 +2072,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.int_unsigned,
@@ -2072,6 +2143,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
.int_unsigned => .{
@@ -2163,6 +2238,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
.usize,
@@ -2277,6 +2356,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
};
}
@@ -2357,6 +2440,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
}
}
@@ -2436,6 +2523,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
}
}
@@ -2515,6 +2606,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
};
}
@@ -2591,6 +2686,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
};
}
@@ -2667,6 +2766,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> unreachable,
};
}
@@ -2743,6 +2846,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> false,
};
}
@@ -2800,8 +2907,13 @@ pub const Type = extern union {
.error_union,
.error_set,
.error_set_single,
+ .@"opaque",
=> return null,
+ .@"enum" => @panic("TODO onePossibleValue enum"),
+ .@"struct" => @panic("TODO onePossibleValue struct"),
+ .@"union" => @panic("TODO onePossibleValue union"),
+
.empty_struct => return Value.initTag(.empty_struct_value),
.void => return Value.initTag(.void_value),
.noreturn => return Value.initTag(.unreachable_value),
@@ -2907,6 +3019,10 @@ pub const Type = extern union {
.empty_struct,
.inferred_alloc_const,
.inferred_alloc_mut,
+ .@"enum",
+ .@"struct",
+ .@"union",
+ .@"opaque",
=> return false,
.c_const_pointer,
@@ -2997,6 +3113,10 @@ pub const Type = extern union {
=> unreachable,
.empty_struct => self.castTag(.empty_struct).?.data,
+ .@"enum" => &self.castTag(.@"enum").?.scope,
+ .@"struct" => &self.castTag(.@"struct").?.scope,
+ .@"union" => &self.castTag(.@"union").?.scope,
+ .@"opaque" => &self.castTag(.@"opaque").?.scope,
};
}
@@ -3137,6 +3257,10 @@ pub const Type = extern union {
error_set,
error_set_single,
empty_struct,
+ @"enum",
+ @"struct",
+ @"union",
+ @"opaque",
pub const last_no_payload_tag = Tag.inferred_alloc_const;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -3219,6 +3343,10 @@ pub const Type = extern union {
.error_set => Payload.Decl,
.error_set_single => Payload.Name,
.empty_struct => Payload.ContainerScope,
+ .@"enum" => Payload.Enum,
+ .@"struct" => Payload.Struct,
+ .@"union" => Payload.Union,
+ .@"opaque" => Payload.Opaque,
};
}
@@ -3332,6 +3460,16 @@ pub const Type = extern union {
base: Payload,
data: *Module.Scope.Container,
};
+
+ pub const Opaque = struct {
+ base: Payload = .{ .tag = .@"opaque" },
+
+ scope: Module.Scope.Container,
+ };
+
+ pub const Enum = @import("type/Enum.zig");
+ pub const Struct = @import("type/Struct.zig");
+ pub const Union = @import("type/Union.zig");
};
};
diff --git a/src/type/Enum.zig b/src/type/Enum.zig
new file mode 100644
index 0000000000..9b9ec5b319
--- /dev/null
+++ b/src/type/Enum.zig
@@ -0,0 +1,55 @@
+const std = @import("std");
+const zir = @import("../zir.zig");
+const Value = @import("../value.zig").Value;
+const Type = @import("../type.zig").Type;
+const Module = @import("../Module.zig");
+const Scope = Module.Scope;
+const Enum = @This();
+
+base: Type.Payload = .{ .tag = .@"enum" },
+
+analysis: union(enum) {
+ queued: Zir,
+ in_progress,
+ resolved: Size,
+ failed,
+},
+scope: Scope.Container,
+
+pub const Field = struct {
+ value: Value,
+};
+
+pub const Zir = struct {
+ body: zir.Module.Body,
+ inst: *zir.Inst,
+};
+
+pub const Size = struct {
+ tag_type: Type,
+ fields: std.StringArrayHashMapUnmanaged(Field),
+};
+
+pub fn resolve(self: *Enum, mod: *Module, scope: *Scope) !void {
+ const zir = switch (self.analysis) {
+ .failed => return error.AnalysisFail,
+ .resolved => return,
+ .in_progress => {
+ return mod.fail(scope, src, "enum '{}' depends on itself", .{enum_name});
+ },
+ .queued => |zir| zir,
+ };
+ self.analysis = .in_progress;
+
+ // TODO
+}
+
+// TODO should this resolve the type or assert that it has already been resolved?
+pub fn abiAlignment(self: *Enum, target: std.Target) u32 {
+ switch (self.analysis) {
+ .queued => unreachable, // alignment has not been resolved
+ .in_progress => unreachable, // alignment has not been resolved
+ .failed => unreachable, // type resolution failed
+ .resolved => |r| return r.tag_type.abiAlignment(target),
+ }
+}
diff --git a/src/type/Struct.zig b/src/type/Struct.zig
new file mode 100644
index 0000000000..d6a591c95e
--- /dev/null
+++ b/src/type/Struct.zig
@@ -0,0 +1,56 @@
+const std = @import("std");
+const zir = @import("../zir.zig");
+const Value = @import("../value.zig").Value;
+const Type = @import("../type.zig").Type;
+const Module = @import("../Module.zig");
+const Scope = Module.Scope;
+const Struct = @This();
+
+base: Type.Payload = .{ .tag = .@"struct" },
+
+analysis: union(enum) {
+ queued: Zir,
+ zero_bits_in_progress,
+ zero_bits: Zero,
+ in_progress,
+ // alignment: Align,
+ resolved: Size,
+ failed,
+},
+scope: Scope.Container,
+
+pub const Field = struct {
+ value: Value,
+};
+
+pub const Zir = struct {
+ body: zir.Module.Body,
+ inst: *zir.Inst,
+};
+
+pub const Zero = struct {
+ is_zero_bits: bool,
+ fields: std.StringArrayHashMapUnmanaged(Field),
+};
+
+pub const Size = struct {
+ is_zero_bits: bool,
+ alignment: u32,
+ size: u32,
+ fields: std.StringArrayHashMapUnmanaged(Field),
+};
+
+pub fn resolveZeroBits(self: *Struct, mod: *Module, scope: *Scope) !void {
+ const zir = switch (self.analysis) {
+ .failed => return error.AnalysisFail,
+ .zero_bits_in_progress => {
+ return mod.fail(scope, src, "struct '{}' depends on itself", .{});
+ },
+ .queued => |zir| zir,
+ else => return,
+ };
+
+ self.analysis = .zero_bits_in_progress;
+
+ // TODO
+}
diff --git a/src/type/Union.zig b/src/type/Union.zig
new file mode 100644
index 0000000000..26cc1796c6
--- /dev/null
+++ b/src/type/Union.zig
@@ -0,0 +1,56 @@
+const std = @import("std");
+const zir = @import("../zir.zig");
+const Value = @import("../value.zig").Value;
+const Type = @import("../type.zig").Type;
+const Module = @import("../Module.zig");
+const Scope = Module.Scope;
+const Union = @This();
+
+base: Type.Payload = .{ .tag = .@"struct" },
+
+analysis: union(enum) {
+ queued: Zir,
+ zero_bits_in_progress,
+ zero_bits: Zero,
+ in_progress,
+ // alignment: Align,
+ resolved: Size,
+ failed,
+},
+scope: Scope.Container,
+
+pub const Field = struct {
+ value: Value,
+};
+
+pub const Zir = struct {
+ body: zir.Module.Body,
+ inst: *zir.Inst,
+};
+
+pub const Zero = struct {
+ is_zero_bits: bool,
+ fields: std.StringArrayHashMapUnmanaged(Field),
+};
+
+pub const Size = struct {
+ is_zero_bits: bool,
+ alignment: u32,
+ size: u32,
+ fields: std.StringArrayHashMapUnmanaged(Field),
+};
+
+pub fn resolveZeroBits(self: *Union, mod: *Module, scope: *Scope) !void {
+ const zir = switch (self.analysis) {
+ .failed => return error.AnalysisFail,
+ .zero_bits_in_progress => {
+ return mod.fail(scope, src, "union '{}' depends on itself", .{});
+ },
+ .queued => |zir| zir,
+ else => return,
+ };
+
+ self.analysis = .zero_bits_in_progress;
+
+ // TODO
+}
diff --git a/src/value.zig b/src/value.zig
index 036e3b71bf..5b0563ca98 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -389,7 +389,6 @@ pub const Value = extern union {
},
.@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
- // memory is managed by the declaration
.error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
.inferred_alloc => unreachable,
@@ -2025,6 +2024,7 @@ pub const Value = extern union {
data: f128,
};
+ // TODO move to type.zig
pub const ErrorSet = struct {
pub const base_tag = Tag.error_set;
diff --git a/src/zir.zig b/src/zir.zig
index 8d99218b3d..0ccb09efac 100644
--- a/src/zir.zig
+++ b/src/zir.zig
@@ -133,6 +133,12 @@ pub const Inst = struct {
condbr,
/// Special case, has no textual representation.
@"const",
+ /// Container field with just the name.
+ container_field_named,
+ /// Container field with a type and a name,
+ container_field_typed,
+ /// Container field with all the bells and whistles.
+ container_field,
/// Declares the beginning of a statement. Used for debug info.
dbg_stmt,
/// Represents a pointer to a global decl by name.
@@ -263,6 +269,8 @@ pub const Inst = struct {
store_to_inferred_ptr,
/// String Literal. Makes an anonymous Decl and then takes a pointer to it.
str,
+ /// Create a struct type.
+ struct_type,
/// Arithmetic subtraction. Asserts no integer overflow.
sub,
/// Twos complement wrapping integer subtraction.
@@ -282,6 +290,8 @@ pub const Inst = struct {
xor,
/// Create an optional type '?T'
optional_type,
+ /// Create a union type.
+ union_type,
/// Unwraps an optional value 'lhs.?'
unwrap_optional_safe,
/// Same as previous, but without safety checks. Used for orelse, if and while
@@ -294,8 +304,10 @@ pub const Inst = struct {
unwrap_err_code,
/// Takes a *E!T and raises a compiler error if T != void
ensure_err_payload_void,
- /// Enum literal
+ /// Create a enum literal,
enum_literal,
+ /// Create an enum type.
+ enum_type,
/// A switch expression.
switchbr,
/// A range in a switch case, `lhs...rhs`.
@@ -430,6 +442,12 @@ pub const Inst = struct {
.slice => Slice,
.switchbr => SwitchBr,
.typeof_peer => TypeOfPeer,
+ .container_field_named => ContainerFieldNamed,
+ .container_field_typed => ContainerFieldTyped,
+ .container_field => ContainerField,
+ .enum_type => EnumType,
+ .union_type => UnionType,
+ .struct_type => StructType,
};
}
@@ -544,6 +562,9 @@ pub const Inst = struct {
.resolve_inferred_alloc,
.set_eval_branch_quota,
.compilelog,
+ .enum_type,
+ .union_type,
+ .struct_type,
=> false,
.@"break",
@@ -556,6 +577,9 @@ pub const Inst = struct {
.@"unreachable",
.loop,
.switchbr,
+ .container_field_named,
+ .container_field_typed,
+ .container_field,
=> true,
};
}
@@ -1079,6 +1103,88 @@ pub const Inst = struct {
},
kw_args: struct {},
};
+
+ pub const ContainerFieldNamed = struct {
+ pub const base_tag = Tag.container_field_named;
+ base: Inst,
+
+ positionals: struct {
+ bytes: []const u8,
+ },
+ kw_args: struct {},
+ };
+
+ pub const ContainerFieldTyped = struct {
+ pub const base_tag = Tag.container_field_typed;
+ base: Inst,
+
+ positionals: struct {
+ bytes: []const u8,
+ ty: *Inst,
+ },
+ kw_args: struct {},
+ };
+
+ pub const ContainerField = struct {
+ pub const base_tag = Tag.container_field;
+ base: Inst,
+
+ positionals: struct {
+ bytes: []const u8,
+ },
+ kw_args: struct {
+ ty: ?*Inst = null,
+ init: ?*Inst = null,
+ alignment: ?*Inst = null,
+ is_comptime: bool = false,
+ },
+ };
+
+ pub const EnumType = struct {
+ pub const base_tag = Tag.enum_type;
+ base: Inst,
+
+ positionals: struct {
+ fields: []*Inst,
+ },
+ kw_args: struct {
+ tag_type: ?*Inst = null,
+ layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
+ },
+ };
+
+ pub const StructType = struct {
+ pub const base_tag = Tag.struct_type;
+ base: Inst,
+
+ positionals: struct {
+ fields: []*Inst,
+ },
+ kw_args: struct {
+ layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
+ },
+ };
+
+ pub const UnionType = struct {
+ pub const base_tag = Tag.union_type;
+ base: Inst,
+
+ positionals: struct {
+ fields: []*Inst,
+ },
+ kw_args: struct {
+ init_inst: ?*Inst = null,
+ init_kind: InitKind = .none,
+ layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
+ },
+
+ // TODO error: values of type '(enum literal)' must be comptime known
+ pub const InitKind = enum {
+ enum_type,
+ tag_type,
+ none,
+ };
+ };
};
pub const ErrorMsg = struct {
diff --git a/src/zir_sema.zig b/src/zir_sema.zig
index 596cd5b24e..6302ab29e4 100644
--- a/src/zir_sema.zig
+++ b/src/zir_sema.zig
@@ -155,6 +155,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
.booland => return analyzeInstBoolOp(mod, scope, old_inst.castTag(.booland).?),
.boolor => return analyzeInstBoolOp(mod, scope, old_inst.castTag(.boolor).?),
+
+ .container_field_named,
+ .container_field_typed,
+ .container_field,
+ .enum_type,
+ .union_type,
+ .struct_type,
+ => return mod.fail(scope, old_inst.src, "TODO analyze container instructions", .{}),
}
}