order-independent declarations

code constructs and traverses a dependency graph in a deterministic
order.
This commit is contained in:
Andrew Kelley 2016-01-09 23:49:22 -07:00
parent 6d9119fcd9
commit 1fe1235e14
6 changed files with 504 additions and 202 deletions

View File

@ -14,6 +14,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
TypeTableEntry *expected_type, AstNode *node); TypeTableEntry *expected_type, AstNode *node);
static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
AstNode *node, AstNodeNumberLiteral *out_number_literal); AstNode *node, AstNodeNumberLiteral *out_number_literal);
static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, DeclNode *decl_node);
static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
static AstNode *first_executing_node(AstNode *node) { static AstNode *first_executing_node(AstNode *node) {
switch (node->type) { switch (node->type) {
@ -438,6 +441,9 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
{ {
Buf *name = &node->data.type.primitive_name; Buf *name = &node->data.type.primitive_name;
auto table_entry = import->type_table.maybe_get(name); auto table_entry = import->type_table.maybe_get(name);
if (!table_entry) {
table_entry = g->primitive_type_table.maybe_get(name);
}
if (table_entry) { if (table_entry) {
type_node->entry = table_entry->value; type_node->entry = table_entry->value;
} else { } else {
@ -716,10 +722,19 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
} }
} }
static void preview_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node, TypeTableEntry *struct_type) { static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
assert(node->type == NodeTypeFnDef); AstNode *proto_node)
AstNode *proto_node = node->data.fn_def.fn_proto; {
assert(proto_node->type == NodeTypeFnProto); AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node;
AstNode *extern_node = proto_node->data.fn_proto.extern_node;
AstNode *struct_node = proto_node->data.fn_proto.struct_node;
TypeTableEntry *struct_type;
if (struct_node) {
struct_type = struct_node->codegen_node->data.struct_decl_node.type_entry;
} else {
struct_type = nullptr;
}
Buf *proto_name = &proto_node->data.fn_proto.name; Buf *proto_name = &proto_node->data.fn_proto.name;
auto fn_table = struct_type ? &struct_type->data.structure.fn_table : &import->fn_table; auto fn_table = struct_type ? &struct_type->data.structure.fn_table : &import->fn_table;
@ -727,69 +742,74 @@ static void preview_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node,
auto entry = fn_table->maybe_get(proto_name); auto entry = fn_table->maybe_get(proto_name);
bool skip = false; bool skip = false;
bool is_internal = (proto_node->data.fn_proto.visib_mod != VisibModExport); bool is_internal = (proto_node->data.fn_proto.visib_mod != VisibModExport);
bool is_c_compat = !is_internal || extern_node;
bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate); bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate);
if (entry) { if (entry) {
add_node_error(g, node, add_node_error(g, proto_node,
buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
alloc_codegen_node(node); proto_node->codegen_node->data.fn_proto_node.skip = true;
node->codegen_node->data.fn_def_node.skip = true;
skip = true; skip = true;
} else if (is_pub) { } else if (is_pub) {
auto entry = fn_table->maybe_get(proto_name); auto entry = fn_table->maybe_get(proto_name);
if (entry) { if (entry) {
add_node_error(g, node, add_node_error(g, proto_node, buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); proto_node->codegen_node->data.fn_proto_node.skip = true;
alloc_codegen_node(node);
node->codegen_node->data.fn_def_node.skip = true;
skip = true; skip = true;
} }
} }
if (proto_node->data.fn_proto.is_var_args) { if (!extern_node && proto_node->data.fn_proto.is_var_args) {
add_node_error(g, node, add_node_error(g, proto_node,
buf_sprintf("variadic arguments only allowed in extern functions")); buf_sprintf("variadic arguments only allowed in extern functions"));
} }
if (!skip) { if (skip) {
FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); return;
fn_table_entry->import_entry = import; }
fn_table_entry->proto_node = proto_node;
fn_table_entry->fn_def_node = node;
fn_table_entry->internal_linkage = is_internal;
fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv;
fn_table_entry->label_table.init(8);
fn_table_entry->member_of_struct = struct_type;
if (struct_type) { FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
buf_resize(&fn_table_entry->symbol_name, 0); fn_table_entry->import_entry = import;
buf_appendf(&fn_table_entry->symbol_name, "%s_%s", fn_table_entry->proto_node = proto_node;
buf_ptr(&struct_type->name), fn_table_entry->fn_def_node = fn_def_node;
buf_ptr(proto_name)); fn_table_entry->internal_linkage = !is_c_compat;
} else { fn_table_entry->is_extern = extern_node;
buf_init_from_buf(&fn_table_entry->symbol_name, proto_name); fn_table_entry->calling_convention = is_c_compat ? LLVMCCallConv : LLVMFastCallConv;
} fn_table_entry->label_table.init(8);
fn_table_entry->member_of_struct = struct_type;
g->fn_protos.append(fn_table_entry); if (struct_type) {
buf_resize(&fn_table_entry->symbol_name, 0);
buf_appendf(&fn_table_entry->symbol_name, "%s_%s",
buf_ptr(&struct_type->name),
buf_ptr(proto_name));
} else {
buf_init_from_buf(&fn_table_entry->symbol_name, proto_name);
}
g->fn_protos.append(fn_table_entry);
if (!extern_node) {
g->fn_defs.append(fn_table_entry); g->fn_defs.append(fn_table_entry);
}
fn_table->put(proto_name, fn_table_entry); fn_table->put(proto_name, fn_table_entry);
if (!struct_type && if (!struct_type &&
g->bootstrap_import && g->bootstrap_import &&
import == g->root_import && buf_eql_str(proto_name, "main")) import == g->root_import && buf_eql_str(proto_name, "main"))
{ {
g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); g->bootstrap_import->fn_table.put(proto_name, fn_table_entry);
} }
resolve_function_proto(g, proto_node, fn_table_entry, import); resolve_function_proto(g, proto_node, fn_table_entry, import);
alloc_codegen_node(proto_node); proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
preview_function_labels(g, node->data.fn_def.body, fn_table_entry); if (fn_def_node) {
preview_function_labels(g, fn_def_node->data.fn_def.body, fn_table_entry);
} }
} }
static void preview_function_declarations(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:
for (int i = 0; i < node->data.extern_block.directives->length; i += 1) { for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
@ -803,33 +823,9 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
buf_sprintf("invalid directive: '%s'", buf_ptr(name))); buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
} }
} }
for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
assert(fn_decl->type == NodeTypeFnDecl);
AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
fn_table_entry->proto_node = fn_proto;
fn_table_entry->is_extern = true;
fn_table_entry->calling_convention = LLVMCCallConv;
fn_table_entry->import_entry = import;
fn_table_entry->label_table.init(8);
buf_init_from_buf(&fn_table_entry->symbol_name, &fn_proto->data.fn_proto.name);
resolve_function_proto(g, fn_proto, fn_table_entry, import);
Buf *name = &fn_proto->data.fn_proto.name;
g->fn_protos.append(fn_table_entry);
import->fn_table.put(name, fn_table_entry);
alloc_codegen_node(fn_proto);
fn_proto->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
}
break; break;
case NodeTypeFnDef: case NodeTypeFnProto:
preview_fn_def(g, import, node, nullptr); preview_fn_proto(g, import, node);
break; break;
case NodeTypeRootExportDecl: case NodeTypeRootExportDecl:
if (import == g->root_import) { if (import == g->root_import) {
@ -881,95 +877,22 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
resolve_struct_type(g, import, type_entry); resolve_struct_type(g, import, type_entry);
for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { // struct member fns will get resolved independently
AstNode *fn_def_node = node->data.struct_decl.fns.at(i); break;
preview_fn_def(g, import, fn_def_node, type_entry); }
} case NodeTypeVariableDeclaration:
{
VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
nullptr, node);
g->global_vars.append(var);
break; break;
} }
case NodeTypeUse: case NodeTypeUse:
case NodeTypeVariableDeclaration:
// nothing to do here // nothing to do here
break; break;
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeFnProto:
case NodeTypeType:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeRoot:
case NodeTypeBlock:
case NodeTypeBinOpExpr:
case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeUnreachable:
case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeSymbol:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr:
case NodeTypeIfBoolExpr:
case NodeTypeIfVarExpr:
case NodeTypeWhileExpr:
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
case NodeTypeStructValueExpr:
case NodeTypeStructValueField:
case NodeTypeCompilerFnExpr:
case NodeTypeCompilerFnType:
zig_unreachable();
}
}
static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) {
case NodeTypeStructDecl:
{
alloc_codegen_node(node);
StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node;
Buf *name = &node->data.struct_decl.name;
auto table_entry = import->type_table.maybe_get(name);
if (table_entry) {
struct_codegen->type_entry = table_entry->value;
add_node_error(g, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name));
entry->data.structure.decl_node = node;
entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
LLVMZigTag_DW_structure_type(), buf_ptr(&node->data.struct_decl.name),
LLVMZigFileToScope(import->di_file), import->di_file, node->line + 1);
buf_init_from_buf(&entry->name, name);
// put off adding the debug type until we do the full struct body
// this type is incomplete until we do another pass
import->type_table.put(&entry->name, entry);
struct_codegen->type_entry = entry;
}
break;
}
case NodeTypeExternBlock:
case NodeTypeFnDef: case NodeTypeFnDef:
case NodeTypeRootExportDecl:
case NodeTypeUse:
case NodeTypeVariableDeclaration:
// nothing to do
break;
case NodeTypeDirective: case NodeTypeDirective:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeFnProto:
case NodeTypeType: case NodeTypeType:
case NodeTypeFnDecl: case NodeTypeFnDecl:
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
@ -2552,15 +2475,15 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeFnDef); assert(node->type == NodeTypeFnDef);
if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) { AstNode *fn_proto_node = node->data.fn_def.fn_proto;
assert(fn_proto_node->type == NodeTypeFnProto);
if (fn_proto_node->codegen_node->data.fn_proto_node.skip) {
// we detected an error with this function definition which prevents us // we detected an error with this function definition which prevents us
// from further analyzing it. // from further analyzing it.
return; return;
} }
AstNode *fn_proto_node = node->data.fn_def.fn_proto;
assert(fn_proto_node->type == NodeTypeFnProto);
alloc_codegen_node(node); alloc_codegen_node(node);
BlockContext *context = new_block_context(node, import->block_context); BlockContext *context = new_block_context(node, import->block_context);
node->codegen_node->data.fn_def_node.block_context = context; node->codegen_node->data.fn_def_node.block_context = context;
@ -2630,7 +2553,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
} }
} }
static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) { switch (node->type) {
case NodeTypeFnDef: case NodeTypeFnDef:
analyze_top_level_fn_def(g, import, node); analyze_top_level_fn_def(g, import, node);
@ -2733,12 +2656,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
break; break;
} }
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
{ // handled in resolve phase
VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context, break;
nullptr, node);
g->global_vars.append(var);
break;
}
case NodeTypeDirective: case NodeTypeDirective:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeFnProto: case NodeTypeFnProto:
@ -2779,24 +2698,389 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
} }
} }
static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *expr_node,
assert(node->type == NodeTypeRoot); DeclNode *decl_node)
{
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { switch (expr_node->type) {
AstNode *child = node->data.root.top_level_decls.at(i); case NodeTypeNumberLiteral:
preview_function_declarations(g, import, child); case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeUnreachable:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
// no dependencies on other top level declarations
break;
case NodeTypeSymbol:
decl_node->deps.put(&expr_node->data.symbol, expr_node);
break;
case NodeTypeBinOpExpr:
collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op1, decl_node);
collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op2, decl_node);
break;
case NodeTypeReturnExpr:
collect_expr_decl_deps(g, import, expr_node->data.return_expr.expr, decl_node);
break;
case NodeTypeCastExpr:
collect_expr_decl_deps(g, import, expr_node->data.cast_expr.expr, decl_node);
collect_type_decl_deps(g, import, expr_node->data.cast_expr.type, decl_node);
break;
case NodeTypePrefixOpExpr:
collect_expr_decl_deps(g, import, expr_node->data.prefix_op_expr.primary_expr, decl_node);
break;
case NodeTypeFnCallExpr:
collect_expr_decl_deps(g, import, expr_node->data.fn_call_expr.fn_ref_expr, decl_node);
for (int i = 0; i < expr_node->data.fn_call_expr.params.length; i += 1) {
AstNode *arg_node = expr_node->data.fn_call_expr.params.at(i);
collect_expr_decl_deps(g, import, arg_node, decl_node);
}
break;
case NodeTypeArrayAccessExpr:
collect_expr_decl_deps(g, import, expr_node->data.array_access_expr.array_ref_expr, decl_node);
collect_expr_decl_deps(g, import, expr_node->data.array_access_expr.subscript, decl_node);
break;
case NodeTypeSliceExpr:
collect_expr_decl_deps(g, import, expr_node->data.slice_expr.array_ref_expr, decl_node);
collect_expr_decl_deps(g, import, expr_node->data.slice_expr.start, decl_node);
if (expr_node->data.slice_expr.end) {
collect_expr_decl_deps(g, import, expr_node->data.slice_expr.end, decl_node);
}
break;
case NodeTypeFieldAccessExpr:
collect_expr_decl_deps(g, import, expr_node->data.field_access_expr.struct_expr, decl_node);
break;
case NodeTypeIfBoolExpr:
collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.condition, decl_node);
collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.then_block, decl_node);
if (expr_node->data.if_bool_expr.else_node) {
collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.else_node, decl_node);
}
break;
case NodeTypeIfVarExpr:
if (expr_node->data.if_var_expr.var_decl.type) {
collect_type_decl_deps(g, import, expr_node->data.if_var_expr.var_decl.type, decl_node);
}
if (expr_node->data.if_var_expr.var_decl.expr) {
collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.var_decl.expr, decl_node);
}
collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.then_block, decl_node);
if (expr_node->data.if_bool_expr.else_node) {
collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.else_node, decl_node);
}
break;
case NodeTypeWhileExpr:
collect_expr_decl_deps(g, import, expr_node->data.while_expr.condition, decl_node);
collect_expr_decl_deps(g, import, expr_node->data.while_expr.body, decl_node);
break;
case NodeTypeBlock:
for (int i = 0; i < expr_node->data.block.statements.length; i += 1) {
AstNode *stmt = expr_node->data.block.statements.at(i);
collect_expr_decl_deps(g, import, stmt, decl_node);
}
break;
case NodeTypeAsmExpr:
for (int i = 0; i < expr_node->data.asm_expr.output_list.length; i += 1) {
AsmOutput *asm_output = expr_node->data.asm_expr.output_list.at(i);
if (asm_output->return_type) {
collect_type_decl_deps(g, import, asm_output->return_type, decl_node);
} else {
decl_node->deps.put(&asm_output->variable_name, expr_node);
}
}
for (int i = 0; i < expr_node->data.asm_expr.input_list.length; i += 1) {
AsmInput *asm_input = expr_node->data.asm_expr.input_list.at(i);
collect_expr_decl_deps(g, import, asm_input->expr, decl_node);
}
break;
case NodeTypeStructValueExpr:
collect_type_decl_deps(g, import, expr_node->data.struct_val_expr.type, decl_node);
for (int i = 0; i < expr_node->data.struct_val_expr.fields.length; i += 1) {
AstNode *field_node = expr_node->data.struct_val_expr.fields.at(i);
assert(field_node->type == NodeTypeStructValueField);
collect_expr_decl_deps(g, import, field_node->data.struct_val_field.expr, decl_node);
}
break;
case NodeTypeCompilerFnExpr:
collect_expr_decl_deps(g, import, expr_node->data.compiler_fn_expr.expr, decl_node);
break;
case NodeTypeCompilerFnType:
collect_type_decl_deps(g, import, expr_node->data.compiler_fn_type.type, decl_node);
break;
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeFnProto:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeType:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeVariableDeclaration:
case NodeTypeUse:
case NodeTypeLabel:
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
zig_unreachable();
} }
} }
static void preview_types_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, DeclNode *decl_node) {
assert(type_node->type == NodeTypeType);
switch (type_node->data.type.type) {
case AstNodeTypeTypePrimitive:
{
Buf *name = &type_node->data.type.primitive_name;
auto table_entry = g->primitive_type_table.maybe_get(name);
if (!table_entry) {
table_entry = import->type_table.maybe_get(name);
}
if (!table_entry) {
decl_node->deps.put(name, type_node);
}
break;
}
case AstNodeTypeTypePointer:
collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node);
break;
case AstNodeTypeTypeArray:
collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node);
if (type_node->data.type.array_size) {
collect_expr_decl_deps(g, import, type_node->data.type.array_size, decl_node);
}
break;
case AstNodeTypeTypeMaybe:
collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node);
break;
case AstNodeTypeTypeCompilerExpr:
collect_expr_decl_deps(g, import, type_node->data.type.compiler_expr, decl_node);
break;
}
}
static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) {
case NodeTypeStructDecl:
{
alloc_codegen_node(node);
StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node;
Buf *name = &node->data.struct_decl.name;
auto table_entry = import->type_table.maybe_get(name);
if (!table_entry) {
table_entry = g->primitive_type_table.maybe_get(name);
}
if (table_entry) {
struct_codegen->type_entry = table_entry->value;
add_node_error(g, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name));
entry->data.structure.decl_node = node;
entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
LLVMZigTag_DW_structure_type(), buf_ptr(&node->data.struct_decl.name),
LLVMZigFileToScope(import->di_file), import->di_file, node->line + 1);
buf_init_from_buf(&entry->name, name);
// put off adding the debug type until we do the full struct body
// this type is incomplete until we do another pass
import->type_table.put(&entry->name, entry);
struct_codegen->type_entry = entry;
}
// determine which other top level declarations this struct depends on.
DeclNode *decl_node = &node->codegen_node->decl_node;
for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) {
AstNode *field_node = node->data.struct_decl.fields.at(i);
AstNode *type_node = field_node->data.struct_field.type;
collect_type_decl_deps(g, import, type_node, decl_node);
}
node->codegen_node->decl_node.name = name;
node->codegen_node->decl_node.import = import;
if (decl_node->deps.size() > 0) {
g->unresolved_top_level_decls.put(name, node);
} else {
resolve_top_level_decl(g, import, node);
}
// handle the member function definitions independently
for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
AstNode *fn_def_node = node->data.struct_decl.fns.at(i);
AstNode *fn_proto_node = fn_def_node->data.fn_def.fn_proto;
fn_proto_node->data.fn_proto.struct_node = node;
detect_top_level_decl_deps(g, import, fn_def_node);
}
break;
}
case NodeTypeExternBlock:
for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
assert(fn_decl->type == NodeTypeFnDecl);
AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
fn_proto->data.fn_proto.extern_node = node;
detect_top_level_decl_deps(g, import, fn_proto);
}
resolve_top_level_decl(g, import, node);
break;
case NodeTypeFnDef:
node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;
detect_top_level_decl_deps(g, import, node->data.fn_def.fn_proto);
break;
case NodeTypeVariableDeclaration:
{
// determine which other top level declarations this variable declaration depends on.
alloc_codegen_node(node);
DeclNode *decl_node = &node->codegen_node->decl_node;
if (node->data.variable_declaration.type) {
collect_type_decl_deps(g, import, node->data.variable_declaration.type, decl_node);
}
if (node->data.variable_declaration.expr) {
collect_expr_decl_deps(g, import, node->data.variable_declaration.expr, decl_node);
}
Buf *name = &node->data.variable_declaration.symbol;
node->codegen_node->decl_node.name = name;
node->codegen_node->decl_node.import = import;
if (decl_node->deps.size() > 0) {
g->unresolved_top_level_decls.put(name, node);
} else {
resolve_top_level_decl(g, import, node);
}
break;
}
case NodeTypeFnProto:
{
// determine which other top level declarations this function prototype depends on.
alloc_codegen_node(node);
DeclNode *decl_node = &node->codegen_node->decl_node;
for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
AstNode *param_node = node->data.fn_proto.params.at(i);
assert(param_node->type == NodeTypeParamDecl);
collect_type_decl_deps(g, import, param_node->data.param_decl.type, decl_node);
}
Buf *name = &node->data.fn_proto.name;
node->codegen_node->decl_node.name = name;
node->codegen_node->decl_node.import = import;
if (decl_node->deps.size() > 0) {
g->unresolved_top_level_decls.put(name, node);
} else {
resolve_top_level_decl(g, import, node);
}
break;
}
case NodeTypeRootExportDecl:
resolve_top_level_decl(g, import, node);
break;
case NodeTypeUse:
// nothing to do
break;
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeType:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeRoot:
case NodeTypeBlock:
case NodeTypeBinOpExpr:
case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeUnreachable:
case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeSymbol:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr:
case NodeTypeIfBoolExpr:
case NodeTypeIfVarExpr:
case NodeTypeWhileExpr:
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
case NodeTypeStructValueExpr:
case NodeTypeStructValueField:
case NodeTypeCompilerFnExpr:
case NodeTypeCompilerFnType:
zig_unreachable();
}
}
static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
auto it = node->codegen_node->decl_node.deps.entry_iterator();
for (;;) {
auto *entry = it.next();
if (!entry)
break;
auto unresolved_entry = g->unresolved_top_level_decls.maybe_get(entry->key);
if (!unresolved_entry) {
continue;
}
AstNode *child_node = unresolved_entry->value;
if (child_node->codegen_node->decl_node.in_current_deps) {
zig_panic("TODO infinite top level decl loop");
}
// set temporary flag
child_node->codegen_node->decl_node.in_current_deps = true;
recursive_resolve_decl(g, child_node->codegen_node->decl_node.import, child_node);
// unset temporary flag
child_node->codegen_node->decl_node.in_current_deps = false;
}
resolve_top_level_decl(g, import, node);
g->unresolved_top_level_decls.remove(node->codegen_node->decl_node.name);
}
static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeRoot); assert(node->type == NodeTypeRoot);
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
AstNode *child = node->data.root.top_level_decls.at(i); AstNode *child = node->data.root.top_level_decls.at(i);
preview_types(g, import, child); detect_top_level_decl_deps(g, import, child);
} }
while (g->unresolved_top_level_decls.size() > 0) {
// for the sake of determinism, find the element with the lowest
// insert index and resolve that one.
AstNode *decl_node = nullptr;
auto it = g->unresolved_top_level_decls.entry_iterator();
for (;;) {
auto *entry = it.next();
if (!entry)
break;
AstNode *this_node = entry->value;
if (!decl_node || this_node->create_index < decl_node->create_index) {
decl_node = this_node;
}
}
// set temporary flag
decl_node->codegen_node->decl_node.in_current_deps = true;
recursive_resolve_decl(g, decl_node->codegen_node->decl_node.import, decl_node);
// unset temporary flag
decl_node->codegen_node->decl_node.in_current_deps = false;
}
} }
static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
@ -2804,7 +3088,7 @@ static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, A
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
AstNode *child = node->data.root.top_level_decls.at(i); AstNode *child = node->data.root.top_level_decls.at(i);
analyze_top_level_declaration(g, import, child); analyze_top_level_decl(g, import, child);
} }
} }
@ -2817,21 +3101,9 @@ void semantic_analyze(CodeGen *g) {
break; break;
ImportTableEntry *import = entry->value; ImportTableEntry *import = entry->value;
preview_types_root(g, import, import->root); resolve_top_level_declarations_root(g, import, import->root);
} }
} }
{
auto it = g->import_table.entry_iterator();
for (;;) {
auto *entry = it.next();
if (!entry)
break;
ImportTableEntry *import = entry->value;
find_function_declarations_root(g, import, import->root);
}
}
{ {
auto it = g->import_table.entry_iterator(); auto it = g->import_table.entry_iterator();
for (;;) { for (;;) {
@ -2844,7 +3116,6 @@ void semantic_analyze(CodeGen *g) {
} }
} }
if (!g->root_out_name) { if (!g->root_out_name) {
add_node_error(g, g->root_import->root, add_node_error(g, g->root_import->root,
buf_sprintf("missing export declaration and output name not provided")); buf_sprintf("missing export declaration and output name not provided"));
@ -2857,5 +3128,6 @@ void semantic_analyze(CodeGen *g) {
void alloc_codegen_node(AstNode *node) { void alloc_codegen_node(AstNode *node) {
assert(!node->codegen_node); assert(!node->codegen_node);
node->codegen_node = allocate<CodeGenNode>(1); node->codegen_node = allocate<CodeGenNode>(1);
node->codegen_node->decl_node.deps.init(1);
} }

View File

@ -178,6 +178,10 @@ struct CodeGen {
HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table; HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
uint32_t next_unresolved_index;
struct { struct {
TypeTableEntry *entry_bool; TypeTableEntry *entry_bool;
@ -270,12 +274,12 @@ struct TypeNode {
struct FnProtoNode { struct FnProtoNode {
FnTableEntry *fn_table_entry; FnTableEntry *fn_table_entry;
bool skip;
}; };
struct FnDefNode { struct FnDefNode {
TypeTableEntry *implicit_return_type; TypeTableEntry *implicit_return_type;
BlockContext *block_context; BlockContext *block_context;
bool skip;
}; };
@ -364,6 +368,15 @@ struct FnCallNode {
BuiltinFnEntry *builtin_fn; BuiltinFnEntry *builtin_fn;
}; };
struct DeclNode {
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps;
Buf *name;
ImportTableEntry *import;
// set this flag temporarily to detect infinite loops
bool in_current_deps;
};
// TODO get rid of this structure and put the data directly in the appropriate AST node
struct CodeGenNode { struct CodeGenNode {
union { union {
TypeNode type_node; // for NodeTypeType TypeNode type_node; // for NodeTypeType
@ -388,6 +401,7 @@ struct CodeGenNode {
FnCallNode fn_call_node; // for NodeTypeFnCallExpr FnCallNode fn_call_node; // for NodeTypeFnCallExpr
} data; } data;
ExprNode expr_node; // for all the expression nodes ExprNode expr_node; // for all the expression nodes
DeclNode decl_node; // for all top level decls
}; };
void semantic_analyze(CodeGen *g); void semantic_analyze(CodeGen *g);

View File

@ -23,6 +23,8 @@ CodeGen *codegen_create(Buf *root_source_dir) {
g->link_table.init(32); g->link_table.init(32);
g->import_table.init(32); g->import_table.init(32);
g->builtin_fn_table.init(32); g->builtin_fn_table.init(32);
g->primitive_type_table.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;
@ -2109,6 +2111,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned()); LLVMZigEncoding_DW_ATE_unsigned());
g->builtin_types.entry_bool = entry; g->builtin_types.entry_bool = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2120,6 +2123,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned()); LLVMZigEncoding_DW_ATE_unsigned());
g->builtin_types.entry_u8 = entry; g->builtin_types.entry_u8 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2132,6 +2136,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned()); LLVMZigEncoding_DW_ATE_unsigned());
g->builtin_types.entry_u16 = entry; g->builtin_types.entry_u16 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2144,6 +2149,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned()); LLVMZigEncoding_DW_ATE_unsigned());
g->builtin_types.entry_u32 = entry; g->builtin_types.entry_u32 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2156,6 +2162,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned()); LLVMZigEncoding_DW_ATE_unsigned());
g->builtin_types.entry_u64 = entry; g->builtin_types.entry_u64 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false); g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false);
{ {
@ -2169,6 +2176,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_signed()); LLVMZigEncoding_DW_ATE_signed());
g->builtin_types.entry_i8 = entry; g->builtin_types.entry_i8 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2181,6 +2189,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_signed()); LLVMZigEncoding_DW_ATE_signed());
g->builtin_types.entry_i16 = entry; g->builtin_types.entry_i16 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2193,6 +2202,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_signed()); LLVMZigEncoding_DW_ATE_signed());
g->builtin_types.entry_i32 = entry; g->builtin_types.entry_i32 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2205,6 +2215,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_signed()); LLVMZigEncoding_DW_ATE_signed());
g->builtin_types.entry_i64 = entry; g->builtin_types.entry_i64 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2217,6 +2228,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_signed()); LLVMZigEncoding_DW_ATE_signed());
g->builtin_types.entry_isize = entry; g->builtin_types.entry_isize = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
@ -2229,6 +2241,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned()); LLVMZigEncoding_DW_ATE_unsigned());
g->builtin_types.entry_usize = entry; g->builtin_types.entry_usize = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
@ -2240,6 +2253,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_float()); LLVMZigEncoding_DW_ATE_float());
g->builtin_types.entry_f32 = entry; g->builtin_types.entry_f32 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
@ -2251,6 +2265,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_float()); LLVMZigEncoding_DW_ATE_float());
g->builtin_types.entry_f64 = entry; g->builtin_types.entry_f64 = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
@ -2260,6 +2275,7 @@ static void define_builtin_types(CodeGen *g) {
entry->size_in_bits, entry->align_in_bits, entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned()); LLVMZigEncoding_DW_ATE_unsigned());
g->builtin_types.entry_void = entry; g->builtin_types.entry_void = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
@ -2267,6 +2283,7 @@ static void define_builtin_types(CodeGen *g) {
buf_init_from_str(&entry->name, "unreachable"); buf_init_from_str(&entry->name, "unreachable");
entry->di_type = g->builtin_types.entry_void->di_type; entry->di_type = g->builtin_types.entry_void->di_type;
g->builtin_types.entry_unreachable = entry; g->builtin_types.entry_unreachable = entry;
g->primitive_type_table.put(&entry->name, entry);
} }
} }
@ -2506,21 +2523,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
import_entry->path = full_path; import_entry->path = full_path;
import_entry->fn_table.init(32); import_entry->fn_table.init(32);
import_entry->type_table.init(32); import_entry->type_table.init(32);
import_entry->type_table.put(&g->builtin_types.entry_bool->name, g->builtin_types.entry_bool);
import_entry->type_table.put(&g->builtin_types.entry_u8->name, g->builtin_types.entry_u8);
import_entry->type_table.put(&g->builtin_types.entry_u16->name, g->builtin_types.entry_u16);
import_entry->type_table.put(&g->builtin_types.entry_u32->name, g->builtin_types.entry_u32);
import_entry->type_table.put(&g->builtin_types.entry_u64->name, g->builtin_types.entry_u64);
import_entry->type_table.put(&g->builtin_types.entry_i8->name, g->builtin_types.entry_i8);
import_entry->type_table.put(&g->builtin_types.entry_i16->name, g->builtin_types.entry_i16);
import_entry->type_table.put(&g->builtin_types.entry_i32->name, g->builtin_types.entry_i32);
import_entry->type_table.put(&g->builtin_types.entry_i64->name, g->builtin_types.entry_i64);
import_entry->type_table.put(&g->builtin_types.entry_isize->name, g->builtin_types.entry_isize);
import_entry->type_table.put(&g->builtin_types.entry_usize->name, g->builtin_types.entry_usize);
import_entry->type_table.put(&g->builtin_types.entry_f32->name, g->builtin_types.entry_f32);
import_entry->type_table.put(&g->builtin_types.entry_f64->name, g->builtin_types.entry_f64);
import_entry->type_table.put(&g->builtin_types.entry_void->name, g->builtin_types.entry_void);
import_entry->type_table.put(&g->builtin_types.entry_unreachable->name, g->builtin_types.entry_unreachable);
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color); import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
assert(import_entry->root); assert(import_entry->root);

