Commit 1f9734d1ee

Andrew Kelley <superjoe30@gmail.com>
2016-02-04 08:58:45
allow defining errors with the same name
they get the same value, too.
1 parent a6d4335
src/all_types.hpp
@@ -271,6 +271,7 @@ struct AstNodeErrorValueDecl {
 
     // populated by semantic analyzer
     TopLevelDecl top_level_decl;
+    ErrorTableEntry *err;
 };
 
 enum BinOpType {
@@ -1034,6 +1035,7 @@ struct CodeGen {
     HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
     HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
     HashMap<FnTypeId, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
+    HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
 
     uint32_t next_unresolved_index;
 
@@ -1111,7 +1113,6 @@ struct CodeGen {
     LLVMValueRef trap_fn_val;
     bool error_during_imports;
     uint32_t next_node_index;
-    uint32_t next_error_index;
     uint32_t error_value_count;
     TypeTableEntry *err_tag_type;
     LLVMValueRef int_overflow_fns[2][3][4]; // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
src/analyze.cpp
@@ -1290,36 +1290,39 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
     }
 }
 
-static void resolve_error_value_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+static void preview_error_value_decl(CodeGen *g, AstNode *node) {
     assert(node->type == NodeTypeErrorValueDecl);
 
     ErrorTableEntry *err = allocate<ErrorTableEntry>(1);
 
-    err->value = g->next_error_index;
-    g->next_error_index += 1;
-
     err->decl_node = node;
     buf_init_from_buf(&err->name, &node->data.error_value_decl.name);
 
-    auto existing_entry = import->block_context->error_table.maybe_get(&err->name);
+    auto existing_entry = g->error_table.maybe_get(&err->name);
     if (existing_entry) {
-        add_node_error(g, node, buf_sprintf("redefinition of error '%s'", buf_ptr(&err->name)));
+        // duplicate error definitions allowed and they get the same value
+        err->value = existing_entry->value->value;
     } else {
-        import->block_context->error_table.put(&err->name, err);
+        err->value = g->error_value_count;
+        g->error_value_count += 1;
+        g->error_table.put(&err->name, err);
     }
 
+    node->data.error_value_decl.err = err;
+}
+
+static void resolve_error_value_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+    assert(node->type == NodeTypeErrorValueDecl);
+
+    ErrorTableEntry *err = node->data.error_value_decl.err;
+
+    import->block_context->error_table.put(&err->name, err);
+
     bool is_pub = (node->data.error_value_decl.visib_mod != VisibModPrivate);
     if (is_pub) {
         for (int i = 0; i < import->importers.length; i += 1) {
             ImporterInfo importer = import->importers.at(i);
-            auto table_entry = importer.import->block_context->error_table.maybe_get(&err->name);
-            if (table_entry) {
-                add_node_error(g, importer.source_node,
-                    buf_sprintf("import of error '%s' overrides existing definition",
-                        buf_ptr(&err->name)));
-            } else {
-                importer.import->block_context->error_table.put(&err->name, err);
-            }
+            importer.import->block_context->error_table.put(&err->name, err);
         }
     }
 }
@@ -2516,7 +2519,7 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
     add_node_error(g, node,
             buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
 
-    return get_error_type(g, g->builtin_types.entry_void);
+    return g->builtin_types.entry_invalid;
 }
 
 
@@ -2759,6 +2762,16 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
                 are_equal = true;
             }
         }
+        if (bin_op_type == BinOpTypeCmpEq) {
+            answer = are_equal;
+        } else if (bin_op_type == BinOpTypeCmpNotEq) {
+            answer = !are_equal;
+        } else {
+            zig_unreachable();
+        }
+    } else if (resolved_type->id == TypeTableEntryIdPureError) {
+        bool are_equal = op1_val->data.x_err.err == op2_val->data.x_err.err;
+
         if (bin_op_type == BinOpTypeCmpEq) {
             answer = are_equal;
         } else if (bin_op_type == BinOpTypeCmpNotEq) {
@@ -5402,7 +5415,7 @@ void semantic_analyze(CodeGen *g) {
 
                     target_import->importers.append({import, child});
                 } else if (child->type == NodeTypeErrorValueDecl) {
-                    g->error_value_count += 1;
+                    preview_error_value_decl(g, child);
                 }
             }
         }
@@ -5428,8 +5441,6 @@ void semantic_analyze(CodeGen *g) {
         }
     }
 
-    assert(g->error_value_count == g->next_error_index);
-
     {
         auto it = g->import_table.entry_iterator();
         for (;;) {
src/codegen.cpp
@@ -28,10 +28,10 @@ CodeGen *codegen_create(Buf *root_source_dir) {
     g->primitive_type_table.init(32);
     g->unresolved_top_level_decls.init(32);
     g->fn_type_table.init(32);
+    g->error_table.init(16);
     g->is_release_build = false;
     g->is_test_build = false;
     g->root_source_dir = root_source_dir;
-    g->next_error_index = 1;
     g->error_value_count = 1;
 
     g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);
test/run_tests.cpp
@@ -1789,11 +1789,6 @@ enum A {}
 enum A {}
     )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'");
 
-    add_compile_fail_case("redefinition of error values", R"SOURCE(
-error A;
-error A;
-    )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of error 'A'");
-
     add_compile_fail_case("redefinition of global variables", R"SOURCE(
 var a : i32 = 1;
 var a : i32 = 2;
test/self_hosted.zig
@@ -35,3 +35,14 @@ fn a_func() -> i32 { 13 }
 fn call_struct_field(foo: Foo) -> i32 {
     return foo.ptr();
 }
+
+
+
+error AnError;
+error AnError;
+error SecondError;
+
+#attribute("test")
+fn redefinition_of_error_values_allowed() {
+    if (error.AnError == error.SecondError) unreachable{}
+}