Commit 079728752e

Andrew Kelley <andrew@ziglang.org>
2019-02-20 14:04:46
deduplicate compile errors for undeclared identifiers
closes #111
1 parent 067968c
Changed files (3)
src/ir.cpp
@@ -3674,6 +3674,22 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode
     return ir_build_const_null(irb, scope, node);
 }
 
+static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode *node, Buf *var_name) {
+    ScopeDecls *scope_decls = nullptr;
+    while (scope != nullptr) {
+        if (scope->id == ScopeIdDecls) {
+            scope_decls = reinterpret_cast<ScopeDecls *>(scope);
+        }
+        scope = scope->parent;
+    }
+    TldVar *tld_var = allocate<TldVar>(1);
+    init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base);
+    tld_var->base.resolution = TldResolutionInvalid;
+    tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, 
+            &g->invalid_instruction->value, &tld_var->base, g->builtin_types.entry_invalid);
+    scope_decls->decl_table.put(var_name, &tld_var->base);
+}
+
 static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
     Error err;
     assert(node->type == NodeTypeSymbol);
@@ -3727,8 +3743,9 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
         return irb->codegen->invalid_instruction;
     }
 
-    // TODO put a variable of same name with invalid type in global scope
+    // put a variable of same name with invalid type in global scope
     // so that future references to this same name will find a variable with an invalid type
+    populate_invalid_variable_in_scope(irb->codegen, scope, node, variable_name);
     add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
     return irb->codegen->invalid_instruction;
 }
test/compile_errors.zig
@@ -1,6 +1,22 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.addCase(x: {
+        var tc = cases.create(
+            "deduplicate undeclared identifier",
+            \\export fn a() void {
+            \\    x += 1;
+            \\}
+            \\export fn b() void {
+            \\    x += 1;
+            \\}
+        ,
+            ".tmp_source.zig:2:5: error: use of undeclared identifier 'x'",
+        );
+        tc.expect_exact = true;
+        break :x tc;
+    });
+
     cases.addTest(
         "export generic function",
         \\export fn foo(num: var) i32 {
@@ -2280,7 +2296,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\}
     ,
         ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",
-        ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'",
     );
 
     cases.add(
@@ -5618,8 +5633,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         ".tmp_source.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",
     );
 
-    cases.add(
-        "compileLog of tagged enum doesn't crash the compiler",
+    cases.add("compileLog of tagged enum doesn't crash the compiler",
         \\const Bar = union(enum(u32)) {
         \\    X: i32 = 1
         \\};
@@ -5631,7 +5645,5 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\pub fn main () void {
         \\    comptime testCompileLog(Bar{.X = 123});
         \\}
-    ,
-        ".tmp_source.zig:6:5: error: found compile log statement"
-    );
+    , ".tmp_source.zig:6:5: error: found compile log statement");
 }
test/tests.zig
@@ -716,7 +716,8 @@ pub const CompileErrorContext = struct {
                 for (self.case.expected_errors.toSliceConst()) |expected| {
                     if (mem.indexOf(u8, stderr, expected) == null) {
                         warn(
-                            \\\n=========== Expected compile error: ============
+                            \\
+                            \\=========== Expected compile error: ============
                             \\{}
                             \\
                         , expected);