Commit 6a053ffcc8

Vexu <git@vexu.eu>
2020-08-20 17:50:13
stage2: comptime decl
1 parent d312d64
Changed files (3)
src-self-hosted/Module.zig
@@ -1485,6 +1485,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
                 const type_node = var_decl.getTrailer("type_node") orelse
                     break :blk null;
 
+                // Temporary arena for the zir instructions.
                 var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
                 defer type_scope_arena.deinit();
                 var type_scope: Scope.GenZIR = .{
@@ -1539,7 +1540,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
                             try self.coerce(&inner_block.base, some, ret.operand)
                         else
                             ret.operand;
-                        const val = try self.resolveConstValue(&inner_block.base, coerced);
+                        const val = coerced.value() orelse
+                            return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
 
                         var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena);
                         break :blk try val.copy(block_scope.arena);
@@ -1603,7 +1605,41 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
             }
             return type_changed;
         },
-        .Comptime => @panic("TODO comptime decl"),
+        .Comptime => {
+            const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node);
+
+            decl.analysis = .in_progress;
+
+            // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
+            var analysis_arena = std.heap.ArenaAllocator.init(self.gpa);
+            defer analysis_arena.deinit();
+            var gen_scope: Scope.GenZIR = .{
+                .decl = decl,
+                .arena = &analysis_arena.allocator,
+                .parent = decl.scope,
+            };
+            defer gen_scope.instructions.deinit(self.gpa);
+
+            // TODO comptime scope here
+            _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr);
+
+            var block_scope: Scope.Block = .{
+                .parent = null,
+                .func = null,
+                .decl = decl,
+                .instructions = .{},
+                .arena = &analysis_arena.allocator,
+            };
+            defer block_scope.instructions.deinit(self.gpa);
+
+            _ = try zir_sema.analyzeBody(self, &block_scope.base, .{
+                .instructions = gen_scope.instructions.items,
+            });
+
+            decl.analysis = .complete;
+            decl.generation = self.generation;
+            return true;
+        },
         .Use => @panic("TODO usingnamespace decl"),
         else => unreachable,
     }
@@ -1794,7 +1830,16 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
                 }
             }
         } else if (src_decl.castTag(.Comptime)) |comptime_node| {
-            log.err("TODO: analyze comptime decl", .{});
+            const name_index = self.getNextAnonNameIndex();
+            const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
+            defer self.gpa.free(name);
+
+            const name_hash = root_scope.fullyQualifiedNameHash(name);
+            const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
+
+            const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
+            root_scope.decls.appendAssumeCapacity(new_decl);
+            self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
         } else if (src_decl.castTag(.ContainerField)) |container_field| {
             log.err("TODO: analyze container field", .{});
         } else if (src_decl.castTag(.TestDecl)) |test_decl| {
test/stage2/compare_output.zig
@@ -23,11 +23,6 @@ pub fn addCases(ctx: *TestContext) !void {
 
         case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
 
-        case.addError(
-            \\export fn _start() noreturn {
-            \\}
-        , &[_][]const u8{":2:1: error: expected noreturn, found void"});
-
         // Regular old hello world
         case.addCompareOutput(
             \\export fn _start() noreturn {
test/stage2/compile_errors.zig
@@ -67,6 +67,18 @@ pub fn addCases(ctx: *TestContext) !void {
         \\fn entry() void {}
     , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
 
+    ctx.compileError("incorrect return type", linux_x64,
+        \\export fn _start() noreturn {
+        \\}
+    , &[_][]const u8{":2:1: error: expected noreturn, found void"});
+
+    ctx.compileError("extern variable has no type", linux_x64,
+        \\comptime {
+        \\    _ = foo;
+        \\}
+        \\extern var foo;
+    , &[_][]const u8{":4:1: error: unable to infer variable type"});
+
     //ctx.incrementalFailure("function redefinition", linux_x64,
     //    \\fn entry() void {}
     //    \\fn entry() void {}
@@ -108,28 +120,4 @@ pub fn addCases(ctx: *TestContext) !void {
     //    \\    return 36893488147419103232;
     //    \\}
     //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
-
-    //ctx.testCompileError(
-    //    \\comptime {
-    //    \\    var a: *align(4) align(4) i32 = 0;
-    //    \\}
-    //, "1.zig", 2, 22, "Extra align qualifier");
-
-    //ctx.testCompileError(
-    //    \\comptime {
-    //    \\    var b: *const const i32 = 0;
-    //    \\}
-    //, "1.zig", 2, 19, "Extra align qualifier");
-
-    //ctx.testCompileError(
-    //    \\comptime {
-    //    \\    var c: *volatile volatile i32 = 0;
-    //    \\}
-    //, "1.zig", 2, 22, "Extra align qualifier");
-
-    //ctx.testCompileError(
-    //    \\comptime {
-    //    \\    var d: *allowzero allowzero i32 = 0;
-    //    \\}
-    //, "1.zig", 2, 23, "Extra align qualifier");
 }