From f173d078c780c9946742c4ce686ccd0dccdb7e98 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Nov 2020 13:03:48 +0200 Subject: [PATCH] stage2: outline container types --- src/Module.zig | 30 +++++++++++++- src/type.zig | 99 ++++++++++++++++++++++++++++++++++++++++++++- src/type/Enum.zig | 55 +++++++++++++++++++++++++ src/type/Struct.zig | 57 ++++++++++++++++++++++++++ src/type/Union.zig | 57 ++++++++++++++++++++++++++ src/value.zig | 3 +- 6 files changed, 298 insertions(+), 3 deletions(-) create mode 100644 src/type/Enum.zig create mode 100644 src/type/Struct.zig create mode 100644 src/type/Union.zig diff --git a/src/Module.zig b/src/Module.zig index 81dc72e601..3e6be31be1 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -428,7 +428,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) { @@ -1515,6 +1515,7 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void // an incremental update. This code handles both cases. const tree = try self.getAstTree(container_scope); const decls = tree.root_node.decls(); + // const decls = container_scope.root_node.decls(); try self.comp.work_queue.ensureUnusedCapacity(decls.len); try container_scope.decls.ensureCapacity(self.gpa, decls.len); @@ -2272,6 +2273,33 @@ 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); + 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.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 base_name = switch (tree.token_ids[base_token]) { + .Keyword_struct => "struct", + .Keyword_enum => "enum", + .Keyword_union => "union", + 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); } diff --git a/src/type.zig b/src/type.zig index 31f84cdec4..02a5245e40 100644 --- a/src/type.zig +++ b/src/type.zig @@ -90,7 +90,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, } } @@ -442,6 +444,11 @@ pub const Type = extern union { .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle), .empty_struct => return self.copyPayloadShallow(allocator, Payload.EmptyStruct), + + // memory managed by the decl + .@"enum" => return self, + .@"struct" => return self, + .@"union" => return self, } } @@ -673,6 +680,10 @@ pub const Type = extern union { const payload = @fieldParentPtr(Payload.ErrorSetSingle, "base", ty.ptr_otherwise); return out_stream.print("error{{{}}}", .{payload.name}); }, + // TODO improve + .@"enum" => return out_stream.writeAll("enum {}"), + .@"struct" => return out_stream.writeAll("struct {}"), + .@"union" => return out_stream.writeAll("union {}"), } unreachable; } @@ -784,6 +795,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, @@ -908,6 +923,10 @@ pub const Type = extern union { @panic("TODO abiAlignment error union"); }, + .@"enum" => self.cast(Payload.Enum).?.abiAlignment(), + .@"struct" => @panic("TODO"), + .@"union" => @panic("TODO"), + .c_void, .void, .type, @@ -1050,6 +1069,10 @@ pub const Type = extern union { } @panic("TODO abiSize error union"); }, + + .@"enum" => @panic("TODO"), + .@"struct" => @panic("TODO"), + .@"union" => @panic("TODO"), }; } @@ -1117,6 +1140,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .single_const_pointer, @@ -1192,6 +1218,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .const_slice, @@ -1264,6 +1293,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .single_const_pointer, @@ -1345,6 +1377,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .pointer => { @@ -1421,6 +1456,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .pointer => { @@ -1539,6 +1577,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, .array => self.cast(Payload.Array).?.elem_type, @@ -1667,6 +1708,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, .array => self.cast(Payload.Array).?.len, @@ -1733,6 +1777,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, .single_const_pointer, @@ -1816,6 +1863,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .int_signed, @@ -1891,6 +1941,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .int_unsigned, @@ -1956,6 +2009,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits }, @@ -2039,6 +2095,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, .usize, @@ -2151,6 +2210,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, }; } @@ -2229,6 +2291,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, } } @@ -2306,6 +2371,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, } } @@ -2383,6 +2451,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, }; } @@ -2457,6 +2528,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, }; } @@ -2531,6 +2605,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => unreachable, }; } @@ -2605,6 +2682,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => false, }; } @@ -2664,6 +2744,10 @@ pub const Type = extern union { .error_set_single, => 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), @@ -2773,6 +2857,9 @@ pub const Type = extern union { .error_set, .error_set_single, .empty_struct, + .@"enum", + .@"struct", + .@"union", => return false, .c_const_pointer, @@ -2861,6 +2948,9 @@ pub const Type = extern union { => unreachable, .empty_struct => self.cast(Type.Payload.EmptyStruct).?.scope, + .@"enum" => &self.cast(Type.Payload.Enum).?.scope, + .@"struct" => &self.cast(Type.Payload.Struct).?.scope, + .@"union" => &self.cast(Type.Payload.Union).?.scope, }; } @@ -3012,6 +3102,9 @@ pub const Type = extern union { error_set, error_set_single, empty_struct, + @"enum", + @"struct", + @"union", pub const last_no_payload_tag = Tag.const_slice_u8; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -3127,6 +3220,10 @@ 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"); }; }; diff --git a/src/type/Enum.zig b/src/type/Enum.zig new file mode 100644 index 0000000000..0042ddc8bf --- /dev/null +++ b/src/type/Enum.zig @@ -0,0 +1,55 @@ +const std = @import("std"); +const Value = @import("../value.zig").Value; +const Type = @import("../type.zig").Type; +const Module = @import("../Module.zig"); +const Scope = Module.Scope; + +base: Type.Payload = .{ .tag = .@"enum" }, + +analysis: union(enum) { + queued: Zir, + in_progress, + resolved: Size, + failed, +}, + +pub const Field = struct { + value: Value, +}; + +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, + fields: std.AutoArrayHashMap([]const u8, 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) 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(), + } +} diff --git a/src/type/Struct.zig b/src/type/Struct.zig new file mode 100644 index 0000000000..bb1fe56995 --- /dev/null +++ b/src/type/Struct.zig @@ -0,0 +1,57 @@ +const std = @import("std"); +const Value = @import("../value.zig").Value; +const Type = @import("../type.zig").Type; +const Module = @import("../Module.zig"); +const Scope = Module.Scope; + +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, + arena: std.heap.ArenaAllocator.State, +}; + +pub const Zero = struct { + is_zero_bits: bool, + fields: std.AutoArrayHashMap([]const u8, Field), +}; + +pub const Size = struct { + is_zero_bits: bool, + alignment: u32, + size: u32, + fields: std.AutoArrayHashMap([]const u8, Field), +}; + +pub fn resolveZeroBits(self: *Enum, 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 +} + +pub fn resolveSize(self: *Enum,) \ No newline at end of file diff --git a/src/type/Union.zig b/src/type/Union.zig new file mode 100644 index 0000000000..bb1fe56995 --- /dev/null +++ b/src/type/Union.zig @@ -0,0 +1,57 @@ +const std = @import("std"); +const Value = @import("../value.zig").Value; +const Type = @import("../type.zig").Type; +const Module = @import("../Module.zig"); +const Scope = Module.Scope; + +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, + arena: std.heap.ArenaAllocator.State, +}; + +pub const Zero = struct { + is_zero_bits: bool, + fields: std.AutoArrayHashMap([]const u8, Field), +}; + +pub const Size = struct { + is_zero_bits: bool, + alignment: u32, + size: u32, + fields: std.AutoArrayHashMap([]const u8, Field), +}; + +pub fn resolveZeroBits(self: *Enum, 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 +} + +pub fn resolveSize(self: *Enum,) \ No newline at end of file diff --git a/src/value.zig b/src/value.zig index 8cbffecab6..5ca40d5f32 100644 --- a/src/value.zig +++ b/src/value.zig @@ -252,7 +252,7 @@ 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), + .error_set => return self, } } @@ -1865,6 +1865,7 @@ pub const Value = extern union { val: f128, }; + // TODO move to type.zig pub const ErrorSet = struct { base: Payload = .{ .tag = .error_set },