allow defining errors with the same name

they get the same value, too.
master
Andrew Kelley 2016-02-04 00:58:45 -07:00
parent a6d4335217
commit 1f9734d1ee
5 changed files with 44 additions and 26 deletions

View File

@ -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]

View File

@ -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 (;;) {

View File

@ -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);

View File

@ -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;

View File

@ -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{}
}