rewrite scope implementation

* now there are not extra unused hash tables
 * each variable declaration opens a new scope inside a function
This commit is contained in:
Andrew Kelley 2016-12-01 21:08:12 -05:00
parent c6ace9720c
commit f6cbb73c74
7 changed files with 425 additions and 271 deletions

View file

@ -31,6 +31,7 @@ struct ConstExprValue;
struct IrInstruction; struct IrInstruction;
struct IrInstructionCast; struct IrInstructionCast;
struct IrBasicBlock; struct IrBasicBlock;
struct ScopeDecls;
struct IrExecutable { struct IrExecutable {
ZigList<IrBasicBlock *> basic_block_list; ZigList<IrBasicBlock *> basic_block_list;
@ -251,8 +252,8 @@ struct AstNodeFnDef {
// populated by semantic analyzer // populated by semantic analyzer
TypeTableEntry *implicit_return_type; TypeTableEntry *implicit_return_type;
// the first child block context Scope *containing_scope;
Scope *scope; Scope *child_scope;
}; };
struct AstNodeFnDecl { struct AstNodeFnDecl {
@ -638,7 +639,7 @@ struct AstNodeStructDecl {
ZigList<AstNode *> decls; ZigList<AstNode *> decls;
// populated by semantic analyzer // populated by semantic analyzer
Scope *scope; ScopeDecls *decls_scope;
TypeTableEntry *type_entry; TypeTableEntry *type_entry;
TypeTableEntry *generic_fn_type; TypeTableEntry *generic_fn_type;
bool skip; bool skip;
@ -884,7 +885,7 @@ struct TypeTableEntryStruct {
uint64_t size_bytes; uint64_t size_bytes;
bool is_invalid; // true if any fields are invalid bool is_invalid; // true if any fields are invalid
bool is_slice; bool is_slice;
Scope *scope; ScopeDecls *decls_scope;
// set this flag temporarily to detect infinite loops // set this flag temporarily to detect infinite loops
bool embedded_in_current; bool embedded_in_current;
@ -910,7 +911,7 @@ struct TypeTableEntryEnum {
TypeTableEntry *tag_type; TypeTableEntry *tag_type;
TypeTableEntry *union_type; TypeTableEntry *union_type;
Scope *scope; ScopeDecls *decls_scope;
// set this flag temporarily to detect infinite loops // set this flag temporarily to detect infinite loops
bool embedded_in_current; bool embedded_in_current;
@ -926,7 +927,7 @@ struct TypeTableEntryUnion {
TypeStructField *fields; TypeStructField *fields;
uint64_t size_bytes; uint64_t size_bytes;
bool is_invalid; // true if any fields are invalid bool is_invalid; // true if any fields are invalid
Scope *scope; ScopeDecls *decls_scope;
// set this flag temporarily to detect infinite loops // set this flag temporarily to detect infinite loops
bool embedded_in_current; bool embedded_in_current;
@ -1044,7 +1045,7 @@ struct ImportTableEntry {
ZigLLVMDIFile *di_file; ZigLLVMDIFile *di_file;
Buf *source_code; Buf *source_code;
ZigList<size_t> *line_offsets; ZigList<size_t> *line_offsets;
Scope *scope; ScopeDecls *decls_scope;
AstNode *c_import_node; AstNode *c_import_node;
bool any_imports_failed; bool any_imports_failed;
@ -1070,8 +1071,6 @@ struct FnTableEntry {
AstNode *proto_node; AstNode *proto_node;
AstNode *fn_def_node; AstNode *fn_def_node;
ImportTableEntry *import_entry; ImportTableEntry *import_entry;
// Required to be a pre-order traversal of the AST. (parents must come before children)
ZigList<Scope *> all_block_contexts;
Buf symbol_name; Buf symbol_name;
TypeTableEntry *type_entry; // function type TypeTableEntry *type_entry; // function type
bool internal_linkage; bool internal_linkage;
@ -1310,7 +1309,8 @@ struct VariableTableEntry {
ZigLLVMDILocalVariable *di_loc_var; ZigLLVMDILocalVariable *di_loc_var;
size_t src_arg_index; size_t src_arg_index;
size_t gen_arg_index; size_t gen_arg_index;
Scope *scope; Scope *parent_scope;
Scope *child_scope;
LLVMValueRef param_value_ref; LLVMValueRef param_value_ref;
bool force_depends_on_compile_var; bool force_depends_on_compile_var;
ImportTableEntry *import; ImportTableEntry *import;
@ -1334,28 +1334,79 @@ struct LabelTableEntry {
struct Scope { struct Scope {
AstNode *node; AstNode *node;
// any variables that are introduced by this scope // if the scope has a parent, this is it. Every scope has a parent except
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table; // ScopeIdGlobal
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> var_table;
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
// if the block is inside a function, this is the function it is in:
FnTableEntry *fn_entry;
// if the block has a parent, this is it
Scope *parent; Scope *parent;
// if break or continue is valid in this context, this is the loop node that
// it would pertain to
AstNode *parent_loop_node;
ZigLLVMDIScope *di_scope; ZigLLVMDIScope *di_scope;
Buf *c_import_buf;
bool safety_off; bool safety_off;
AstNode *safety_set_node; AstNode *safety_set_node;
}; };
// This scope comes from global declarations or from
// declarations in a container declaration
// NodeTypeRoot, NodeTypeContainerDecl
struct ScopeDecls {
Scope base;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table;
};
// This scope comes from a container declaration such as a struct,
// enum, or union.
struct ScopeContainer {
Scope base;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table;
};
// This scope comes from a block expression in user code.
// NodeTypeBlock
struct ScopeBlock {
Scope base;
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
};
// This scope is created from every defer expression.
// NodeTypeDefer
struct ScopeDefer {
Scope base;
};
// This scope is created for every variable declaration inside an IrExecutable
// NodeTypeVariableDeclaration, NodeTypeParamDecl
struct ScopeVarDecl {
Scope base;
// The variable that creates this scope
VariableTableEntry *var;
};
// This scope is created for a @cImport
// NodeTypeFnCallExpr
struct ScopeCImport {
Scope base;
Buf c_import_buf;
};
// This scope is created for a loop such as for or while in order to
// make break and continue statements work.
// NodeTypeForExpr or NodeTypeWhileExpr
struct ScopeLoop {
Scope base;
};
// This scope is created for a function definition.
// NodeTypeFnDef
struct ScopeFnBody {
Scope base;
FnTableEntry *fn_entry;
};
enum AtomicOrder { enum AtomicOrder {
AtomicOrderUnordered, AtomicOrderUnordered,
AtomicOrderMonotonic, AtomicOrderMonotonic,

View file

@ -115,26 +115,24 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
return entry; return entry;
} }
static Scope **get_container_block_context_ptr(TypeTableEntry *type_entry) { static ScopeDecls **get_container_scope_ptr(TypeTableEntry *type_entry) {
if (type_entry->id == TypeTableEntryIdStruct) { if (type_entry->id == TypeTableEntryIdStruct) {
return &type_entry->data.structure.scope; return &type_entry->data.structure.decls_scope;
} else if (type_entry->id == TypeTableEntryIdEnum) { } else if (type_entry->id == TypeTableEntryIdEnum) {
return &type_entry->data.enumeration.scope; return &type_entry->data.enumeration.decls_scope;
} else if (type_entry->id == TypeTableEntryIdUnion) { } else if (type_entry->id == TypeTableEntryIdUnion) {
return &type_entry->data.unionation.scope; return &type_entry->data.unionation.decls_scope;
} }
zig_unreachable(); zig_unreachable();
} }
Scope *get_container_block_context(TypeTableEntry *type_entry) { ScopeDecls *get_container_scope(TypeTableEntry *type_entry) {
return *get_container_block_context_ptr(type_entry); return *get_container_scope_ptr(type_entry);
} }
static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *source_node, static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *source_node, Scope *parent_scope) {
Scope *parent_context)
{
TypeTableEntry *entry = new_type_table_entry(id); TypeTableEntry *entry = new_type_table_entry(id);
*get_container_block_context_ptr(entry) = new_scope(source_node, parent_context); *get_container_scope_ptr(entry) = create_decls_scope(source_node, parent_scope);
return entry; return entry;
} }
@ -766,11 +764,11 @@ static TypeTableEntryId container_to_type(ContainerKind kind) {
zig_unreachable(); zig_unreachable();
} }
TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *context, TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *scope,
ContainerKind kind, AstNode *decl_node, const char *name) ContainerKind kind, AstNode *decl_node, const char *name)
{ {
TypeTableEntryId type_id = container_to_type(kind); TypeTableEntryId type_id = container_to_type(kind);
TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, context); TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope);
switch (kind) { switch (kind) {
case ContainerKindStruct: case ContainerKindStruct:
@ -844,10 +842,10 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
return result; return result;
} }
static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, Scope *context, static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, Scope *scope,
AstNode *node) AstNode *node)
{ {
IrInstruction *result = analyze_const_value(g, context, node, g->builtin_types.entry_type); IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type);
if (result->type_entry->id == TypeTableEntryIdInvalid) if (result->type_entry->id == TypeTableEntryIdInvalid)
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
@ -861,7 +859,7 @@ static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) {
} }
// fn_table_entry is populated if and only if there is a function definition for this prototype // fn_table_entry is populated if and only if there is a function definition for this prototype
static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, Scope *context, static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, Scope *scope,
TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold, FnTableEntry *fn_table_entry) TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold, FnTableEntry *fn_table_entry)
{ {
assert(node->type == NodeTypeFnProto); assert(node->type == NodeTypeFnProto);
@ -888,7 +886,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
if (fn_proto->skip) { if (fn_proto->skip) {
type_entry = g->builtin_types.entry_invalid; type_entry = g->builtin_types.entry_invalid;
} else { } else {
type_entry = analyze_type_expr(g, import, context, child->data.param_decl.type); type_entry = analyze_type_expr(g, import, scope, child->data.param_decl.type);
} }
switch (type_entry->id) { switch (type_entry->id) {
@ -951,7 +949,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
if (fn_proto->skip) { if (fn_proto->skip) {
fn_type_id.return_type = g->builtin_types.entry_invalid; fn_type_id.return_type = g->builtin_types.entry_invalid;
} else { } else {
fn_type_id.return_type = analyze_type_expr(g, import, context, fn_proto->return_type); fn_type_id.return_type = analyze_type_expr(g, import, scope, fn_proto->return_type);
} }
switch (fn_type_id.return_type->id) { switch (fn_type_id.return_type->id) {
case TypeTableEntryIdInvalid: case TypeTableEntryIdInvalid:
@ -1022,7 +1020,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
} }
static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
ImportTableEntry *import, Scope *containing_context) ImportTableEntry *import, Scope *containing_scope)
{ {
assert(node->type == NodeTypeFnProto); assert(node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &node->data.fn_proto; AstNodeFnProto *fn_proto = &node->data.fn_proto;
@ -1037,7 +1035,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, containing_context, nullptr, node, TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, containing_scope, nullptr, node,
fn_proto->is_nakedcc, fn_proto->is_coldcc, fn_table_entry); fn_proto->is_nakedcc, fn_proto->is_coldcc, fn_table_entry);
fn_table_entry->type_entry = fn_type; fn_table_entry->type_entry = fn_type;
@ -1060,8 +1058,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
} }
if (fn_table_entry->fn_def_node) { if (fn_table_entry->fn_def_node) {
Scope *context = new_scope(fn_table_entry->fn_def_node, containing_context); fn_table_entry->fn_def_node->data.fn_def.containing_scope = create_fndef_scope(
fn_table_entry->fn_def_node->data.fn_def.scope = context; fn_table_entry->fn_def_node, containing_scope, fn_table_entry);
} }
if (!fn_wants_full_static_eval(fn_table_entry)) { if (!fn_wants_full_static_eval(fn_table_entry)) {
@ -1095,23 +1093,6 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim", "true"); ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim", "true");
ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim-non-leaf", nullptr); ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim-non-leaf", nullptr);
} }
if (fn_table_entry->fn_def_node) {
// Add debug info.
unsigned line_number = node->line + 1;
unsigned scope_line = line_number;
bool is_definition = fn_table_entry->fn_def_node != nullptr;
unsigned flags = 0;
bool is_optimized = g->is_release_build;
ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
containing_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
import->di_file, line_number,
fn_type->di_type, fn_table_entry->internal_linkage,
is_definition, scope_line, flags, is_optimized, nullptr);
fn_table_entry->fn_def_node->data.fn_def.scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
}
} }
} }
@ -1151,7 +1132,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
uint64_t biggest_align_in_bits = 0; uint64_t biggest_align_in_bits = 0;
uint64_t biggest_union_member_size_in_bits = 0; uint64_t biggest_union_member_size_in_bits = 0;
Scope *context = enum_type->data.enumeration.scope; Scope *scope = &enum_type->data.enumeration.decls_scope->base;
// set temporary flag // set temporary flag
enum_type->data.enumeration.embedded_in_current = true; enum_type->data.enumeration.embedded_in_current = true;
@ -1161,7 +1142,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
AstNode *field_node = decl_node->data.struct_decl.fields.at(i); AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
type_enum_field->name = field_node->data.struct_field.name; type_enum_field->name = field_node->data.struct_field.name;
TypeTableEntry *field_type = analyze_type_expr(g, import, context, TypeTableEntry *field_type = analyze_type_expr(g, import, scope,
field_node->data.struct_field.type); field_node->data.struct_field.type);
type_enum_field->type_entry = field_type; type_enum_field->type_entry = field_type;
type_enum_field->value = i; type_enum_field->value = i;
@ -1337,14 +1318,14 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
// this field should be set to true only during the recursive calls to resolve_struct_type // this field should be set to true only during the recursive calls to resolve_struct_type
struct_type->data.structure.embedded_in_current = true; struct_type->data.structure.embedded_in_current = true;
Scope *context = struct_type->data.structure.scope; Scope *scope = &struct_type->data.structure.decls_scope->base;
size_t gen_field_index = 0; size_t gen_field_index = 0;
for (size_t i = 0; i < field_count; i += 1) { for (size_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.struct_decl.fields.at(i); AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
type_struct_field->name = field_node->data.struct_field.name; type_struct_field->name = field_node->data.struct_field.name;
TypeTableEntry *field_type = analyze_type_expr(g, import, context, TypeTableEntry *field_type = analyze_type_expr(g, import, scope,
field_node->data.struct_field.type); field_node->data.struct_field.type);
type_struct_field->type_entry = field_type; type_struct_field->type_entry = field_type;
type_struct_field->src_index = i; type_struct_field->src_index = i;
@ -1463,7 +1444,7 @@ static bool get_is_generic_fn(AstNode *proto_node) {
} }
static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node, static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,
Scope *containing_context) Scope *containing_scope)
{ {
assert(proto_node->type == NodeTypeFnProto); assert(proto_node->type == NodeTypeFnProto);
@ -1515,7 +1496,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
} else { } else {
resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context); resolve_function_proto(g, proto_node, fn_table_entry, import, containing_scope);
if (!fn_wants_full_static_eval(fn_table_entry)) { if (!fn_wants_full_static_eval(fn_table_entry)) {
g->fn_protos.append(fn_table_entry); g->fn_protos.append(fn_table_entry);
@ -1546,7 +1527,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
} }
} }
static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, Scope *scope, static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope,
AstNode *node, Buf *name) AstNode *node, Buf *name)
{ {
assert(import); assert(import);
@ -1562,19 +1543,17 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, Scope *scop
g->resolve_queue.append(node); g->resolve_queue.append(node);
} }
node->scope = scope; node->scope = &decls_scope->base;
auto entry = scope->decl_table.maybe_get(name); auto entry = decls_scope->decl_table.put_unique(name, node);
if (entry) { if (entry) {
AstNode *other_decl_node = entry->value; AstNode *other_decl_node = entry->value;
ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(g, msg, other_decl_node, buf_sprintf("previous definition is here")); add_error_note(g, msg, other_decl_node, buf_sprintf("previous definition is here"));
} else {
scope->decl_table.put(name, node);
} }
} }
static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, Scope *context, AstNode *node) { static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node) {
assert(node->type == NodeTypeContainerDecl); assert(node->type == NodeTypeContainerDecl);
if (node->data.struct_decl.type_entry) { if (node->data.struct_decl.type_entry) {
@ -1583,7 +1562,7 @@ static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, Scope *contex
} }
Buf *name = node->data.struct_decl.name; Buf *name = node->data.struct_decl.name;
TypeTableEntry *container_type = get_partial_container_type(g, import, context, TypeTableEntry *container_type = get_partial_container_type(g, import, &decls_scope->base,
node->data.struct_decl.kind, node, buf_ptr(name)); node->data.struct_decl.kind, node, buf_ptr(name));
node->data.struct_decl.type_entry = container_type; node->data.struct_decl.type_entry = container_type;
@ -1591,8 +1570,8 @@ static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, Scope *contex
for (size_t i = 0; i < node->data.struct_decl.decls.length; i += 1) { for (size_t i = 0; i < node->data.struct_decl.decls.length; i += 1) {
AstNode *child_node = node->data.struct_decl.decls.at(i); AstNode *child_node = node->data.struct_decl.decls.at(i);
get_as_top_level_decl(child_node)->parent_decl = node; get_as_top_level_decl(child_node)->parent_decl = node;
Scope *child_context = get_container_block_context(container_type); ScopeDecls *child_scope = get_container_scope(container_type);
scan_decls(g, import, child_context, child_node); scan_decls(g, import, child_scope, child_node);
} }
} }
@ -1644,37 +1623,37 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk; node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk;
} }
void scan_decls(CodeGen *g, ImportTableEntry *import, Scope *context, AstNode *node) { void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node) {
switch (node->type) { switch (node->type) {
case NodeTypeRoot: case NodeTypeRoot:
for (size_t i = 0; i < import->root->data.root.top_level_decls.length; i += 1) { for (size_t i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
AstNode *child = import->root->data.root.top_level_decls.at(i); AstNode *child = import->root->data.root.top_level_decls.at(i);
scan_decls(g, import, context, child); scan_decls(g, import, decls_scope, child);
} }
break; break;
case NodeTypeContainerDecl: case NodeTypeContainerDecl:
{ {
Buf *name = node->data.struct_decl.name; Buf *name = node->data.struct_decl.name;
add_top_level_decl(g, import, context, node, name); add_top_level_decl(g, import, decls_scope, node, name);
if (node->data.struct_decl.generic_params.length == 0) { if (node->data.struct_decl.generic_params.length == 0) {
scan_struct_decl(g, import, context, node); scan_struct_decl(g, import, decls_scope, node);
} }
} }
break; break;
case NodeTypeFnDef: case NodeTypeFnDef:
node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node; node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;
scan_decls(g, import, context, node->data.fn_def.fn_proto); scan_decls(g, import, decls_scope, node->data.fn_def.fn_proto);
break; break;
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
{ {
Buf *name = node->data.variable_declaration.symbol; Buf *name = node->data.variable_declaration.symbol;
add_top_level_decl(g, import, context, node, name); add_top_level_decl(g, import, decls_scope, node, name);
break; break;
} }
case NodeTypeTypeDecl: case NodeTypeTypeDecl:
{ {
Buf *name = node->data.type_decl.symbol; Buf *name = node->data.type_decl.symbol;
add_top_level_decl(g, import, context, node, name); add_top_level_decl(g, import, decls_scope, node, name);
break; break;
} }
case NodeTypeFnProto: case NodeTypeFnProto:
@ -1688,14 +1667,14 @@ void scan_decls(CodeGen *g, ImportTableEntry *import, Scope *context, AstNode *n
} }
count_inline_and_var_args(node); count_inline_and_var_args(node);
add_top_level_decl(g, import, context, node, fn_name); add_top_level_decl(g, import, decls_scope, node, fn_name);
break; break;
} }
case NodeTypeUse: case NodeTypeUse:
{ {
TopLevelDecl *tld = get_as_top_level_decl(node); TopLevelDecl *tld = get_as_top_level_decl(node);
tld->import = import; tld->import = import;
node->scope = context; node->scope = &decls_scope->base;
g->use_queue.append(node); g->use_queue.append(node);
tld->import->use_decls.append(node); tld->import->use_decls.append(node);
break; break;
@ -1816,22 +1795,22 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
// Set name to nullptr to make the variable anonymous (not visible to programmer). // Set name to nullptr to make the variable anonymous (not visible to programmer).
// TODO merge with definition of add_local_var in ir.cpp // TODO merge with definition of add_local_var in ir.cpp
static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import, static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
Scope *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node, Scope *parent_scope, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node)
bool shadowable)
{ {
VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
variable_entry->type = type_entry; variable_entry->type = type_entry;
variable_entry->scope = context; variable_entry->parent_scope = parent_scope;
variable_entry->import = import; variable_entry->import = import;
variable_entry->shadowable = shadowable; variable_entry->shadowable = false;
variable_entry->mem_slot_index = SIZE_MAX; variable_entry->mem_slot_index = SIZE_MAX;
if (name) { assert(name);
buf_init_from_buf(&variable_entry->name, name); buf_init_from_buf(&variable_entry->name, name);
if (type_entry->id != TypeTableEntryIdInvalid) { if (type_entry->id != TypeTableEntryIdInvalid) {
VariableTableEntry *existing_var = find_variable(g, context, name); VariableTableEntry *existing_var = find_variable(g, parent_scope, name);
if (existing_var && !existing_var->shadowable) { if (existing_var && !existing_var->shadowable) {
ErrorMsg *msg = add_node_error(g, source_node, ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
@ -1845,7 +1824,7 @@ static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_
buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
variable_entry->type = g->builtin_types.entry_invalid; variable_entry->type = g->builtin_types.entry_invalid;
} else { } else {
AstNode *decl_node = find_decl(context, name); AstNode *decl_node = find_decl(parent_scope, name);
if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
ErrorMsg *msg = add_node_error(g, source_node, ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redefinition of '%s'", buf_ptr(name))); buf_sprintf("redefinition of '%s'", buf_ptr(name)));
@ -1856,30 +1835,25 @@ static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_
} }
} }
context->var_table.put(&variable_entry->name, variable_entry); Scope *child_scope;
if (source_node->type == NodeTypeParamDecl) {
child_scope = create_var_scope(source_node, parent_scope, variable_entry);
} else { } else {
// TODO replace _anon with @anon and make sure all tests still pass // it's already in the decls table
buf_init_from_str(&variable_entry->name, "_anon"); child_scope = parent_scope;
}
if (context->fn_entry) {
context->fn_entry->variable_list.append(variable_entry);
} }
variable_entry->src_is_const = is_const; variable_entry->src_is_const = is_const;
variable_entry->gen_is_const = is_const; variable_entry->gen_is_const = is_const;
variable_entry->decl_node = source_node; variable_entry->decl_node = source_node;
variable_entry->val_node = val_node; variable_entry->val_node = val_node;
variable_entry->child_scope = child_scope;
return variable_entry; return variable_entry;
} }
static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
Scope *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node)
{
return add_local_var_shadowable(g, source_node, import, context, name, type_entry, is_const, val_node, false);
}
static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeVariableDeclaration); assert(node->type == NodeTypeVariableDeclaration);
@ -1889,8 +1863,6 @@ static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node
bool is_export = (var_decl->top_level_decl.visib_mod == VisibModExport); bool is_export = (var_decl->top_level_decl.visib_mod == VisibModExport);
bool is_extern = var_decl->is_extern; bool is_extern = var_decl->is_extern;
assert(!scope->fn_entry);
TypeTableEntry *explicit_type = nullptr; TypeTableEntry *explicit_type = nullptr;
if (var_decl->type) { if (var_decl->type) {
TypeTableEntry *proposed_type = analyze_type_expr(g, import, scope, var_decl->type); TypeTableEntry *proposed_type = analyze_type_expr(g, import, scope, var_decl->type);
@ -1980,7 +1952,7 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
if (node->data.type_decl.override_type) { if (node->data.type_decl.override_type) {
entry = node->data.type_decl.override_type; entry = node->data.type_decl.override_type;
} else { } else {
TypeTableEntry *child_type = analyze_type_expr(g, import, import->scope, type_node); TypeTableEntry *child_type = analyze_type_expr(g, import, &import->decls_scope->base, type_node);
if (child_type->id == TypeTableEntryIdInvalid) { if (child_type->id == TypeTableEntryIdInvalid) {
entry = child_type; entry = child_type;
} else { } else {
@ -2170,52 +2142,105 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
return false; return false;
} }
Scope *new_scope(AstNode *node, Scope *parent) { ScopeDecls *create_decls_scope(AstNode *node, Scope *parent) {
Scope *context = allocate<Scope>(1); assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl);
context->node = node; ScopeDecls *scope = allocate<ScopeDecls>(1);
context->parent = parent; scope->base.node = node;
context->decl_table.init(1); scope->base.parent = parent;
context->var_table.init(1); scope->decl_table.init(4);
context->label_table.init(1); return scope;
if (parent) {
context->parent_loop_node = parent->parent_loop_node;
context->c_import_buf = parent->c_import_buf;
}
if (node && node->type == NodeTypeFnDef) {
AstNode *fn_proto_node = node->data.fn_def.fn_proto;
context->fn_entry = fn_proto_node->data.fn_proto.fn_table_entry;
} else if (parent) {
context->fn_entry = parent->fn_entry;
}
if (context->fn_entry) {
context->fn_entry->all_block_contexts.append(context);
}
return context;
} }
AstNode *find_decl(Scope *context, Buf *name) { Scope *create_block_scope(AstNode *node, Scope *parent) {
while (context) { assert(node->type == NodeTypeBlock);
auto entry = context->decl_table.maybe_get(name); ScopeBlock *scope = allocate<ScopeBlock>(1);
if (entry) { scope->base.node = node;
scope->base.parent = parent;
scope->label_table.init(1);
return &scope->base;
}
Scope *create_defer_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeDefer);
ScopeDefer *scope = allocate<ScopeDefer>(1);
scope->base.node = node;
scope->base.parent = parent;
return &scope->base;
}
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
assert(node->type == NodeTypeVariableDeclaration || node->type == NodeTypeParamDecl);
ScopeVarDecl *scope = allocate<ScopeVarDecl>(1);
scope->base.node = node;
scope->base.parent = parent;
scope->var = var;
return &scope->base;
}
Scope *create_cimport_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeFnCallExpr);
ScopeCImport *scope = allocate<ScopeCImport>(1);
scope->base.node = node;
scope->base.parent = parent;
buf_resize(&scope->c_import_buf, 0);
return &scope->base;
}
Scope *create_loop_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr);
ScopeLoop *scope = allocate<ScopeLoop>(1);
scope->base.node = node;
scope->base.parent = parent;
return &scope->base;
}
Scope *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) {
assert(node->type == NodeTypeFnDef);
ScopeFnBody *scope = allocate<ScopeFnBody>(1);
scope->base.node = node;
scope->base.parent = parent;
scope->fn_entry = fn_entry;
return &scope->base;
}
AstNode *find_decl(Scope *scope, Buf *name) {
while (scope) {
if (scope->node->type == NodeTypeRoot ||
scope->node->type == NodeTypeContainerDecl)
{
ScopeDecls *decls_scope = (ScopeDecls *)scope;
auto entry = decls_scope->decl_table.maybe_get(name);
if (entry)
return entry->value; return entry->value;
} }
context = context->parent; scope = scope->parent;
} }
return nullptr; return nullptr;
} }
VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name) { VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) {
Scope *context = orig_context; while (scope) {
while (context) { if (scope->node->type == NodeTypeVariableDeclaration ||
auto entry = context->var_table.maybe_get(name); scope->node->type == NodeTypeParamDecl)
{
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
if (buf_eql_buf(name, &var_scope->var->name))
return var_scope->var;
} else if (scope->node->type == NodeTypeRoot ||
scope->node->type == NodeTypeContainerDecl)
{
ScopeDecls *decls_scope = (ScopeDecls *)scope;
auto entry = decls_scope->decl_table.maybe_get(name);
if (entry) { if (entry) {
return entry->value; AstNode *decl_node = entry->value;
if (decl_node->type == NodeTypeVariableDeclaration) {
VariableTableEntry *var = decl_node->data.variable_declaration.variable;
if (var)
return var;
} }
context = context->parent; }
}
scope = scope->parent;
} }
return nullptr; return nullptr;
@ -2355,7 +2380,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
} }
fn_table_entry->anal_state = FnAnalStateProbing; fn_table_entry->anal_state = FnAnalStateProbing;
Scope *context = node->data.fn_def.scope; Scope *child_scope = node->data.fn_def.containing_scope;
TypeTableEntry *fn_type = fn_table_entry->type_entry; TypeTableEntry *fn_type = fn_table_entry->type_entry;
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
@ -2381,16 +2406,20 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
add_node_error(g, param_decl_node, buf_sprintf("missing parameter name")); add_node_error(g, param_decl_node, buf_sprintf("missing parameter name"));
} }
VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, param_decl->name, VariableTableEntry *var = add_local_var(g, param_decl_node, import, child_scope, param_decl->name,
type, true, nullptr); type, true, nullptr);
var->src_arg_index = i; var->src_arg_index = i;
param_decl_node->data.param_decl.variable = var; param_decl_node->data.param_decl.variable = var;
child_scope = var->child_scope;
fn_table_entry->variable_list.append(var);
if (fn_type->data.fn.gen_param_info) { if (fn_type->data.fn.gen_param_info) {
var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index; var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
} }
} }
node->data.fn_def.child_scope = child_scope;
TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type; TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type;
if (fn_type->data.fn.fn_type_id.is_extern && handle_is_ptr(expected_type)) { if (fn_type->data.fn.fn_type_id.is_extern && handle_is_ptr(expected_type)) {
@ -2456,7 +2485,7 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
continue; continue;
} }
if (target_tld->visib_mod != VisibModPrivate) { if (target_tld->visib_mod != VisibModPrivate) {
auto existing_entry = tld->import->scope->decl_table.maybe_get(target_tld->name); auto existing_entry = tld->import->decls_scope->decl_table.put_unique(target_tld->name, decl_node);
if (existing_entry) { if (existing_entry) {
AstNode *existing_decl = existing_entry->value; AstNode *existing_decl = existing_entry->value;
if (existing_decl != decl_node) { if (existing_decl != decl_node) {
@ -2466,8 +2495,6 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
add_error_note(g, msg, existing_decl, buf_sprintf("previous definition here")); add_error_note(g, msg, existing_decl, buf_sprintf("previous definition here"));
add_error_note(g, msg, decl_node, buf_sprintf("imported definition here")); add_error_note(g, msg, decl_node, buf_sprintf("imported definition here"));
} }
} else {
tld->import->scope->decl_table.put(target_tld->name, decl_node);
} }
} }
} }
@ -2494,7 +2521,7 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeUse); assert(node->type == NodeTypeUse);
TopLevelDecl *tld = get_as_top_level_decl(node); TopLevelDecl *tld = get_as_top_level_decl(node);
IrInstruction *result = analyze_const_value(g, tld->import->scope, node->data.use.expr, IrInstruction *result = analyze_const_value(g, &tld->import->decls_scope->base, node->data.use.expr,
g->builtin_types.entry_namespace); g->builtin_types.entry_namespace);
if (result->type_entry->id == TypeTableEntryIdInvalid) if (result->type_entry->id == TypeTableEntryIdInvalid)
tld->import->any_imports_failed = true; tld->import->any_imports_failed = true;
@ -2553,8 +2580,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
g->import_table.put(abs_full_path, import_entry); g->import_table.put(abs_full_path, import_entry);
g->import_queue.append(import_entry); g->import_queue.append(import_entry);
import_entry->scope = new_scope(import_entry->root, nullptr); import_entry->decls_scope = create_decls_scope(import_entry->root, nullptr);
import_entry->scope->di_scope = ZigLLVMFileToScope(import_entry->di_file);
assert(import_entry->root->type == NodeTypeRoot); assert(import_entry->root->type == NodeTypeRoot);
@ -2581,7 +2607,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
void semantic_analyze(CodeGen *g) { void semantic_analyze(CodeGen *g) {
for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) { for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) {
ImportTableEntry *import = g->import_queue.at(g->import_queue_index); ImportTableEntry *import = g->import_queue.at(g->import_queue_index);
scan_decls(g, import, import->scope, import->root); scan_decls(g, import, import->decls_scope, import->root);
} }
for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) { for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {

View file

@ -15,7 +15,6 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg); ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
TypeTableEntry *new_type_table_entry(TypeTableEntryId id); TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
Scope *new_scope(AstNode *node, Scope *parent);
bool is_node_void_expr(AstNode *node); bool is_node_void_expr(AstNode *node);
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bits); TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bits);
@ -59,11 +58,19 @@ TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
bool type_is_complete(TypeTableEntry *type_entry); bool type_is_complete(TypeTableEntry *type_entry);
void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
Scope *get_container_block_context(TypeTableEntry *type_entry); ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
bool is_container_ref(TypeTableEntry *type_entry); bool is_container_ref(TypeTableEntry *type_entry);
void scan_decls(CodeGen *g, ImportTableEntry *import, Scope *context, AstNode *node); void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node);
void preview_use_decl(CodeGen *g, AstNode *node); void preview_use_decl(CodeGen *g, AstNode *node);
void resolve_use_decl(CodeGen *g, AstNode *node); void resolve_use_decl(CodeGen *g, AstNode *node);
ScopeDecls *create_decls_scope(AstNode *node, Scope *parent);
Scope *create_block_scope(AstNode *node, Scope *parent);
Scope *create_defer_scope(AstNode *node, Scope *parent);
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
Scope *create_cimport_scope(AstNode *node, Scope *parent);
Scope *create_loop_scope(AstNode *node, Scope *parent);
Scope *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
#endif #endif

