parent
bfceb18631
commit
1543043bf5
|
@ -22,6 +22,7 @@ struct FnTableEntry;
|
||||||
struct BlockContext;
|
struct BlockContext;
|
||||||
struct TypeTableEntry;
|
struct TypeTableEntry;
|
||||||
struct VariableTableEntry;
|
struct VariableTableEntry;
|
||||||
|
struct ErrorTableEntry;
|
||||||
struct BuiltinFnEntry;
|
struct BuiltinFnEntry;
|
||||||
struct LabelTableEntry;
|
struct LabelTableEntry;
|
||||||
struct TypeStructField;
|
struct TypeStructField;
|
||||||
|
@ -69,6 +70,7 @@ struct ConstExprValue {
|
||||||
bool x_bool;
|
bool x_bool;
|
||||||
FnTableEntry *x_fn;
|
FnTableEntry *x_fn;
|
||||||
TypeTableEntry *x_type;
|
TypeTableEntry *x_type;
|
||||||
|
ErrorTableEntry *x_err;
|
||||||
ConstExprValue *x_maybe;
|
ConstExprValue *x_maybe;
|
||||||
ConstEnumValue x_enum;
|
ConstEnumValue x_enum;
|
||||||
ConstStructValue x_struct;
|
ConstStructValue x_struct;
|
||||||
|
@ -996,6 +998,7 @@ struct CodeGen {
|
||||||
LLVMValueRef memset_fn_val;
|
LLVMValueRef memset_fn_val;
|
||||||
bool error_during_imports;
|
bool error_during_imports;
|
||||||
uint32_t next_node_index;
|
uint32_t next_node_index;
|
||||||
|
uint32_t next_error_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VariableTableEntry {
|
struct VariableTableEntry {
|
||||||
|
@ -1010,12 +1013,19 @@ struct VariableTableEntry {
|
||||||
int gen_arg_index;
|
int gen_arg_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ErrorTableEntry {
|
||||||
|
Buf name;
|
||||||
|
uint32_t value;
|
||||||
|
AstNode *decl_node;
|
||||||
|
};
|
||||||
|
|
||||||
struct BlockContext {
|
struct BlockContext {
|
||||||
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
|
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
|
||||||
FnTableEntry *fn_entry; // null at the module scope
|
FnTableEntry *fn_entry; // null at the module scope
|
||||||
BlockContext *parent; // null when this is the root
|
BlockContext *parent; // null when this is the root
|
||||||
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
|
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
|
||||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
|
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
|
||||||
|
HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
|
||||||
ZigList<AstNode *> cast_alloca_list;
|
ZigList<AstNode *> cast_alloca_list;
|
||||||
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
|
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
|
||||||
ZigList<VariableTableEntry *> variable_list;
|
ZigList<VariableTableEntry *> variable_list;
|
||||||
|
|
117
src/analyze.cpp
117
src/analyze.cpp
|
@ -224,48 +224,26 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
|
||||||
return child_type->error_parent;
|
return child_type->error_parent;
|
||||||
} else {
|
} else {
|
||||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdError);
|
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdError);
|
||||||
zig_panic("TODO get_error_type");
|
|
||||||
// create a struct with a boolean whether this is the null value
|
|
||||||
assert(child_type->type_ref);
|
assert(child_type->type_ref);
|
||||||
LLVMTypeRef elem_types[] = {
|
|
||||||
child_type->type_ref,
|
|
||||||
LLVMInt1Type(),
|
|
||||||
};
|
|
||||||
entry->type_ref = LLVMStructType(elem_types, 2, false);
|
|
||||||
buf_resize(&entry->name, 0);
|
|
||||||
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
|
|
||||||
entry->size_in_bits = child_type->size_in_bits + 8;
|
|
||||||
entry->align_in_bits = child_type->align_in_bits;
|
|
||||||
assert(child_type->di_type);
|
assert(child_type->di_type);
|
||||||
|
|
||||||
|
buf_resize(&entry->name, 0);
|
||||||
|
buf_appendf(&entry->name, "%%%s", buf_ptr(&child_type->name));
|
||||||
|
|
||||||
LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
|
entry->data.error.child_type = child_type;
|
||||||
LLVMZigDIFile *di_file = nullptr;
|
|
||||||
unsigned line = 0;
|
|
||||||
entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
|
|
||||||
LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
|
|
||||||
compile_unit_scope, di_file, line);
|
|
||||||
|
|
||||||
LLVMZigDIType *di_element_types[] = {
|
if (child_type->size_in_bits == 0) {
|
||||||
LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
|
TypeTableEntry *tag_type = get_smallest_unsigned_int_type(g, g->next_error_index);
|
||||||
"val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
|
entry->type_ref = tag_type->type_ref;
|
||||||
child_type->di_type),
|
entry->size_in_bits = tag_type->size_in_bits;
|
||||||
LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
|
entry->align_in_bits = tag_type->align_in_bits;
|
||||||
"maybe", di_file, line, 8, 8, 8, 0,
|
entry->di_type = tag_type->di_type;
|
||||||
child_type->di_type),
|
|
||||||
};
|
|
||||||
LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
|
|
||||||
compile_unit_scope,
|
|
||||||
buf_ptr(&entry->name),
|
|
||||||
di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
|
|
||||||
nullptr, di_element_types, 2, 0, nullptr, "");
|
|
||||||
|
|
||||||
LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
|
} else {
|
||||||
entry->di_type = replacement_di_type;
|
zig_panic("TODO get_error_type non-void");
|
||||||
|
}
|
||||||
|
|
||||||
entry->data.maybe.child_type = child_type;
|
child_type->error_parent = entry;
|
||||||
|
|
||||||
child_type->maybe_parent = entry;
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -938,6 +916,40 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void resolve_error_value_decl(CodeGen *g, ImportTableEntry *import, 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);
|
||||||
|
if (existing_entry) {
|
||||||
|
add_node_error(g, node, buf_sprintf("redefinition of error '%s'", buf_ptr(&err->name)));
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
|
static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case NodeTypeExternBlock:
|
case NodeTypeExternBlock:
|
||||||
|
@ -984,10 +996,8 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeTypeErrorValueDecl:
|
case NodeTypeErrorValueDecl:
|
||||||
{
|
resolve_error_value_decl(g, import, node);
|
||||||
zig_panic("TODO resolve_top_level_decl NodeTypeErrorValueDecl");
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NodeTypeUse:
|
case NodeTypeUse:
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
break;
|
break;
|
||||||
|
@ -1388,6 +1398,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
|
||||||
context->parent = parent;
|
context->parent = parent;
|
||||||
context->variable_table.init(8);
|
context->variable_table.init(8);
|
||||||
context->type_table.init(8);
|
context->type_table.init(8);
|
||||||
|
context->error_table.init(8);
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
context->parent_loop_node = parent->parent_loop_node;
|
context->parent_loop_node = parent->parent_loop_node;
|
||||||
|
@ -1799,6 +1810,13 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F
|
||||||
return fn->type_entry;
|
return fn->type_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, ErrorTableEntry *err) {
|
||||||
|
Expr *expr = get_resolved_expr(node);
|
||||||
|
expr->const_val.ok = true;
|
||||||
|
expr->const_val.data.x_err = err;
|
||||||
|
return get_error_type(g, g->builtin_types.entry_void);
|
||||||
|
}
|
||||||
|
|
||||||
static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) {
|
static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) {
|
||||||
Expr *expr = get_resolved_expr(node);
|
Expr *expr = get_resolved_expr(node);
|
||||||
expr->const_val.ok = true;
|
expr->const_val.ok = true;
|
||||||
|
@ -2333,7 +2351,13 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Block
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
buf_init_from_buf(&variable_entry->name, name);
|
buf_init_from_buf(&variable_entry->name, name);
|
||||||
VariableTableEntry *existing_var = find_local_variable(context, name);
|
VariableTableEntry *existing_var;
|
||||||
|
|
||||||
|
if (context->fn_entry) {
|
||||||
|
existing_var = find_local_variable(context, name);
|
||||||
|
} else {
|
||||||
|
existing_var = find_variable(context, name);
|
||||||
|
}
|
||||||
|
|
||||||
if (existing_var) {
|
if (existing_var) {
|
||||||
add_node_error(g, source_node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
|
add_node_error(g, source_node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
|
||||||
|
@ -2511,7 +2535,18 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
|
||||||
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
|
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
|
||||||
BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
|
BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
|
||||||
{
|
{
|
||||||
zig_panic("TODO analyze_error_literal_expr");
|
Buf *err_name = &node->data.error_literal.symbol;
|
||||||
|
|
||||||
|
auto err_table_entry = import->block_context->error_table.maybe_get(err_name);
|
||||||
|
|
||||||
|
if (err_table_entry) {
|
||||||
|
return resolve_expr_const_val_as_err(g, node, err_table_entry->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||||
|
|
|
@ -26,6 +26,7 @@ CodeGen *codegen_create(Buf *root_source_dir) {
|
||||||
g->unresolved_top_level_decls.init(32);
|
g->unresolved_top_level_decls.init(32);
|
||||||
g->build_type = CodeGenBuildTypeDebug;
|
g->build_type = CodeGenBuildTypeDebug;
|
||||||
g->root_source_dir = root_source_dir;
|
g->root_source_dir = root_source_dir;
|
||||||
|
g->next_error_index = 1;
|
||||||
|
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1484,6 +1484,21 @@ struct A { x : i32, }
|
||||||
struct A { y : i32, }
|
struct A { y : i32, }
|
||||||
)SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'");
|
)SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'");
|
||||||
|
|
||||||
|
add_compile_fail_case("redefinition of enums", R"SOURCE(
|
||||||
|
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(
|
||||||
|
%.A;
|
||||||
|
%.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;
|
||||||
|
)SOURCE", 1, ".tmp_source.zig:3:1: error: redeclaration of variable 'a'");
|
||||||
|
|
||||||
add_compile_fail_case("byvalue struct on exported functions", R"SOURCE(
|
add_compile_fail_case("byvalue struct on exported functions", R"SOURCE(
|
||||||
struct A { x : i32, }
|
struct A { x : i32, }
|
||||||
export fn f(a : A) => {}
|
export fn f(a : A) => {}
|
||||||
|
@ -1608,6 +1623,7 @@ extern {
|
||||||
}
|
}
|
||||||
const x = foo();
|
const x = foo();
|
||||||
)SOURCE", 1, ".tmp_source.zig:5:11: error: global variable initializer requires constant expression");
|
)SOURCE", 1, ".tmp_source.zig:5:11: error: global variable initializer requires constant expression");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_compiler_invocation(TestCase *test_case) {
|
static void print_compiler_invocation(TestCase *test_case) {
|
||||||
|
|
Loading…
Reference in New Issue