diff --git a/src/all_types.hpp b/src/all_types.hpp index b65caeb24e..4b84254c7b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -20,6 +20,8 @@ struct AstNode; struct ImportTableEntry; struct FnTableEntry; struct Scope; +struct ScopeBlock; +struct ScopeFnDef; struct TypeTableEntry; struct VariableTableEntry; struct ErrorTableEntry; @@ -33,6 +35,13 @@ struct IrInstructionCast; struct IrBasicBlock; struct ScopeDecls; +struct IrGotoItem { + AstNode *source_node; + IrBasicBlock *bb; + size_t instruction_index; + Scope *scope; +}; + struct IrExecutable { ZigList basic_block_list; size_t mem_slot_count; @@ -41,8 +50,9 @@ struct IrExecutable { size_t backward_branch_quota; bool invalid; ZigList all_labels; - ZigList goto_list; + ZigList goto_list; bool is_inline; + FnTableEntry *fn_entry; }; enum OutType { @@ -129,36 +139,62 @@ enum ReturnKnowledge { ReturnKnowledgeSkipDefers, }; -struct StructValExprCodeGen { - TypeTableEntry *type_entry; - LLVMValueRef ptr; - AstNode *source_node; -}; - enum VisibMod { VisibModPrivate, VisibModPub, VisibModExport, }; +enum TldId { + TldIdVar, + TldIdFn, + TldIdContainer, + TldIdTypeDef, +}; + enum TldResolution { TldResolutionUnresolved, TldResolutionInvalid, TldResolutionOk, }; -struct TopLevelDecl { - // populated by parser +struct Tld { + TldId id; Buf *name; VisibMod visib_mod; + AstNode *source_node; - // populated by semantic analyzer ImportTableEntry *import; + Scope *parent_scope; // set this flag temporarily to detect infinite loops bool dep_loop_flag; TldResolution resolution; - AstNode *parent_decl; - IrInstruction *value; + Tld *parent_tld; +}; + +struct TldVar { + Tld base; + + VariableTableEntry *var; +}; + +struct TldFn { + Tld base; + + FnTableEntry *fn_entry; +}; + +struct TldContainer { + Tld base; + + ScopeDecls *decls_scope; + TypeTableEntry *type_entry; +}; + +struct TldTypeDef { + Tld base; + + TypeTableEntry *type_entry; }; struct TypeEnumField { @@ -223,7 +259,7 @@ struct AstNodeRoot { }; struct AstNodeFnProto { - TopLevelDecl top_level_decl; + VisibMod visib_mod; Buf *name; ZigList params; AstNode *return_type; @@ -232,28 +268,12 @@ struct AstNodeFnProto { bool is_inline; bool is_coldcc; bool is_nakedcc; - - // populated by semantic analyzer: - - // the function definition this fn proto is inside. can be null. AstNode *fn_def_node; - FnTableEntry *fn_table_entry; - bool skip; - // computed from params field - size_t inline_arg_count; - size_t inline_or_var_type_arg_count; - // if this is a generic function implementation, this points to the generic node - AstNode *generic_proto_node; }; struct AstNodeFnDef { AstNode *fn_proto; AstNode *body; - - // populated by semantic analyzer - TypeTableEntry *implicit_return_type; - Scope *containing_scope; - Scope *child_scope; }; struct AstNodeFnDecl { @@ -265,21 +285,10 @@ struct AstNodeParamDecl { AstNode *type; bool is_noalias; bool is_inline; - - // populated by semantic analyzer - VariableTableEntry *variable; }; struct AstNodeBlock { ZigList statements; - - // populated by semantic analyzer - // this one is the scope that the block itself introduces - Scope *child_block; - // this is the innermost scope created by defers and var decls. - // you can follow its parents up to child_block. it will equal - // child_block if there are no defers or var decls in the block. - Scope *nested_block; }; enum ReturnKind { @@ -298,14 +307,13 @@ struct AstNodeDefer { ReturnKind kind; AstNode *expr; - // populated by semantic analyzer: - size_t index_in_block; - LLVMBasicBlockRef basic_block; - Scope *child_block; + // temporary data used in IR generation + // TODO populate during gen_defer + Scope *child_scope; }; struct AstNodeVariableDeclaration { - TopLevelDecl top_level_decl; + VisibMod visib_mod; Buf *symbol; bool is_const; bool is_inline; @@ -313,28 +321,19 @@ struct AstNodeVariableDeclaration { // one or both of type and expr will be non null AstNode *type; AstNode *expr; - - // populated by semantic analyzer - VariableTableEntry *variable; }; struct AstNodeTypeDecl { - TopLevelDecl top_level_decl; + VisibMod visib_mod; Buf *symbol; AstNode *child_type; - - // populated by semantic analyzer - // if this is set, don't process the node; we've already done so - // and here is the type (with id TypeTableEntryIdTypeDecl) - TypeTableEntry *override_type; - TypeTableEntry *child_type_entry; }; struct AstNodeErrorValueDecl { - TopLevelDecl top_level_decl; + // always invalid if it's not VisibModPrivate but can be parsed that way + VisibMod visib_mod; Buf *name; - // populated by semantic analyzer ErrorTableEntry *err; }; @@ -388,19 +387,12 @@ struct AstNodeBinOpExpr { AstNode *op1; BinOpType bin_op; AstNode *op2; - - // populated by semantic analyzer: - // for when op is BinOpTypeAssign - VariableTableEntry *var_entry; }; struct AstNodeUnwrapErrorExpr { AstNode *op1; AstNode *symbol; // can be null AstNode *op2; - - // populated by semantic analyzer: - VariableTableEntry *var; }; enum CastOp { @@ -429,21 +421,11 @@ struct AstNodeFnCallExpr { AstNode *fn_ref_expr; ZigList params; bool is_builtin; - - // populated by semantic analyzer: - BuiltinFnEntry *builtin_fn; - FnTableEntry *fn_entry; - CastOp cast_op; - // if cast_op is CastOpArrayToString, this will be a pointer to - // the string struct on the stack - LLVMValueRef tmp_ptr; }; struct AstNodeArrayAccessExpr { AstNode *array_ref_expr; AstNode *subscript; - - // populated by semantic analyzer: }; struct AstNodeSliceExpr { @@ -451,22 +433,11 @@ struct AstNodeSliceExpr { AstNode *start; AstNode *end; bool is_const; - - // populated by semantic analyzer: - StructValExprCodeGen resolved_struct_val_expr; }; struct AstNodeFieldAccessExpr { AstNode *struct_expr; Buf *field_name; - - // populated by semantic analyzer - TypeStructField *type_struct_field; - TypeEnumField *type_enum_field; - StructValExprCodeGen resolved_struct_val_expr; // for enum values - TypeTableEntry *bare_container_type; - bool is_member_fn; - AstNode *container_init_expr_node; }; enum PrefixOp { @@ -487,24 +458,21 @@ enum PrefixOp { struct AstNodePrefixOpExpr { PrefixOp prefix_op; AstNode *primary_expr; - - // populated by semantic analyzer }; struct AstNodeUse { + VisibMod visib_mod; AstNode *expr; - // populated by semantic analyzer - TopLevelDecl top_level_decl; + TldResolution resolution; + IrInstruction *value; }; struct AstNodeIfBoolExpr { AstNode *condition; AstNode *then_block; AstNode *else_node; // null, block node, or other if expr node - bool is_inline; // TODO - - // populated by semantic analyzer + bool is_inline; // TODO parse inline if }; struct AstNodeIfVarExpr { @@ -512,10 +480,7 @@ struct AstNodeIfVarExpr { AstNode *then_block; AstNode *else_node; // null, block node, or other if expr node bool var_is_ptr; - bool is_inline; // TODO - - // populated by semantic analyzer - TypeTableEntry *type; + bool is_inline; // TODO parse inline ?if? }; struct AstNodeWhileExpr { @@ -523,11 +488,6 @@ struct AstNodeWhileExpr { AstNode *continue_expr; AstNode *body; bool is_inline; - - // populated by semantic analyzer - bool condition_always_true; - bool contains_break; - bool contains_continue; }; struct AstNodeForExpr { @@ -537,20 +497,12 @@ struct AstNodeForExpr { AstNode *body; bool elem_is_ptr; bool is_inline; - - // populated by semantic analyzer - bool contains_break; - bool contains_continue; - VariableTableEntry *elem_var; - VariableTableEntry *index_var; }; struct AstNodeSwitchExpr { AstNode *expr; ZigList prongs; bool is_inline; - - // populated by semantic analyzer }; struct AstNodeSwitchProng { @@ -573,10 +525,6 @@ struct AstNodeLabel { struct AstNodeGoto { Buf *name; bool is_inline; - - // populated by semantic analyzer - IrBasicBlock *bb; - size_t instruction_index; }; struct AsmOutput { @@ -584,9 +532,6 @@ struct AsmOutput { Buf *constraint; Buf *variable_name; AstNode *return_type; // null unless "=r" and return - - // populated by semantic analyzer - VariableTableEntry *variable; }; struct AsmInput { @@ -619,8 +564,6 @@ struct AstNodeAsmExpr { ZigList output_list; ZigList input_list; ZigList clobber_list; - - // populated by semantic analyzer }; enum ContainerKind { @@ -630,23 +573,17 @@ enum ContainerKind { }; struct AstNodeStructDecl { - TopLevelDecl top_level_decl; + VisibMod visib_mod; Buf *name; ContainerKind kind; ZigList generic_params; bool generic_params_is_var_args; // always an error but it can happen from parsing ZigList fields; ZigList decls; - - // populated by semantic analyzer - ScopeDecls *decls_scope; - TypeTableEntry *type_entry; - TypeTableEntry *generic_fn_type; - bool skip; }; struct AstNodeStructField { - TopLevelDecl top_level_decl; + VisibMod visib_mod; Buf *name; AstNode *type; }; @@ -654,14 +591,10 @@ struct AstNodeStructField { struct AstNodeStringLiteral { Buf *buf; bool c; - - // populated by semantic analyzer: }; struct AstNodeCharLiteral { uint8_t value; - - // populated by semantic analyzer: }; struct AstNodeNumberLiteral { @@ -670,16 +603,11 @@ struct AstNodeNumberLiteral { // overflow is true if when parsing the number, we discovered it would not // fit without losing data in a uint64_t or double bool overflow; - - // populated by semantic analyzer }; struct AstNodeStructValueField { Buf *name; AstNode *expr; - - // populated by semantic analyzer - TypeStructField *type_struct_field; }; enum ContainerInitKind { @@ -691,68 +619,47 @@ struct AstNodeContainerInitExpr { AstNode *type; ZigList entries; ContainerInitKind kind; - - // populated by semantic analyzer - StructValExprCodeGen resolved_struct_val_expr; - TypeTableEntry *enum_type; }; struct AstNodeNullLiteral { - // populated by semantic analyzer }; struct AstNodeUndefinedLiteral { - // populated by semantic analyzer }; struct AstNodeZeroesLiteral { - // populated by semantic analyzer }; struct AstNodeThisLiteral { - // populated by semantic analyzer }; struct AstNodeSymbolExpr { Buf *symbol; - - // populated by semantic analyzer - TypeEnumField *enum_field; - uint32_t err_value; }; struct AstNodeBoolLiteral { bool value; - - // populated by semantic analyzer }; struct AstNodeBreakExpr { - // populated by semantic analyzer }; struct AstNodeContinueExpr { - // populated by semantic analyzer }; struct AstNodeArrayType { AstNode *size; AstNode *child_type; bool is_const; - - // populated by semantic analyzer }; struct AstNodeErrorType { - // populated by semantic analyzer }; struct AstNodeTypeLiteral { - // populated by semantic analyzer }; struct AstNodeVarLiteral { - // populated by semantic analyzer }; struct AstNode { @@ -761,9 +668,6 @@ struct AstNode { size_t column; uint32_t create_index; // for determinism purposes ImportTableEntry *owner; - // the context in which this expression/node is evaluated. - // for blocks, this points to the containing scope, not the block's own scope for its children. - Scope *scope; union { AstNodeRoot root; AstNodeFnDef fn_def; @@ -822,26 +726,12 @@ struct FnTypeParamInfo { TypeTableEntry *type; }; -struct GenericParamValue { - TypeTableEntry *type; - AstNode *node; - size_t impl_index; -}; - -struct GenericFnTypeId { - AstNode *decl_node; // the generic fn or container decl node - GenericParamValue *generic_params; - size_t generic_param_count; -}; - -uint32_t generic_fn_type_id_hash(GenericFnTypeId *id); -bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b); - struct FnTypeId { TypeTableEntry *return_type; FnTypeParamInfo *param_info; size_t param_count; + size_t next_param_index; bool is_var_args; bool is_naked; bool is_cold; @@ -945,6 +835,7 @@ struct FnGenParamInfo { struct TypeTableEntryFn { FnTypeId fn_type_id; + bool is_generic; TypeTableEntry *gen_return_type; size_t gen_param_count; FnGenParamInfo *gen_param_info; @@ -955,10 +846,6 @@ struct TypeTableEntryFn { TypeTableEntry *bound_fn_parent; }; -struct TypeTableEntryGenericFn { - AstNode *decl_node; -}; - struct TypeTableEntryBoundFn { TypeTableEntry *fn_type; }; @@ -993,7 +880,6 @@ enum TypeTableEntryId { TypeTableEntryIdTypeDecl, TypeTableEntryIdNamespace, TypeTableEntryIdBlock, - TypeTableEntryIdGenericFn, TypeTableEntryIdBoundFn, }; @@ -1018,7 +904,6 @@ struct TypeTableEntry { TypeTableEntryUnion unionation; TypeTableEntryFn fn; TypeTableEntryTypeDecl type_decl; - TypeTableEntryGenericFn generic_fn; TypeTableEntryBoundFn bound_fn; } data; @@ -1056,10 +941,9 @@ enum FnAnalState { FnAnalStateReady, FnAnalStateProbing, FnAnalStateComplete, - FnAnalStateSkipped, + FnAnalStateInvalid, }; - enum FnInline { FnInlineAuto, FnInlineAlways, @@ -1067,14 +951,18 @@ enum FnInline { }; struct FnTableEntry { - LLVMValueRef fn_value; + LLVMValueRef llvm_value; AstNode *proto_node; AstNode *fn_def_node; + ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls + Scope *child_scope; // parent is scope for last parameter + ScopeBlock *def_scope; // parent is child_scope ImportTableEntry *import_entry; Buf symbol_name; TypeTableEntry *type_entry; // function type + TypeTableEntry *implicit_return_type; bool internal_linkage; - bool is_extern; + bool disable_export; bool is_test; FnInline fn_inline; FnAnalState anal_state; @@ -1161,11 +1049,10 @@ struct CodeGen { HashMap primitive_type_table; HashMap fn_type_table; HashMap error_table; - HashMap generic_table; ZigList import_queue; size_t import_queue_index; - ZigList resolve_queue; + ZigList resolve_queue; size_t resolve_queue_index; ZigList use_queue; size_t use_queue_index; @@ -1249,6 +1136,7 @@ struct CodeGen { // The function definitions this module includes. There must be a corresponding // fn_protos entry. ZigList fn_defs; + size_t fn_defs_index; // The function prototypes this module includes. In the case of external declarations, // there will not be a corresponding fn_defs entry. ZigList fn_protos; @@ -1258,6 +1146,7 @@ struct CodeGen { FnTableEntry *cur_fn; FnTableEntry *main_fn; LLVMValueRef cur_ret_ptr; + LLVMValueRef cur_fn_val; ZigList break_block_stack; ZigList continue_block_stack; bool c_want_stdint; @@ -1295,6 +1184,7 @@ struct CodeGen { IrInstruction *invalid_instruction; }; +// TODO after merging IR branch, we can probably delete some of these fields struct VariableTableEntry { Buf name; TypeTableEntry *type; @@ -1304,8 +1194,6 @@ struct VariableTableEntry { bool is_inline; // which node is the declaration of the variable AstNode *decl_node; - // which node contains the ConstExprValue for this variable's value - AstNode *val_node; ZigLLVMDILocalVariable *di_loc_var; size_t src_arg_index; size_t gen_arg_index; @@ -1313,10 +1201,10 @@ struct VariableTableEntry { Scope *child_scope; LLVMValueRef param_value_ref; bool force_depends_on_compile_var; - ImportTableEntry *import; bool shadowable; size_t mem_slot_index; size_t ref_count; + ConstExprValue *value; }; struct ErrorTableEntry { @@ -1339,9 +1227,6 @@ struct Scope { Scope *parent; ZigLLVMDIScope *di_scope; - - bool safety_off; - AstNode *safety_set_node; }; // This scope comes from global declarations or from @@ -1350,15 +1235,12 @@ struct Scope { struct ScopeDecls { Scope base; - HashMap decl_table; -}; - -// This scope comes from a container declaration such as a struct, -// enum, or union. -struct ScopeContainer { - Scope base; - - HashMap decl_table; + HashMap decl_table; + bool safety_off; + AstNode *safety_set_node; + ImportTableEntry *import; + // If this is a scope from a container, this is the type entry, otherwise null + TypeTableEntry *container_type; }; // This scope comes from a block expression in user code. @@ -1367,6 +1249,8 @@ struct ScopeBlock { Scope base; HashMap label_table; + bool safety_off; + AstNode *safety_set_node; }; // This scope is created from every defer expression. @@ -1401,7 +1285,7 @@ struct ScopeLoop { // This scope is created for a function definition. // NodeTypeFnDef -struct ScopeFnBody { +struct ScopeFnDef { Scope base; FnTableEntry *fn_entry; @@ -1479,6 +1363,7 @@ enum IrInstructionId { struct IrInstruction { IrInstructionId id; + Scope *scope; AstNode *source_node; ConstExprValue static_value; TypeTableEntry *type_entry; @@ -1798,6 +1683,7 @@ struct IrInstructionAsm { // Most information on inline assembly comes from the source node. IrInstruction **input_list; IrInstruction **output_types; + VariableTableEntry **output_vars; size_t return_count; bool has_side_effects; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index baa74365cd..c913d4a256 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -19,8 +19,8 @@ static const size_t default_backward_branch_quota = 1000; -static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type); -static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); +static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type); +static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type); AstNode *first_executing_node(AstNode *node) { switch (node->type) { @@ -130,9 +130,82 @@ ScopeDecls *get_container_scope(TypeTableEntry *type_entry) { return *get_container_scope_ptr(type_entry); } +void init_scope(Scope *dest, AstNode *node, Scope *parent) { + dest->node = node; + dest->parent = parent; +} + +static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import) { + assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl); + ScopeDecls *scope = allocate(1); + init_scope(&scope->base, node, parent); + scope->decl_table.init(4); + scope->container_type = container_type; + scope->import = import; + return scope; +} + +Scope *create_block_scope(AstNode *node, Scope *parent) { + assert(node->type == NodeTypeBlock); + ScopeBlock *scope = allocate(1); + init_scope(&scope->base, node, parent); + scope->label_table.init(1); + return &scope->base; +} + +Scope *create_defer_scope(AstNode *node, Scope *parent) { + assert(node->type == NodeTypeDefer); + ScopeDefer *scope = allocate(1); + init_scope(&scope->base, node, parent); + return &scope->base; +} + +Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) { + assert(node->type == NodeTypeVariableDeclaration || node->type == NodeTypeParamDecl); + ScopeVarDecl *scope = allocate(1); + init_scope(&scope->base, node, parent); + scope->var = var; + return &scope->base; +} + +Scope *create_cimport_scope(AstNode *node, Scope *parent) { + assert(node->type == NodeTypeFnCallExpr); + ScopeCImport *scope = allocate(1); + init_scope(&scope->base, node, 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(1); + init_scope(&scope->base, node, parent); + return &scope->base; +} + +ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) { + assert(node->type == NodeTypeFnDef); + ScopeFnDef *scope = allocate(1); + init_scope(&scope->base, node, parent); + scope->fn_entry = fn_entry; + return scope; +} + +ImportTableEntry *get_scope_import(Scope *scope) { + while (scope) { + if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) { + ScopeDecls *decls_scope = (ScopeDecls *)scope; + assert(decls_scope->import); + return decls_scope->import; + } + scope = scope->parent; + } + zig_unreachable(); +} + static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *source_node, Scope *parent_scope) { TypeTableEntry *entry = new_type_table_entry(id); - *get_container_scope_ptr(entry) = create_decls_scope(source_node, parent_scope); + *get_container_scope_ptr(entry) = create_decls_scope(source_node, parent_scope, entry, get_scope_import(parent_scope)); return entry; } @@ -179,7 +252,6 @@ bool type_is_complete(TypeTableEntry *type_entry) { case TypeTableEntryIdTypeDecl: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: return true; } @@ -202,14 +274,6 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { return get_int_type(g, false, bits_needed_for_unsigned(x)); } -static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) { - TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn); - buf_init_from_str(&entry->name, "(generic function)"); - entry->zero_bits = true; - entry->data.generic_fn.decl_node = decl_node; - return entry; -} - TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { assert(child_type->id != TypeTableEntryIdInvalid); TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; @@ -643,8 +707,7 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) { return bound_fn_type; } -// accepts ownership of fn_type_id memory -TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info) { +TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { auto table_entry = g->fn_type_table.maybe_get(fn_type_id); if (table_entry) { return table_entry->value; @@ -685,68 +748,66 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_inf buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name)); } - if (gen_debug_info) { - // next, loop over the parameters again and compute debug information - // and codegen information - bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); - // +1 for maybe making the first argument the return value - LLVMTypeRef *gen_param_types = allocate(1 + fn_type_id->param_count); - // +1 because 0 is the return type and +1 for maybe making first arg ret val - ZigLLVMDIType **param_di_types = allocate(2 + fn_type_id->param_count); - param_di_types[0] = fn_type_id->return_type->di_type; - size_t gen_param_index = 0; - TypeTableEntry *gen_return_type; - if (!type_has_bits(fn_type_id->return_type)) { - gen_return_type = g->builtin_types.entry_void; - } else if (first_arg_return) { - TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); + // next, loop over the parameters again and compute debug information + // and codegen information + bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); + // +1 for maybe making the first argument the return value + LLVMTypeRef *gen_param_types = allocate(1 + fn_type_id->param_count); + // +1 because 0 is the return type and +1 for maybe making first arg ret val + ZigLLVMDIType **param_di_types = allocate(2 + fn_type_id->param_count); + param_di_types[0] = fn_type_id->return_type->di_type; + size_t gen_param_index = 0; + TypeTableEntry *gen_return_type; + if (!type_has_bits(fn_type_id->return_type)) { + gen_return_type = g->builtin_types.entry_void; + } else if (first_arg_return) { + TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); + gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_index += 1; + // after the gen_param_index += 1 because 0 is the return type + param_di_types[gen_param_index] = gen_type->di_type; + gen_return_type = g->builtin_types.entry_void; + } else { + gen_return_type = fn_type_id->return_type; + } + fn_type->data.fn.gen_return_type = gen_return_type; + + fn_type->data.fn.gen_param_info = allocate(fn_type_id->param_count); + for (size_t i = 0; i < fn_type_id->param_count; i += 1) { + FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; + TypeTableEntry *type_entry = src_param_info->type; + FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; + + gen_param_info->src_index = i; + gen_param_info->gen_index = SIZE_MAX; + + assert(type_is_complete(type_entry)); + if (type_has_bits(type_entry)) { + TypeTableEntry *gen_type; + if (handle_is_ptr(type_entry)) { + gen_type = get_pointer_to_type(g, type_entry, true); + gen_param_info->is_byval = true; + } else { + gen_type = type_entry; + } gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_info->gen_index = gen_param_index; + gen_param_info->type = gen_type; + gen_param_index += 1; + // after the gen_param_index += 1 because 0 is the return type param_di_types[gen_param_index] = gen_type->di_type; - gen_return_type = g->builtin_types.entry_void; - } else { - gen_return_type = fn_type_id->return_type; } - fn_type->data.fn.gen_return_type = gen_return_type; - - fn_type->data.fn.gen_param_info = allocate(fn_type_id->param_count); - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; - TypeTableEntry *type_entry = src_param_info->type; - FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; - - gen_param_info->src_index = i; - gen_param_info->gen_index = SIZE_MAX; - - assert(type_is_complete(type_entry)); - if (type_has_bits(type_entry)) { - TypeTableEntry *gen_type; - if (handle_is_ptr(type_entry)) { - gen_type = get_pointer_to_type(g, type_entry, true); - gen_param_info->is_byval = true; - } else { - gen_type = type_entry; - } - gen_param_types[gen_param_index] = gen_type->type_ref; - gen_param_info->gen_index = gen_param_index; - gen_param_info->type = gen_type; - - gen_param_index += 1; - - // after the gen_param_index += 1 because 0 is the return type - param_di_types[gen_param_index] = gen_type->di_type; - } - } - - fn_type->data.fn.gen_param_count = gen_param_index; - - fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, - gen_param_types, gen_param_index, fn_type_id->is_var_args); - fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); - fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); } + fn_type->data.fn.gen_param_count = gen_param_index; + + fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, + gen_param_types, gen_param_index, fn_type_id->is_var_args); + fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); + fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); + g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); return fn_type; @@ -767,6 +828,7 @@ static TypeTableEntryId container_to_type(ContainerKind kind) { TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *scope, ContainerKind kind, AstNode *decl_node, const char *name) { + TypeTableEntryId type_id = container_to_type(kind); TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope); @@ -782,7 +844,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, break; } - unsigned line = decl_node ? decl_node->line : 0; + unsigned line = decl_node->line; entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, @@ -794,6 +856,14 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, return entry; } +static TypeTableEntry *get_partial_container_type_tld(CodeGen *g, Scope *scope, TldContainer *tld_container) { + ImportTableEntry *import = tld_container->base.import; + AstNode *container_node = tld_container->base.source_node; + assert(container_node->type == NodeTypeContainerDecl); + ContainerKind kind = container_node->data.struct_decl.kind; + return get_partial_container_type(g, import, scope, kind, container_node, buf_ptr(tld_container->base.name)); +} + TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry) { if (type_entry->id == TypeTableEntryIdTypeDecl) { @@ -842,9 +912,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod return result; } -static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, Scope *scope, - AstNode *node) -{ +static TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type); if (result->type_entry->id == TypeTableEntryIdInvalid) return g->builtin_types.entry_invalid; @@ -853,71 +921,77 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, S return result->static_value.data.x_type; } -static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) { - assert(fn_table_entry); - return false; +static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { + TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); + fn_type->data.fn.fn_type_id = *fn_type_id; + fn_type->data.fn.is_generic = true; + return fn_type; } -// 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 *scope, - TypeTableEntry *expected_type, AstNode *node, bool is_naked, bool is_cold, FnTableEntry *fn_table_entry) -{ - assert(node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &node->data.fn_proto; - - if (fn_proto->skip) { - return g->builtin_types.entry_invalid; - } +static TypeTableEntry *analyze_fn_type(CodeGen *g, TldFn *tld_fn) { + AstNode *proto_node = tld_fn->base.source_node; + assert(proto_node->type == NodeTypeFnProto); + AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; FnTypeId fn_type_id = {0}; - fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport); - fn_type_id.is_naked = is_naked; - fn_type_id.is_cold = is_cold; + fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); + fn_type_id.is_naked = fn_proto->is_nakedcc; + fn_type_id.is_cold = fn_proto->is_coldcc; fn_type_id.param_count = fn_proto->params.length; fn_type_id.param_info = allocate_nonzero(fn_type_id.param_count); - + fn_type_id.next_param_index = 0; fn_type_id.is_var_args = fn_proto->is_var_args; - for (size_t i = 0; i < fn_type_id.param_count; i += 1) { - AstNode *child = fn_proto->params.at(i); - assert(child->type == NodeTypeParamDecl); + FnTableEntry *fn_entry = tld_fn->fn_entry; + Scope *child_scope = fn_entry->fndef_scope ? &fn_entry->fndef_scope->base : tld_fn->base.parent_scope; - TypeTableEntry *type_entry; - if (fn_proto->skip) { - type_entry = g->builtin_types.entry_invalid; - } else { - type_entry = analyze_type_expr(g, import, scope, child->data.param_decl.type); + for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { + AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); + assert(param_node->type == NodeTypeParamDecl); + + bool param_is_inline = param_node->data.param_decl.is_inline; + + if (param_is_inline) { + if (fn_type_id.is_extern) { + add_node_error(g, param_node, + buf_sprintf("inline parameter not allowed in extern function")); + return g->builtin_types.entry_invalid; + } + return get_generic_fn_type(g, &fn_type_id); } + if (fn_entry && buf_len(param_node->data.param_decl.name) == 0) { + add_node_error(g, param_node, buf_sprintf("missing parameter name")); + } + + TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type); + switch (type_entry->id) { case TypeTableEntryIdInvalid: - fn_proto->skip = true; - break; - case TypeTableEntryIdNumLitFloat: - case TypeTableEntryIdNumLitInt: + return g->builtin_types.entry_invalid; + case TypeTableEntryIdUnreachable: case TypeTableEntryIdUndefLit: case TypeTableEntryIdNullLit: - case TypeTableEntryIdUnreachable: + add_node_error(g, param_node->data.param_decl.type, + buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name))); + return g->builtin_types.entry_invalid; + case TypeTableEntryIdVar: + if (fn_type_id.is_extern) { + add_node_error(g, param_node->data.param_decl.type, + buf_sprintf("parameter of type 'var' not allowed in extern function")); + return g->builtin_types.entry_invalid; + } + return get_generic_fn_type(g, &fn_type_id); + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: - if (!fn_proto->skip) { - fn_proto->skip = true; - add_node_error(g, child->data.param_decl.type, - buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name))); - } - break; case TypeTableEntryIdMetaType: - if (!child->data.param_decl.is_inline) { - if (!fn_proto->skip) { - fn_proto->skip = true; - add_node_error(g, child->data.param_decl.type, - buf_sprintf("parameter of type '%s' must be declared inline", - buf_ptr(&type_entry->name))); - } - } - break; + add_node_error(g, param_node->data.param_decl.type, + buf_sprintf("parameter of type '%s' must be declared inline", + buf_ptr(&type_entry->name))); + return g->builtin_types.entry_invalid; case TypeTableEntryIdVoid: case TypeTableEntryIdBool: case TypeTableEntryIdInt: @@ -933,44 +1007,38 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: break; - case TypeTableEntryIdVar: - // var types are treated as generic functions; if we get to this code we should - // already be an instantiated function. - zig_unreachable(); } - if (type_entry->id == TypeTableEntryIdInvalid) { - fn_proto->skip = true; - } - FnTypeParamInfo *param_info = &fn_type_id.param_info[i]; + FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; param_info->type = type_entry; - param_info->is_noalias = child->data.param_decl.is_noalias; + param_info->is_noalias = param_node->data.param_decl.is_noalias; } - if (fn_proto->skip) { - fn_type_id.return_type = g->builtin_types.entry_invalid; - } else { - fn_type_id.return_type = analyze_type_expr(g, import, scope, fn_proto->return_type); - } + fn_type_id.return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); + switch (fn_type_id.return_type->id) { case TypeTableEntryIdInvalid: - fn_proto->skip = true; - break; - case TypeTableEntryIdNumLitFloat: - case TypeTableEntryIdNumLitInt: + return g->builtin_types.entry_invalid; + case TypeTableEntryIdUndefLit: case TypeTableEntryIdNullLit: + add_node_error(g, fn_proto->return_type, + buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); + return g->builtin_types.entry_invalid; + + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: - if (!fn_proto->skip) { - fn_proto->skip = true; - add_node_error(g, fn_proto->return_type, - buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name))); - } - break; case TypeTableEntryIdMetaType: + if (fn_type_id.is_extern) { + add_node_error(g, fn_proto->return_type, + buf_sprintf("return type '%s' not allowed in extern function", + buf_ptr(&fn_type_id.return_type->name))); + return g->builtin_types.entry_invalid; + } + return get_generic_fn_type(g, &fn_type_id); case TypeTableEntryIdUnreachable: case TypeTableEntryIdVoid: case TypeTableEntryIdBool: @@ -989,114 +1057,10 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor break; } - - if (fn_proto->skip) { - return g->builtin_types.entry_invalid; - } - - if (fn_table_entry && fn_type_id.return_type->id == TypeTableEntryIdMetaType) { - ErrorMsg *err_msg = nullptr; - for (size_t i = 0; i < fn_proto->params.length; i += 1) { - AstNode *param_decl_node = fn_proto->params.at(i); - assert(param_decl_node->type == NodeTypeParamDecl); - if (!param_decl_node->data.param_decl.is_inline) { - if (!err_msg) { - err_msg = add_node_error(g, fn_proto->return_type, - buf_sprintf("function with return type '%s' must declare all parameters inline", - buf_ptr(&fn_type_id.return_type->name))); - } - add_error_note(g, err_msg, param_decl_node, - buf_sprintf("non-inline parameter here")); - } - } - if (err_msg) { - fn_proto->skip = true; - return g->builtin_types.entry_invalid; - } - } - - bool gen_debug_info = fn_table_entry && !fn_wants_full_static_eval(fn_table_entry); - return get_fn_type(g, &fn_type_id, gen_debug_info); + return get_fn_type(g, &fn_type_id); } -static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, - ImportTableEntry *import, Scope *containing_scope) -{ - assert(node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &node->data.fn_proto; - - if (fn_proto->skip) { - return; - } - - bool is_internal = (fn_proto->top_level_decl.visib_mod != VisibModExport); - bool is_c_compat = !is_internal || fn_proto->is_extern; - fn_table_entry->internal_linkage = !is_c_compat; - - - - 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_table_entry->type_entry = fn_type; - - if (fn_type->id == TypeTableEntryIdInvalid) { - fn_proto->skip = true; - return; - } - - if (fn_proto->is_inline) { - fn_table_entry->fn_inline = FnInlineAlways; - } - - - Buf *symbol_name; - if (is_c_compat) { - symbol_name = &fn_table_entry->symbol_name; - } else { - symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name)); - } - - if (fn_table_entry->fn_def_node) { - fn_table_entry->fn_def_node->data.fn_def.containing_scope = create_fndef_scope( - fn_table_entry->fn_def_node, containing_scope, fn_table_entry); - } - - if (!fn_wants_full_static_eval(fn_table_entry)) { - fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); - - switch (fn_table_entry->fn_inline) { - case FnInlineAlways: - LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); - break; - case FnInlineNever: - LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoInlineAttribute); - break; - case FnInlineAuto: - break; - } - if (fn_type->data.fn.fn_type_id.is_naked) { - LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute); - } - - LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? - LLVMInternalLinkage : LLVMExternalLinkage); - - if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { - LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute); - } - LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention); - if (!fn_table_entry->is_extern) { - LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute); - } - if (!g->is_release_build && fn_table_entry->fn_inline != FnInlineAlways) { - ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim", "true"); - ZigLLVMAddFunctionAttr(fn_table_entry->fn_value, "no-frame-pointer-elim-non-leaf", nullptr); - } - } -} - -static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type) { +static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { // if you change this logic you likely must also change similar logic in parseh.cpp assert(enum_type->id == TypeTableEntryIdEnum); @@ -1133,6 +1097,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt uint64_t biggest_union_member_size_in_bits = 0; Scope *scope = &enum_type->data.enumeration.decls_scope->base; + ImportTableEntry *import = get_scope_import(scope); // set temporary flag enum_type->data.enumeration.embedded_in_current = true; @@ -1142,17 +1107,16 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt AstNode *field_node = decl_node->data.struct_decl.fields.at(i); TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; type_enum_field->name = field_node->data.struct_field.name; - TypeTableEntry *field_type = analyze_type_expr(g, import, scope, - field_node->data.struct_field.type); + TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); type_enum_field->type_entry = field_type; type_enum_field->value = i; di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); if (field_type->id == TypeTableEntryIdStruct) { - resolve_struct_type(g, import, field_type); + resolve_struct_type(g, field_type); } else if (field_type->id == TypeTableEntryIdEnum) { - resolve_enum_type(g, import, field_type); + resolve_enum_type(g, field_type); } else if (field_type->id == TypeTableEntryIdInvalid) { enum_type->data.enumeration.is_invalid = true; continue; @@ -1281,7 +1245,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt } } -static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type) { +static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { // if you change the logic of this function likely you must make a similar change in // parseh.cpp assert(struct_type->id == TypeTableEntryIdStruct); @@ -1319,22 +1283,23 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE struct_type->data.structure.embedded_in_current = true; Scope *scope = &struct_type->data.structure.decls_scope->base; + ImportTableEntry *import = get_scope_import(scope); size_t gen_field_index = 0; for (size_t i = 0; i < field_count; i += 1) { AstNode *field_node = decl_node->data.struct_decl.fields.at(i); TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; type_struct_field->name = field_node->data.struct_field.name; - TypeTableEntry *field_type = analyze_type_expr(g, import, scope, + TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); type_struct_field->type_entry = field_type; type_struct_field->src_index = i; type_struct_field->gen_index = SIZE_MAX; if (field_type->id == TypeTableEntryIdStruct) { - resolve_struct_type(g, import, field_type); + resolve_struct_type(g, field_type); } else if (field_type->id == TypeTableEntryIdEnum) { - resolve_enum_type(g, import, field_type); + resolve_enum_type(g, field_type); } else if (field_type->id == TypeTableEntryIdInvalid) { struct_type->data.structure.is_invalid = true; continue; @@ -1408,16 +1373,13 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE struct_type->zero_bits = (debug_size_in_bits == 0); } -static void resolve_union_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type) { +static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { zig_panic("TODO"); } -static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t sep) { - TopLevelDecl *tld = get_as_top_level_decl(decl_node); - AstNode *parent_decl = tld->parent_decl; - - if (parent_decl) { - get_fully_qualified_decl_name(buf, parent_decl, sep); +static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { + if (tld->parent_tld) { + get_fully_qualified_decl_name(buf, tld->parent_tld, sep); buf_append_char(buf, sep); buf_append_buf(buf, tld->name); } else { @@ -1425,183 +1387,109 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t } } -static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) { - assert(node->type == NodeTypeContainerDecl); - - if (node->data.struct_decl.generic_params_is_var_args) { - add_node_error(g, node, buf_sprintf("generic parameters cannot be var args")); - node->data.struct_decl.skip = true; - node->data.struct_decl.generic_fn_type = g->builtin_types.entry_invalid; - return; - } - - node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node); -} - -static bool get_is_generic_fn(AstNode *proto_node) { +static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { + ImportTableEntry *import = tld_fn->base.import; + AstNode *proto_node = tld_fn->base.source_node; assert(proto_node->type == NodeTypeFnProto); - return proto_node->data.fn_proto.inline_or_var_type_arg_count > 0; -} + AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; -static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node, - Scope *containing_scope) -{ - assert(proto_node->type == NodeTypeFnProto); + AstNode *fn_def_node = fn_proto->fn_def_node; - if (proto_node->data.fn_proto.skip) { - return; - } - - bool is_generic_instance = proto_node->data.fn_proto.generic_proto_node; - bool is_generic_fn = get_is_generic_fn(proto_node); - assert(!is_generic_instance || !is_generic_fn); - - AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl; - Buf *proto_name = proto_node->data.fn_proto.name; - - AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node; - bool is_extern = proto_node->data.fn_proto.is_extern; - - assert(!is_extern || !is_generic_instance); - - if (fn_def_node && proto_node->data.fn_proto.is_var_args) { + if (fn_def_node && fn_proto->is_var_args) { add_node_error(g, proto_node, buf_sprintf("variadic arguments only allowed in extern function declarations")); + tld_fn->base.resolution = TldResolutionInvalid; + return; } FnTableEntry *fn_table_entry = allocate(1); fn_table_entry->analyzed_executable.backward_branch_quota = default_backward_branch_quota; + fn_table_entry->ir_executable.fn_entry = fn_table_entry; + fn_table_entry->analyzed_executable.fn_entry = fn_table_entry; fn_table_entry->import_entry = import; fn_table_entry->proto_node = proto_node; fn_table_entry->fn_def_node = fn_def_node; - fn_table_entry->is_extern = is_extern; + fn_table_entry->fn_inline = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; + fn_table_entry->internal_linkage = (fn_proto->visib_mod != VisibModExport); - get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_'); + get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); - proto_node->data.fn_proto.fn_table_entry = fn_table_entry; + tld_fn->fn_entry = fn_table_entry; - if (is_generic_fn) { - fn_table_entry->type_entry = get_generic_fn_type(g, proto_node); - - if (is_extern || proto_node->data.fn_proto.top_level_decl.visib_mod == VisibModExport) { - for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { - AstNode *param_decl_node = proto_node->data.fn_proto.params.at(i); - if (param_decl_node->data.param_decl.is_inline) { - proto_node->data.fn_proto.skip = true; - add_node_error(g, param_decl_node, - buf_sprintf("inline parameter not allowed in extern function")); - } - } - } - - - } else { - resolve_function_proto(g, proto_node, fn_table_entry, import, containing_scope); - - if (!fn_wants_full_static_eval(fn_table_entry)) { - g->fn_protos.append(fn_table_entry); - - if (fn_def_node) { - g->fn_defs.append(fn_table_entry); - } - - bool is_main_fn = !is_generic_instance && - !parent_decl && (import == g->root_import) && - !proto_node->data.fn_proto.skip && - buf_eql_str(proto_name, "main"); - if (is_main_fn) { - g->main_fn = fn_table_entry; - } - - if (is_main_fn && !g->link_libc) { - TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); - TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; - if (actual_return_type != err_void) { - AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type; - add_node_error(g, return_type_node, - buf_sprintf("expected return type of main to be '%%void', instead is '%s'", - buf_ptr(&actual_return_type->name))); - } - } - } - } -} - -static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, - AstNode *node, Buf *name) -{ - assert(import); - - TopLevelDecl *tld = get_as_top_level_decl(node); - tld->import = import; - tld->name = name; - - bool want_to_resolve = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport); - bool is_generic_container = (node->type == NodeTypeContainerDecl && - node->data.struct_decl.generic_params.length > 0); - if (want_to_resolve && !is_generic_container) { - g->resolve_queue.append(node); + if (fn_table_entry->fn_def_node) { + fn_table_entry->fndef_scope = create_fndef_scope( + fn_table_entry->fn_def_node, tld_fn->base.parent_scope, fn_table_entry); } - node->scope = &decls_scope->base; + fn_table_entry->type_entry = analyze_fn_type(g, tld_fn); - auto entry = decls_scope->decl_table.put_unique(name, node); - if (entry) { - AstNode *other_decl_node = entry->value; - 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")); - } -} - -static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node) { - assert(node->type == NodeTypeContainerDecl); - - if (node->data.struct_decl.type_entry) { - // already scanned; we can ignore. This can happen from importing from an .h file. + if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { + tld_fn->base.resolution = TldResolutionInvalid; return; } - Buf *name = node->data.struct_decl.name; - 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.type_entry = container_type; + if (!fn_table_entry->type_entry->data.fn.is_generic) { + g->fn_protos.append(fn_table_entry); - // handle the member function definitions independently - for (size_t i = 0; i < node->data.struct_decl.decls.length; i += 1) { - AstNode *child_node = node->data.struct_decl.decls.at(i); - get_as_top_level_decl(child_node)->parent_decl = node; - ScopeDecls *child_scope = get_container_scope(container_type); - scan_decls(g, import, child_scope, child_node); + if (fn_def_node) + g->fn_defs.append(fn_table_entry); + + Tld *parent_tld = tld_fn->base.parent_tld; + bool is_main_fn = !parent_tld && (import == g->root_import) && + buf_eql_str(&fn_table_entry->symbol_name, "main"); + if (is_main_fn) + g->main_fn = fn_table_entry; + + if (is_main_fn && !g->link_libc) { + TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); + TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; + if (actual_return_type != err_void) { + add_node_error(g, fn_proto->return_type, + buf_sprintf("expected return type of main to be '%%void', instead is '%s'", + buf_ptr(&actual_return_type->name))); + } + } } } -static void count_inline_and_var_args(AstNode *proto_node) { - assert(proto_node->type == NodeTypeFnProto); +static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { + bool want_to_resolve = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport); + if (want_to_resolve) + g->resolve_queue.append(tld); - size_t *inline_arg_count = &proto_node->data.fn_proto.inline_arg_count; - size_t *inline_or_var_type_arg_count = &proto_node->data.fn_proto.inline_or_var_type_arg_count; + auto entry = decls_scope->decl_table.put_unique(tld->name, tld); + if (entry) { + Tld *other_tld = entry->value; + ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name))); + add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here")); + return; + } +} - *inline_arg_count = 0; - *inline_or_var_type_arg_count = 0; +static void scan_struct_decl(CodeGen *g, ScopeDecls *decls_scope, TldContainer *tld_container) { + assert(!tld_container->type_entry); - // TODO run these nodes through the type analysis system rather than looking for - // specialized ast nodes. this would get fooled by `{var}` instead of `var` which - // is supposed to be equivalent - for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(i); - assert(param_node->type == NodeTypeParamDecl); - if (param_node->data.param_decl.is_inline) { - *inline_arg_count += 1; - *inline_or_var_type_arg_count += 1; - } else if (param_node->data.param_decl.type->type == NodeTypeVarLiteral) { - *inline_or_var_type_arg_count += 1; - } + AstNode *container_node = tld_container->base.source_node; + assert(container_node->type == NodeTypeContainerDecl); + + TypeTableEntry *container_type = get_partial_container_type_tld(g, &decls_scope->base, tld_container); + tld_container->type_entry = container_type; + + // handle the member function definitions independently + for (size_t i = 0; i < container_node->data.struct_decl.decls.length; i += 1) { + AstNode *child_node = container_node->data.struct_decl.decls.at(i); + ScopeDecls *child_scope = get_container_scope(container_type); + scan_decls(g, tld_container->base.import, child_scope, child_node, &tld_container->base); } } static void preview_error_value_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeErrorValueDecl); + if (node->data.error_value_decl.visib_mod != VisibModPrivate) { + add_node_error(g, node, buf_sprintf("error values require no visibility modifier")); + } + ErrorTableEntry *err = allocate(1); err->decl_node = node; @@ -1620,40 +1508,61 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) { } node->data.error_value_decl.err = err; - node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk; } -void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node) { +void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, + Scope *parent_scope, Tld *parent_tld) +{ + tld->id = id; + tld->name = name; + tld->visib_mod = visib_mod; + tld->source_node = source_node; + tld->import = source_node->owner; + tld->parent_scope = parent_scope; + tld->parent_tld = parent_tld; +} + +void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node, Tld *parent_tld) { switch (node->type) { case NodeTypeRoot: 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); - scan_decls(g, import, decls_scope, child); + scan_decls(g, import, decls_scope, child, parent_tld); } break; case NodeTypeContainerDecl: { Buf *name = node->data.struct_decl.name; - add_top_level_decl(g, import, decls_scope, node, name); + VisibMod visib_mod = node->data.struct_decl.visib_mod; + TldContainer *tld_container = allocate(1); + init_tld(&tld_container->base, TldIdContainer, name, visib_mod, node, &decls_scope->base, parent_tld); + add_top_level_decl(g, decls_scope, &tld_container->base); if (node->data.struct_decl.generic_params.length == 0) { - scan_struct_decl(g, import, decls_scope, node); + scan_struct_decl(g, decls_scope, tld_container); + } else { + zig_panic("TODO all structs anonymous?"); } } break; case NodeTypeFnDef: - node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node; - scan_decls(g, import, decls_scope, node->data.fn_def.fn_proto); + scan_decls(g, import, decls_scope, node->data.fn_def.fn_proto, parent_tld); break; case NodeTypeVariableDeclaration: { Buf *name = node->data.variable_declaration.symbol; - add_top_level_decl(g, import, decls_scope, node, name); + VisibMod visib_mod = node->data.variable_declaration.visib_mod; + TldVar *tld_var = allocate(1); + init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base, parent_tld); + add_top_level_decl(g, decls_scope, &tld_var->base); break; } case NodeTypeTypeDecl: { Buf *name = node->data.type_decl.symbol; - add_top_level_decl(g, import, decls_scope, node, name); + VisibMod visib_mod = node->data.type_decl.visib_mod; + TldTypeDef *tld_typedef = allocate(1); + init_tld(&tld_typedef->base, TldIdTypeDef, name, visib_mod, node, &decls_scope->base, parent_tld); + add_top_level_decl(g, decls_scope, &tld_typedef->base); break; } case NodeTypeFnProto: @@ -1661,22 +1570,20 @@ void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, A // if the name is missing, we immediately announce an error Buf *fn_name = node->data.fn_proto.name; if (buf_len(fn_name) == 0) { - node->data.fn_proto.skip = true; add_node_error(g, node, buf_sprintf("missing function name")); break; } - count_inline_and_var_args(node); - add_top_level_decl(g, import, decls_scope, node, fn_name); + VisibMod visib_mod = node->data.fn_proto.visib_mod; + TldFn *tld_fn = allocate(1); + init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base, parent_tld); + add_top_level_decl(g, decls_scope, &tld_fn->base); break; } case NodeTypeUse: { - TopLevelDecl *tld = get_as_top_level_decl(node); - tld->import = import; - node->scope = &decls_scope->base; g->use_queue.append(node); - tld->import->use_decls.append(node); + import->use_decls.append(node); break; } case NodeTypeErrorValueDecl: @@ -1727,30 +1634,22 @@ void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, A } } -static void resolve_struct_instance(CodeGen *g, ImportTableEntry *import, AstNode *node) { - TypeTableEntry *type_entry = node->data.struct_decl.type_entry; +static void resolve_decl_container(CodeGen *g, TldContainer *tld_container) { + TypeTableEntry *type_entry = tld_container->type_entry; assert(type_entry); - // struct/enum member fns will get resolved independently - - switch (node->data.struct_decl.kind) { - case ContainerKindStruct: - resolve_struct_type(g, import, type_entry); - break; + switch (type_entry->id) { + case TypeTableEntryIdStruct: + resolve_struct_type(g, tld_container->type_entry); + return; case ContainerKindEnum: - resolve_enum_type(g, import, type_entry); - break; + resolve_enum_type(g, tld_container->type_entry); + return; case ContainerKindUnion: - resolve_union_type(g, import, type_entry); - break; - } -} - -static void resolve_struct_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { - if (node->data.struct_decl.generic_params.length > 0) { - return preview_generic_fn_proto(g, import, node); - } else { - return resolve_struct_instance(g, import, node); + resolve_union_type(g, tld_container->type_entry); + return; + default: + zig_unreachable(); } } @@ -1786,7 +1685,6 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: case TypeTableEntryIdFn: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: return type_entry; } @@ -1795,15 +1693,16 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt // Set name to nullptr to make the variable anonymous (not visible to programmer). // TODO merge with definition of add_local_var in ir.cpp -static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import, - Scope *parent_scope, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node) +VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, + TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value) { VariableTableEntry *variable_entry = allocate(1); variable_entry->type = type_entry; variable_entry->parent_scope = parent_scope; - variable_entry->import = import; variable_entry->shadowable = false; variable_entry->mem_slot_index = SIZE_MAX; + variable_entry->value = init_value; + variable_entry->src_arg_index = SIZE_MAX; assert(name); @@ -1824,11 +1723,11 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Impor buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); variable_entry->type = g->builtin_types.entry_invalid; } else { - AstNode *decl_node = find_decl(parent_scope, name); - if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { + Tld *tld = find_decl(parent_scope, name); + if (tld && tld->id != TldIdVar) { ErrorMsg *msg = add_node_error(g, source_node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); - add_error_note(g, msg, decl_node, buf_sprintf("previous definition is here")); + add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); variable_entry->type = g->builtin_types.entry_invalid; } } @@ -1847,78 +1746,84 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Impor variable_entry->src_is_const = is_const; variable_entry->gen_is_const = is_const; variable_entry->decl_node = source_node; - variable_entry->val_node = val_node; variable_entry->child_scope = child_scope; return variable_entry; } -static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { - assert(node->type == NodeTypeVariableDeclaration); +static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { + AstNodeVariableDeclaration *var_decl = &tld_var->base.source_node->data.variable_declaration; - AstNodeVariableDeclaration *var_decl = &node->data.variable_declaration; - Scope *scope = node->scope; bool is_const = var_decl->is_const; - bool is_export = (var_decl->top_level_decl.visib_mod == VisibModExport); + bool is_export = (tld_var->base.visib_mod == VisibModExport); bool is_extern = var_decl->is_extern; TypeTableEntry *explicit_type = nullptr; if (var_decl->type) { - TypeTableEntry *proposed_type = analyze_type_expr(g, import, scope, var_decl->type); + TypeTableEntry *proposed_type = analyze_type_expr(g, tld_var->base.parent_scope, var_decl->type); explicit_type = validate_var_type(g, var_decl->type, proposed_type); } + AstNode *source_node = tld_var->base.source_node; + + IrInstruction *init_value = nullptr; + TypeTableEntry *implicit_type = nullptr; if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) { implicit_type = explicit_type; } else if (var_decl->expr) { - IrInstruction *result = analyze_const_value(g, scope, var_decl->expr, explicit_type); - assert(result); - implicit_type = result->type_entry; + init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type); + assert(init_value); + implicit_type = init_value->type_entry; if (implicit_type->id == TypeTableEntryIdUnreachable) { - add_node_error(g, node, buf_sprintf("variable initialization is unreachable")); + add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); implicit_type = g->builtin_types.entry_invalid; } else if ((!is_const || is_export) && (implicit_type->id == TypeTableEntryIdNumLitFloat || implicit_type->id == TypeTableEntryIdNumLitInt)) { - add_node_error(g, node, buf_sprintf("unable to infer variable type")); + add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); implicit_type = g->builtin_types.entry_invalid; } else if (implicit_type->id == TypeTableEntryIdNullLit) { - add_node_error(g, node, buf_sprintf("unable to infer variable type")); + add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); implicit_type = g->builtin_types.entry_invalid; } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) { - add_node_error(g, node, buf_sprintf("variable of type 'type' must be constant")); + add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); implicit_type = g->builtin_types.entry_invalid; } - if (implicit_type->id != TypeTableEntryIdInvalid) { - assert(result->static_value.special != ConstValSpecialRuntime); - var_decl->top_level_decl.value = result; - } + assert(implicit_type->id == TypeTableEntryIdInvalid || init_value->static_value.special != ConstValSpecialRuntime); } else if (!is_extern) { - add_node_error(g, node, buf_sprintf("variables must be initialized")); + add_node_error(g, source_node, buf_sprintf("variables must be initialized")); implicit_type = g->builtin_types.entry_invalid; } TypeTableEntry *type = explicit_type ? explicit_type : implicit_type; assert(type != nullptr); // should have been caught by the parser - VariableTableEntry *var = add_local_var(g, node, import, scope, - var_decl->symbol, type, is_const, var_decl->expr); + tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, + var_decl->symbol, type, is_const, &init_value->static_value); - var_decl->variable = var; - - g->global_vars.append(var); + g->global_vars.append(tld_var->var); } -void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) { - TopLevelDecl *tld = get_as_top_level_decl(node); - if (tld->resolution != TldResolutionUnresolved) { +static void resolve_decl_typedef(CodeGen *g, TldTypeDef *tld_typedef) { + AstNode *typedef_node = tld_typedef->base.source_node; + assert(typedef_node->type == NodeTypeTypeDecl); + AstNode *type_node = typedef_node->data.type_decl.child_type; + Buf *decl_name = typedef_node->data.type_decl.symbol; + + TypeTableEntry *child_type = analyze_type_expr(g, tld_typedef->base.parent_scope, type_node); + tld_typedef->type_entry = (child_type->id == TypeTableEntryIdInvalid) ? + child_type : get_typedecl_type(g, buf_ptr(decl_name), child_type); +} + +void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only) { + if (tld->resolution != TldResolutionUnresolved) return; - } - if (pointer_only && node->type == NodeTypeContainerDecl) { + if (pointer_only && tld->id == TldIdContainer) { + g->resolve_queue.append(tld); return; } @@ -1926,90 +1831,38 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) { assert(import); if (tld->dep_loop_flag) { - add_node_error(g, node, buf_sprintf("'%s' depends on itself", buf_ptr(tld->name))); + add_node_error(g, tld->source_node, buf_sprintf("'%s' depends on itself", buf_ptr(tld->name))); tld->resolution = TldResolutionInvalid; return; } else { tld->dep_loop_flag = true; } - switch (node->type) { - case NodeTypeFnProto: - preview_fn_proto_instance(g, import, node, node->scope); - break; - case NodeTypeContainerDecl: - resolve_struct_decl(g, import, node); - break; - case NodeTypeVariableDeclaration: - resolve_var_decl(g, import, node); - break; - case NodeTypeTypeDecl: + switch (tld->id) { + case TldIdVar: { - AstNode *type_node = node->data.type_decl.child_type; - Buf *decl_name = node->data.type_decl.symbol; - - TypeTableEntry *entry; - if (node->data.type_decl.override_type) { - entry = node->data.type_decl.override_type; - } else { - TypeTableEntry *child_type = analyze_type_expr(g, import, &import->decls_scope->base, type_node); - if (child_type->id == TypeTableEntryIdInvalid) { - entry = child_type; - } else { - entry = get_typedecl_type(g, buf_ptr(decl_name), child_type); - } - } - node->data.type_decl.child_type_entry = entry; + TldVar *tld_var = (TldVar *)tld; + resolve_decl_var(g, tld_var); + break; + } + case TldIdFn: + { + TldFn *tld_fn = (TldFn *)tld; + resolve_decl_fn(g, tld_fn); + break; + } + case TldIdContainer: + { + TldContainer *tld_container = (TldContainer *)tld; + resolve_decl_container(g, tld_container); + break; + } + case TldIdTypeDef: + { + TldTypeDef *tld_typedef = (TldTypeDef *)tld; + resolve_decl_typedef(g, tld_typedef); break; } - case NodeTypeErrorValueDecl: - break; - case NodeTypeUse: - zig_panic("TODO resolve_top_level_decl NodeTypeUse"); - break; - case NodeTypeFnDef: - case NodeTypeParamDecl: - case NodeTypeFnDecl: - case NodeTypeReturnExpr: - case NodeTypeDefer: - case NodeTypeRoot: - case NodeTypeBlock: - case NodeTypeBinOpExpr: - case NodeTypeUnwrapErrorExpr: - case NodeTypeFnCallExpr: - case NodeTypeArrayAccessExpr: - case NodeTypeSliceExpr: - case NodeTypeNumberLiteral: - case NodeTypeStringLiteral: - case NodeTypeCharLiteral: - case NodeTypeBoolLiteral: - case NodeTypeNullLiteral: - case NodeTypeUndefinedLiteral: - case NodeTypeZeroesLiteral: - case NodeTypeThisLiteral: - case NodeTypeSymbol: - case NodeTypePrefixOpExpr: - case NodeTypeIfBoolExpr: - case NodeTypeIfVarExpr: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeSwitchExpr: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeLabel: - case NodeTypeGoto: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeAsmExpr: - case NodeTypeFieldAccessExpr: - case NodeTypeStructField: - case NodeTypeStructValueField: - case NodeTypeContainerInitExpr: - case NodeTypeArrayType: - case NodeTypeErrorType: - case NodeTypeTypeLiteral: - case NodeTypeVarLiteral: - zig_unreachable(); } tld->resolution = TldResolutionOk; @@ -2028,7 +1881,6 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) { case TypeTableEntryIdNullLit: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: return false; @@ -2142,68 +1994,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry * return false; } -ScopeDecls *create_decls_scope(AstNode *node, Scope *parent) { - assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl); - ScopeDecls *scope = allocate(1); - scope->base.node = node; - scope->base.parent = parent; - scope->decl_table.init(4); - return scope; -} - -Scope *create_block_scope(AstNode *node, Scope *parent) { - assert(node->type == NodeTypeBlock); - ScopeBlock *scope = allocate(1); - 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(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(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(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(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(1); - scope->base.node = node; - scope->base.parent = parent; - scope->fn_entry = fn_entry; - return &scope->base; -} - -AstNode *find_decl(Scope *scope, Buf *name) { +Tld *find_decl(Scope *scope, Buf *name) { while (scope) { if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) @@ -2232,11 +2023,11 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) { ScopeDecls *decls_scope = (ScopeDecls *)scope; auto entry = decls_scope->decl_table.maybe_get(name); if (entry) { - AstNode *decl_node = entry->value; - if (decl_node->type == NodeTypeVariableDeclaration) { - VariableTableEntry *var = decl_node->data.variable_declaration.variable; - if (var) - return var; + Tld *tld = entry->value; + if (tld->id == TldIdVar) { + TldVar *tld_var = (TldVar *)tld; + if (tld_var->var) + return tld_var->var; } } } @@ -2246,6 +2037,17 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) { return nullptr; } +FnTableEntry *scope_fn_entry(Scope *scope) { + while (scope) { + if (scope->node->type == NodeTypeFnDef) { + ScopeFnDef *fn_scope = (ScopeFnDef *)scope; + return fn_scope->fn_entry; + } + scope = scope->parent; + } + return nullptr; +} + TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name) { for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; @@ -2296,7 +2098,6 @@ static bool is_container(TypeTableEntry *type_entry) { case TypeTableEntryIdTypeDecl: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: return false; } @@ -2317,13 +2118,13 @@ TypeTableEntry *container_ref_type(TypeTableEntry *type_entry) { void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { switch (type_entry->id) { case TypeTableEntryIdStruct: - resolve_struct_type(g, type_entry->data.structure.decl_node->owner, type_entry); + resolve_struct_type(g, type_entry); break; case TypeTableEntryIdEnum: - resolve_enum_type(g, type_entry->data.enumeration.decl_node->owner, type_entry); + resolve_enum_type(g, type_entry); break; case TypeTableEntryIdUnion: - resolve_union_type(g, type_entry->data.unionation.decl_node->owner, type_entry); + resolve_union_type(g, type_entry); break; case TypeTableEntryIdPointer: case TypeTableEntryIdMetaType: @@ -2344,7 +2145,6 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { case TypeTableEntryIdTypeDecl: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdVar: @@ -2362,54 +2162,41 @@ bool type_is_codegen_pointer(TypeTableEntry *type) { return false; } - - static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { - ImportTableEntry *import = fn_table_entry->import_entry; - AstNode *node = fn_table_entry->fn_def_node; - assert(node->type == NodeTypeFnDef); - - AstNode *fn_proto_node = node->data.fn_def.fn_proto; - assert(fn_proto_node->type == NodeTypeFnProto); - - if (fn_proto_node->data.fn_proto.skip) { - // we detected an error with this function definition which prevents us - // from further analyzing it. - fn_table_entry->anal_state = FnAnalStateSkipped; + assert(fn_table_entry->anal_state != FnAnalStateProbing); + if (fn_table_entry->anal_state != FnAnalStateReady) return; - } + fn_table_entry->anal_state = FnAnalStateProbing; - Scope *child_scope = node->data.fn_def.containing_scope; + AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; + Scope *child_scope = &fn_table_entry->fndef_scope->base; + assert(child_scope); + + // define local variables for parameters TypeTableEntry *fn_type = fn_table_entry->type_entry; + assert(!fn_type->data.fn.is_generic); FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; - for (size_t i = 0; i < fn_proto->params.length; i += 1) { + for (size_t i = 0; i < fn_type_id->param_count; i += 1) { AstNode *param_decl_node = fn_proto->params.at(i); - assert(param_decl_node->type == NodeTypeParamDecl); - - // define local variables for parameters AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl; - TypeTableEntry *type = fn_type_id->param_info[i].type; + FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; - if (param_decl->is_noalias && !type_is_codegen_pointer(type)) { + TypeTableEntry *param_type = param_info->type; + bool is_noalias = param_info->is_noalias; + + if (is_noalias && !type_is_codegen_pointer(param_type)) { add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter")); } - if (fn_type->data.fn.fn_type_id.is_extern && handle_is_ptr(type)) { + if (fn_type_id->is_extern && handle_is_ptr(param_type)) { add_node_error(g, param_decl_node, buf_sprintf("byvalue types not yet supported on extern function parameters")); } - if (buf_len(param_decl->name) == 0) { - add_node_error(g, param_decl_node, buf_sprintf("missing parameter name")); - } - - VariableTableEntry *var = add_local_var(g, param_decl_node, import, child_scope, param_decl->name, - type, true, nullptr); + VariableTableEntry *var = add_variable(g, param_decl_node, child_scope, param_decl->name, param_type, true, nullptr); var->src_arg_index = i; - param_decl_node->data.param_decl.variable = var; child_scope = var->child_scope; fn_table_entry->variable_list.append(var); @@ -2418,19 +2205,18 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { } } - node->data.fn_def.child_scope = child_scope; + fn_table_entry->child_scope = child_scope; - TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type; + TypeTableEntry *expected_type = fn_type_id->return_type; - if (fn_type->data.fn.fn_type_id.is_extern && handle_is_ptr(expected_type)) { - add_node_error(g, fn_proto_node->data.fn_proto.return_type, + if (fn_type_id->is_extern && handle_is_ptr(expected_type)) { + add_node_error(g, fn_proto->return_type, buf_sprintf("byvalue types not yet supported on extern function return values")); } ir_gen_fn(g, fn_table_entry); if (fn_table_entry->ir_executable.invalid) { - fn_proto_node->data.fn_proto.skip = true; - fn_table_entry->anal_state = FnAnalStateSkipped; + fn_table_entry->anal_state = FnAnalStateInvalid; return; } if (g->verbose) { @@ -2443,9 +2229,16 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, &fn_table_entry->analyzed_executable, expected_type, fn_proto->return_type); - node->data.fn_def.implicit_return_type = block_return_type; + fn_table_entry->implicit_return_type = block_return_type; - if (block_return_type->id != TypeTableEntryIdInvalid && g->verbose) { + if (block_return_type->id == TypeTableEntryIdInvalid || + fn_table_entry->analyzed_executable.invalid) + { + fn_table_entry->anal_state = FnAnalStateInvalid; + return; + } + + if (g->verbose) { fprintf(stderr, "{ // (analyzed)\n"); ir_print(stderr, &fn_table_entry->analyzed_executable, 4); fprintf(stderr, "}\n"); @@ -2454,16 +2247,14 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { fn_table_entry->anal_state = FnAnalStateComplete; } -static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node) { - TopLevelDecl *tld = get_as_top_level_decl(dst_use_node); - - IrInstruction *use_target_value = tld->value; +static void add_symbols_from_import(CodeGen *g, AstNode *dst_use_node) { + IrInstruction *use_target_value = dst_use_node->data.use.value; if (use_target_value->type_entry->id == TypeTableEntryIdInvalid) { - tld->import->any_imports_failed = true; + dst_use_node->owner->any_imports_failed = true; return; } - tld->resolution = TldResolutionOk; + dst_use_node->data.use.resolution = TldResolutionOk; ConstExprValue *const_val = &use_target_value->static_value; assert(const_val->special != ConstValSpecialRuntime); @@ -2472,59 +2263,60 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * assert(target_import); if (target_import->any_imports_failed) { - tld->import->any_imports_failed = true; + dst_use_node->owner->any_imports_failed = true; } - for (size_t i = 0; i < target_import->root->data.root.top_level_decls.length; i += 1) { - AstNode *decl_node = target_import->root->data.root.top_level_decls.at(i); - if (decl_node->type == NodeTypeFnDef) { - decl_node = decl_node->data.fn_def.fn_proto; - } - TopLevelDecl *target_tld = get_as_top_level_decl(decl_node); - if (!target_tld->name) { + auto it = target_import->decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *target_tld = entry->value; + if (target_tld->import != target_import || + target_tld->visib_mod == VisibModPrivate) + { continue; } - if (target_tld->visib_mod != VisibModPrivate) { - auto existing_entry = tld->import->decls_scope->decl_table.put_unique(target_tld->name, decl_node); - if (existing_entry) { - AstNode *existing_decl = existing_entry->value; - if (existing_decl != decl_node) { - ErrorMsg *msg = add_node_error(g, dst_use_node, - buf_sprintf("import of '%s' overrides existing definition", - buf_ptr(target_tld->name))); - add_error_note(g, msg, existing_decl, buf_sprintf("previous definition here")); - add_error_note(g, msg, decl_node, buf_sprintf("imported definition here")); - } + + auto existing_entry = dst_use_node->owner->decls_scope->decl_table.put_unique(target_tld->name, target_tld); + if (existing_entry) { + Tld *existing_decl = existing_entry->value; + if (existing_decl != target_tld) { + ErrorMsg *msg = add_node_error(g, dst_use_node, + buf_sprintf("import of '%s' overrides existing definition", + buf_ptr(target_tld->name))); + add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here")); + add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here")); } } } for (size_t i = 0; i < target_import->use_decls.length; i += 1) { AstNode *use_decl_node = target_import->use_decls.at(i); - TopLevelDecl *target_tld = get_as_top_level_decl(use_decl_node); - if (target_tld->visib_mod != VisibModPrivate) { - add_symbols_from_import(g, use_decl_node, dst_use_node); - } + if (use_decl_node->data.use.visib_mod != VisibModPrivate) + add_symbols_from_import(g, dst_use_node); } - } void resolve_use_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeUse); - if (get_as_top_level_decl(node)->resolution != TldResolutionUnresolved) { + + if (node->data.use.resolution != TldResolutionUnresolved) return; - } - add_symbols_from_import(g, node, node); + add_symbols_from_import(g, node); } void preview_use_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeUse); - TopLevelDecl *tld = get_as_top_level_decl(node); - IrInstruction *result = analyze_const_value(g, &tld->import->decls_scope->base, node->data.use.expr, - g->builtin_types.entry_namespace); + IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, + node->data.use.expr, g->builtin_types.entry_namespace); + if (result->type_entry->id == TypeTableEntryIdInvalid) - tld->import->any_imports_failed = true; + node->owner->any_imports_failed = true; + + node->data.use.value = result; } ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, @@ -2580,7 +2372,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, g->import_table.put(abs_full_path, import_entry); g->import_queue.append(import_entry); - import_entry->decls_scope = create_decls_scope(import_entry->root, nullptr); + import_entry->decls_scope = create_decls_scope(import_entry->root, nullptr, nullptr, import_entry); assert(import_entry->root->type == NodeTypeRoot); @@ -2592,7 +2384,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, assert(proto_node->type == NodeTypeFnProto); Buf *proto_name = proto_node->data.fn_proto.name; - bool is_private = (proto_node->data.fn_proto.top_level_decl.visib_mod == VisibModPrivate); + bool is_private = (proto_node->data.fn_proto.visib_mod == VisibModPrivate); if (buf_eql_str(proto_name, "main") && !is_private) { g->have_exported_main = true; @@ -2607,7 +2399,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, void semantic_analyze(CodeGen *g) { for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) { ImportTableEntry *import = g->import_queue.at(g->import_queue_index); - scan_decls(g, import, import->decls_scope, import->root); + scan_decls(g, import, import->decls_scope, import->root, nullptr); } for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) { @@ -2620,82 +2412,22 @@ void semantic_analyze(CodeGen *g) { resolve_use_decl(g, use_decl_node); } - for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { - AstNode *decl_node = g->resolve_queue.at(g->resolve_queue_index); - bool pointer_only = false; - resolve_top_level_decl(g, decl_node, pointer_only); - } + while (g->resolve_queue_index < g->resolve_queue.length || + g->fn_defs_index < g->fn_defs.length) + { + for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { + Tld *tld = g->resolve_queue.at(g->resolve_queue_index); + bool pointer_only = false; + resolve_top_level_decl(g, tld, pointer_only); + } - for (size_t i = 0; i < g->fn_defs.length; i += 1) { - FnTableEntry *fn_entry = g->fn_defs.at(i); - if (fn_entry->anal_state == FnAnalStateReady) { + for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { + FnTableEntry *fn_entry = g->fn_defs.at(g->fn_defs_index); analyze_fn_body(g, fn_entry); } } } -TopLevelDecl *get_as_top_level_decl(AstNode *node) { - switch (node->type) { - case NodeTypeVariableDeclaration: - return &node->data.variable_declaration.top_level_decl; - case NodeTypeFnProto: - return &node->data.fn_proto.top_level_decl; - case NodeTypeFnDef: - return &node->data.fn_def.fn_proto->data.fn_proto.top_level_decl; - case NodeTypeContainerDecl: - return &node->data.struct_decl.top_level_decl; - case NodeTypeErrorValueDecl: - return &node->data.error_value_decl.top_level_decl; - case NodeTypeUse: - return &node->data.use.top_level_decl; - case NodeTypeTypeDecl: - return &node->data.type_decl.top_level_decl; - case NodeTypeNumberLiteral: - case NodeTypeReturnExpr: - case NodeTypeDefer: - case NodeTypeBinOpExpr: - case NodeTypeUnwrapErrorExpr: - case NodeTypePrefixOpExpr: - case NodeTypeFnCallExpr: - case NodeTypeArrayAccessExpr: - case NodeTypeSliceExpr: - case NodeTypeFieldAccessExpr: - case NodeTypeIfBoolExpr: - case NodeTypeIfVarExpr: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeSwitchExpr: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeAsmExpr: - case NodeTypeContainerInitExpr: - case NodeTypeRoot: - case NodeTypeFnDecl: - case NodeTypeParamDecl: - case NodeTypeBlock: - case NodeTypeStringLiteral: - case NodeTypeCharLiteral: - case NodeTypeSymbol: - case NodeTypeBoolLiteral: - case NodeTypeNullLiteral: - case NodeTypeUndefinedLiteral: - case NodeTypeZeroesLiteral: - case NodeTypeThisLiteral: - case NodeTypeLabel: - case NodeTypeGoto: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeStructField: - case NodeTypeStructValueField: - case NodeTypeArrayType: - case NodeTypeErrorType: - case NodeTypeTypeLiteral: - case NodeTypeVarLiteral: - zig_unreachable(); - } - zig_unreachable(); -} - bool is_node_void_expr(AstNode *node) { if (node->type == NodeTypeContainerInitExpr && node->data.container_init_expr.kind == ContainerInitKindArray) @@ -2749,7 +2481,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { case TypeTableEntryIdNullLit: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: zig_unreachable(); @@ -2902,7 +2633,6 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) return hash_ptr(const_val->data.x_import); case TypeTableEntryIdBlock: return hash_ptr(const_val->data.x_block); - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdUnreachable: @@ -2912,45 +2642,6 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) zig_unreachable(); } -uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { - zig_panic("TODO generic_fn_type_id_hash"); - //uint32_t result = 0; - //result += hash_ptr(id->decl_node); - //for (size_t i = 0; i < id->generic_param_count; i += 1) { - // GenericParamValue *generic_param = &id->generic_params[i]; - // if (generic_param->node) { - // ConstExprValue *const_val = &get_resolved_expr(generic_param->node)->instruction->static_value; - // assert(const_val->special != ConstValSpecialRuntime); - // result += hash_const_val(generic_param->type, const_val); - // } - // result += hash_ptr(generic_param->type); - //} - //return result; -} - -bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { - zig_panic("TODO generic_fn_type_id_eql"); - //if (a->decl_node != b->decl_node) return false; - //assert(a->generic_param_count == b->generic_param_count); - //for (size_t i = 0; i < a->generic_param_count; i += 1) { - // GenericParamValue *a_val = &a->generic_params[i]; - // GenericParamValue *b_val = &b->generic_params[i]; - // if (a_val->type != b_val->type) return false; - // if (a_val->node && b_val->node) { - // ConstExprValue *a_const_val = &get_resolved_expr(a_val->node)->instruction->static_value; - // ConstExprValue *b_const_val = &get_resolved_expr(b_val->node)->instruction->static_value; - // assert(a_const_val->special != ConstValSpecialRuntime); - // assert(b_const_val->special != ConstValSpecialRuntime); - // if (!const_values_equal(a_const_val, b_const_val, a_val->type)) { - // return false; - // } - // } else { - // assert(!a_val->node && !b_val->node); - // } - //} - //return true; -} - bool type_has_bits(TypeTableEntry *type_entry) { assert(type_entry); assert(type_entry->id != TypeTableEntryIdInvalid); @@ -2981,7 +2672,6 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) case TypeTableEntryIdVoid: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: zig_unreachable(); diff --git a/src/analyze.hpp b/src/analyze.hpp index 4201643876..0b40cb8f48 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -22,11 +22,11 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, size_t size_in_bits); TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type); TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type); -TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info); +TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type); TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size); TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); -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); TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type); @@ -49,9 +49,8 @@ AstNode *first_executing_node(AstNode *node); // TODO move these over, these used to be static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type); VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name); -AstNode *find_decl(Scope *context, Buf *name); -void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only); -TopLevelDecl *get_as_top_level_decl(AstNode *node); +Tld *find_decl(Scope *scope, Buf *name); +void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only); bool type_is_codegen_pointer(TypeTableEntry *type); TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry); TypeTableEntry *container_ref_type(TypeTableEntry *type_entry); @@ -61,16 +60,21 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); ScopeDecls *get_container_scope(TypeTableEntry *type_entry); TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); bool is_container_ref(TypeTableEntry *type_entry); -void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node); +void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node, Tld *parent_tld); void preview_use_decl(CodeGen *g, AstNode *node); void resolve_use_decl(CodeGen *g, AstNode *node); +FnTableEntry *scope_fn_entry(Scope *scope); +ImportTableEntry *get_scope_import(Scope *scope); +void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, + Scope *parent_scope, Tld *parent_tld); +VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, + TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value); -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); +ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); #endif diff --git a/src/ast_render.cpp b/src/ast_render.cpp index c98b0e81a7..9318d8edc3 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -377,7 +377,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { break; case NodeTypeFnProto: { - const char *pub_str = visib_mod_string(node->data.fn_proto.top_level_decl.visib_mod); + const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); const char *extern_str = extern_string(node->data.fn_proto.is_extern); const char *inline_str = inline_string(node->data.fn_proto.is_inline); fprintf(ar->f, "%s%s%sfn ", pub_str, inline_str, extern_str); @@ -460,7 +460,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } case NodeTypeVariableDeclaration: { - const char *pub_str = visib_mod_string(node->data.variable_declaration.top_level_decl.visib_mod); + const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod); const char *extern_str = extern_string(node->data.variable_declaration.is_extern); const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const); fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var); @@ -478,7 +478,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } case NodeTypeTypeDecl: { - const char *pub_str = visib_mod_string(node->data.type_decl.top_level_decl.visib_mod); + const char *pub_str = visib_mod_string(node->data.type_decl.visib_mod); const char *var_name = buf_ptr(node->data.type_decl.symbol); fprintf(ar->f, "%stype %s = ", pub_str, var_name); render_node_grouped(ar, node->data.type_decl.child_type); @@ -575,7 +575,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { case NodeTypeContainerDecl: { const char *struct_name = buf_ptr(node->data.struct_decl.name); - const char *pub_str = visib_mod_string(node->data.struct_decl.top_level_decl.visib_mod); + const char *pub_str = visib_mod_string(node->data.struct_decl.visib_mod); const char *container_str = container_string(node->data.struct_decl.kind); fprintf(ar->f, "%s%s %s {\n", pub_str, container_str, struct_name); ar->indent += ar->indent_size; diff --git a/src/codegen.cpp b/src/codegen.cpp index 26ca633b8d..8b8650a546 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -60,7 +60,6 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { g->primitive_type_table.init(32); g->fn_type_table.init(32); g->error_table.init(16); - g->generic_table.init(16); g->is_release_build = false; g->is_test_build = false; g->want_h_file = true; @@ -227,13 +226,59 @@ 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_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val); +static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { + if (fn_table_entry->llvm_value) + return fn_table_entry->llvm_value; + + Buf *symbol_name; + if (!fn_table_entry->internal_linkage) { + symbol_name = &fn_table_entry->symbol_name; + } else { + symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name)); + } + + TypeTableEntry *fn_type = fn_table_entry->type_entry; + fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); + + switch (fn_table_entry->fn_inline) { + case FnInlineAlways: + LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMAlwaysInlineAttribute); + break; + case FnInlineNever: + LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoInlineAttribute); + break; + case FnInlineAuto: + break; + } + if (fn_type->data.fn.fn_type_id.is_naked) { + LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNakedAttribute); + } + + LLVMSetLinkage(fn_table_entry->llvm_value, fn_table_entry->internal_linkage ? + LLVMInternalLinkage : LLVMExternalLinkage); + + if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { + LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoReturnAttribute); + } + LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention); + if (!fn_type->data.fn.fn_type_id.is_extern) { + LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoUnwindAttribute); + } + if (!g->is_release_build && fn_table_entry->fn_inline != FnInlineAlways) { + ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true"); + ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr); + } + + return fn_table_entry->llvm_value; +} + 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; + ScopeFnDef *fn_scope = (ScopeFnDef *)scope; FnTableEntry *fn_table_entry = fn_scope->fn_entry; unsigned line_number = fn_table_entry->proto_node->line + 1; unsigned scope_line = line_number; @@ -247,11 +292,13 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { 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) - { + ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); + } else if (scope->node->type == NodeTypeRoot) { scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file); + } else if (scope->node->type == NodeTypeContainerDecl) { + ScopeDecls *decls_scope = (ScopeDecls *)scope; + assert(decls_scope->container_type); + scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type); } else { assert(scope->parent); ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, @@ -265,11 +312,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { return scope->di_scope; } -static void set_debug_source_node(CodeGen *g, AstNode *node) { - assert(node->scope); - ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, get_di_scope(g, node->scope)); -} - static void clear_debug_source_node(CodeGen *g) { ZigLLVMClearCurrentDebugLocation(g->builder); } @@ -350,24 +392,25 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntr } } -static bool want_debug_safety_recursive(CodeGen *g, Scope *context) { - if (context->safety_set_node || !context->parent) { - return !context->safety_off; - } - context->safety_off = !want_debug_safety_recursive(g, context->parent); - context->safety_set_node = context->parent->safety_set_node; - return !context->safety_off; -} - -static bool want_debug_safety(CodeGen *g, AstNode *node) { - if (g->is_release_build) { - return false; - } - return want_debug_safety_recursive(g, node->scope); -} - static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) { - return want_debug_safety(g, instruction->source_node); + if (g->is_release_build) + return false; + + // TODO memoize + Scope *scope = instruction->scope; + while (scope) { + if (scope->node->type == NodeTypeBlock) { + ScopeBlock *block_scope = (ScopeBlock *)scope; + if (block_scope->safety_set_node) + return !block_scope->safety_off; + } else if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) { + ScopeDecls *decls_scope = (ScopeDecls *)scope; + if (decls_scope->safety_set_node) + return !decls_scope->safety_off; + } + scope = scope->parent; + } + return true; } static void gen_debug_safety_crash(CodeGen *g) { @@ -388,10 +431,10 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, upper_value = nullptr; } - LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckOk"); + LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk"); LLVMBasicBlockRef lower_ok_block = upper_value ? - LLVMAppendBasicBlock(g->cur_fn->fn_value, "FirstBoundsCheckOk") : ok_block; + LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block; LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, ""); LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block); @@ -408,7 +451,7 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMPositionBuilderAtEnd(g->builder, ok_block); } -static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type_non_canon, +static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type_non_canon, TypeTableEntry *wanted_type_non_canon, LLVMValueRef expr_val) { TypeTableEntry *actual_type = get_underlying_type(actual_type_non_canon); @@ -430,13 +473,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT if (actual_bits >= wanted_bits && actual_type->id == TypeTableEntryIdInt && !wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed && - want_debug_safety(g, source_node)) + want_debug_safety) { LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail"); LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -464,7 +507,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, ""); } else if (actual_type->id == TypeTableEntryIdInt) { LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); - if (!want_debug_safety(g, source_node)) { + if (!want_debug_safety) { return trunc_val; } LLVMValueRef orig_val; @@ -474,8 +517,8 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, ""); } LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -502,8 +545,8 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -645,8 +688,8 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry, } LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -656,11 +699,11 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry, return result; } -static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2, +static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2, TypeTableEntry *type_entry, bool exact) { - if (want_debug_safety(g, source_node)) { + if (want_debug_safety) { LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); LLVMValueRef is_zero_bit; if (type_entry->id == TypeTableEntryIdInt) { @@ -670,8 +713,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, } else { zig_unreachable(); } - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail"); LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -688,7 +731,7 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, assert(type_entry->id == TypeTableEntryIdInt); if (exact) { - if (want_debug_safety(g, source_node)) { + if (want_debug_safety) { LLVMValueRef remainder_val; if (type_entry->data.integral.is_signed) { remainder_val = LLVMBuildSRem(g->builder, val1, val2, ""); @@ -698,8 +741,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -727,7 +770,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, IrBinOp op_id = bin_op_instruction->op_id; IrInstruction *op1 = bin_op_instruction->op1; IrInstruction *op2 = bin_op_instruction->op2; - AstNode *source_node = bin_op_instruction->base.source_node; assert(op1->type_entry == op2->type_entry); @@ -801,7 +843,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap); if (is_wrapping) { return LLVMBuildShl(g->builder, op1_value, op2_value, ""); - } else if (want_debug_safety(g, source_node)) { + } else if (ir_want_debug_safety(g, &bin_op_instruction->base)) { return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value); } else if (op1->type_entry->data.integral.is_signed) { return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, ""); @@ -824,7 +866,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, bool is_wrapping = (op_id == IrBinOpSubWrap); if (is_wrapping) { return LLVMBuildSub(g->builder, op1_value, op2_value, ""); - } else if (want_debug_safety(g, source_node)) { + } else if (ir_want_debug_safety(g, &bin_op_instruction->base)) { return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value); } else if (op1->type_entry->data.integral.is_signed) { return LLVMBuildNSWSub(g->builder, op1_value, op2_value, ""); @@ -842,7 +884,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, bool is_wrapping = (op_id == IrBinOpMultWrap); if (is_wrapping) { return LLVMBuildMul(g->builder, op1_value, op2_value, ""); - } else if (want_debug_safety(g, source_node)) { + } else if (ir_want_debug_safety(g, &bin_op_instruction->base)) { return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value); } else if (op1->type_entry->data.integral.is_signed) { return LLVMBuildNSWMul(g->builder, op1_value, op2_value, ""); @@ -853,7 +895,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, zig_unreachable(); } case IrBinOpDiv: - return gen_div(g, source_node, op1_value, op2_value, op1->type_entry, false); + return gen_div(g, ir_want_debug_safety(g, &bin_op_instruction->base), + op1_value, op2_value, op1->type_entry, false); case IrBinOpMod: if (op1->type_entry->id == TypeTableEntryIdFloat) { return LLVMBuildFRem(g->builder, op1_value, op2_value, ""); @@ -885,8 +928,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, case CastOpErrToInt: assert(actual_type->id == TypeTableEntryIdErrorUnion); if (!type_has_bits(actual_type->data.error.child_type)) { - return gen_widen_or_shorten(g, cast_instruction->base.source_node, - g->err_tag_type, wanted_type, expr_val); + return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base), + g->err_tag_type, wanted_type, expr_val); } else { zig_panic("TODO"); } @@ -954,7 +997,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, case CastOpPointerReinterpret: return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); case CastOpWidenOrShorten: - return gen_widen_or_shorten(g, cast_instruction->base.source_node, actual_type, wanted_type, expr_val); + return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base), + actual_type, wanted_type, expr_val); case CastOpToUnknownSizeArray: { assert(cast_instruction->tmp_ptr); @@ -1021,8 +1065,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, ""); LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref); LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail"); LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -1087,10 +1131,10 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); case CastOpIntToEnum: - return gen_widen_or_shorten(g, cast_instruction->base.source_node, + return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base), actual_type, wanted_type->data.enumeration.tag_type, expr_val); case CastOpEnumToInt: - return gen_widen_or_shorten(g, cast_instruction->base.source_node, + return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base), actual_type->data.enumeration.tag_type, wanted_type, expr_val); } zig_unreachable(); @@ -1197,8 +1241,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst } LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); - LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError"); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk"); + LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk"); LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); LLVMPositionBuilderAtEnd(g->builder, err_block); @@ -1231,8 +1275,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst cond_val = LLVMBuildLoad(g->builder, maybe_null_ptr, ""); } - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk"); - LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeNull"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk"); + LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeNull"); LLVMBuildCondBr(g->builder, cond_val, ok_block, null_block); LLVMPositionBuilderAtEnd(g->builder, null_block); @@ -1408,7 +1452,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr LLVMValueRef fn_val; TypeTableEntry *fn_type; if (instruction->fn_entry) { - fn_val = instruction->fn_entry->fn_value; + fn_val = fn_llvm_value(g, instruction->fn_entry); fn_type = instruction->fn_entry->type_entry; } else { assert(instruction->fn_ref); @@ -1563,7 +1607,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru } if (!is_return) { - VariableTableEntry *variable = asm_output->variable; + VariableTableEntry *variable = instruction->output_vars[i]; assert(variable); param_types[param_index] = LLVMTypeOf(variable->value_ref); param_values[param_index] = variable->value_ref; @@ -1638,8 +1682,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) { LLVMValueRef nonnull_bit = gen_null_bit(g, ptr_type, maybe_ptr); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail"); LLVMBuildCondBr(g->builder, nonnull_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -1730,8 +1774,18 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru } } +static void set_debug_location(CodeGen *g, IrInstruction *instruction) { + AstNode *source_node = instruction->source_node; + Scope *scope = instruction->scope; + + assert(source_node); + assert(scope); + + ZigLLVMSetCurrentDebugLocation(g->builder, source_node->line + 1, source_node->column + 1, get_di_scope(g, scope)); +} + static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { - set_debug_source_node(g, instruction->source_node); + set_debug_location(g, instruction); switch (instruction->id) { case IrInstructionIdInvalid: @@ -1961,7 +2015,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE } } case TypeTableEntryIdFn: - return const_val->data.x_fn->fn_value; + return fn_llvm_value(g, const_val->data.x_fn); case TypeTableEntryIdPointer: { TypeTableEntry *child_type = type_entry->data.pointer.child_type; @@ -2021,7 +2075,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE case TypeTableEntryIdNullLit: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: zig_unreachable(); @@ -2107,7 +2160,7 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) { LLVMValueRef name_val = LLVMConstStruct(name_fields, 2, false); LLVMValueRef fields[] = { name_val, - fn_entry->fn_value, + fn_llvm_value(g, fn_entry), }; return LLVMConstStruct(fields, 2, false); } @@ -2157,7 +2210,7 @@ static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) { assert(executable->basic_block_list.length > 0); for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { IrBasicBlock *bb = executable->basic_block_list.at(block_i); - bb->llvm_block = LLVMAppendBasicBlock(fn->fn_value, bb->name_hint); + bb->llvm_block = LLVMAppendBasicBlock(fn_llvm_value(g, fn), bb->name_hint); } IrBasicBlock *entry_bb = executable->basic_block_list.at(0); LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block); @@ -2167,11 +2220,14 @@ static void gen_global_var(CodeGen *g, VariableTableEntry *var, LLVMValueRef ini TypeTableEntry *type_entry) { assert(var->gen_is_const); - assert(var->import); assert(type_entry); + + ImportTableEntry *import = get_scope_import(var->parent_scope); + assert(import); + bool is_local_to_unit = true; ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name), - buf_ptr(&var->name), var->import->di_file, var->decl_node->line + 1, + buf_ptr(&var->name), import->di_file, var->decl_node->line + 1, type_entry->di_type, is_local_to_unit, init_val); } @@ -2187,7 +2243,7 @@ static void do_code_gen(CodeGen *g) { if (var->type->id == TypeTableEntryIdNumLitFloat) { // Generate debug info for it but that's it. - ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value; + ConstExprValue *const_val = var->value; assert(const_val->special != ConstValSpecialRuntime); TypeTableEntry *var_type = g->builtin_types.entry_f64; LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float); @@ -2197,7 +2253,7 @@ static void do_code_gen(CodeGen *g) { if (var->type->id == TypeTableEntryIdNumLitInt) { // Generate debug info for it but that's it. - ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value; + ConstExprValue *const_val = var->value; assert(const_val->special != ConstValSpecialRuntime); TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ? g->builtin_types.entry_isize : g->builtin_types.entry_usize; @@ -2222,13 +2278,12 @@ static void do_code_gen(CodeGen *g) { LLVMSetLinkage(global_value, LLVMExternalLinkage); } else { - IrInstruction *instruction = var->decl_node->data.variable_declaration.top_level_decl.value; - render_const_val(g, instruction->type_entry, &instruction->static_value); - render_const_val_global(g, instruction->type_entry, &instruction->static_value); - global_value = instruction->static_value.llvm_global; + render_const_val(g, var->type, var->value); + render_const_val_global(g, var->type, var->value); + global_value = var->value->llvm_global; // TODO debug info for function pointers if (var->gen_is_const && var->type->id != TypeTableEntryIdFn) { - gen_global_var(g, var, instruction->static_value.llvm_value, var->type); + gen_global_var(g, var, var->value->llvm_value, var->type); } } @@ -2246,12 +2301,8 @@ static void do_code_gen(CodeGen *g) { // Generate function prototypes for (size_t fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) { FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i); - if (should_skip_fn_codegen(g, fn_table_entry)) { - // huge time saver - LLVMDeleteFunction(fn_table_entry->fn_value); - fn_table_entry->fn_value = nullptr; + if (should_skip_fn_codegen(g, fn_table_entry)) continue; - } AstNode *proto_node = fn_table_entry->proto_node; assert(proto_node->type == NodeTypeFnProto); @@ -2259,16 +2310,18 @@ static void do_code_gen(CodeGen *g) { TypeTableEntry *fn_type = fn_table_entry->type_entry; + LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry); + if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) { // nothing to do } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) { - ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 0); + ZigLLVMAddNonNullAttr(fn_val, 0); } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) && !fn_type->data.fn.fn_type_id.is_extern) { - LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0); + LLVMValueRef first_arg = LLVMGetParam(fn_val, 0); LLVMAddAttribute(first_arg, LLVMStructRetAttribute); - ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 1); + ZigLLVMAddNonNullAttr(fn_val, 1); } @@ -2286,7 +2339,7 @@ static void do_code_gen(CodeGen *g) { } TypeTableEntry *param_type = info->type; - LLVMValueRef argument_val = LLVMGetParam(fn_table_entry->fn_value, gen_index); + LLVMValueRef argument_val = LLVMGetParam(fn_val, gen_index); bool param_is_noalias = param_node->data.param_decl.is_noalias; if (param_is_noalias) { LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); @@ -2295,7 +2348,7 @@ static void do_code_gen(CodeGen *g) { LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute); } if (param_type->id == TypeTableEntryIdPointer) { - ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, gen_index + 1); + ZigLLVMAddNonNullAttr(fn_val, gen_index + 1); } if (is_byval) { // TODO @@ -2345,14 +2398,13 @@ static void do_code_gen(CodeGen *g) { // Generate function definitions. for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) { FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i); - if (should_skip_fn_codegen(g, fn_table_entry)) { - // huge time saver + if (should_skip_fn_codegen(g, fn_table_entry)) continue; - } ImportTableEntry *import = fn_table_entry->import_entry; - LLVMValueRef fn = fn_table_entry->fn_value; + LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); g->cur_fn = fn_table_entry; + g->cur_fn_val = fn; if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) { g->cur_ret_ptr = LLVMGetParam(fn, 0); } else { @@ -2401,7 +2453,18 @@ static void do_code_gen(CodeGen *g) { if (var->is_inline) continue; - if (var->parent_scope->node->type == NodeTypeFnDef) { + if (var->src_arg_index == SIZE_MAX) { + var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name)); + + + unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref); + LLVMSetAlignment(var->value_ref, align_bytes); + + 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, + var->type->di_type, !g->strip_debug_symbols, 0); + + } else { assert(var->gen_arg_index != SIZE_MAX); TypeTableEntry *gen_type; if (handle_is_ptr(var->type)) { @@ -2417,31 +2480,21 @@ static void do_code_gen(CodeGen *g) { 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); - } else { - var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name)); - - - unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref); - LLVMSetAlignment(var->value_ref, align_bytes); - - 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, - var->type->di_type, !g->strip_debug_symbols, 0); } } // create debug variable declarations for parameters + // rely on the first variables in the variable_list being parameters. + size_t next_var_i = 0; for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) { - AstNode *param_decl = fn_proto->params.at(param_i); - assert(param_decl->type == NodeTypeParamDecl); - FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i]; - - if (info->gen_index == SIZE_MAX) { + if (info->gen_index == SIZE_MAX) continue; - } - VariableTableEntry *variable = param_decl->data.param_decl.variable; + VariableTableEntry *variable = fn_table_entry->variable_list.at(next_var_i); + assert(variable->src_arg_index != SIZE_MAX); + next_var_i += 1; + assert(variable); assert(variable->value_ref); @@ -3308,7 +3361,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { zig_panic("TODO"); case TypeTableEntryIdInvalid: case TypeTableEntryIdMetaType: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: @@ -3343,7 +3395,7 @@ void codegen_generate_h_file(CodeGen *g) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - if (fn_proto->top_level_decl.visib_mod != VisibModExport) + if (fn_proto->visib_mod != VisibModExport) continue; FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; diff --git a/src/eval.cpp b/src/eval.cpp index ee7102e62c..161598419b 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -55,7 +55,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty zig_panic("TODO"); case TypeTableEntryIdBlock: zig_panic("TODO"); - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdUnreachable: diff --git a/src/ir.cpp b/src/ir.cpp index 54fa8d9f0e..f759c887aa 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2016 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + #include "analyze.hpp" #include "error.hpp" #include "eval.hpp" @@ -71,6 +78,10 @@ static size_t exec_next_mem_slot(IrExecutable *exec) { return result; } +static FnTableEntry *exec_fn_entry(IrExecutable *exec) { + return exec->fn_entry; +} + static void ir_link_new_instruction(IrInstruction *new_instruction, IrInstruction *old_instruction) { new_instruction->other = old_instruction; old_instruction->other = new_instruction; @@ -289,26 +300,27 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { } template -static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { +static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); special_instruction->base.id = ir_instruction_id(special_instruction); + special_instruction->base.scope = scope; special_instruction->base.source_node = source_node; special_instruction->base.debug_id = exec_next_debug_id(exec); return special_instruction; } template -static T *ir_build_instruction(IrBuilder *irb, AstNode *source_node) { +static T *ir_build_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { assert(source_node); - T *special_instruction = ir_create_instruction(irb->exec, source_node); + T *special_instruction = ir_create_instruction(irb->exec, scope, source_node); ir_instruction_append(irb->current_basic_block, &special_instruction->base); return special_instruction; } -static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, TypeTableEntry *dest_type, +static IrInstruction *ir_build_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, TypeTableEntry *dest_type, IrInstruction *value, CastOp cast_op) { - IrInstructionCast *cast_instruction = ir_build_instruction(irb, source_node); + IrInstructionCast *cast_instruction = ir_build_instruction(irb, scope, source_node); cast_instruction->dest_type = dest_type; cast_instruction->value = value; cast_instruction->cast_op = cast_op; @@ -318,10 +330,10 @@ static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, TypeTa return &cast_instruction->base; } -static IrInstruction *ir_build_cond_br(IrBuilder *irb, AstNode *source_node, IrInstruction *condition, +static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *condition, IrBasicBlock *then_block, IrBasicBlock *else_block, bool is_inline) { - IrInstructionCondBr *cond_br_instruction = ir_build_instruction(irb, source_node); + IrInstructionCondBr *cond_br_instruction = ir_build_instruction(irb, scope, source_node); cond_br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; cond_br_instruction->base.static_value.special = ConstValSpecialStatic; cond_br_instruction->condition = condition; @@ -339,14 +351,14 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, AstNode *source_node, IrI static IrInstruction *ir_build_cond_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *condition, IrBasicBlock *then_block, IrBasicBlock *else_block, bool is_inline) { - IrInstruction *new_instruction = ir_build_cond_br(irb, old_instruction->source_node, + IrInstruction *new_instruction = ir_build_cond_br(irb, old_instruction->scope, old_instruction->source_node, condition, then_block, else_block, is_inline); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_return(IrBuilder *irb, AstNode *source_node, IrInstruction *return_value) { - IrInstructionReturn *return_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *return_value) { + IrInstructionReturn *return_instruction = ir_build_instruction(irb, scope, source_node); return_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; return_instruction->base.static_value.special = ConstValSpecialStatic; return_instruction->value = return_value; @@ -359,38 +371,38 @@ static IrInstruction *ir_build_return(IrBuilder *irb, AstNode *source_node, IrIn static IrInstruction *ir_build_return_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *return_value) { - IrInstruction *new_instruction = ir_build_return(irb, old_instruction->source_node, return_value); + IrInstruction *new_instruction = ir_build_return(irb, old_instruction->scope, old_instruction->source_node, return_value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_create_const(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node, TypeTableEntry *type_entry, bool depends_on_compile_var) { assert(type_entry); - IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, source_node); + IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, scope, source_node); const_instruction->base.type_entry = type_entry; const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var; return &const_instruction->base; } -static IrInstruction *ir_build_const_void(IrBuilder *irb, AstNode *source_node) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_void; const_instruction->base.static_value.special = ConstValSpecialStatic; return &const_instruction->base; } -static IrInstruction *ir_build_const_undefined(IrBuilder *irb, AstNode *source_node) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_undefined(IrBuilder *irb, Scope *scope, AstNode *source_node) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.static_value.special = ConstValSpecialUndef; const_instruction->base.type_entry = irb->codegen->builtin_types.entry_undef; return &const_instruction->base; } -static IrInstruction *ir_build_const_bignum(IrBuilder *irb, AstNode *source_node, BigNum *bignum) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_bignum(IrBuilder *irb, Scope *scope, AstNode *source_node, BigNum *bignum) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = (bignum->kind == BigNumKindInt) ? irb->codegen->builtin_types.entry_num_lit_int : irb->codegen->builtin_types.entry_num_lit_float; const_instruction->base.static_value.special = ConstValSpecialStatic; @@ -398,79 +410,77 @@ static IrInstruction *ir_build_const_bignum(IrBuilder *irb, AstNode *source_node return &const_instruction->base; } -static IrInstruction *ir_build_const_null(IrBuilder *irb, AstNode *source_node) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_null(IrBuilder *irb, Scope *scope, AstNode *source_node) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_null; const_instruction->base.static_value.special = ConstValSpecialStatic; return &const_instruction->base; } -static IrInstruction *ir_build_const_usize(IrBuilder *irb, AstNode *source_node, uint64_t value) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode *source_node, uint64_t value) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_usize; const_instruction->base.static_value.special = ConstValSpecialStatic; bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, value); return &const_instruction->base; } -static IrInstruction *ir_create_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) { - IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, source_node); +static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node, + TypeTableEntry *type_entry) +{ + IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, scope, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_type; const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_type = type_entry; return &const_instruction->base; } -static IrInstruction *ir_build_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) { - IrInstruction *instruction = ir_create_const_type(irb, source_node, type_entry); +static IrInstruction *ir_build_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node, + TypeTableEntry *type_entry) +{ + IrInstruction *instruction = ir_create_const_type(irb, scope, source_node, type_entry); ir_instruction_append(irb->current_basic_block, instruction); return instruction; } -static IrInstruction *ir_build_const_fn(IrBuilder *irb, AstNode *source_node, FnTableEntry *fn_entry) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = fn_entry->type_entry; const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_fn = fn_entry; return &const_instruction->base; } -static IrInstruction *ir_build_const_generic_fn(IrBuilder *irb, AstNode *source_node, TypeTableEntry *fn_type) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); - const_instruction->base.type_entry = fn_type; - const_instruction->base.static_value.special = ConstValSpecialStatic; - const_instruction->base.static_value.data.x_type = fn_type; - return &const_instruction->base; -} - -static IrInstruction *ir_build_const_import(IrBuilder *irb, AstNode *source_node, ImportTableEntry *import) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_namespace; const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_import = import; return &const_instruction->base; } -static IrInstruction *ir_build_const_scope(IrBuilder *irb, AstNode *source_node, Scope *scope) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_scope(IrBuilder *irb, Scope *parent_scope, AstNode *source_node, + Scope *target_scope) +{ + IrInstructionConst *const_instruction = ir_build_instruction(irb, parent_scope, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_block; const_instruction->base.static_value.special = ConstValSpecialStatic; - const_instruction->base.static_value.data.x_block = scope; + const_instruction->base.static_value.data.x_block = target_scope; return &const_instruction->base; } -static IrInstruction *ir_build_const_bool(IrBuilder *irb, AstNode *source_node, bool value) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_bool(IrBuilder *irb, Scope *scope, AstNode *source_node, bool value) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_bool; const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_bool = value; return &const_instruction->base; } -static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry, IrInstruction *first_arg, bool depends_on_compile_var) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.type_entry = get_bound_fn_type(irb->codegen, fn_entry); const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var; @@ -479,8 +489,8 @@ static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, AstNode *source_no return &const_instruction->base; } -static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, AstNode *source_node, Buf *str) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *str) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8; TypeTableEntry *type_entry = get_array_type(irb->codegen, u8_type, buf_len(str)); const_instruction->base.type_entry = type_entry; @@ -498,7 +508,7 @@ static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, AstNode *source_nod return &const_instruction->base; } -static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, AstNode *source_node, Buf *str) { +static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *str) { // first we build the underlying array size_t len_with_null = buf_len(str) + 1; ConstExprValue *array_val = allocate(1); @@ -515,7 +525,7 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, AstNode *source_n bignum_init_unsigned(&null_char->data.x_bignum, 0); // then make the pointer point to it - IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8; TypeTableEntry *type_entry = get_pointer_to_type(irb->codegen, u8_type, true); const_instruction->base.type_entry = type_entry; @@ -528,10 +538,10 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, AstNode *source_n return &const_instruction->base; } -static IrInstruction *ir_build_bin_op(IrBuilder *irb, AstNode *source_node, IrBinOp op_id, +static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, IrInstruction *op1, IrInstruction *op2) { - IrInstructionBinOp *bin_op_instruction = ir_build_instruction(irb, source_node); + IrInstructionBinOp *bin_op_instruction = ir_build_instruction(irb, scope, source_node); bin_op_instruction->op_id = op_id; bin_op_instruction->op1 = op1; bin_op_instruction->op2 = op2; @@ -545,13 +555,14 @@ static IrInstruction *ir_build_bin_op(IrBuilder *irb, AstNode *source_node, IrBi static IrInstruction *ir_build_bin_op_from(IrBuilder *irb, IrInstruction *old_instruction, IrBinOp op_id, IrInstruction *op1, IrInstruction *op2) { - IrInstruction *new_instruction = ir_build_bin_op(irb, old_instruction->source_node, op_id, op1, op2); + IrInstruction *new_instruction = ir_build_bin_op(irb, old_instruction->scope, + old_instruction->source_node, op_id, op1, op2); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_var_ptr(IrBuilder *irb, AstNode *source_node, VariableTableEntry *var) { - IrInstructionVarPtr *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, VariableTableEntry *var) { + IrInstructionVarPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->var = var; ir_ref_var(var); @@ -560,16 +571,16 @@ static IrInstruction *ir_build_var_ptr(IrBuilder *irb, AstNode *source_node, Var } static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, VariableTableEntry *var) { - IrInstruction *new_instruction = ir_build_var_ptr(irb, old_instruction->source_node, var); + IrInstruction *new_instruction = ir_build_var_ptr(irb, old_instruction->scope, old_instruction->source_node, var); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *array_ptr, +static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on) { - IrInstructionElemPtr *instruction = ir_build_instruction(irb, source_node); + IrInstructionElemPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->array_ptr = array_ptr; instruction->elem_index = elem_index; instruction->safety_check_on = safety_check_on; @@ -583,16 +594,16 @@ static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, Ir static IrInstruction *ir_build_elem_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on) { - IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->source_node, array_ptr, elem_index, - safety_check_on); + IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->scope, + old_instruction->source_node, array_ptr, elem_index, safety_check_on); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_field_ptr(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *container_ptr, Buf *field_name) { - IrInstructionFieldPtr *instruction = ir_build_instruction(irb, source_node); + IrInstructionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->container_ptr = container_ptr; instruction->field_name = field_name; @@ -601,10 +612,10 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *struct_ptr, TypeStructField *field) { - IrInstructionStructFieldPtr *instruction = ir_build_instruction(irb, source_node); + IrInstructionStructFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->struct_ptr = struct_ptr; instruction->field = field; @@ -616,16 +627,16 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, AstNode *source_ static IrInstruction *ir_build_struct_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *struct_ptr, TypeStructField *type_struct_field) { - IrInstruction *new_instruction = ir_build_struct_field_ptr(irb, old_instruction->source_node, - struct_ptr, type_struct_field); + IrInstruction *new_instruction = ir_build_struct_field_ptr(irb, old_instruction->scope, + old_instruction->source_node, struct_ptr, type_struct_field); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *enum_ptr, TypeEnumField *field) { - IrInstructionEnumFieldPtr *instruction = ir_build_instruction(irb, source_node); + IrInstructionEnumFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->enum_ptr = enum_ptr; instruction->field = field; @@ -637,16 +648,16 @@ static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, AstNode *source_no static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *enum_ptr, TypeEnumField *type_enum_field) { - IrInstruction *new_instruction = ir_build_enum_field_ptr(irb, old_instruction->source_node, - enum_ptr, type_enum_field); + IrInstruction *new_instruction = ir_build_enum_field_ptr(irb, old_instruction->scope, + old_instruction->source_node, enum_ptr, type_enum_field); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args) { - IrInstructionCall *call_instruction = ir_build_instruction(irb, source_node); + IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node); call_instruction->fn_entry = fn_entry; call_instruction->fn_ref = fn_ref; call_instruction->arg_count = arg_count; @@ -663,18 +674,19 @@ static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args) { - IrInstruction *new_instruction = ir_build_call(irb, old_instruction->source_node, fn_entry, fn_ref, arg_count, args); + IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope, + old_instruction->source_node, fn_entry, fn_ref, arg_count, args); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_phi(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node, size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values) { assert(incoming_count != 0); assert(incoming_count != SIZE_MAX); - IrInstructionPhi *phi_instruction = ir_build_instruction(irb, source_node); + IrInstructionPhi *phi_instruction = ir_build_instruction(irb, scope, source_node); phi_instruction->incoming_count = incoming_count; phi_instruction->incoming_blocks = incoming_blocks; phi_instruction->incoming_values = incoming_values; @@ -690,14 +702,16 @@ static IrInstruction *ir_build_phi(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_phi_from(IrBuilder *irb, IrInstruction *old_instruction, size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values) { - IrInstruction *new_instruction = ir_build_phi(irb, old_instruction->source_node, + IrInstruction *new_instruction = ir_build_phi(irb, old_instruction->scope, old_instruction->source_node, incoming_count, incoming_blocks, incoming_values); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_create_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) { - IrInstructionBr *br_instruction = ir_create_instruction(irb->exec, source_node); +static IrInstruction *ir_create_br(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrBasicBlock *dest_block, bool is_inline) +{ + IrInstructionBr *br_instruction = ir_create_instruction(irb->exec, scope, source_node); br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; br_instruction->base.static_value.special = ConstValSpecialStatic; br_instruction->dest_block = dest_block; @@ -708,20 +722,23 @@ static IrInstruction *ir_create_br(IrBuilder *irb, AstNode *source_node, IrBasic return &br_instruction->base; } -static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) { - IrInstruction *instruction = ir_create_br(irb, source_node, dest_block, is_inline); +static IrInstruction *ir_build_br(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrBasicBlock *dest_block, bool is_inline) +{ + IrInstruction *instruction = ir_create_br(irb, scope, source_node, dest_block, is_inline); ir_instruction_append(irb->current_basic_block, instruction); return instruction; } static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrBasicBlock *dest_block) { - IrInstruction *new_instruction = ir_build_br(irb, old_instruction->source_node, dest_block, false); + IrInstruction *new_instruction = ir_build_br(irb, old_instruction->scope, + old_instruction->source_node, dest_block, false); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_un_op(IrBuilder *irb, AstNode *source_node, IrUnOp op_id, IrInstruction *value) { - IrInstructionUnOp *br_instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, IrInstruction *value) { + IrInstructionUnOp *br_instruction = ir_build_instruction(irb, scope, source_node); br_instruction->op_id = op_id; br_instruction->value = value; @@ -733,16 +750,17 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, AstNode *source_node, IrUnO static IrInstruction *ir_build_un_op_from(IrBuilder *irb, IrInstruction *old_instruction, IrUnOp op_id, IrInstruction *value) { - IrInstruction *new_instruction = ir_build_un_op(irb, old_instruction->source_node, op_id, value); + IrInstruction *new_instruction = ir_build_un_op(irb, old_instruction->scope, + old_instruction->source_node, op_id, value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_container_init_list(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *container_type, size_t item_count, IrInstruction **items) { IrInstructionContainerInitList *container_init_list_instruction = - ir_build_instruction(irb, source_node); + ir_build_instruction(irb, scope, source_node); container_init_list_instruction->container_type = container_type; container_init_list_instruction->item_count = item_count; container_init_list_instruction->items = items; @@ -758,17 +776,17 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, AstNode *sour static IrInstruction *ir_build_container_init_list_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *container_type, size_t item_count, IrInstruction **items) { - IrInstruction *new_instruction = ir_build_container_init_list(irb, old_instruction->source_node, - container_type, item_count, items); + IrInstruction *new_instruction = ir_build_container_init_list(irb, old_instruction->scope, + old_instruction->source_node, container_type, item_count, items); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields) { IrInstructionContainerInitFields *container_init_fields_instruction = - ir_build_instruction(irb, source_node); + ir_build_instruction(irb, scope, source_node); container_init_fields_instruction->container_type = container_type; container_init_fields_instruction->field_count = field_count; container_init_fields_instruction->fields = fields; @@ -781,10 +799,10 @@ static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, AstNode *so return &container_init_fields_instruction->base; } -static IrInstruction *ir_build_struct_init(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_struct_init(IrBuilder *irb, Scope *scope, AstNode *source_node, TypeTableEntry *struct_type, size_t field_count, IrInstructionStructInitField *fields) { - IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, source_node); + IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, scope, source_node); struct_init_instruction->struct_type = struct_type; struct_init_instruction->field_count = field_count; struct_init_instruction->fields = fields; @@ -798,30 +816,30 @@ static IrInstruction *ir_build_struct_init(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *old_instruction, TypeTableEntry *struct_type, size_t field_count, IrInstructionStructInitField *fields) { - IrInstruction *new_instruction = ir_build_struct_init(irb, old_instruction->source_node, - struct_type, field_count, fields); + IrInstruction *new_instruction = ir_build_struct_init(irb, old_instruction->scope, + old_instruction->source_node, struct_type, field_count, fields); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_unreachable(IrBuilder *irb, AstNode *source_node) { +static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionUnreachable *unreachable_instruction = - ir_build_instruction(irb, source_node); + ir_build_instruction(irb, scope, source_node); unreachable_instruction->base.static_value.special = ConstValSpecialStatic; unreachable_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; return &unreachable_instruction->base; } static IrInstruction *ir_build_unreachable_from(IrBuilder *irb, IrInstruction *old_instruction) { - IrInstruction *new_instruction = ir_build_unreachable(irb, old_instruction->source_node); + IrInstruction *new_instruction = ir_build_unreachable(irb, old_instruction->scope, old_instruction->source_node); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_store_ptr(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr, IrInstruction *value) { - IrInstructionStorePtr *instruction = ir_build_instruction(irb, source_node); + IrInstructionStorePtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->base.static_value.special = ConstValSpecialStatic; instruction->base.type_entry = irb->codegen->builtin_types.entry_void; instruction->ptr = ptr; @@ -836,15 +854,16 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_store_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr, IrInstruction *value) { - IrInstruction *new_instruction = ir_build_store_ptr(irb, old_instruction->source_node, ptr, value); + IrInstruction *new_instruction = ir_build_store_ptr(irb, old_instruction->scope, + old_instruction->source_node, ptr, value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node, VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value) { - IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, source_node); + IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, scope, source_node); decl_var_instruction->base.static_value.special = ConstValSpecialStatic; decl_var_instruction->base.type_entry = irb->codegen->builtin_types.entry_void; decl_var_instruction->var = var; @@ -860,13 +879,14 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_instruction, VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value) { - IrInstruction *new_instruction = ir_build_var_decl(irb, old_instruction->source_node, var, var_type, init_value); + IrInstruction *new_instruction = ir_build_var_decl(irb, old_instruction->scope, + old_instruction->source_node, var, var_type, init_value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_load_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *ptr) { - IrInstructionLoadPtr *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { + IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->ptr = ptr; ir_ref_instruction(ptr); @@ -875,13 +895,14 @@ static IrInstruction *ir_build_load_ptr(IrBuilder *irb, AstNode *source_node, Ir } static IrInstruction *ir_build_load_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr) { - IrInstruction *new_instruction = ir_build_load_ptr(irb, old_instruction->source_node, ptr); + IrInstruction *new_instruction = ir_build_load_ptr(irb, old_instruction->scope, + old_instruction->source_node, ptr); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_typeof(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionTypeOf *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionTypeOf *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -889,8 +910,8 @@ static IrInstruction *ir_build_typeof(IrBuilder *irb, AstNode *source_node, IrIn return &instruction->base; } -static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionToPtrType *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -898,8 +919,8 @@ static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionPtrTypeChild *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionPtrTypeChild *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -907,10 +928,10 @@ static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, AstNode *source_no return &instruction->base; } -static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node, IrInstruction *fn_value, +static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn_value, IrInstruction *is_test) { - IrInstructionSetFnTest *instruction = ir_build_instruction(irb, source_node); + IrInstructionSetFnTest *instruction = ir_build_instruction(irb, scope, source_node); instruction->fn_value = fn_value; instruction->is_test = is_test; @@ -920,10 +941,10 @@ static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_set_fn_visible(IrBuilder *irb, AstNode *source_node, IrInstruction *fn_value, +static IrInstruction *ir_build_set_fn_visible(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn_value, IrInstruction *is_visible) { - IrInstructionSetFnVisible *instruction = ir_build_instruction(irb, source_node); + IrInstructionSetFnVisible *instruction = ir_build_instruction(irb, scope, source_node); instruction->fn_value = fn_value; instruction->is_visible = is_visible; @@ -933,10 +954,10 @@ static IrInstruction *ir_build_set_fn_visible(IrBuilder *irb, AstNode *source_no return &instruction->base; } -static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_value, IrInstruction *debug_safety_on) { - IrInstructionSetDebugSafety *instruction = ir_build_instruction(irb, source_node); + IrInstructionSetDebugSafety *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_value = scope_value; instruction->debug_safety_on = debug_safety_on; @@ -946,10 +967,10 @@ static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, AstNode *source_ return &instruction->base; } -static IrInstruction *ir_build_array_type(IrBuilder *irb, AstNode *source_node, IrInstruction *size, +static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size, IrInstruction *child_type) { - IrInstructionArrayType *instruction = ir_build_instruction(irb, source_node); + IrInstructionArrayType *instruction = ir_build_instruction(irb, scope, source_node); instruction->size = size; instruction->child_type = child_type; @@ -959,10 +980,10 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_slice_type(IrBuilder *irb, AstNode *source_node, bool is_const, +static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node, bool is_const, IrInstruction *child_type) { - IrInstructionSliceType *instruction = ir_build_instruction(irb, source_node); + IrInstructionSliceType *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_const = is_const; instruction->child_type = child_type; @@ -971,12 +992,13 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_asm(IrBuilder *irb, AstNode *source_node, IrInstruction **input_list, - IrInstruction **output_types, size_t return_count, bool has_side_effects) +static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction **input_list, + IrInstruction **output_types, VariableTableEntry **output_vars, size_t return_count, bool has_side_effects) { - IrInstructionAsm *instruction = ir_build_instruction(irb, source_node); + IrInstructionAsm *instruction = ir_build_instruction(irb, scope, source_node); instruction->input_list = input_list; instruction->output_types = output_types; + instruction->output_vars = output_vars; instruction->return_count = return_count; instruction->has_side_effects = has_side_effects; @@ -995,16 +1017,16 @@ static IrInstruction *ir_build_asm(IrBuilder *irb, AstNode *source_node, IrInstr } static IrInstruction *ir_build_asm_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction **input_list, - IrInstruction **output_types, size_t return_count, bool has_side_effects) + IrInstruction **output_types, VariableTableEntry **output_vars, size_t return_count, bool has_side_effects) { - IrInstruction *new_instruction = ir_build_asm(irb, old_instruction->source_node, input_list, output_types, - return_count, has_side_effects); + IrInstruction *new_instruction = ir_build_asm(irb, old_instruction->scope, + old_instruction->source_node, input_list, output_types, output_vars, return_count, has_side_effects); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_compile_var(IrBuilder *irb, AstNode *source_node, IrInstruction *name) { - IrInstructionCompileVar *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_compile_var(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) { + IrInstructionCompileVar *instruction = ir_build_instruction(irb, scope, source_node); instruction->name = name; ir_ref_instruction(name); @@ -1012,8 +1034,8 @@ static IrInstruction *ir_build_compile_var(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrInstruction *type_value) { - IrInstructionSizeOf *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) { + IrInstructionSizeOf *instruction = ir_build_instruction(irb, scope, source_node); instruction->type_value = type_value; ir_ref_instruction(type_value); @@ -1021,8 +1043,8 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrI return &instruction->base; } -static IrInstruction *ir_build_test_null(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionTestNull *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionTestNull *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -1033,15 +1055,16 @@ static IrInstruction *ir_build_test_null(IrBuilder *irb, AstNode *source_node, I static IrInstruction *ir_build_test_null_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) { - IrInstruction *new_instruction = ir_build_test_null(irb, old_instruction->source_node, value); + IrInstruction *new_instruction = ir_build_test_null(irb, old_instruction->scope, + old_instruction->source_node, value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, AstNode *source_node, IrInstruction *value, +static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value, bool safety_check_on) { - IrInstructionUnwrapMaybe *instruction = ir_build_instruction(irb, source_node); + IrInstructionUnwrapMaybe *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; instruction->safety_check_on = safety_check_on; @@ -1053,14 +1076,14 @@ static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, AstNode *source_node static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value, bool safety_check_on) { - IrInstruction *new_instruction = ir_build_unwrap_maybe(irb, old_instruction->source_node, + IrInstruction *new_instruction = ir_build_unwrap_maybe(irb, old_instruction->scope, old_instruction->source_node, value, safety_check_on); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_clz(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionClz *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_clz(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionClz *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -1069,13 +1092,13 @@ static IrInstruction *ir_build_clz(IrBuilder *irb, AstNode *source_node, IrInstr } static IrInstruction *ir_build_clz_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) { - IrInstruction *new_instruction = ir_build_clz(irb, old_instruction->source_node, value); + IrInstruction *new_instruction = ir_build_clz(irb, old_instruction->scope, old_instruction->source_node, value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_ctz(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionCtz *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_ctz(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionCtz *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -1084,15 +1107,15 @@ static IrInstruction *ir_build_ctz(IrBuilder *irb, AstNode *source_node, IrInstr } static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) { - IrInstruction *new_instruction = ir_build_ctz(irb, old_instruction->source_node, value); + IrInstruction *new_instruction = ir_build_ctz(irb, old_instruction->scope, old_instruction->source_node, value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_switch_br(IrBuilder *irb, AstNode *source_node, IrInstruction *target_value, +static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value, IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, bool is_inline) { - IrInstructionSwitchBr *instruction = ir_build_instruction(irb, source_node); + IrInstructionSwitchBr *instruction = ir_build_instruction(irb, scope, source_node); instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; instruction->base.static_value.special = ConstValSpecialStatic; instruction->target_value = target_value; @@ -1116,16 +1139,16 @@ static IrInstruction *ir_build_switch_br_from(IrBuilder *irb, IrInstruction *old IrInstruction *target_value, IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, bool is_inline) { - IrInstruction *new_instruction = ir_build_switch_br(irb, old_instruction->source_node, + IrInstruction *new_instruction = ir_build_switch_br(irb, old_instruction->scope, old_instruction->source_node, target_value, else_block, case_count, cases, is_inline); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_switch_target(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_switch_target(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value_ptr) { - IrInstructionSwitchTarget *instruction = ir_build_instruction(irb, source_node); + IrInstructionSwitchTarget *instruction = ir_build_instruction(irb, scope, source_node); instruction->target_value_ptr = target_value_ptr; ir_ref_instruction(target_value_ptr); @@ -1133,10 +1156,10 @@ static IrInstruction *ir_build_switch_target(IrBuilder *irb, AstNode *source_nod return &instruction->base; } -static IrInstruction *ir_build_switch_var(IrBuilder *irb, AstNode *source_node, +static IrInstruction *ir_build_switch_var(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value_ptr, IrInstruction *prong_value) { - IrInstructionSwitchVar *instruction = ir_build_instruction(irb, source_node); + IrInstructionSwitchVar *instruction = ir_build_instruction(irb, scope, source_node); instruction->target_value_ptr = target_value_ptr; instruction->prong_value = prong_value; @@ -1146,8 +1169,8 @@ static IrInstruction *ir_build_switch_var(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_enum_tag(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionEnumTag *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_enum_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionEnumTag *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -1156,13 +1179,14 @@ static IrInstruction *ir_build_enum_tag(IrBuilder *irb, AstNode *source_node, Ir } static IrInstruction *ir_build_enum_tag_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) { - IrInstruction *new_instruction = ir_build_enum_tag(irb, old_instruction->source_node, value); + IrInstruction *new_instruction = ir_build_enum_tag(irb, old_instruction->scope, + old_instruction->source_node, value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_static_eval(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionStaticEval *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_static_eval(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionStaticEval *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -1170,8 +1194,8 @@ static IrInstruction *ir_build_static_eval(IrBuilder *irb, AstNode *source_node, return &instruction->base; } -static IrInstruction *ir_build_import(IrBuilder *irb, AstNode *source_node, IrInstruction *name) { - IrInstructionImport *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_import(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) { + IrInstructionImport *instruction = ir_build_instruction(irb, scope, source_node); instruction->name = name; ir_ref_instruction(name); @@ -1179,8 +1203,8 @@ static IrInstruction *ir_build_import(IrBuilder *irb, AstNode *source_node, IrIn return &instruction->base; } -static IrInstruction *ir_build_array_len(IrBuilder *irb, AstNode *source_node, IrInstruction *array_value) { - IrInstructionArrayLen *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_array_len(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_value) { + IrInstructionArrayLen *instruction = ir_build_instruction(irb, scope, source_node); instruction->array_value = array_value; ir_ref_instruction(array_value); @@ -1191,13 +1215,14 @@ static IrInstruction *ir_build_array_len(IrBuilder *irb, AstNode *source_node, I static IrInstruction *ir_build_array_len_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *array_value) { - IrInstruction *new_instruction = ir_build_array_len(irb, old_instruction->source_node, array_value); + IrInstruction *new_instruction = ir_build_array_len(irb, old_instruction->scope, + old_instruction->source_node, array_value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static IrInstruction *ir_build_ref(IrBuilder *irb, AstNode *source_node, IrInstruction *value) { - IrInstructionRef *instruction = ir_build_instruction(irb, source_node); +static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { + IrInstructionRef *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value); @@ -1206,12 +1231,12 @@ static IrInstruction *ir_build_ref(IrBuilder *irb, AstNode *source_node, IrInstr } static IrInstruction *ir_build_ref_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) { - IrInstruction *new_instruction = ir_build_ref(irb, old_instruction->source_node, value); + IrInstruction *new_instruction = ir_build_ref(irb, old_instruction->scope, old_instruction->source_node, value); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } -static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, +static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers, bool gen_maybe_defers) { while (inner_scope != outer_scope) { @@ -1221,29 +1246,16 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o (gen_maybe_defers && inner_scope->node->data.defer.kind == ReturnKindMaybe))) { 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, parent_scope); } 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, Scope *scope, AstNode *node) { assert(node->type == NodeTypeReturnExpr); - Scope *scope = node->scope; - - if (!scope_fn_entry(scope)) { + if (!exec_fn_entry(irb->exec)) { add_node_error(irb->codegen, node, buf_sprintf("return expression outside function definition")); return irb->codegen->invalid_instruction; } @@ -1254,12 +1266,12 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *node) { { IrInstruction *return_value; if (expr_node) { - return_value = ir_gen_node(irb, expr_node, node->scope); + return_value = ir_gen_node(irb, expr_node, scope); } else { - return_value = ir_build_const_void(irb, node); + return_value = ir_build_const_void(irb, scope, node); } - return ir_build_return(irb, node, return_value); + return ir_build_return(irb, scope, node, return_value); } case ReturnKindError: zig_panic("TODO gen IR for %%return"); @@ -1275,15 +1287,15 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { irb->current_basic_block = basic_block; } -static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, +static VariableTableEntry *create_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) { VariableTableEntry *variable_entry = allocate(1); variable_entry->parent_scope = parent_scope; - variable_entry->import = node->owner; variable_entry->shadowable = is_shadowable; variable_entry->mem_slot_index = SIZE_MAX; variable_entry->is_inline = is_inline; + variable_entry->src_arg_index = SIZE_MAX; if (name) { buf_init_from_buf(&variable_entry->name, name); @@ -1302,11 +1314,11 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Scope buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); variable_entry->type = codegen->builtin_types.entry_invalid; } else { - AstNode *decl_node = find_decl(parent_scope, name); - if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { + Tld *tld = find_decl(parent_scope, name); + if (tld && tld->id != TldIdVar) { ErrorMsg *msg = add_node_error(codegen, node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); - add_error_note(codegen, msg, decl_node, buf_sprintf("previous definition is here")); + add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); variable_entry->type = codegen->builtin_types.entry_invalid; } } @@ -1333,7 +1345,7 @@ static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, 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) { - VariableTableEntry *var = add_local_var(irb->codegen, node, scope, name, + VariableTableEntry *var = create_local_var(irb->codegen, node, scope, name, src_is_const, gen_is_const, is_shadowable, is_inline); if (is_inline || gen_is_const) var->mem_slot_index = exec_next_mem_slot(irb->exec); @@ -1341,10 +1353,9 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s return var; } -static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) { +static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) { assert(block_node->type == NodeTypeBlock); - Scope *parent_scope = block_node->scope; Scope *outer_block_scope = create_block_scope(block_node, parent_scope); Scope *child_scope = outer_block_scope; @@ -1353,56 +1364,57 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) { AstNode *statement_node = block_node->data.block.statements.at(i); return_value = ir_gen_node(irb, statement_node, child_scope); if (statement_node->type == NodeTypeDefer && return_value != irb->codegen->invalid_instruction) { - // defer starts a new block context - child_scope = statement_node->data.defer.child_block; + // defer starts a new scope + child_scope = statement_node->data.defer.child_scope; assert(child_scope); } else if (return_value->id == IrInstructionIdDeclVar) { + // variable declarations start a new scope IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)return_value; child_scope = decl_var_instruction->var->child_scope; } } if (!return_value) - return_value = ir_build_const_void(irb, block_node); + return_value = ir_build_const_void(irb, child_scope, block_node); - ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false, false); + ir_gen_defers_for_block(irb, parent_scope, child_scope, outer_block_scope, false, false); return return_value; } -static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, AstNode *node, IrBinOp op_id) { - IrInstruction *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, node->scope); - IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, node->scope); - return ir_build_bin_op(irb, node, op_id, op1, op2); +static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { + IrInstruction *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope); + IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); + return ir_build_bin_op(irb, scope, node, op_id, op1, op2); } -static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) { - IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, node->scope, LValPurposeAssign); +static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) { + IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPurposeAssign); if (lvalue == irb->codegen->invalid_instruction) return lvalue; - IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, node->scope); + IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); if (rvalue == irb->codegen->invalid_instruction) return rvalue; - ir_build_store_ptr(irb, node, lvalue, rvalue); - return ir_build_const_void(irb, node); + ir_build_store_ptr(irb, scope, node, lvalue, rvalue); + return ir_build_const_void(irb, scope, node); } -static IrInstruction *ir_gen_assign_op(IrBuilder *irb, AstNode *node, IrBinOp op_id) { - IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, node->scope, LValPurposeAssign); +static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { + IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPurposeAssign); if (lvalue == irb->codegen->invalid_instruction) return lvalue; - IrInstruction *op1 = ir_build_load_ptr(irb, node->data.bin_op_expr.op1, lvalue); - IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, node->scope); + IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue); + IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); if (op2 == irb->codegen->invalid_instruction) return op2; - IrInstruction *result = ir_build_bin_op(irb, node, op_id, op1, op2); - ir_build_store_ptr(irb, node, lvalue, result); - return ir_build_const_void(irb, node); + IrInstruction *result = ir_build_bin_op(irb, scope, node, op_id, op1, op2); + ir_build_store_ptr(irb, scope, node, lvalue, result); + return ir_build_const_void(irb, scope, node); } -static IrInstruction *ir_gen_bin_op(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeBinOpExpr); BinOpType bin_op_type = node->data.bin_op_expr.bin_op; @@ -1410,95 +1422,95 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, AstNode *node) { case BinOpTypeInvalid: zig_unreachable(); case BinOpTypeAssign: - return ir_gen_assign(irb, node); + return ir_gen_assign(irb, scope, node); case BinOpTypeAssignTimes: - return ir_gen_assign_op(irb, node, IrBinOpMult); + return ir_gen_assign_op(irb, scope, node, IrBinOpMult); case BinOpTypeAssignTimesWrap: - return ir_gen_assign_op(irb, node, IrBinOpMultWrap); + return ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap); case BinOpTypeAssignDiv: - return ir_gen_assign_op(irb, node, IrBinOpDiv); + return ir_gen_assign_op(irb, scope, node, IrBinOpDiv); case BinOpTypeAssignMod: - return ir_gen_assign_op(irb, node, IrBinOpMod); + return ir_gen_assign_op(irb, scope, node, IrBinOpMod); case BinOpTypeAssignPlus: - return ir_gen_assign_op(irb, node, IrBinOpAdd); + return ir_gen_assign_op(irb, scope, node, IrBinOpAdd); case BinOpTypeAssignPlusWrap: - return ir_gen_assign_op(irb, node, IrBinOpAddWrap); + return ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap); case BinOpTypeAssignMinus: - return ir_gen_assign_op(irb, node, IrBinOpSub); + return ir_gen_assign_op(irb, scope, node, IrBinOpSub); case BinOpTypeAssignMinusWrap: - return ir_gen_assign_op(irb, node, IrBinOpSubWrap); + return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap); case BinOpTypeAssignBitShiftLeft: - return ir_gen_assign_op(irb, node, IrBinOpBitShiftLeft); + return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeft); case BinOpTypeAssignBitShiftLeftWrap: - return ir_gen_assign_op(irb, node, IrBinOpBitShiftLeftWrap); + return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftWrap); case BinOpTypeAssignBitShiftRight: - return ir_gen_assign_op(irb, node, IrBinOpBitShiftRight); + return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRight); case BinOpTypeAssignBitAnd: - return ir_gen_assign_op(irb, node, IrBinOpBinAnd); + return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd); case BinOpTypeAssignBitXor: - return ir_gen_assign_op(irb, node, IrBinOpBinXor); + return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor); case BinOpTypeAssignBitOr: - return ir_gen_assign_op(irb, node, IrBinOpBinOr); + return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr); case BinOpTypeAssignBoolAnd: - return ir_gen_assign_op(irb, node, IrBinOpBoolAnd); + return ir_gen_assign_op(irb, scope, node, IrBinOpBoolAnd); case BinOpTypeAssignBoolOr: - return ir_gen_assign_op(irb, node, IrBinOpBoolOr); + return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr); case BinOpTypeBoolOr: case BinOpTypeBoolAnd: // note: this is not a direct mapping to IrBinOpBoolOr/And // because of the control flow zig_panic("TODO gen IR for bool or/and"); case BinOpTypeCmpEq: - return ir_gen_bin_op_id(irb, node, IrBinOpCmpEq); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq); case BinOpTypeCmpNotEq: - return ir_gen_bin_op_id(irb, node, IrBinOpCmpNotEq); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq); case BinOpTypeCmpLessThan: - return ir_gen_bin_op_id(irb, node, IrBinOpCmpLessThan); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan); case BinOpTypeCmpGreaterThan: - return ir_gen_bin_op_id(irb, node, IrBinOpCmpGreaterThan); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan); case BinOpTypeCmpLessOrEq: - return ir_gen_bin_op_id(irb, node, IrBinOpCmpLessOrEq); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq); case BinOpTypeCmpGreaterOrEq: - return ir_gen_bin_op_id(irb, node, IrBinOpCmpGreaterOrEq); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq); case BinOpTypeBinOr: - return ir_gen_bin_op_id(irb, node, IrBinOpBinOr); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr); case BinOpTypeBinXor: - return ir_gen_bin_op_id(irb, node, IrBinOpBinXor); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor); case BinOpTypeBinAnd: - return ir_gen_bin_op_id(irb, node, IrBinOpBinAnd); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd); case BinOpTypeBitShiftLeft: - return ir_gen_bin_op_id(irb, node, IrBinOpBitShiftLeft); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeft); case BinOpTypeBitShiftLeftWrap: - return ir_gen_bin_op_id(irb, node, IrBinOpBitShiftLeftWrap); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftWrap); case BinOpTypeBitShiftRight: - return ir_gen_bin_op_id(irb, node, IrBinOpBitShiftRight); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRight); case BinOpTypeAdd: - return ir_gen_bin_op_id(irb, node, IrBinOpAdd); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd); case BinOpTypeAddWrap: - return ir_gen_bin_op_id(irb, node, IrBinOpAddWrap); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap); case BinOpTypeSub: - return ir_gen_bin_op_id(irb, node, IrBinOpSub); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpSub); case BinOpTypeSubWrap: - return ir_gen_bin_op_id(irb, node, IrBinOpSubWrap); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap); case BinOpTypeMult: - return ir_gen_bin_op_id(irb, node, IrBinOpMult); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpMult); case BinOpTypeMultWrap: - return ir_gen_bin_op_id(irb, node, IrBinOpMultWrap); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap); case BinOpTypeDiv: - return ir_gen_bin_op_id(irb, node, IrBinOpDiv); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpDiv); case BinOpTypeMod: - return ir_gen_bin_op_id(irb, node, IrBinOpMod); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpMod); case BinOpTypeArrayCat: - return ir_gen_bin_op_id(irb, node, IrBinOpArrayCat); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat); case BinOpTypeArrayMult: - return ir_gen_bin_op_id(irb, node, IrBinOpArrayMult); + return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); case BinOpTypeUnwrapMaybe: zig_panic("TODO gen IR for unwrap maybe binary operation"); } zig_unreachable(); } -static IrInstruction *ir_gen_num_lit(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_num_lit(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeNumberLiteral); if (node->data.number_literal.overflow) { @@ -1506,95 +1518,95 @@ static IrInstruction *ir_gen_num_lit(IrBuilder *irb, AstNode *node) { return irb->codegen->invalid_instruction; } - return ir_build_const_bignum(irb, node, node->data.number_literal.bignum); + return ir_build_const_bignum(irb, scope, node, node->data.number_literal.bignum); } -static IrInstruction *ir_gen_null_literal(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeNullLiteral); - return ir_build_const_null(irb, node); + return ir_build_const_null(irb, scope, node); } -static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node, +static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld *tld, LValPurpose lval, Scope *scope) { - resolve_top_level_decl(irb->codegen, decl_node, lval != LValPurposeNone); - TopLevelDecl *tld = get_as_top_level_decl(decl_node); + resolve_top_level_decl(irb->codegen, tld, lval != LValPurposeNone); if (tld->resolution == TldResolutionInvalid) return irb->codegen->invalid_instruction; - if (decl_node->type == NodeTypeVariableDeclaration) { - VariableTableEntry *var = decl_node->data.variable_declaration.variable; - IrInstruction *var_ptr = ir_build_var_ptr(irb, source_node, var); - if (lval != LValPurposeNone) - return var_ptr; - else - return ir_build_load_ptr(irb, source_node, var_ptr); - } else if (decl_node->type == NodeTypeFnProto) { - FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; - assert(fn_entry->type_entry); - IrInstruction *ref_instruction; - if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) { - ref_instruction = ir_build_const_generic_fn(irb, source_node, fn_entry->type_entry); - } else { - ref_instruction = ir_build_const_fn(irb, source_node, fn_entry); + switch (tld->id) { + case TldIdVar: + { + TldVar *tld_var = (TldVar *)tld; + VariableTableEntry *var = tld_var->var; + IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, source_node, var); + if (lval != LValPurposeNone) + return var_ptr; + else + return ir_build_load_ptr(irb, scope, source_node, var_ptr); } - if (lval != LValPurposeNone) - return ir_build_ref(irb, source_node, ref_instruction); - else - return ref_instruction; - } else if (decl_node->type == NodeTypeContainerDecl) { - IrInstruction *ref_instruction; - if (decl_node->data.struct_decl.generic_params.length > 0) { - TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type; - assert(type_entry); - ref_instruction = ir_build_const_generic_fn(irb, source_node, type_entry); - } else { - ref_instruction = ir_build_const_type(irb, source_node, decl_node->data.struct_decl.type_entry); + case TldIdFn: + { + TldFn *tld_fn = (TldFn *)tld; + FnTableEntry *fn_entry = tld_fn->fn_entry; + assert(fn_entry->type_entry); + IrInstruction *ref_instruction = ir_build_const_fn(irb, scope, source_node, fn_entry); + if (lval != LValPurposeNone) + return ir_build_ref(irb, scope, source_node, ref_instruction); + else + return ref_instruction; + } + case TldIdContainer: + { + TldContainer *tld_container = (TldContainer *)tld; + + IrInstruction *ref_instruction = ir_build_const_type(irb, scope, source_node, tld_container->type_entry); + if (lval != LValPurposeNone) + return ir_build_ref(irb, scope, source_node, ref_instruction); + else + return ref_instruction; + } + case TldIdTypeDef: + { + TldTypeDef *tld_typedef = (TldTypeDef *)tld; + TypeTableEntry *typedef_type = tld_typedef->type_entry; + IrInstruction *ref_instruction = ir_build_const_type(irb, scope, source_node, typedef_type); + if (lval != LValPurposeNone) + return ir_build_ref(irb, scope, source_node, ref_instruction); + else + return ref_instruction; } - if (lval != LValPurposeNone) - return ir_build_ref(irb, source_node, ref_instruction); - else - return ref_instruction; - } else if (decl_node->type == NodeTypeTypeDecl) { - TypeTableEntry *child_type = decl_node->data.type_decl.child_type_entry; - IrInstruction *ref_instruction = ir_build_const_type(irb, source_node, child_type); - if (lval != LValPurposeNone) - return ir_build_ref(irb, source_node, ref_instruction); - else - return ref_instruction; - } else { - zig_unreachable(); } + zig_unreachable(); } -static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose lval) { +static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { assert(node->type == NodeTypeSymbol); Buf *variable_name = node->data.symbol_expr.symbol; auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name); if (primitive_table_entry) { - IrInstruction *value = ir_build_const_type(irb, node, primitive_table_entry->value); + IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_table_entry->value); if (lval == LValPurposeAddressOf) { - return ir_build_un_op(irb, node, IrUnOpAddressOf, value); + return ir_build_un_op(irb, scope, node, IrUnOpAddressOf, value); } else { return value; } } - VariableTableEntry *var = find_variable(irb->codegen, node->scope, variable_name); + VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name); if (var) { - IrInstruction *var_ptr = ir_build_var_ptr(irb, node, var); + IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var); if (lval != LValPurposeNone) return var_ptr; else - return ir_build_load_ptr(irb, node, var_ptr); + return ir_build_load_ptr(irb, scope, node, var_ptr); } - AstNode *decl_node = find_decl(node->scope, variable_name); - if (decl_node) - return ir_gen_decl_ref(irb, node, decl_node, lval, node->scope); + Tld *tld = find_decl(scope, variable_name); + if (tld) + return ir_gen_decl_ref(irb, node, tld, lval, scope); if (node->owner->any_imports_failed) { // skip the error message since we had a failing import in this file @@ -1606,47 +1618,47 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose l return irb->codegen->invalid_instruction; } -static IrInstruction *ir_gen_array_access(IrBuilder *irb, AstNode *node, LValPurpose lval) { +static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { assert(node->type == NodeTypeArrayAccessExpr); AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; - IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, node->scope, + IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPurposeAddressOf); if (array_ref_instruction == irb->codegen->invalid_instruction) return array_ref_instruction; AstNode *subscript_node = node->data.array_access_expr.subscript; - IrInstruction *subscript_instruction = ir_gen_node(irb, subscript_node, node->scope); + IrInstruction *subscript_instruction = ir_gen_node(irb, subscript_node, scope); if (subscript_instruction == irb->codegen->invalid_instruction) return subscript_instruction; - IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, node, array_ref_instruction, + IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction, subscript_instruction, true); if (lval != LValPurposeNone) return ptr_instruction; - return ir_build_load_ptr(irb, node, ptr_instruction); + return ir_build_load_ptr(irb, scope, node, ptr_instruction); } -static IrInstruction *ir_gen_field_access(IrBuilder *irb, AstNode *node, LValPurpose lval) { +static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { assert(node->type == NodeTypeFieldAccessExpr); AstNode *container_ref_node = node->data.field_access_expr.struct_expr; Buf *field_name = node->data.field_access_expr.field_name; - IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, node->scope, + IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPurposeAddressOf); if (container_ref_instruction == irb->codegen->invalid_instruction) return container_ref_instruction; - IrInstruction *ptr_instruction = ir_build_field_ptr(irb, node, container_ref_instruction, field_name); + IrInstruction *ptr_instruction = ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name); if (lval != LValPurposeNone) return ptr_instruction; - return ir_build_load_ptr(irb, node, ptr_instruction); + return ir_build_load_ptr(irb, scope, node, ptr_instruction); } -static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeFnCallExpr); AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; @@ -1675,115 +1687,115 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { case BuiltinFnIdInvalid: zig_unreachable(); case BuiltinFnIdUnreachable: - return ir_build_unreachable(irb, node); + return ir_build_unreachable(irb, scope, node); case BuiltinFnIdTypeof: { AstNode *arg_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg = ir_gen_node(irb, arg_node, node->scope); + IrInstruction *arg = ir_gen_node(irb, arg_node, scope); if (arg == irb->codegen->invalid_instruction) return arg; - return ir_build_typeof(irb, node, arg); + return ir_build_typeof(irb, scope, node, arg); } case BuiltinFnIdSetFnTest: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, node->scope); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - return ir_build_set_fn_test(irb, node, arg0_value, arg1_value); + return ir_build_set_fn_test(irb, scope, node, arg0_value, arg1_value); } case BuiltinFnIdSetFnVisible: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, node->scope); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - return ir_build_set_fn_visible(irb, node, arg0_value, arg1_value); + return ir_build_set_fn_visible(irb, scope, node, arg0_value, arg1_value); } case BuiltinFnIdSetDebugSafety: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, node->scope); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - return ir_build_set_debug_safety(irb, node, arg0_value, arg1_value); + return ir_build_set_debug_safety(irb, scope, node, arg0_value, arg1_value); } case BuiltinFnIdCompileVar: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - return ir_build_compile_var(irb, node, arg0_value); + return ir_build_compile_var(irb, scope, node, arg0_value); } case BuiltinFnIdSizeof: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - return ir_build_size_of(irb, node, arg0_value); + return ir_build_size_of(irb, scope, node, arg0_value); } case BuiltinFnIdCtz: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - return ir_build_ctz(irb, node, arg0_value); + return ir_build_ctz(irb, scope, node, arg0_value); } case BuiltinFnIdClz: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - return ir_build_clz(irb, node, arg0_value); + return ir_build_clz(irb, scope, node, arg0_value); } case BuiltinFnIdStaticEval: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - return ir_build_static_eval(irb, node, arg0_value); + return ir_build_static_eval(irb, scope, node, arg0_value); } case BuiltinFnIdImport: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->scope); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - if (scope_fn_entry(node->scope)) { + if (exec_fn_entry(irb->exec)) { add_node_error(irb->codegen, node, buf_sprintf("import valid only at top level scope")); return irb->codegen->invalid_instruction; } - return ir_build_import(irb, node, arg0_value); + return ir_build_import(irb, scope, node, arg0_value); } case BuiltinFnIdMemcpy: case BuiltinFnIdMemset: @@ -1816,14 +1828,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { zig_unreachable(); } -static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeFnCallExpr); if (node->data.fn_call_expr.is_builtin) - return ir_gen_builtin_fn_call(irb, node); + return ir_gen_builtin_fn_call(irb, scope, node); AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, node->scope); + IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); if (fn_ref == irb->codegen->invalid_instruction) return fn_ref; @@ -1831,16 +1843,16 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) { IrInstruction **args = allocate(arg_count); for (size_t i = 0; i < arg_count; i += 1) { AstNode *arg_node = node->data.fn_call_expr.params.at(i); - args[i] = ir_gen_node(irb, arg_node, node->scope); + args[i] = ir_gen_node(irb, arg_node, scope); } - return ir_build_call(irb, node, nullptr, fn_ref, arg_count, args); + return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args); } -static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeIfBoolExpr); - IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, node->scope); + IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); if (condition == irb->codegen->invalid_instruction) return condition; @@ -1852,26 +1864,26 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) { IrBasicBlock *endif_block = ir_build_basic_block(irb, "EndIf"); bool is_inline = ir_should_inline(irb) || node->data.if_bool_expr.is_inline; - ir_build_cond_br(irb, condition->source_node, condition, then_block, else_block, is_inline); + ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_inline); ir_set_cursor_at_end(irb, then_block); - IrInstruction *then_expr_result = ir_gen_node(irb, then_node, node->scope); + IrInstruction *then_expr_result = ir_gen_node(irb, then_node, scope); if (then_expr_result == irb->codegen->invalid_instruction) return then_expr_result; IrBasicBlock *after_then_block = irb->current_basic_block; - ir_build_br(irb, node, endif_block, is_inline); + ir_build_br(irb, scope, node, endif_block, is_inline); ir_set_cursor_at_end(irb, else_block); IrInstruction *else_expr_result; if (else_node) { - else_expr_result = ir_gen_node(irb, else_node, node->scope); + else_expr_result = ir_gen_node(irb, else_node, scope); if (else_expr_result == irb->codegen->invalid_instruction) return else_expr_result; } else { - else_expr_result = ir_build_const_void(irb, node); + else_expr_result = ir_build_const_void(irb, scope, node); } IrBasicBlock *after_else_block = irb->current_basic_block; - ir_build_br(irb, node, endif_block, is_inline); + ir_build_br(irb, scope, node, endif_block, is_inline); ir_set_cursor_at_end(irb, endif_block); IrInstruction **incoming_values = allocate(2); @@ -1881,14 +1893,14 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) { incoming_blocks[0] = after_then_block; incoming_blocks[1] = after_else_block; - return ir_build_phi(irb, node, 2, incoming_blocks, incoming_values); + return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); } -static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, AstNode *node, IrUnOp op_id, LValPurpose lval) { +static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LValPurpose lval) { assert(node->type == NodeTypePrefixOpExpr); AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - IrInstruction *value = ir_gen_node_extra(irb, expr_node, node->scope, lval); + IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval); if (value == irb->codegen->invalid_instruction) return value; @@ -1896,27 +1908,27 @@ static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, AstNode *node, Ir return value; } - return ir_build_un_op(irb, node, op_id, value); + return ir_build_un_op(irb, scope, node, op_id, value); } -static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, AstNode *node, IrUnOp op_id) { - return ir_gen_prefix_op_id_lval(irb, node, op_id, LValPurposeNone); +static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) { + return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValPurposeNone); } -static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, AstNode *node, LValPurpose lval) { +static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { AstNode *expr = node->data.prefix_op_expr.primary_expr; - IrInstruction *value = ir_gen_node_extra(irb, expr, node->scope, LValPurposeAddressOf); + IrInstruction *value = ir_gen_node_extra(irb, expr, scope, LValPurposeAddressOf); if (value == irb->codegen->invalid_instruction) return value; - IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, node, value, true); + IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, value, true); if (lval == LValPurposeNone) - return ir_build_load_ptr(irb, node, unwrapped_ptr); + return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); else return unwrapped_ptr; } -static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValPurpose lval) { +static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { assert(node->type == NodeTypePrefixOpExpr); PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; @@ -1925,38 +1937,38 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node, LValP case PrefixOpInvalid: zig_unreachable(); case PrefixOpBoolNot: - return ir_gen_prefix_op_id(irb, node, IrUnOpBoolNot); + return ir_gen_prefix_op_id(irb, scope, node, IrUnOpBoolNot); case PrefixOpBinNot: - return ir_gen_prefix_op_id(irb, node, IrUnOpBinNot); + return ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot); case PrefixOpNegation: - return ir_gen_prefix_op_id(irb, node, IrUnOpNegation); + return ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation); case PrefixOpNegationWrap: - return ir_gen_prefix_op_id(irb, node, IrUnOpNegationWrap); + return ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap); case PrefixOpAddressOf: - return ir_gen_prefix_op_id_lval(irb, node, IrUnOpAddressOf, LValPurposeAddressOf); + return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpAddressOf, LValPurposeAddressOf); case PrefixOpConstAddressOf: - return ir_gen_prefix_op_id_lval(irb, node, IrUnOpConstAddressOf, LValPurposeAddressOf); + return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpConstAddressOf, LValPurposeAddressOf); case PrefixOpDereference: - return ir_gen_prefix_op_id_lval(irb, node, IrUnOpDereference, lval); + return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval); case PrefixOpMaybe: - return ir_gen_prefix_op_id(irb, node, IrUnOpMaybe); + return ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe); case PrefixOpError: - return ir_gen_prefix_op_id(irb, node, IrUnOpError); + return ir_gen_prefix_op_id(irb, scope, node, IrUnOpError); case PrefixOpUnwrapError: - return ir_gen_prefix_op_id(irb, node, IrUnOpUnwrapError); + return ir_gen_prefix_op_id(irb, scope, node, IrUnOpUnwrapError); case PrefixOpUnwrapMaybe: - return ir_gen_prefix_op_unwrap_maybe(irb, node, lval); + return ir_gen_prefix_op_unwrap_maybe(irb, scope, node, lval); } zig_unreachable(); } -static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeContainerInitExpr); AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; ContainerInitKind kind = container_init_expr->kind; - IrInstruction *container_type = ir_gen_node(irb, container_init_expr->type, node->scope); + IrInstruction *container_type = ir_gen_node(irb, container_init_expr->type, scope); if (container_type == irb->codegen->invalid_instruction) return container_type; @@ -1969,7 +1981,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node) Buf *name = entry_node->data.struct_val_field.name; AstNode *expr_node = entry_node->data.struct_val_field.expr; - IrInstruction *expr_value = ir_gen_node(irb, expr_node, node->scope); + IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); if (expr_value == irb->codegen->invalid_instruction) return expr_value; @@ -1977,39 +1989,39 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node) fields[i].value = expr_value; fields[i].source_node = entry_node; } - return ir_build_container_init_fields(irb, node, container_type, field_count, fields); + return ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields); } else if (kind == ContainerInitKindArray) { size_t item_count = container_init_expr->entries.length; IrInstruction **values = allocate(item_count); for (size_t i = 0; i < item_count; i += 1) { AstNode *expr_node = container_init_expr->entries.at(i); - IrInstruction *expr_value = ir_gen_node(irb, expr_node, node->scope); + IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); if (expr_value == irb->codegen->invalid_instruction) return expr_value; values[i] = expr_value; } - return ir_build_container_init_list(irb, node, container_type, item_count, values); + return ir_build_container_init_list(irb, scope, node, container_type, item_count, values); } else { zig_unreachable(); } } -static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeVariableDeclaration); AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; IrInstruction *type_instruction; if (variable_declaration->type != nullptr) { - type_instruction = ir_gen_node(irb, variable_declaration->type, node->scope); + type_instruction = ir_gen_node(irb, variable_declaration->type, scope); if (type_instruction == irb->codegen->invalid_instruction) return type_instruction; } else { type_instruction = nullptr; } - IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, node->scope); + IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); if (init_value == irb->codegen->invalid_instruction) return init_value; @@ -2017,7 +2029,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) { bool is_const = variable_declaration->is_const; bool is_extern = variable_declaration->is_extern; bool is_inline = ir_should_inline(irb) || variable_declaration->is_inline; - VariableTableEntry *var = ir_create_var(irb, node, node->scope, + VariableTableEntry *var = ir_create_var(irb, node, scope, 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 @@ -2028,10 +2040,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) { return irb->codegen->invalid_instruction; } - return ir_build_var_decl(irb, node, var, type_instruction, init_value); + return ir_build_var_decl(irb, scope, node, var, type_instruction, init_value); } -static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeWhileExpr); AstNode *continue_expr_node = node->data.while_expr.continue_expr; @@ -2043,37 +2055,35 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { IrBasicBlock *end_block = ir_build_basic_block(irb, "WhileEnd"); bool is_inline = ir_should_inline(irb) || node->data.while_expr.is_inline; - ir_build_br(irb, node, cond_block, is_inline); + ir_build_br(irb, scope, node, cond_block, is_inline); if (continue_expr_node) { ir_set_cursor_at_end(irb, continue_block); - ir_gen_node(irb, continue_expr_node, node->scope); - ir_build_br(irb, node, cond_block, is_inline); + ir_gen_node(irb, continue_expr_node, scope); + ir_build_br(irb, scope, node, cond_block, is_inline); } ir_set_cursor_at_end(irb, cond_block); - IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, node->scope); - ir_build_cond_br(irb, node->data.while_expr.condition, cond_val, body_block, end_block, is_inline); + IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); + ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, body_block, end_block, is_inline); ir_set_cursor_at_end(irb, body_block); irb->break_block_stack.append(end_block); irb->continue_block_stack.append(continue_block); - ir_gen_node(irb, node->data.while_expr.body, node->scope); + ir_gen_node(irb, node->data.while_expr.body, scope); irb->break_block_stack.pop(); irb->continue_block_stack.pop(); - ir_build_br(irb, node, continue_block, is_inline); + ir_build_br(irb, scope, node, continue_block, is_inline); ir_set_cursor_at_end(irb, end_block); - return ir_build_const_void(irb, node); + return ir_build_const_void(irb, scope, node); } -static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeForExpr); - Scope *parent_scope = node->scope; - AstNode *array_node = node->data.for_expr.array_expr; AstNode *elem_node = node->data.for_expr.elem_node; AstNode *index_node = node->data.for_expr.index_node; @@ -2089,48 +2099,45 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) { if (array_val == irb->codegen->invalid_instruction) return array_val; - IrInstruction *array_type = ir_build_typeof(irb, array_node, array_val); - IrInstruction *pointer_type = ir_build_to_ptr_type(irb, array_node, array_type); + IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val); + IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type); IrInstruction *elem_var_type; if (node->data.for_expr.elem_is_ptr) { elem_var_type = pointer_type; } else { - elem_var_type = ir_build_ptr_type_child(irb, elem_node, pointer_type); + elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); } bool is_inline = ir_should_inline(irb) || node->data.for_expr.is_inline; Scope *child_scope = create_loop_scope(node, parent_scope); - elem_node->scope = child_scope; // TODO make it an error to write to element variable or i variable. Buf *elem_var_name = elem_node->data.symbol_expr.symbol; - node->data.for_expr.elem_var = ir_create_var(irb, elem_node, child_scope, elem_var_name, + VariableTableEntry *elem_var = ir_create_var(irb, elem_node, child_scope, elem_var_name, true, false, false, is_inline); - child_scope = node->data.for_expr.elem_var->child_scope; + child_scope = elem_var->child_scope; - 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); - IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, node, node->data.for_expr.elem_var); + IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); + ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, undefined_value); + IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); AstNode *index_var_source_node; + VariableTableEntry *index_var; if (index_node) { index_var_source_node = index_node; Buf *index_var_name = index_node->data.symbol_expr.symbol; - index_node->scope = child_scope; - node->data.for_expr.index_var = ir_create_var(irb, index_node, child_scope, index_var_name, - true, false, false, is_inline); + index_var = ir_create_var(irb, index_node, child_scope, index_var_name, true, false, false, is_inline); } else { index_var_source_node = node; - node->data.for_expr.index_var = ir_create_var(irb, node, child_scope, nullptr, - true, false, true, is_inline); + index_var = ir_create_var(irb, node, child_scope, nullptr, true, false, true, is_inline); } - child_scope = node->data.for_expr.index_var->child_scope; + child_scope = index_var->child_scope; - IrInstruction *usize = ir_build_const_type(irb, node, irb->codegen->builtin_types.entry_usize); - IrInstruction *zero = ir_build_const_usize(irb, node, 0); - IrInstruction *one = ir_build_const_usize(irb, node, 1); - ir_build_var_decl(irb, index_var_source_node, node->data.for_expr.index_var, usize, zero); - IrInstruction *index_ptr = ir_build_var_ptr(irb, node, node->data.for_expr.index_var); + IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); + IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); + IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); + ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, zero); + IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); IrBasicBlock *cond_block = ir_build_basic_block(irb, "ForCond"); @@ -2138,23 +2145,23 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) { IrBasicBlock *end_block = ir_build_basic_block(irb, "ForEnd"); IrBasicBlock *continue_block = ir_build_basic_block(irb, "ForContinue"); - IrInstruction *len_val = ir_build_array_len(irb, node, array_val); - ir_build_br(irb, node, cond_block, is_inline); + IrInstruction *len_val = ir_build_array_len(irb, child_scope, node, array_val); + ir_build_br(irb, child_scope, node, cond_block, is_inline); ir_set_cursor_at_end(irb, cond_block); - IrInstruction *index_val = ir_build_load_ptr(irb, node, index_ptr); - IrInstruction *cond = ir_build_bin_op(irb, node, IrBinOpCmpLessThan, index_val, len_val); - ir_build_cond_br(irb, node, cond, body_block, end_block, is_inline); + IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr); + IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val); + ir_build_cond_br(irb, child_scope, node, cond, body_block, end_block, is_inline); ir_set_cursor_at_end(irb, body_block); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, node, array_val, index_val, true); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val, index_val, true); IrInstruction *elem_val; if (node->data.for_expr.elem_is_ptr) { elem_val = elem_ptr; } else { - elem_val = ir_build_load_ptr(irb, node, elem_ptr); + elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr); } - ir_build_store_ptr(irb, node, elem_var_ptr, elem_val); + ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val); irb->break_block_stack.append(end_block); irb->continue_block_stack.append(continue_block); @@ -2162,61 +2169,60 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) { irb->break_block_stack.pop(); irb->continue_block_stack.pop(); - ir_build_br(irb, node, continue_block, is_inline); + ir_build_br(irb, child_scope, node, continue_block, is_inline); ir_set_cursor_at_end(irb, continue_block); - IrInstruction *new_index_val = ir_build_bin_op(irb, node, IrBinOpAdd, index_val, one); - ir_build_store_ptr(irb, node, index_ptr, new_index_val); - ir_build_br(irb, node, cond_block, is_inline); + IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one); + ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val); + ir_build_br(irb, child_scope, node, cond_block, is_inline); ir_set_cursor_at_end(irb, end_block); - return ir_build_const_void(irb, node); + return ir_build_const_void(irb, child_scope, node); } -static IrInstruction *ir_gen_this_literal(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeThisLiteral); - Scope *scope = node->scope; - if (!scope->parent) - return ir_build_const_import(irb, node, node->owner); + return ir_build_const_import(irb, scope, node, node->owner); - FnTableEntry *fn_entry = scope_fn_entry(scope); + FnTableEntry *fn_entry = exec_fn_entry(irb->exec); if (fn_entry && scope->parent && scope->parent->parent && !scope_fn_entry(scope->parent->parent)) { - return ir_build_const_fn(irb, node, fn_entry); + return ir_build_const_fn(irb, scope, node, fn_entry); } if (scope->node->type == NodeTypeContainerDecl) { - TypeTableEntry *container_type = scope->node->data.struct_decl.type_entry; + ScopeDecls *decls_scope = (ScopeDecls *)scope; + TypeTableEntry *container_type = decls_scope->container_type; assert(container_type); - return ir_build_const_type(irb, node, container_type); + return ir_build_const_type(irb, scope, node, container_type); } if (scope->node->type == NodeTypeBlock) - return ir_build_const_scope(irb, node, scope); + return ir_build_const_scope(irb, scope, node, scope); zig_unreachable(); } -static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeBoolLiteral); - return ir_build_const_bool(irb, node, node->data.bool_literal.value); + return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value); } -static IrInstruction *ir_gen_string_literal(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_string_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeStringLiteral); if (node->data.string_literal.c) { - return ir_build_const_c_str_lit(irb, node, node->data.string_literal.buf); + return ir_build_const_c_str_lit(irb, scope, node, node->data.string_literal.buf); } else { - return ir_build_const_str_lit(irb, node, node->data.string_literal.buf); + return ir_build_const_str_lit(irb, scope, node, node->data.string_literal.buf); } } -static IrInstruction *ir_gen_array_type(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeArrayType); AstNode *size_node = node->data.array_type.size; @@ -2229,35 +2235,36 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, AstNode *node) { return irb->codegen->invalid_instruction; } - IrInstruction *size_value = ir_gen_node(irb, size_node, node->scope); + IrInstruction *size_value = ir_gen_node(irb, size_node, scope); if (size_value == irb->codegen->invalid_instruction) return size_value; - IrInstruction *child_type = ir_gen_node(irb, child_type_node, node->scope); + IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope); if (child_type == irb->codegen->invalid_instruction) return child_type; - return ir_build_array_type(irb, node, size_value, child_type); + return ir_build_array_type(irb, scope, node, size_value, child_type); } else { IrInstruction *child_type = ir_gen_node_extra(irb, child_type_node, - node->scope, LValPurposeAddressOf); + scope, LValPurposeAddressOf); if (child_type == irb->codegen->invalid_instruction) return child_type; - return ir_build_slice_type(irb, node, is_const, child_type); + return ir_build_slice_type(irb, scope, node, is_const, child_type); } } -static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeUndefinedLiteral); - return ir_build_const_undefined(irb, node); + return ir_build_const_undefined(irb, scope, node); } -static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeAsmExpr); IrInstruction **input_list = allocate(node->data.asm_expr.input_list.length); IrInstruction **output_types = allocate(node->data.asm_expr.output_list.length); + VariableTableEntry **output_vars = allocate(node->data.asm_expr.output_list.length); size_t return_count = 0; bool is_volatile = node->data.asm_expr.is_volatile; if (!is_volatile && node->data.asm_expr.output_list.length == 0) { @@ -2270,7 +2277,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) { if (asm_output->return_type) { return_count += 1; - IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, node->scope); + IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, scope); if (return_type == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; if (return_count > 1) { @@ -2281,9 +2288,9 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) { output_types[i] = return_type; } else { Buf *variable_name = asm_output->variable_name; - VariableTableEntry *var = find_variable(irb->codegen, node->scope, variable_name); + VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name); if (var) { - asm_output->variable = var; + output_vars[i] = var; } else { add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); @@ -2293,17 +2300,17 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) { } for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) { AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, node->scope); + IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, scope); if (input_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; input_list[i] = input_value; } - return ir_build_asm(irb, node, input_list, output_types, return_count, is_volatile); + return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile); } -static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeIfVarExpr); AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl; @@ -2312,51 +2319,51 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) { AstNode *else_node = node->data.if_var_expr.else_node; bool var_is_ptr = node->data.if_var_expr.var_is_ptr; - IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, node->scope, LValPurposeAddressOf); + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); if (expr_value == irb->codegen->invalid_instruction) return expr_value; - IrInstruction *is_nonnull_value = ir_build_test_null(irb, node, expr_value); + IrInstruction *is_nonnull_value = ir_build_test_null(irb, scope, node, expr_value); IrBasicBlock *then_block = ir_build_basic_block(irb, "MaybeThen"); IrBasicBlock *else_block = ir_build_basic_block(irb, "MaybeElse"); IrBasicBlock *endif_block = ir_build_basic_block(irb, "MaybeEndIf"); bool is_inline = ir_should_inline(irb) || node->data.if_var_expr.is_inline; - ir_build_cond_br(irb, node, is_nonnull_value, then_block, else_block, is_inline); + ir_build_cond_br(irb, scope, node, is_nonnull_value, then_block, else_block, is_inline); ir_set_cursor_at_end(irb, then_block); IrInstruction *var_type = nullptr; if (var_decl->type) { - var_type = ir_gen_node(irb, var_decl->type, node->scope); + var_type = ir_gen_node(irb, var_decl->type, scope); if (var_type == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; } bool is_shadowable = false; bool is_const = var_decl->is_const; - VariableTableEntry *var = ir_create_var(irb, node, node->scope, + VariableTableEntry *var = ir_create_var(irb, node, scope, 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_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); + IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, expr_value, false); + IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value); + ir_build_var_decl(irb, scope, node, var, var_type, var_value); IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var->child_scope); if (then_expr_result == irb->codegen->invalid_instruction) return then_expr_result; IrBasicBlock *after_then_block = irb->current_basic_block; - ir_build_br(irb, node, endif_block, is_inline); + ir_build_br(irb, scope, node, endif_block, is_inline); ir_set_cursor_at_end(irb, else_block); IrInstruction *else_expr_result; if (else_node) { - else_expr_result = ir_gen_node(irb, else_node, node->scope); + else_expr_result = ir_gen_node(irb, else_node, scope); if (else_expr_result == irb->codegen->invalid_instruction) return else_expr_result; } else { - else_expr_result = ir_build_const_void(irb, node); + else_expr_result = ir_build_const_void(irb, scope, node); } IrBasicBlock *after_else_block = irb->current_basic_block; - ir_build_br(irb, node, endif_block, is_inline); + ir_build_br(irb, scope, node, endif_block, is_inline); ir_set_cursor_at_end(irb, endif_block); IrInstruction **incoming_values = allocate(2); @@ -2366,10 +2373,10 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) { incoming_blocks[0] = after_then_block; incoming_blocks[1] = after_else_block; - return ir_build_phi(irb, node, 2, incoming_blocks, incoming_values); + return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); } -static bool ir_gen_switch_prong_expr(IrBuilder *irb, AstNode *switch_node, AstNode *prong_node, +static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, IrBasicBlock *end_block, bool is_inline, IrInstruction *target_value_ptr, IrInstruction *prong_value, ZigList *incoming_blocks, ZigList *incoming_values) { @@ -2386,39 +2393,39 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, AstNode *switch_node, AstNo bool is_shadowable = false; bool is_const = true; - VariableTableEntry *var = ir_create_var(irb, var_symbol_node, switch_node->scope, + VariableTableEntry *var = ir_create_var(irb, var_symbol_node, scope, var_name, is_const, is_const, is_shadowable, is_inline); child_scope = var->child_scope; IrInstruction *var_value; if (prong_value) { - IrInstruction *var_ptr_value = ir_build_switch_var(irb, var_symbol_node, target_value_ptr, prong_value); - var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, var_symbol_node, var_ptr_value); + IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value); + var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); } else { - var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, var_symbol_node, target_value_ptr); + var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); } IrInstruction *var_type = nullptr; // infer the type - ir_build_var_decl(irb, var_symbol_node, var, var_type, var_value); + ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, var_value); } else { - child_scope = switch_node->scope; + child_scope = scope; } IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope); if (expr_result == irb->codegen->invalid_instruction) return false; - ir_build_br(irb, switch_node, end_block, is_inline); + ir_build_br(irb, scope, switch_node, end_block, is_inline); incoming_blocks->append(irb->current_basic_block); incoming_values->append(expr_result); return true; } -static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeSwitchExpr); AstNode *target_node = node->data.switch_expr.expr; - IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, node->scope, LValPurposeAddressOf); + IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPurposeAddressOf); if (target_value_ptr == irb->codegen->invalid_instruction) return target_value_ptr; - IrInstruction *target_value = ir_build_switch_target(irb, node, target_value_ptr); + IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr); IrBasicBlock *else_block = ir_build_basic_block(irb, "SwitchElse"); IrBasicBlock *end_block = ir_build_basic_block(irb, "SwitchEnd"); @@ -2446,7 +2453,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { IrBasicBlock *prev_block = irb->current_basic_block; ir_set_cursor_at_end(irb, else_block); - if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block, + if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block, is_inline, target_value_ptr, nullptr, &incoming_blocks, &incoming_values)) { return irb->codegen->invalid_instruction; @@ -2460,41 +2467,40 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); last_item_node = item_node; if (item_node->type == NodeTypeSwitchRange) { - item_node->scope = node->scope; AstNode *start_node = item_node->data.switch_range.start; AstNode *end_node = item_node->data.switch_range.end; - IrInstruction *start_value = ir_gen_node(irb, start_node, node->scope); + IrInstruction *start_value = ir_gen_node(irb, start_node, scope); if (start_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *end_value = ir_gen_node(irb, end_node, node->scope); + IrInstruction *end_value = ir_gen_node(irb, end_node, scope); if (end_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *start_value_const = ir_build_static_eval(irb, start_node, start_value); - IrInstruction *end_value_const = ir_build_static_eval(irb, start_node, end_value); + IrInstruction *start_value_const = ir_build_static_eval(irb, scope, start_node, start_value); + IrInstruction *end_value_const = ir_build_static_eval(irb, scope, start_node, end_value); - IrInstruction *lower_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpGreaterOrEq, + IrInstruction *lower_range_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpGreaterOrEq, target_value, start_value_const); - IrInstruction *upper_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpLessOrEq, + IrInstruction *upper_range_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpLessOrEq, target_value, end_value_const); - IrInstruction *both_ok = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd, + IrInstruction *both_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolAnd, lower_range_ok, upper_range_ok); if (ok_bit) { - ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolOr, both_ok, ok_bit); + ok_bit = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolOr, both_ok, ok_bit); } else { ok_bit = both_ok; } } else { - IrInstruction *item_value = ir_gen_node(irb, item_node, node->scope); + IrInstruction *item_value = ir_gen_node(irb, item_node, scope); if (item_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *cmp_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpEq, + IrInstruction *cmp_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpEq, item_value, target_value); if (ok_bit) { - ok_bit = ir_build_bin_op(irb, item_node, IrBinOpBoolOr, cmp_ok, ok_bit); + ok_bit = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolOr, cmp_ok, ok_bit); } else { ok_bit = cmp_ok; } @@ -2506,10 +2512,10 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { assert(ok_bit); assert(last_item_node); - ir_build_cond_br(irb, last_item_node, ok_bit, range_block_yes, range_block_no, is_inline); + ir_build_cond_br(irb, scope, last_item_node, ok_bit, range_block_yes, range_block_no, is_inline); ir_set_cursor_at_end(irb, range_block_yes); - if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block, + if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block, is_inline, target_value_ptr, nullptr, &incoming_blocks, &incoming_values)) { return irb->codegen->invalid_instruction; @@ -2524,7 +2530,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); assert(item_node->type != NodeTypeSwitchRange); - IrInstruction *item_value = ir_gen_node(irb, item_node, node->scope); + IrInstruction *item_value = ir_gen_node(irb, item_node, scope); if (item_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -2538,7 +2544,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { IrBasicBlock *prev_block = irb->current_basic_block; ir_set_cursor_at_end(irb, prong_block); - if (!ir_gen_switch_prong_expr(irb, node, prong_node, end_block, + if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block, is_inline, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values)) { return irb->codegen->invalid_instruction; @@ -2551,19 +2557,19 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { } if (cases.length == 0) { - ir_build_br(irb, node, else_block, is_inline); + ir_build_br(irb, scope, node, else_block, is_inline); } else { - ir_build_switch_br(irb, node, target_value, else_block, cases.length, cases.items, is_inline); + ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_inline); } if (!else_prong) { ir_set_cursor_at_end(irb, else_block); - ir_build_unreachable(irb, node); + ir_build_unreachable(irb, scope, node); } ir_set_cursor_at_end(irb, end_block); assert(incoming_blocks.length == incoming_values.length); - return ir_build_phi(irb, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); } static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) { @@ -2589,7 +2595,7 @@ static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) { return nullptr; } -static IrInstruction *ir_gen_label(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_label(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeLabel); Buf *label_name = node->data.label.name; @@ -2599,35 +2605,38 @@ static IrInstruction *ir_gen_label(IrBuilder *irb, AstNode *node) { label->bb = label_block; irb->exec->all_labels.append(label); - LabelTableEntry *existing_label = find_label(irb->exec, node->scope, label_name); + LabelTableEntry *existing_label = find_label(irb->exec, scope, label_name); if (existing_label) { ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("duplicate label name '%s'", buf_ptr(label_name))); add_error_note(irb->codegen, msg, existing_label->decl_node, buf_sprintf("other label here")); return irb->codegen->invalid_instruction; } else { - ScopeBlock *scope_block = find_block_scope(irb->exec, node->scope); + ScopeBlock *scope_block = find_block_scope(irb->exec, scope); scope_block->label_table.put(label_name, label); } bool is_inline = ir_should_inline(irb); - ir_build_br(irb, node, label_block, is_inline); + ir_build_br(irb, scope, node, label_block, is_inline); ir_set_cursor_at_end(irb, label_block); - return ir_build_const_void(irb, node); + return ir_build_const_void(irb, scope, node); } -static IrInstruction *ir_gen_goto(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeGoto); // make a placeholder unreachable statement and a note to come back and // replace the instruction with a branch instruction - node->data.goto_expr.bb = irb->current_basic_block; - node->data.goto_expr.instruction_index = irb->current_basic_block->instruction_list.length; - irb->exec->goto_list.append(node); - return ir_build_unreachable(irb, node); + IrGotoItem *goto_item = irb->exec->goto_list.add_one(); + goto_item->bb = irb->current_basic_block; + goto_item->instruction_index = irb->current_basic_block->instruction_list.length; + goto_item->source_node = node; + goto_item->scope = scope; + + return ir_build_unreachable(irb, scope, node); } -static IrInstruction *ir_lval_wrap(IrBuilder *irb, IrInstruction *value, LValPurpose lval) { +static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) { if (lval == LValPurposeNone) return value; if (value == irb->codegen->invalid_instruction) @@ -2635,75 +2644,73 @@ static IrInstruction *ir_lval_wrap(IrBuilder *irb, IrInstruction *value, LValPur // We needed a pointer to a value, but we got a value. So we create // an instruction which just makes a const pointer of it. - return ir_build_ref(irb, value->source_node, value); + return ir_build_ref(irb, scope, value->source_node, value); } -static IrInstruction *ir_gen_type_literal(IrBuilder *irb, AstNode *node) { +static IrInstruction *ir_gen_type_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeTypeLiteral); - return ir_build_const_type(irb, node, irb->codegen->builtin_types.entry_type); + return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_type); } static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LValPurpose lval) { assert(scope); - node->scope = scope; - switch (node->type) { case NodeTypeStructValueField: zig_unreachable(); case NodeTypeBlock: - return ir_lval_wrap(irb, ir_gen_block(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); case NodeTypeBinOpExpr: - return ir_lval_wrap(irb, ir_gen_bin_op(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval); case NodeTypeNumberLiteral: - return ir_lval_wrap(irb, ir_gen_num_lit(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_num_lit(irb, scope, node), lval); case NodeTypeSymbol: - return ir_gen_symbol(irb, node, lval); + return ir_gen_symbol(irb, scope, node, lval); case NodeTypeFnCallExpr: - return ir_lval_wrap(irb, ir_gen_fn_call(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_fn_call(irb, scope, node), lval); case NodeTypeIfBoolExpr: - return ir_lval_wrap(irb, ir_gen_if_bool_expr(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval); case NodeTypePrefixOpExpr: - return ir_gen_prefix_op_expr(irb, node, lval); + return ir_gen_prefix_op_expr(irb, scope, node, lval); case NodeTypeContainerInitExpr: - return ir_lval_wrap(irb, ir_gen_container_init_expr(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval); case NodeTypeVariableDeclaration: - return ir_lval_wrap(irb, ir_gen_var_decl(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval); case NodeTypeWhileExpr: - return ir_lval_wrap(irb, ir_gen_while_expr(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval); case NodeTypeForExpr: - return ir_lval_wrap(irb, ir_gen_for_expr(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node), lval); case NodeTypeArrayAccessExpr: - return ir_gen_array_access(irb, node, lval); + return ir_gen_array_access(irb, scope, node, lval); case NodeTypeReturnExpr: - return ir_lval_wrap(irb, ir_gen_return(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_return(irb, scope, node), lval); case NodeTypeFieldAccessExpr: - return ir_gen_field_access(irb, node, lval); + return ir_gen_field_access(irb, scope, node, lval); case NodeTypeThisLiteral: - return ir_lval_wrap(irb, ir_gen_this_literal(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval); case NodeTypeBoolLiteral: - return ir_lval_wrap(irb, ir_gen_bool_literal(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); case NodeTypeArrayType: - return ir_lval_wrap(irb, ir_gen_array_type(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval); case NodeTypeStringLiteral: - return ir_lval_wrap(irb, ir_gen_string_literal(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval); case NodeTypeUndefinedLiteral: - return ir_lval_wrap(irb, ir_gen_undefined_literal(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval); case NodeTypeAsmExpr: - return ir_lval_wrap(irb, ir_gen_asm_expr(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval); case NodeTypeNullLiteral: - return ir_lval_wrap(irb, ir_gen_null_literal(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); case NodeTypeIfVarExpr: - return ir_lval_wrap(irb, ir_gen_if_var_expr(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_if_var_expr(irb, scope, node), lval); case NodeTypeSwitchExpr: - return ir_lval_wrap(irb, ir_gen_switch_expr(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); case NodeTypeLabel: - return ir_lval_wrap(irb, ir_gen_label(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_label(irb, scope, node), lval); case NodeTypeGoto: - return ir_lval_wrap(irb, ir_gen_goto(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval); case NodeTypeTypeLiteral: - return ir_lval_wrap(irb, ir_gen_type_literal(irb, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_type_literal(irb, scope, node), lval); case NodeTypeUnwrapErrorExpr: case NodeTypeDefer: case NodeTypeSliceExpr: @@ -2744,22 +2751,23 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { static bool ir_goto_pass2(IrBuilder *irb) { for (size_t i = 0; i < irb->exec->goto_list.length; i += 1) { - AstNode *goto_node = irb->exec->goto_list.at(i); - size_t instruction_index = goto_node->data.goto_expr.instruction_index; - IrInstruction **slot = &goto_node->data.goto_expr.bb->instruction_list.at(instruction_index); + IrGotoItem *goto_item = &irb->exec->goto_list.at(i); + AstNode *source_node = goto_item->source_node; + size_t instruction_index = goto_item->instruction_index; + IrInstruction **slot = &goto_item->bb->instruction_list.at(instruction_index); IrInstruction *old_instruction = *slot; - Buf *label_name = goto_node->data.goto_expr.name; - LabelTableEntry *label = find_label(irb->exec, goto_node->scope, label_name); + Buf *label_name = source_node->data.goto_expr.name; + LabelTableEntry *label = find_label(irb->exec, goto_item->scope, label_name); if (!label) { - add_node_error(irb->codegen, goto_node, + add_node_error(irb->codegen, source_node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); return false; } label->used = true; - bool is_inline = ir_should_inline(irb) || goto_node->data.goto_expr.is_inline; - IrInstruction *new_instruction = ir_create_br(irb, goto_node, label->bb, is_inline); + bool is_inline = ir_should_inline(irb) || source_node->data.goto_expr.is_inline; + IrInstruction *new_instruction = ir_create_br(irb, goto_item->scope, source_node, label->bb, is_inline); new_instruction->ref_count = old_instruction->ref_count; *slot = new_instruction; } @@ -2795,7 +2803,7 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutabl if (irb->exec->invalid) return codegen->invalid_instruction; - IrInstruction *return_instruction = ir_build_return(irb, result->source_node, result); + IrInstruction *return_instruction = ir_build_return(irb, scope, result->source_node, result); assert(return_instruction); if (!ir_goto_pass2(irb)) { @@ -2814,21 +2822,27 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { assert(fn_def_node->type == NodeTypeFnDef); AstNode *body_node = fn_def_node->data.fn_def.body; - Scope *child_scope = fn_def_node->data.fn_def.child_scope; + + assert(fn_entry->child_scope); + Scope *child_scope = fn_entry->child_scope; return ir_gen(codegn, body_node, child_scope, ir_executable); } +static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) { + return add_node_error(ira->codegen, source_instruction->source_node, msg); +} + static IrInstruction *ir_eval_fn(IrAnalyze *ira, IrInstruction *source_instruction, size_t arg_count, IrInstruction **args) { + // TODO count this as part of the backward branch quota zig_panic("TODO ir_eval_fn"); } static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { if (ir_should_inline(&ira->new_irb)) { - add_node_error(ira->codegen, source_instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); + ir_add_error(ira, source_instruction, buf_sprintf("unable to evaluate constant expression")); return false; } return true; @@ -2863,7 +2877,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc const char *num_lit_str = (const_val->data.x_bignum.kind == BigNumKindFloat) ? "float" : "integer"; - add_node_error(ira->codegen, instruction->source_node, + ir_add_error(ira, instruction, buf_sprintf("%s value %s cannot be implicitly casted to type '%s'", num_lit_str, buf_ptr(bignum_to_buf(&const_val->data.x_bignum)), @@ -3052,15 +3066,15 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca) { if (value->static_value.special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->source_node, wanted_type, false); + IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, false); eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry, &result->static_value, wanted_type); return result; } 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->scope, source_instr->source_node, wanted_type, value, cast_op); result->type_entry = wanted_type; if (need_alloca) { - FnTableEntry *fn_entry = scope_fn_entry(source_instr->source_node->scope); + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); if (fn_entry) fn_entry->alloca_list.append(result); } @@ -3153,20 +3167,20 @@ static ConstExprValue *ir_build_const_from(IrAnalyze *ira, IrInstruction *old_in if (old_instruction->id == IrInstructionIdVarPtr) { IrInstructionVarPtr *old_var_ptr_instruction = (IrInstructionVarPtr *)old_instruction; IrInstructionVarPtr *var_ptr_instruction = ir_create_instruction(ira->new_irb.exec, - old_instruction->source_node); + old_instruction->scope, old_instruction->source_node); var_ptr_instruction->var = old_var_ptr_instruction->var; new_instruction = &var_ptr_instruction->base; } else if (old_instruction->id == IrInstructionIdFieldPtr) { IrInstructionFieldPtr *field_ptr_instruction = ir_create_instruction(ira->new_irb.exec, - old_instruction->source_node); + old_instruction->scope, old_instruction->source_node); new_instruction = &field_ptr_instruction->base; } else if (old_instruction->id == IrInstructionIdElemPtr) { IrInstructionElemPtr *elem_ptr_instruction = ir_create_instruction(ira->new_irb.exec, - old_instruction->source_node); + old_instruction->scope, old_instruction->source_node); new_instruction = &elem_ptr_instruction->base; } else { IrInstructionConst *const_instruction = ir_create_instruction(ira->new_irb.exec, - old_instruction->source_node); + old_instruction->scope, old_instruction->source_node); new_instruction = &const_instruction->base; } ir_link_new_instruction(new_instruction, old_instruction); @@ -3553,13 +3567,13 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc if (ptr->static_value.special != ConstValSpecialRuntime) { ConstExprValue *pointee = const_ptr_pointee(&ptr->static_value); if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->source_node, - child_type, pointee->depends_on_compile_var); + IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, + source_instruction->source_node, child_type, pointee->depends_on_compile_var); result->static_value = *pointee; return result; } } - IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->source_node, ptr); + IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, source_instruction->source_node, ptr); load_ptr_instruction->type_entry = child_type; return load_ptr_instruction; } else { @@ -3588,7 +3602,7 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst ir_link_new_instruction(value, source_instruction); return ptr_type; } else { - FnTableEntry *fn_entry = scope_fn_entry(source_instruction->source_node->scope); + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); assert(fn_entry); IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value); fn_entry->alloca_list.append(new_instruction); @@ -3754,7 +3768,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp case TypeTableEntryIdTypeDecl: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: if (!is_equality_cmp) { add_node_error(ira->codegen, source_node, @@ -4057,7 +4070,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc } AstNodeVariableDeclaration *variable_declaration = &var->decl_node->data.variable_declaration; - bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport); + bool is_export = (variable_declaration->visib_mod == VisibModExport); bool is_extern = variable_declaration->is_extern; var->ref_count = 0; @@ -4119,7 +4132,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: case TypeTableEntryIdFn: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: // OK break; @@ -4136,8 +4148,7 @@ 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); - Scope *scope = decl_var_instruction->base.source_node->scope; - FnTableEntry *fn_entry = scope_fn_entry(scope); + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); if (fn_entry) fn_entry->variable_list.append(var); @@ -4241,7 +4252,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal fn_entry, fn_ref, call_param_count, casted_args); if (type_has_bits(return_type) && handle_is_ptr(return_type)) { - FnTableEntry *fn_entry = scope_fn_entry(call_instruction->base.source_node->scope); + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); assert(fn_entry); fn_entry->alloca_list.append(new_call_instruction); } @@ -4288,8 +4299,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction IrInstruction *first_arg_ptr = fn_ref->static_value.data.x_bound_fn.first_arg; return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, nullptr, first_arg_ptr, is_inline); - } else if (fn_ref->type_entry->id == TypeTableEntryIdGenericFn) { - zig_panic("TODO generic fn call"); } else { add_node_error(ira->codegen, fn_ref->source_node, buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->type_entry->name))); @@ -4360,7 +4369,6 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: case TypeTableEntryIdFn: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, @@ -4409,7 +4417,6 @@ static TypeTableEntry *ir_analyze_unary_address_of(IrAnalyze *ira, IrInstruction case TypeTableEntryIdBlock: case TypeTableEntryIdUnreachable: case TypeTableEntryIdVar: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: add_node_error(ira->codegen, un_op_instruction->base.source_node, buf_sprintf("unable to get address of type '%s'", buf_ptr(&target_type->name))); @@ -4508,7 +4515,6 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, @@ -4781,9 +4787,7 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc if (var->mem_slot_index != SIZE_MAX) mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; } else if (var->src_is_const) { - AstNode *var_decl_node = var->decl_node; - assert(var_decl_node->type == NodeTypeVariableDeclaration); - mem_slot = &var_decl_node->data.variable_declaration.top_level_decl.value->static_value; + mem_slot = var->value; assert(mem_slot->special != ConstValSpecialRuntime); } @@ -4925,15 +4929,15 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, if (!is_slice(bare_struct_type)) { ScopeDecls *container_scope = get_container_scope(bare_struct_type); auto entry = container_scope->decl_table.maybe_get(field_name); - AstNode *fn_decl_node = entry ? entry->value : nullptr; - if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) { - resolve_top_level_decl(ira->codegen, fn_decl_node, false); - TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node); + Tld *tld = entry ? entry->value : nullptr; + if (tld && tld->id == TldIdFn) { + resolve_top_level_decl(ira->codegen, tld, false); if (tld->resolution == TldResolutionInvalid) return ira->codegen->builtin_types.entry_invalid; - FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry; + TldFn *tld_fn = (TldFn *)tld; + FnTableEntry *fn_entry = tld_fn->fn_entry; bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var; - IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, + IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, fn_entry, container_ptr, depends_on_compile_var); return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value); } @@ -4976,53 +4980,63 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field } } -static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, AstNode *decl_node, +static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld, bool depends_on_compile_var) { bool pointer_only = false; - resolve_top_level_decl(ira->codegen, decl_node, pointer_only); - TopLevelDecl *tld = get_as_top_level_decl(decl_node); + resolve_top_level_decl(ira->codegen, tld, pointer_only); if (tld->resolution == TldResolutionInvalid) return ira->codegen->builtin_types.entry_invalid; - if (decl_node->type == NodeTypeVariableDeclaration) { - VariableTableEntry *var = decl_node->data.variable_declaration.variable; - return ir_analyze_var_ptr(ira, source_instruction, var); - } else if (decl_node->type == NodeTypeFnProto) { - FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; - assert(fn_entry->type_entry); - - // TODO instead of allocating this every time, put it in the tld value and we can reference - // the same one every time - ConstExprValue *const_val = allocate(1); - const_val->special = ConstValSpecialStatic; - if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) { - const_val->data.x_type = fn_entry->type_entry; - } else { - const_val->data.x_fn = fn_entry; + switch (tld->id) { + case TldIdVar: + { + TldVar *tld_var = (TldVar *)tld; + VariableTableEntry *var = tld_var->var; + return ir_analyze_var_ptr(ira, source_instruction, var); } + case TldIdFn: + { + TldFn *tld_fn = (TldFn *)tld; + FnTableEntry *fn_entry = tld_fn->fn_entry; + assert(fn_entry->type_entry); - return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, depends_on_compile_var); - } else if (decl_node->type == NodeTypeContainerDecl) { - zig_panic("TODO"); - //ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); - //if (decl_node->data.struct_decl.generic_params.length > 0) { - // TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type; - // assert(type_entry); - // out_val->data.x_type = type_entry; - // return type_entry; - //} else { - // out_val->data.x_type = decl_node->data.struct_decl.type_entry; - // return ira->codegen->builtin_types.entry_type; - //} - } else if (decl_node->type == NodeTypeTypeDecl) { - zig_panic("TODO"); - //ConstExprValue *out_val = ir_build_const_from(ira, source_instruction, depends_on_compile_var); - //out_val->data.x_type = decl_node->data.type_decl.child_type_entry; - //return ira->codegen->builtin_types.entry_type; - } else { - zig_unreachable(); + // TODO instead of allocating this every time, put it in the tld value and we can reference + // the same one every time + ConstExprValue *const_val = allocate(1); + const_val->special = ConstValSpecialStatic; + const_val->data.x_fn = fn_entry; + + return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, depends_on_compile_var); + } + case TldIdContainer: + { + TldContainer *tld_container = (TldContainer *)tld; + assert(tld_container->type_entry); + + // TODO instead of allocating this every time, put it in the tld value and we can reference + // the same one every time + ConstExprValue *const_val = allocate(1); + const_val->special = ConstValSpecialStatic; + const_val->data.x_type = tld_container->type_entry; + + return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_container->type_entry, depends_on_compile_var); + } + case TldIdTypeDef: + { + TldTypeDef *tld_typedef = (TldTypeDef *)tld; + assert(tld_typedef->type_entry); + + // TODO instead of allocating this every time, put it in the tld value and we can reference + // the same one every time + ConstExprValue *const_val = allocate(1); + const_val->special = ConstValSpecialStatic; + const_val->data.x_type = tld_typedef->type_entry; + + return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_typedef->type_entry, depends_on_compile_var); + } } + zig_unreachable(); } static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { @@ -5068,10 +5082,10 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru } else if (child_type->id == TypeTableEntryIdStruct) { ScopeDecls *container_scope = get_container_scope(child_type); auto entry = container_scope->decl_table.maybe_get(field_name); - AstNode *decl_node = entry ? entry->value : nullptr; - if (decl_node) { + Tld *tld = entry ? entry->value : nullptr; + if (tld) { bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var; - return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, decl_node, depends_on_compile_var); + return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld, depends_on_compile_var); } else { add_node_error(ira->codegen, source_node, buf_sprintf("container '%s' has no member called '%s'", @@ -5098,30 +5112,29 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru ImportTableEntry *namespace_import = namespace_val->data.x_import; bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var; - AstNode *decl_node = find_decl(&namespace_import->decls_scope->base, field_name); - if (!decl_node) { + Tld *tld = find_decl(&namespace_import->decls_scope->base, field_name); + if (!tld) { // we must now resolve all the use decls + // TODO move this check to find_decl? for (size_t i = 0; i < namespace_import->use_decls.length; i += 1) { AstNode *use_decl_node = namespace_import->use_decls.at(i); - TopLevelDecl *tld = get_as_top_level_decl(use_decl_node); - if (tld->resolution == TldResolutionUnresolved) { + if (use_decl_node->data.use.resolution == TldResolutionUnresolved) { preview_use_decl(ira->codegen, use_decl_node); } resolve_use_decl(ira->codegen, use_decl_node); } - decl_node = find_decl(&namespace_import->decls_scope->base, field_name); + tld = find_decl(&namespace_import->decls_scope->base, field_name); } - if (decl_node) { - TopLevelDecl *tld = get_as_top_level_decl(decl_node); + if (tld) { if (tld->visib_mod == VisibModPrivate && - decl_node->owner != source_node->owner) + tld->import != source_node->owner) { ErrorMsg *msg = add_node_error(ira->codegen, source_node, buf_sprintf("'%s' is private", buf_ptr(field_name))); - add_error_note(ira->codegen, msg, decl_node, buf_sprintf("declared here")); + add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); return ira->codegen->builtin_types.entry_invalid; } - return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, decl_node, depends_on_compile_var); + return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld, depends_on_compile_var); } else { const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)"; add_node_error(ira->codegen, source_node, @@ -5176,7 +5189,8 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru if (ptr->id == IrInstructionIdVarPtr) { IrInstructionVarPtr *var_ptr_inst = (IrInstructionVarPtr *)ptr; VariableTableEntry *var = var_ptr_inst->var; - new_ptr_inst = ir_build_var_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, var); + new_ptr_inst = ir_build_var_ptr(&ira->new_irb, store_ptr_instruction->base.scope, + store_ptr_instruction->base.source_node, var); assert(var->mem_slot_index != SIZE_MAX); ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; mem_slot->special = ConstValSpecialRuntime; @@ -5188,7 +5202,8 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru zig_unreachable(); } new_ptr_inst->type_entry = ptr->type_entry; - ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, new_ptr_inst, casted_value); + ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.scope, + store_ptr_instruction->base.source_node, new_ptr_inst, casted_value); return ir_analyze_void(ira, &store_ptr_instruction->base); } @@ -5212,7 +5227,6 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi case TypeTableEntryIdNullLit: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdMetaType: case TypeTableEntryIdVoid: @@ -5342,14 +5356,13 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_visible(IrAnalyze *ira, fn_entry->fn_export_set_node = source_node; AstNodeFnProto *fn_proto = &fn_entry->proto_node->data.fn_proto; - if (fn_proto->top_level_decl.visib_mod != VisibModExport) { + if (fn_proto->visib_mod != VisibModExport) { ErrorMsg *msg = add_node_error(ira->codegen, source_node, buf_sprintf("function must be marked export to set function visibility")); add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("function declared here")); return ira->codegen->builtin_types.entry_invalid; } - if (!want_export) - LLVMSetLinkage(fn_entry->fn_value, LLVMInternalLinkage); + fn_entry->internal_linkage = !want_export; ir_build_const_from(ira, &set_fn_visible_instruction->base, false); return ira->codegen->builtin_types.entry_void; @@ -5366,24 +5379,33 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, if (!target_val) return ira->codegen->builtin_types.entry_invalid; - Scope *target_context; + bool *safety_off_ptr; + AstNode **safety_set_node_ptr; if (target_type->id == TypeTableEntryIdBlock) { - target_context = target_val->data.x_block; + ScopeBlock *block_scope = (ScopeBlock *)target_val->data.x_block; + safety_off_ptr = &block_scope->safety_off; + safety_set_node_ptr = &block_scope->safety_set_node; } else if (target_type->id == TypeTableEntryIdFn) { - target_context = target_val->data.x_fn->fn_def_node->data.fn_def.child_scope; + FnTableEntry *target_fn = target_val->data.x_fn; + assert(target_fn->def_scope); + safety_off_ptr = &target_fn->def_scope->safety_off; + safety_set_node_ptr = &target_fn->def_scope->safety_set_node; } else if (target_type->id == TypeTableEntryIdMetaType) { + ScopeDecls *decls_scope; TypeTableEntry *type_arg = target_val->data.x_type; if (type_arg->id == TypeTableEntryIdStruct) { - target_context = &type_arg->data.structure.decls_scope->base; + decls_scope = type_arg->data.structure.decls_scope; } else if (type_arg->id == TypeTableEntryIdEnum) { - target_context = &type_arg->data.enumeration.decls_scope->base; + decls_scope = type_arg->data.enumeration.decls_scope; } else if (type_arg->id == TypeTableEntryIdUnion) { - target_context = &type_arg->data.unionation.decls_scope->base; + decls_scope = type_arg->data.unionation.decls_scope; } else { add_node_error(ira->codegen, target_instruction->source_node, buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&type_arg->name))); return ira->codegen->builtin_types.entry_invalid; } + safety_off_ptr = &decls_scope->safety_off; + safety_set_node_ptr = &decls_scope->safety_set_node; } else { add_node_error(ira->codegen, target_instruction->source_node, buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&target_type->name))); @@ -5396,14 +5418,14 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, return ira->codegen->builtin_types.entry_invalid; AstNode *source_node = set_debug_safety_instruction->base.source_node; - if (target_context->safety_set_node) { + if (*safety_set_node_ptr) { ErrorMsg *msg = add_node_error(ira->codegen, source_node, buf_sprintf("function test attribute set twice")); - add_error_note(ira->codegen, msg, target_context->safety_set_node, buf_sprintf("first set here")); + add_error_note(ira->codegen, msg, *safety_set_node_ptr, buf_sprintf("first set here")); return ira->codegen->builtin_types.entry_invalid; } - target_context->safety_set_node = source_node; - target_context->safety_off = !want_debug_safety; + *safety_set_node_ptr = source_node; + *safety_off_ptr = !want_debug_safety; ir_build_const_from(ira, &set_debug_safety_instruction->base, false); return ira->codegen->builtin_types.entry_void; @@ -5450,7 +5472,6 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: { TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const); @@ -5494,7 +5515,7 @@ static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionA } ir_build_asm_from(&ira->new_irb, &asm_instruction->base, input_list, output_types, - asm_instruction->return_count, asm_instruction->has_side_effects); + asm_instruction->output_vars, asm_instruction->return_count, asm_instruction->has_side_effects); return return_type; } @@ -5540,7 +5561,6 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: { TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size); @@ -5611,7 +5631,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, case TypeTableEntryIdBlock: case TypeTableEntryIdNumLitFloat: case TypeTableEntryIdNumLitInt: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: case TypeTableEntryIdMetaType: case TypeTableEntryIdFn: @@ -5905,7 +5924,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, case TypeTableEntryIdMaybe: case TypeTableEntryIdUnion: case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: case TypeTableEntryIdBoundFn: add_node_error(ira->codegen, switch_target_instruction->base.source_node, buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); @@ -6009,7 +6027,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, abs_full_path, search_dir, import_target_path, import_code); - scan_decls(ira->codegen, target_import, target_import->decls_scope, target_import->root); + scan_decls(ira->codegen, target_import, target_import->decls_scope, target_import->root, nullptr); ConstExprValue *out_val = ir_build_const_from(ira, &import_instruction->base, depends_on_compile_var); out_val->data.x_import = target_import; @@ -6064,7 +6082,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru IrInstructionStructInitField *new_fields = allocate(actual_field_count); - FnTableEntry *fn_entry = scope_fn_entry(instruction->source_node->scope); + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); bool outside_fn = (fn_entry == nullptr); ConstExprValue const_val = {}; @@ -6167,7 +6185,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira const_val.data.x_array.elements = allocate(elem_count); const_val.data.x_array.size = elem_count; - FnTableEntry *fn_entry = scope_fn_entry(instruction->base.source_node->scope); + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); bool outside_fn = (fn_entry == nullptr); IrInstruction **new_items = allocate(elem_count); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 0eaf43993f..b38da16108 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -140,14 +140,6 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path)); return; } - case TypeTableEntryIdGenericFn: - { - TypeTableEntry *type_entry = const_val->data.x_type; - AstNode *decl_node = type_entry->data.generic_fn.decl_node; - assert(decl_node->type == NodeTypeFnProto); - fprintf(irp->f, "%s", buf_ptr(decl_node->data.fn_proto.name)); - return; - } case TypeTableEntryIdBoundFn: { FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn; diff --git a/src/parseh.cpp b/src/parseh.cpp index 8d7e2fbce3..4a72a0ee70 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -121,7 +121,7 @@ static AstNode *create_typed_var_decl_node(Context *c, bool is_const, const char AstNode *node = create_node(c, NodeTypeVariableDeclaration); node->data.variable_declaration.symbol = buf_create_from_str(var_name); node->data.variable_declaration.is_const = is_const; - node->data.variable_declaration.top_level_decl.visib_mod = c->visib_mod; + node->data.variable_declaration.visib_mod = c->visib_mod; node->data.variable_declaration.expr = init_node; node->data.variable_declaration.type = type_node; return node; @@ -139,16 +139,6 @@ static AstNode *create_prefix_node(Context *c, PrefixOp op, AstNode *child_node) return node; } -static AstNode *create_struct_field_node(Context *c, const char *name, AstNode *type_node) { - assert(type_node); - AstNode *node = create_node(c, NodeTypeStructField); - node->data.struct_field.name = buf_create_from_str(name); - node->data.struct_field.top_level_decl.visib_mod = VisibModPub; - node->data.struct_field.type = type_node; - - return node; -} - static AstNode *create_param_decl_node(Context *c, const char *name, AstNode *type_node, bool is_noalias) { assert(type_node); AstNode *node = create_node(c, NodeTypeParamDecl); @@ -214,15 +204,6 @@ static AstNode *create_num_lit_signed(Context *c, int64_t x) { return create_prefix_node(c, PrefixOpNegation, num_lit_node); } -static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *child_type_node) { - AstNode *node = create_node(c, NodeTypeTypeDecl); - node->data.type_decl.symbol = buf_create_from_str(name); - node->data.type_decl.top_level_decl.visib_mod = c->visib_mod; - node->data.type_decl.child_type = child_type_node; - - return node; -} - static AstNode *make_type_node(Context *c, TypeTableEntry *type_entry) { zig_panic("TODO bypass AST in parseh"); } @@ -231,7 +212,7 @@ static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_t assert(fn_type->id == TypeTableEntryIdFn); AstNode *node = create_node(c, NodeTypeFnProto); node->data.fn_proto.is_inline = true; - node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod; + node->data.fn_proto.visib_mod = c->visib_mod; node->data.fn_proto.name = name; node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type); @@ -280,25 +261,40 @@ static const char *decl_name(const Decl *decl) { return (const char *)named_decl->getName().bytes_begin(); } -static AstNode *add_typedef_node(Context *c, TypeTableEntry *type_decl) { +static void add_typedef_node(Context *c, TypeTableEntry *type_decl) { assert(type_decl); assert(type_decl->id == TypeTableEntryIdTypeDecl); - AstNode *node = create_type_decl_node(c, buf_ptr(&type_decl->name), - make_type_node(c, type_decl->data.type_decl.child_type)); - node->data.type_decl.override_type = type_decl; + ScopeDecls *decls_scope = c->import->decls_scope; + TldTypeDef *tld_typedef = allocate(1); + init_tld(&tld_typedef->base, TldIdTypeDef, &type_decl->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr); + tld_typedef->type_entry = type_decl; + decls_scope->decl_table.put(&type_decl->name, &tld_typedef->base); c->global_type_table.put(&type_decl->name, type_decl); - c->root->data.root.top_level_decls.append(node); - return node; } -static AstNode *add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_entry) { - AstNode *node = create_var_decl_node(c, buf_ptr(name), make_type_node(c, type_entry)); +static void add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_entry) { + ScopeDecls *decls_scope = c->import->decls_scope; + TldVar *tld_var = allocate(1); + init_tld(&tld_var->base, TldIdVar, name, c->visib_mod, c->source_node, &decls_scope->base, nullptr); + bool is_const = true; + ConstExprValue *init_value = allocate(1); + init_value->special = ConstValSpecialStatic; + init_value->data.x_type = type_entry; + tld_var->var = add_variable(c->codegen, c->source_node, &decls_scope->base, name, type_entry, is_const, init_value); + decls_scope->decl_table.put(name, &tld_var->base); c->global_type_table.put(name, type_entry); - c->root->data.root.top_level_decls.append(node); - return node; +} + +static void add_container_tld(Context *c, TypeTableEntry *type_entry) { + ScopeDecls *decls_scope = c->import->decls_scope; + TldContainer *tld_container = allocate(1); + init_tld(&tld_container->base, TldIdContainer, &type_entry->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr); + tld_container->type_entry = type_entry; + + decls_scope->decl_table.put(&type_entry->name, &tld_container->base); } static AstNode *create_ap_num_lit_node(Context *c, const Decl *source_decl, @@ -617,7 +613,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const param_info->is_noalias = qt.isRestrictQualified(); } - return get_fn_type(c->codegen, &fn_type_id, true); + return get_fn_type(c->codegen, &fn_type_id); } case Type::Record: { @@ -724,7 +720,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { node->data.fn_proto.name = fn_name; node->data.fn_proto.is_extern = fn_type->data.fn.fn_type_id.is_extern; - node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod; + node->data.fn_proto.visib_mod = c->visib_mod; node->data.fn_proto.is_var_args = fn_type->data.fn.fn_type_id.is_var_args; node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type); @@ -939,9 +935,8 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { TypeTableEntry *enum_type = resolve_enum_decl(c, enum_decl); - if (enum_type->id == TypeTableEntryIdInvalid) { + if (enum_type->id == TypeTableEntryIdInvalid) return; - } // make an alias without the "enum_" prefix. this will get emitted at the // end if it doesn't conflict with anything else @@ -951,21 +946,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { if (enum_type->id == TypeTableEntryIdEnum) { if (enum_type->data.enumeration.complete) { - // now create top level decl for the type - AstNode *enum_node = create_node(c, NodeTypeContainerDecl); - enum_node->data.struct_decl.name = &enum_type->name; - enum_node->data.struct_decl.kind = ContainerKindEnum; - enum_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport; - enum_node->data.struct_decl.type_entry = enum_type; - - for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { - TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; - AstNode *type_node = make_type_node(c, type_enum_field->type_entry); - AstNode *field_node = create_struct_field_node(c, buf_ptr(type_enum_field->name), type_node); - enum_node->data.struct_decl.fields.append(field_node); - } - - c->root->data.root.top_level_decls.append(enum_node); + add_container_tld(c, enum_type); } else { TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&enum_type->name), c->codegen->builtin_types.entry_u8); @@ -1127,21 +1108,7 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { } if (struct_type->data.structure.complete) { - // now create a top level decl node for the type - AstNode *struct_node = create_node(c, NodeTypeContainerDecl); - struct_node->data.struct_decl.name = &struct_type->name; - struct_node->data.struct_decl.kind = ContainerKindStruct; - struct_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport; - struct_node->data.struct_decl.type_entry = struct_type; - - for (uint32_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { - TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; - AstNode *type_node = make_type_node(c, type_struct_field->type_entry); - AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node); - struct_node->data.struct_decl.fields.append(field_node); - } - - c->root->data.root.top_level_decls.append(struct_node); + add_container_tld(c, struct_type); } else { TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&struct_type->name), c->codegen->builtin_types.entry_u8); diff --git a/src/parser.cpp b/src/parser.cpp index 00f05b25ec..403271e0ed 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1501,7 +1501,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to node->data.variable_declaration.is_inline = is_inline; node->data.variable_declaration.is_const = is_const; - node->data.variable_declaration.top_level_decl.visib_mod = visib_mod; + node->data.variable_declaration.visib_mod = visib_mod; Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); node->data.variable_declaration.symbol = token_buf(name_token); @@ -2079,7 +2079,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m } AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); - node->data.fn_proto.top_level_decl.visib_mod = visib_mod; + node->data.fn_proto.visib_mod = visib_mod; node->data.fn_proto.is_coldcc = is_coldcc; node->data.fn_proto.is_nakedcc = is_nakedcc; @@ -2144,6 +2144,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man AstNode *node = ast_create_node(pc, NodeTypeFnDef, first_token); node->data.fn_def.fn_proto = fn_proto; node->data.fn_def.body = ast_parse_block(pc, token_index, true); + fn_proto->data.fn_proto.fn_def_node = node; return node; } @@ -2193,7 +2194,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi *token_index += 1; AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw); - node->data.use.top_level_decl.visib_mod = visib_mod; + node->data.use.visib_mod = visib_mod; node->data.use.expr = ast_parse_expression(pc, token_index, true); ast_eat_token(pc, token_index, TokenIdSemicolon); @@ -2227,7 +2228,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token); node->data.struct_decl.kind = kind; node->data.struct_decl.name = token_buf(struct_name); - node->data.struct_decl.top_level_decl.visib_mod = visib_mod; + node->data.struct_decl.visib_mod = visib_mod; Token *paren_or_brace = &pc->tokens->at(*token_index); if (paren_or_brace->id == TokenIdLParen) { @@ -2281,7 +2282,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token); *token_index += 1; - field_node->data.struct_field.top_level_decl.visib_mod = visib_mod; + field_node->data.struct_field.visib_mod = visib_mod; field_node->data.struct_field.name = token_buf(token); Token *expr_or_comma = &pc->tokens->at(*token_index); @@ -2318,7 +2319,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index ast_eat_token(pc, token_index, TokenIdSemicolon); AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token); - node->data.error_value_decl.top_level_decl.visib_mod = visib_mod; + node->data.error_value_decl.visib_mod = visib_mod; node->data.error_value_decl.name = token_buf(name_tok); return node; @@ -2344,7 +2345,7 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, Visib ast_eat_token(pc, token_index, TokenIdSemicolon); - node->data.type_decl.top_level_decl.visib_mod = visib_mod; + node->data.type_decl.visib_mod = visib_mod; return node; }