Commit f173d078c7

Vexu <git@vexu.eu>
2020-11-15 12:03:48
stage2: outline container types
1 parent 643f526
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(),
+    }
+}
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
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
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);
 }
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");
     };
 };
 
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 },