View file

@ -227,9 +227,47 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val); static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val); static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
if (scope->di_scope)
return scope->di_scope;
if (scope->node->type == NodeTypeFnDef) {
assert(scope->parent);
ScopeFnBody *fn_scope = (ScopeFnBody *)scope;
FnTableEntry *fn_table_entry = fn_scope->fn_entry;
unsigned line_number = fn_table_entry->proto_node->line + 1;
unsigned scope_line = line_number;
bool is_definition = fn_table_entry->fn_def_node != nullptr;
unsigned flags = 0;
bool is_optimized = g->is_release_build;
ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "",
scope->node->owner->di_file, line_number,
fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage,
is_definition, scope_line, flags, is_optimized, nullptr);
scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
} else if (scope->node->type == NodeTypeRoot ||
scope->node->type == NodeTypeContainerDecl)
{
scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file);
} else {
assert(scope->parent);
ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
get_di_scope(g, scope->parent),
scope->node->owner->di_file,
scope->node->line + 1,
scope->node->column + 1);
scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
}
return scope->di_scope;
}
static void set_debug_source_node(CodeGen *g, AstNode *node) { static void set_debug_source_node(CodeGen *g, AstNode *node) {
assert(node->scope); assert(node->scope);
ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, node->scope->di_scope); ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, get_di_scope(g, node->scope));
} }
static void clear_debug_source_node(CodeGen *g) { static void clear_debug_source_node(CodeGen *g) {
@ -558,10 +596,9 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node,
} }
static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) { static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) {
Scope *scope = var->scope;
AstNode *source_node = var->decl_node; AstNode *source_node = var->decl_node;
ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc(source_node->line + 1, source_node->column + 1, ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc(source_node->line + 1, source_node->column + 1,
scope->di_scope); get_di_scope(g, var->parent_scope));
ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc, ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc,
LLVMGetInsertBlock(g->builder)); LLVMGetInsertBlock(g->builder));
} }
@ -2133,8 +2170,7 @@ static void gen_global_var(CodeGen *g, VariableTableEntry *var, LLVMValueRef ini
assert(var->import); assert(var->import);
assert(type_entry); assert(type_entry);
bool is_local_to_unit = true; bool is_local_to_unit = true;
ZigLLVMCreateGlobalVariable(g->dbuilder, ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
var->scope->di_scope, buf_ptr(&var->name),
buf_ptr(&var->name), var->import->di_file, var->decl_node->line + 1, buf_ptr(&var->name), var->import->di_file, var->decl_node->line + 1,
type_entry->di_type, is_local_to_unit, init_val); type_entry->di_type, is_local_to_unit, init_val);
} }
@ -2328,24 +2364,6 @@ static void do_code_gen(CodeGen *g) {
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
build_all_basic_blocks(g, fn_table_entry); build_all_basic_blocks(g, fn_table_entry);
// Set up debug info for blocks
for (size_t bc_i = 0; bc_i < fn_table_entry->all_block_contexts.length; bc_i += 1) {
Scope *scope = fn_table_entry->all_block_contexts.at(bc_i);
if (!scope->di_scope) {
ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
scope->parent->di_scope,
import->di_file,
scope->node->line + 1,
scope->node->column + 1);
scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
}
}
clear_debug_source_node(g); clear_debug_source_node(g);
// allocate temporary stack data // allocate temporary stack data
@ -2383,7 +2401,7 @@ static void do_code_gen(CodeGen *g) {
if (var->is_inline) if (var->is_inline)
continue; continue;
if (var->scope->node->type == NodeTypeFnDef) { if (var->parent_scope->node->type == NodeTypeFnDef) {
assert(var->gen_arg_index != SIZE_MAX); assert(var->gen_arg_index != SIZE_MAX);
TypeTableEntry *gen_type; TypeTableEntry *gen_type;
if (handle_is_ptr(var->type)) { if (handle_is_ptr(var->type)) {
@ -2395,7 +2413,7 @@ static void do_code_gen(CodeGen *g) {
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref); unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes); LLVMSetAlignment(var->value_ref, align_bytes);
} }
var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, var->scope->di_scope, var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1, buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
gen_type->di_type, !g->strip_debug_symbols, 0, var->gen_arg_index + 1); gen_type->di_type, !g->strip_debug_symbols, 0, var->gen_arg_index + 1);
@ -2406,7 +2424,7 @@ static void do_code_gen(CodeGen *g) {
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref); unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes); LLVMSetAlignment(var->value_ref, align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, var->scope->di_scope, var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1, buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
var->type->di_type, !g->strip_debug_symbols, 0); var->type->di_type, !g->strip_debug_symbols, 0);
} }

