Commit c1e19f4c0a
Changed files (8)
src/type/Enum.zig
@@ -1,8 +1,10 @@
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" },
@@ -12,6 +14,7 @@ analysis: union(enum) {
resolved: Size,
failed,
},
+scope: Scope.Container,
pub const Field = struct {
value: Value,
@@ -20,13 +23,10 @@ pub const Field = struct {
pub const Zir = struct {
body: zir.Module.Body,
inst: *zir.Inst,
- arena: std.heap.ArenaAllocator.State,
};
pub const Size = struct {
- is_zero_bits: bool,
- alignment: u32,
- size: u32,
+ tag_type: Type,
fields: std.AutoArrayHashMap([]const u8, Field),
};
@@ -45,11 +45,11 @@ pub fn resolve(self: *Enum, mod: *Module, scope: *Scope) !void {
}
// TODO should this resolve the type or assert that it has already been resolved?
-pub fn abiAlignment(self: *Enum) u32 {
+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(),
+ .resolved => |r| return r.tag_type.abiAlignment(target),
}
}
src/type/Struct.zig
@@ -1,8 +1,10 @@
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" },
@@ -11,7 +13,7 @@ analysis: union(enum) {
zero_bits_in_progress,
zero_bits: Zero,
in_progress,
- alignment: Align,
+ // alignment: Align,
resolved: Size,
failed,
},
@@ -24,7 +26,6 @@ pub const Field = struct {
pub const Zir = struct {
body: zir.Module.Body,
inst: *zir.Inst,
- arena: std.heap.ArenaAllocator.State,
};
pub const Zero = struct {
@@ -39,11 +40,11 @@ pub const Size = struct {
fields: std.AutoArrayHashMap([]const u8, Field),
};
-pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void {
+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, "union '{}' depends on itself", .{});
+ return mod.fail(scope, src, "struct '{}' depends on itself", .{});
},
.queued => |zir| zir,
else => return,
@@ -53,5 +54,3 @@ pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void {
// TODO
}
-
-pub fn resolveSize(self: *Enum,)
\ No newline at end of file
src/type/Union.zig
@@ -1,8 +1,10 @@
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" },
@@ -11,7 +13,7 @@ analysis: union(enum) {
zero_bits_in_progress,
zero_bits: Zero,
in_progress,
- alignment: Align,
+ // alignment: Align,
resolved: Size,
failed,
},
@@ -24,7 +26,6 @@ pub const Field = struct {
pub const Zir = struct {
body: zir.Module.Body,
inst: *zir.Inst,
- arena: std.heap.ArenaAllocator.State,
};
pub const Zero = struct {
@@ -39,7 +40,7 @@ pub const Size = struct {
fields: std.AutoArrayHashMap([]const u8, Field),
};
-pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void {
+pub fn resolveZeroBits(self: *Union, mod: *Module, scope: *Scope) !void {
const zir = switch (self.analysis) {
.failed => return error.AnalysisFail,
.zero_bits_in_progress => {
@@ -53,5 +54,3 @@ pub fn resolveZeroBits(self: *Enum, mod: *Module, scope: *Scope) !void {
// TODO
}
-
-pub fn resolveSize(self: *Enum,)
\ No newline at end of file
src/astgen.zig
@@ -281,6 +281,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
.Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}),
.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", .{}),
}
}
@@ -765,6 +765,168 @@ 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 identifierTokenString(mod, 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 => return mod.fail(scope, src, "TODO opaque containers", .{}),
+ else => unreachable,
+ };
+ const type_payload = try arena.create(Value.Payload.Ty);
+ type_payload.* = .{
+ .ty = container_type,
+ };
+ const decl = try mod.createContainerDecl(scope, node.kind_token, &decl_arena, .{
+ .ty = Type.initTag(.type),
+ .val = Value.initPayload(&type_payload.base),
+ });
+ 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;
src/Module.zig
@@ -469,12 +469,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,
@@ -550,7 +550,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 {
@@ -2273,8 +2273,15 @@ pub fn createAnonymousDecl(
return new_decl;
}
-fn createContainerDecl(self: *Module, scope: *Scope, container_node: *std.zig.ast.Node.ContainerDecl) !*Decl {
- const name = try self.getAnonTypeName(scope, container_node.kind_token);
+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;
@@ -2282,18 +2289,25 @@ fn createContainerDecl(self: *Module, scope: *Scope, container_node: *std.zig.as
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 {
- const container = scope.getContainer();
- const tree = self.getAstTree(container);
+ 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]);
@@ -2487,7 +2501,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);
src/type.zig
@@ -923,7 +923,7 @@ pub const Type = extern union {
@panic("TODO abiAlignment error union");
},
- .@"enum" => self.cast(Payload.Enum).?.abiAlignment(),
+ .@"enum" => self.cast(Payload.Enum).?.abiAlignment(target),
.@"struct" => @panic("TODO"),
.@"union" => @panic("TODO"),
@@ -3221,9 +3221,9 @@ pub const Type = extern union {
scope: *Module.Scope.Container,
};
- pub const Enum = @import("value/Enum.zig");
- pub const Struct = @import("value/Struct.zig");
- pub const Union = @import("value/Union.zig");
+ pub const Enum = @import("type/Enum.zig");
+ pub const Struct = @import("type/Struct.zig");
+ pub const Union = @import("type/Union.zig");
};
};
src/zir.zig
@@ -1084,12 +1084,13 @@ pub const Inst = struct {
positionals: struct {
bytes: []const u8,
- ty: ?*Inst,
- init: ?*Inst,
- alignment: ?*Inst,
- is_comptime: bool,
},
- kw_args: struct {},
+ kw_args: struct {
+ ty: ?*Inst = null,
+ init: ?*Inst = null,
+ alignment: ?*Inst = null,
+ is_comptime: bool = false,
+ },
};
pub const EnumType = struct {
@@ -1125,13 +1126,17 @@ pub const Inst = struct {
fields: []*Inst,
},
kw_args: struct {
- init_expr: union(enum) {
- enum_type: ?*Inst,
- tag_type: *Inst,
- none,
- },
+ 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,
+ };
};
};
src/zir_sema.zig
@@ -139,6 +139,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", .{}),
}
}