View File

@ -457,6 +457,7 @@ struct ParseContext {
ZigList<AstNode *> *directive_list; ZigList<AstNode *> *directive_list;
ImportTableEntry *owner; ImportTableEntry *owner;
ErrColor err_color; ErrColor err_color;
uint32_t next_create_index;
}; };
__attribute__ ((format (printf, 4, 5))) __attribute__ ((format (printf, 4, 5)))
@ -512,6 +513,8 @@ static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) {
AstNode *node = allocate<AstNode>(1); AstNode *node = allocate<AstNode>(1);
node->type = type; node->type = type;
node->owner = pc->owner; node->owner = pc->owner;
node->create_index = pc->next_create_index;
pc->next_create_index += 1;
return node; return node;
} }

View File

@ -80,6 +80,16 @@ struct AstNodeFnProto {
ZigList<AstNode *> params; ZigList<AstNode *> params;
AstNode *return_type; AstNode *return_type;
bool is_var_args; bool is_var_args;
// the extern block this fn proto is inside. can be null.
// populated by semantic analyzer.
AstNode *extern_node;
// the struct decl node this fn proto is inside. can be null.
// populated by semantic analyzer.
AstNode *struct_node;
// the function definition this fn proto is inside. can be null.
// populated by semantic analyzer.
AstNode *fn_def_node;
}; };
struct AstNodeFnDef { struct AstNodeFnDef {
@ -369,6 +379,7 @@ struct AstNode {
enum NodeType type; enum NodeType type;
int line; int line;
int column; int column;
uint32_t create_index; // for determinism purposes
CodeGenNode *codegen_node; CodeGenNode *codegen_node;
ImportTableEntry *owner; ImportTableEntry *owner;
union { union {

View File

@ -1203,7 +1203,7 @@ struct A { a : A, }
struct A { b : B, } struct A { b : B, }
struct B { c : C, } struct B { c : C, }
struct C { a : A, } struct C { a : A, }
)SOURCE", 1, ".tmp_source.zig:2:1: error: struct has infinite size"); )SOURCE", 1, ".tmp_source.zig:4:1: error: struct has infinite size");
add_compile_fail_case("invalid struct field", R"SOURCE( add_compile_fail_case("invalid struct field", R"SOURCE(
struct A { x : i32, } struct A { x : i32, }