diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 54 | ||||
| -rw-r--r-- | src/astgen.zig | 177 | ||||
| -rw-r--r-- | src/type.zig | 142 | ||||
| -rw-r--r-- | src/type/Enum.zig | 55 | ||||
| -rw-r--r-- | src/type/Struct.zig | 56 | ||||
| -rw-r--r-- | src/type/Union.zig | 56 | ||||
| -rw-r--r-- | src/value.zig | 2 | ||||
| -rw-r--r-- | src/zir.zig | 108 | ||||
| -rw-r--r-- | src/zir_sema.zig | 8 |
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", .{}), } } |