View file

@ -61,6 +61,15 @@ public:
} }
} }
Entry *put_unique(const K &key, const V &value) {
// TODO make this more efficient
Entry *entry = internal_get(key);
if (entry)
return entry;
put(key, value);
return nullptr;
}
const V &get(const K &key) const { const V &get(const K &key) const {
Entry *entry = internal_get(key); Entry *entry = internal_get(key);
if (!entry) if (!entry)

View file

@ -1211,28 +1211,39 @@ static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instr
return new_instruction; return new_instruction;
} }
static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_block, Scope *outer_block, static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
bool gen_error_defers, bool gen_maybe_defers) bool gen_error_defers, bool gen_maybe_defers)
{ {
while (inner_block != outer_block) { while (inner_scope != outer_scope) {
if (inner_block->node->type == NodeTypeDefer && if (inner_scope->node->type == NodeTypeDefer &&
((inner_block->node->data.defer.kind == ReturnKindUnconditional) || ((inner_scope->node->data.defer.kind == ReturnKindUnconditional) ||
(gen_error_defers && inner_block->node->data.defer.kind == ReturnKindError) || (gen_error_defers && inner_scope->node->data.defer.kind == ReturnKindError) ||
(gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe))) (gen_maybe_defers && inner_scope->node->data.defer.kind == ReturnKindMaybe)))
{ {
AstNode *defer_expr_node = inner_block->node->data.defer.expr; AstNode *defer_expr_node = inner_scope->node->data.defer.expr;
ir_gen_node(irb, defer_expr_node, defer_expr_node->scope); ir_gen_node(irb, defer_expr_node, defer_expr_node->scope);
} }
inner_block = inner_block->parent; inner_scope = inner_scope->parent;
} }
} }
static FnTableEntry *scope_fn_entry(Scope *scope) {
while (scope) {
if (scope->node->type == NodeTypeFnDef) {
ScopeFnBody *fn_scope = (ScopeFnBody *)scope;
return fn_scope->fn_entry;
}
scope = scope->parent;
}
return nullptr;
}
static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *node) { static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *node) {
assert(node->type == NodeTypeReturnExpr); assert(node->type == NodeTypeReturnExpr);
Scope *scope = node->scope; Scope *scope = node->scope;
if (!scope->fn_entry) { if (!scope_fn_entry(scope)) {
add_node_error(irb->codegen, node, buf_sprintf("return expression outside function definition")); add_node_error(irb->codegen, node, buf_sprintf("return expression outside function definition"));
return irb->codegen->invalid_instruction; return irb->codegen->invalid_instruction;
} }
@ -1243,7 +1254,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *node) {
{ {
IrInstruction *return_value; IrInstruction *return_value;
if (expr_node) { if (expr_node) {
return_value = ir_gen_node(irb, expr_node, scope); return_value = ir_gen_node(irb, expr_node, node->scope);
} else { } else {
return_value = ir_build_const_void(irb, node); return_value = ir_build_const_void(irb, node);
} }
@ -1264,11 +1275,11 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
irb->current_basic_block = basic_block; irb->current_basic_block = basic_block;
} }
static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Scope *scope, static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope,
Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline) Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline)
{ {
VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
variable_entry->scope = scope; variable_entry->parent_scope = parent_scope;
variable_entry->import = node->owner; variable_entry->import = node->owner;
variable_entry->shadowable = is_shadowable; variable_entry->shadowable = is_shadowable;
variable_entry->mem_slot_index = SIZE_MAX; variable_entry->mem_slot_index = SIZE_MAX;
@ -1277,7 +1288,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Scope
if (name) { if (name) {
buf_init_from_buf(&variable_entry->name, name); buf_init_from_buf(&variable_entry->name, name);
VariableTableEntry *existing_var = find_variable(codegen, scope, name); VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name);
if (existing_var && !existing_var->shadowable) { if (existing_var && !existing_var->shadowable) {
ErrorMsg *msg = add_node_error(codegen, node, ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
@ -1291,7 +1302,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Scope
buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
variable_entry->type = codegen->builtin_types.entry_invalid; variable_entry->type = codegen->builtin_types.entry_invalid;
} else { } else {
AstNode *decl_node = find_decl(scope, name); AstNode *decl_node = find_decl(parent_scope, name);
if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
ErrorMsg *msg = add_node_error(codegen, node, ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name))); buf_sprintf("redefinition of '%s'", buf_ptr(name)));
@ -1301,28 +1312,32 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Scope
} }
} }
scope->var_table.put(&variable_entry->name, variable_entry);
} else { } else {
assert(is_shadowable); assert(is_shadowable);
// TODO replace _anon with @anon and make sure all tests still pass // TODO make this name not actually be in scope. user should be able to make a variable called "_anon"
// might already be solved, let's just make sure it has test coverage
// maybe we put a prefix on this so the debug info doesn't clobber user debug info for same named variables
buf_init_from_str(&variable_entry->name, "_anon"); buf_init_from_str(&variable_entry->name, "_anon");
} }
variable_entry->src_is_const = src_is_const; variable_entry->src_is_const = src_is_const;
variable_entry->gen_is_const = gen_is_const; variable_entry->gen_is_const = gen_is_const;
variable_entry->decl_node = node; variable_entry->decl_node = node;
variable_entry->child_scope = create_var_scope(node, parent_scope, variable_entry);
return variable_entry; return variable_entry;
} }
// Set name to nullptr to make the variable anonymous (not visible to programmer). // Set name to nullptr to make the variable anonymous (not visible to programmer).
static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *name, // After you call this function var->child_scope has the variable in scope
static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *name,
bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline) bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline)
{ {
VariableTableEntry *var = add_local_var(irb->codegen, node, scope, name, VariableTableEntry *var = add_local_var(irb->codegen, node, scope, name,
src_is_const, gen_is_const, is_shadowable, is_inline); src_is_const, gen_is_const, is_shadowable, is_inline);
if (is_inline || gen_is_const) if (is_inline || gen_is_const)
var->mem_slot_index = exec_next_mem_slot(irb->exec); var->mem_slot_index = exec_next_mem_slot(irb->exec);
assert(var->child_scope);
return var; return var;
} }
@ -1330,7 +1345,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) {
assert(block_node->type == NodeTypeBlock); assert(block_node->type == NodeTypeBlock);
Scope *parent_scope = block_node->scope; Scope *parent_scope = block_node->scope;
Scope *outer_block_scope = new_scope(block_node, parent_scope); Scope *outer_block_scope = create_block_scope(block_node, parent_scope);
Scope *child_scope = outer_block_scope; Scope *child_scope = outer_block_scope;
IrInstruction *return_value = nullptr; IrInstruction *return_value = nullptr;
@ -1341,6 +1356,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) {
// defer starts a new block context // defer starts a new block context
child_scope = statement_node->data.defer.child_block; child_scope = statement_node->data.defer.child_block;
assert(child_scope); assert(child_scope);
} else if (return_value->id == IrInstructionIdDeclVar) {
IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)return_value;
child_scope = decl_var_instruction->var->child_scope;
} }
} }
@ -1760,7 +1778,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
if (arg0_value == irb->codegen->invalid_instruction) if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value; return arg0_value;
if (node->scope->fn_entry) { if (scope_fn_entry(node->scope)) {
add_node_error(irb->codegen, node, buf_sprintf("import valid only at top level scope")); add_node_error(irb->codegen, node, buf_sprintf("import valid only at top level scope"));
return irb->codegen->invalid_instruction; return irb->codegen->invalid_instruction;
} }
@ -1999,8 +2017,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) {
bool is_const = variable_declaration->is_const; bool is_const = variable_declaration->is_const;
bool is_extern = variable_declaration->is_extern; bool is_extern = variable_declaration->is_extern;
bool is_inline = ir_should_inline(irb) || variable_declaration->is_inline; bool is_inline = ir_should_inline(irb) || variable_declaration->is_inline;
VariableTableEntry *var = ir_add_local_var(irb, node, node->scope, VariableTableEntry *var = ir_create_var(irb, node, node->scope,
variable_declaration->symbol, is_const, is_const, is_shadowable, is_inline); variable_declaration->symbol, is_const, is_const, is_shadowable, is_inline);
// we detect IrInstructionIdDeclVar in gen_block to make sure the next node
// is inside var->child_scope
if (!is_extern && !variable_declaration->expr) { if (!is_extern && !variable_declaration->expr) {
var->type = irb->codegen->builtin_types.entry_invalid; var->type = irb->codegen->builtin_types.entry_invalid;
@ -2079,14 +2099,15 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) {
} }
bool is_inline = ir_should_inline(irb) || node->data.for_expr.is_inline; bool is_inline = ir_should_inline(irb) || node->data.for_expr.is_inline;
Scope *child_scope = new_scope(node, parent_scope); Scope *child_scope = create_loop_scope(node, parent_scope);
child_scope->parent_loop_node = node;
elem_node->scope = child_scope; elem_node->scope = child_scope;
// TODO make it an error to write to element variable or i variable. // TODO make it an error to write to element variable or i variable.
Buf *elem_var_name = elem_node->data.symbol_expr.symbol; Buf *elem_var_name = elem_node->data.symbol_expr.symbol;
node->data.for_expr.elem_var = ir_add_local_var(irb, elem_node, child_scope, elem_var_name, node->data.for_expr.elem_var = ir_create_var(irb, elem_node, child_scope, elem_var_name,
true, false, false, is_inline); true, false, false, is_inline);
child_scope = node->data.for_expr.elem_var->child_scope;
IrInstruction *undefined_value = ir_build_const_undefined(irb, elem_node); IrInstruction *undefined_value = ir_build_const_undefined(irb, elem_node);
ir_build_var_decl(irb, elem_node, node->data.for_expr.elem_var, elem_var_type, undefined_value); ir_build_var_decl(irb, elem_node, node->data.for_expr.elem_var, elem_var_type, undefined_value);
IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, node, node->data.for_expr.elem_var); IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, node, node->data.for_expr.elem_var);
@ -2096,13 +2117,15 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) {
index_var_source_node = index_node; index_var_source_node = index_node;
Buf *index_var_name = index_node->data.symbol_expr.symbol; Buf *index_var_name = index_node->data.symbol_expr.symbol;
index_node->scope = child_scope; index_node->scope = child_scope;
node->data.for_expr.index_var = ir_add_local_var(irb, index_node, child_scope, index_var_name, node->data.for_expr.index_var = ir_create_var(irb, index_node, child_scope, index_var_name,
true, false, false, is_inline); true, false, false, is_inline);
} else { } else {
index_var_source_node = node; index_var_source_node = node;
node->data.for_expr.index_var = ir_add_local_var(irb, node, child_scope, nullptr, node->data.for_expr.index_var = ir_create_var(irb, node, child_scope, nullptr,
true, false, true, is_inline); true, false, true, is_inline);
} }
child_scope = node->data.for_expr.index_var->child_scope;
IrInstruction *usize = ir_build_const_type(irb, node, irb->codegen->builtin_types.entry_usize); IrInstruction *usize = ir_build_const_type(irb, node, irb->codegen->builtin_types.entry_usize);
IrInstruction *zero = ir_build_const_usize(irb, node, 0); IrInstruction *zero = ir_build_const_usize(irb, node, 0);
IrInstruction *one = ir_build_const_usize(irb, node, 1); IrInstruction *one = ir_build_const_usize(irb, node, 1);
@ -2159,10 +2182,11 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, AstNode *node) {
if (!scope->parent) if (!scope->parent)
return ir_build_const_import(irb, node, node->owner); return ir_build_const_import(irb, node, node->owner);
if (scope->fn_entry && (!scope->parent->fn_entry || FnTableEntry *fn_entry = scope_fn_entry(scope);
(scope->parent->parent && !scope->parent->parent->fn_entry))) if (fn_entry && scope->parent && scope->parent->parent &&
!scope_fn_entry(scope->parent->parent))
{ {
return ir_build_const_fn(irb, node, scope->fn_entry); return ir_build_const_fn(irb, node, fn_entry);
} }
if (scope->node->type == NodeTypeContainerDecl) { if (scope->node->type == NodeTypeContainerDecl) {
@ -2308,15 +2332,15 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {
if (var_type == irb->codegen->invalid_instruction) if (var_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction; return irb->codegen->invalid_instruction;
} }
Scope *child_scope = new_scope(node, node->scope);
bool is_shadowable = false; bool is_shadowable = false;
bool is_const = var_decl->is_const; bool is_const = var_decl->is_const;
VariableTableEntry *var = ir_add_local_var(irb, node, child_scope, VariableTableEntry *var = ir_create_var(irb, node, node->scope,
var_decl->symbol, is_const, is_const, is_shadowable, is_inline); var_decl->symbol, is_const, is_const, is_shadowable, is_inline);
IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, node, expr_value, false); IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, node, expr_value, false);
IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, node, var_ptr_value); IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, node, var_ptr_value);
ir_build_var_decl(irb, node, var, var_type, var_value); ir_build_var_decl(irb, node, var, var_type, var_value);
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, child_scope); IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var->child_scope);
if (then_expr_result == irb->codegen->invalid_instruction) if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result; return then_expr_result;
IrBasicBlock *after_then_block = irb->current_basic_block; IrBasicBlock *after_then_block = irb->current_basic_block;
@ -2360,11 +2384,11 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, AstNode *switch_node, AstNo
Buf *var_name = var_symbol_node->data.symbol_expr.symbol; Buf *var_name = var_symbol_node->data.symbol_expr.symbol;
bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr; bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr;
child_scope = new_scope(switch_node, switch_node->scope);
bool is_shadowable = false; bool is_shadowable = false;
bool is_const = true; bool is_const = true;
VariableTableEntry *var = ir_add_local_var(irb, var_symbol_node, child_scope, VariableTableEntry *var = ir_create_var(irb, var_symbol_node, switch_node->scope,
var_name, is_const, is_const, is_shadowable, is_inline); var_name, is_const, is_const, is_shadowable, is_inline);
child_scope = var->child_scope;
IrInstruction *var_value; IrInstruction *var_value;
if (prong_value) { if (prong_value) {
IrInstruction *var_ptr_value = ir_build_switch_var(irb, var_symbol_node, target_value_ptr, prong_value); IrInstruction *var_ptr_value = ir_build_switch_var(irb, var_symbol_node, target_value_ptr, prong_value);
@ -2542,14 +2566,25 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
return ir_build_phi(irb, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); return ir_build_phi(irb, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
} }
static LabelTableEntry *find_label(IrExecutable *exec, Scope *orig_context, Buf *name) { static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) {
Scope *context = orig_context; while (scope) {
while (context) { if (scope->node->type == NodeTypeBlock) {
auto entry = context->label_table.maybe_get(name); ScopeBlock *block_scope = (ScopeBlock *)scope;
if (entry) { auto entry = block_scope->label_table.maybe_get(name);
if (entry)
return entry->value; return entry->value;
} }
context = context->parent; scope = scope->parent;
}
return nullptr;
}
static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) {
while (scope) {
if (scope->node->type == NodeTypeBlock)
return (ScopeBlock *)scope;
scope = scope->parent;
} }
return nullptr; return nullptr;
} }
@ -2571,7 +2606,8 @@ static IrInstruction *ir_gen_label(IrBuilder *irb, AstNode *node) {
add_error_note(irb->codegen, msg, existing_label->decl_node, buf_sprintf("other label here")); add_error_note(irb->codegen, msg, existing_label->decl_node, buf_sprintf("other label here"));
return irb->codegen->invalid_instruction; return irb->codegen->invalid_instruction;
} else { } else {
node->scope->label_table.put(label_name, label); ScopeBlock *scope_block = find_block_scope(irb->exec, node->scope);
scope_block->label_table.put(label_name, label);
} }
bool is_inline = ir_should_inline(irb); bool is_inline = ir_should_inline(irb);
@ -2778,9 +2814,9 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
assert(fn_def_node->type == NodeTypeFnDef); assert(fn_def_node->type == NodeTypeFnDef);
AstNode *body_node = fn_def_node->data.fn_def.body; AstNode *body_node = fn_def_node->data.fn_def.body;
Scope *scope = fn_def_node->data.fn_def.scope; Scope *child_scope = fn_def_node->data.fn_def.child_scope;
return ir_gen(codegn, body_node, scope, ir_executable); return ir_gen(codegn, body_node, child_scope, ir_executable);
} }
static IrInstruction *ir_eval_fn(IrAnalyze *ira, IrInstruction *source_instruction, static IrInstruction *ir_eval_fn(IrAnalyze *ira, IrInstruction *source_instruction,
@ -3023,8 +3059,10 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
} else { } else {
IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node, wanted_type, value, cast_op); IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node, wanted_type, value, cast_op);
result->type_entry = wanted_type; result->type_entry = wanted_type;
if (need_alloca && source_instr->source_node->scope->fn_entry) { if (need_alloca) {
source_instr->source_node->scope->fn_entry->alloca_list.append(result); FnTableEntry *fn_entry = scope_fn_entry(source_instr->source_node->scope);
if (fn_entry)
fn_entry->alloca_list.append(result);
} }
return result; return result;
} }
@ -3550,7 +3588,8 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
ir_link_new_instruction(value, source_instruction); ir_link_new_instruction(value, source_instruction);
return ptr_type; return ptr_type;
} else { } else {
FnTableEntry *fn_entry = source_instruction->source_node->scope->fn_entry; FnTableEntry *fn_entry = scope_fn_entry(source_instruction->source_node->scope);
assert(fn_entry);
IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value); IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value);
fn_entry->alloca_list.append(new_instruction); fn_entry->alloca_list.append(new_instruction);
return ptr_type; return ptr_type;
@ -4098,8 +4137,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, casted_init_value); ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, casted_init_value);
Scope *scope = decl_var_instruction->base.source_node->scope; Scope *scope = decl_var_instruction->base.source_node->scope;
if (scope->fn_entry) FnTableEntry *fn_entry = scope_fn_entry(scope);
scope->fn_entry->variable_list.append(var); if (fn_entry)
fn_entry->variable_list.append(var);
return ira->codegen->builtin_types.entry_void; return ira->codegen->builtin_types.entry_void;
} }
@ -4200,8 +4240,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
fn_entry, fn_ref, call_param_count, casted_args); fn_entry, fn_ref, call_param_count, casted_args);
if (type_has_bits(return_type) && handle_is_ptr(return_type)) if (type_has_bits(return_type) && handle_is_ptr(return_type)) {
call_instruction->base.source_node->scope->fn_entry->alloca_list.append(new_call_instruction); FnTableEntry *fn_entry = scope_fn_entry(call_instruction->base.source_node->scope);
assert(fn_entry);
fn_entry->alloca_list.append(new_call_instruction);
}
return ir_finish_anal(ira, return_type); return ir_finish_anal(ira, return_type);
} }
@ -4732,7 +4775,8 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
return var->type; return var->type;
ConstExprValue *mem_slot = nullptr; ConstExprValue *mem_slot = nullptr;
if (var->scope->fn_entry) { FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope);
if (fn_entry) {
// TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing. // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.
if (var->mem_slot_index != SIZE_MAX) if (var->mem_slot_index != SIZE_MAX)
mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
@ -4879,9 +4923,8 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
IrInstruction *container_ptr, TypeTableEntry *container_type) IrInstruction *container_ptr, TypeTableEntry *container_type)
{ {
if (!is_slice(bare_struct_type)) { if (!is_slice(bare_struct_type)) {
Scope *container_block_context = get_container_block_context(bare_struct_type); ScopeDecls *container_scope = get_container_scope(bare_struct_type);
assert(container_block_context); auto entry = container_scope->decl_table.maybe_get(field_name);
auto entry = container_block_context->decl_table.maybe_get(field_name);
AstNode *fn_decl_node = entry ? entry->value : nullptr; AstNode *fn_decl_node = entry ? entry->value : nullptr;
if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) { if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) {
resolve_top_level_decl(ira->codegen, fn_decl_node, false); resolve_top_level_decl(ira->codegen, fn_decl_node, false);
@ -5023,8 +5066,8 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
} else if (child_type->id == TypeTableEntryIdEnum) { } else if (child_type->id == TypeTableEntryIdEnum) {
zig_panic("TODO enum type field"); zig_panic("TODO enum type field");
} else if (child_type->id == TypeTableEntryIdStruct) { } else if (child_type->id == TypeTableEntryIdStruct) {
Scope *container_block_context = get_container_block_context(child_type); ScopeDecls *container_scope = get_container_scope(child_type);
auto entry = container_block_context->decl_table.maybe_get(field_name); auto entry = container_scope->decl_table.maybe_get(field_name);
AstNode *decl_node = entry ? entry->value : nullptr; AstNode *decl_node = entry ? entry->value : nullptr;
if (decl_node) { if (decl_node) {
bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var; bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
@ -5055,7 +5098,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
ImportTableEntry *namespace_import = namespace_val->data.x_import; ImportTableEntry *namespace_import = namespace_val->data.x_import;
bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var; bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
AstNode *decl_node = find_decl(namespace_import->scope, field_name); AstNode *decl_node = find_decl(&namespace_import->decls_scope->base, field_name);
if (!decl_node) { if (!decl_node) {
// we must now resolve all the use decls // we must now resolve all the use decls
for (size_t i = 0; i < namespace_import->use_decls.length; i += 1) { for (size_t i = 0; i < namespace_import->use_decls.length; i += 1) {
@ -5066,7 +5109,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
} }
resolve_use_decl(ira->codegen, use_decl_node); resolve_use_decl(ira->codegen, use_decl_node);
} }
decl_node = find_decl(namespace_import->scope, field_name); decl_node = find_decl(&namespace_import->decls_scope->base, field_name);
} }
if (decl_node) { if (decl_node) {
TopLevelDecl *tld = get_as_top_level_decl(decl_node); TopLevelDecl *tld = get_as_top_level_decl(decl_node);
@ -5327,15 +5370,15 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
if (target_type->id == TypeTableEntryIdBlock) { if (target_type->id == TypeTableEntryIdBlock) {
target_context = target_val->data.x_block; target_context = target_val->data.x_block;
} else if (target_type->id == TypeTableEntryIdFn) { } else if (target_type->id == TypeTableEntryIdFn) {
target_context = target_val->data.x_fn->fn_def_node->data.fn_def.scope; target_context = target_val->data.x_fn->fn_def_node->data.fn_def.child_scope;
} else if (target_type->id == TypeTableEntryIdMetaType) { } else if (target_type->id == TypeTableEntryIdMetaType) {
TypeTableEntry *type_arg = target_val->data.x_type; TypeTableEntry *type_arg = target_val->data.x_type;
if (type_arg->id == TypeTableEntryIdStruct) { if (type_arg->id == TypeTableEntryIdStruct) {
target_context = type_arg->data.structure.scope; target_context = &type_arg->data.structure.decls_scope->base;
} else if (type_arg->id == TypeTableEntryIdEnum) { } else if (type_arg->id == TypeTableEntryIdEnum) {
target_context = type_arg->data.enumeration.scope; target_context = &type_arg->data.enumeration.decls_scope->base;
} else if (type_arg->id == TypeTableEntryIdUnion) { } else if (type_arg->id == TypeTableEntryIdUnion) {
target_context = type_arg->data.unionation.scope; target_context = &type_arg->data.unionation.decls_scope->base;
} else { } else {
add_node_error(ira->codegen, target_instruction->source_node, add_node_error(ira->codegen, target_instruction->source_node,
buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&type_arg->name))); buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&type_arg->name)));
@ -5966,7 +6009,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, ImportTableEntry *target_import = add_source_file(ira->codegen, target_package,
abs_full_path, search_dir, import_target_path, import_code); abs_full_path, search_dir, import_target_path, import_code);
scan_decls(ira->codegen, target_import, target_import->scope, target_import->root); scan_decls(ira->codegen, target_import, target_import->decls_scope, target_import->root);
ConstExprValue *out_val = ir_build_const_from(ira, &import_instruction->base, depends_on_compile_var); ConstExprValue *out_val = ir_build_const_from(ira, &import_instruction->base, depends_on_compile_var);
out_val->data.x_import = target_import; out_val->data.x_import = target_import;
@ -6021,7 +6064,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count); IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count);
FnTableEntry *fn_entry = instruction->source_node->scope->fn_entry; FnTableEntry *fn_entry = scope_fn_entry(instruction->source_node->scope);
bool outside_fn = (fn_entry == nullptr); bool outside_fn = (fn_entry == nullptr);
ConstExprValue const_val = {}; ConstExprValue const_val = {};
@ -6124,7 +6167,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count); const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count);
const_val.data.x_array.size = elem_count; const_val.data.x_array.size = elem_count;
FnTableEntry *fn_entry = instruction->base.source_node->scope->fn_entry; FnTableEntry *fn_entry = scope_fn_entry(instruction->base.source_node->scope);
bool outside_fn = (fn_entry == nullptr); bool outside_fn = (fn_entry == nullptr);
IrInstruction **new_items = allocate<IrInstruction *>(elem_count); IrInstruction **new_items = allocate<IrInstruction *>(elem_count);

View file

@ -817,7 +817,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
const EnumDecl *enum_def = enum_decl->getDefinition(); const EnumDecl *enum_def = enum_decl->getDefinition();
if (!enum_def) { if (!enum_def) {
TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import, TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
c->import->scope, &c->import->decls_scope->base,
ContainerKindEnum, c->source_node, buf_ptr(full_type_name)); ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
c->enum_type_table.put(bare_name, enum_type); c->enum_type_table.put(bare_name, enum_type);
c->decl_table.put(enum_decl, enum_type); c->decl_table.put(enum_decl, enum_type);
@ -842,7 +842,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
if (pure_enum) { if (pure_enum) {
TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import, TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
c->import->scope, &c->import->decls_scope->base,
ContainerKindEnum, c->source_node, buf_ptr(full_type_name)); ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
c->enum_type_table.put(bare_name, enum_type); c->enum_type_table.put(bare_name, enum_type);
c->decl_table.put(enum_decl, enum_type); c->decl_table.put(enum_decl, enum_type);
@ -1002,7 +1002,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import, TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import,
c->import->scope, ContainerKindStruct, c->source_node, buf_ptr(full_type_name)); &c->import->decls_scope->base, ContainerKindStruct, c->source_node, buf_ptr(full_type_name));
c->struct_type_table.put(bare_name, struct_type); c->struct_type_table.put(bare_name, struct_type);
c->decl_table.put(record_decl, struct_type); c->decl_table.put(record_decl, struct_type);