| ... | ... | @@ -40,6 +40,12 @@ static size_t exec_next_debug_id(IrExecutable *exec) { |
| 40 | 40 | return result; |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | static size_t exec_next_var_slot(IrExecutable *exec) { |
| 44 | size_t result = exec->var_slot_count; |
| 45 | exec->var_slot_count += 1; |
| 46 | return result; |
| 47 | } |
| 48 | |
| 43 | 49 | static void ir_link_new_instruction(IrInstruction *new_instruction, IrInstruction *old_instruction) { |
| 44 | 50 | new_instruction->other = old_instruction; |
| 45 | 51 | old_instruction->other = new_instruction; |
| ... | ... | @@ -63,6 +69,10 @@ static void ir_ref_instruction(IrInstruction *instruction) { |
| 63 | 69 | instruction->ref_count += 1; |
| 64 | 70 | } |
| 65 | 71 | |
| 72 | static void ir_ref_var(VariableTableEntry *var) { |
| 73 | var->ref_count += 1; |
| 74 | } |
| 75 | |
| 66 | 76 | static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, const char *name_hint) { |
| 67 | 77 | IrBasicBlock *result = allocate<IrBasicBlock>(1); |
| 68 | 78 | result->name_hint = name_hint; |
| ... | ... | @@ -101,6 +111,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) { |
| 101 | 111 | return IrInstructionIdBinOp; |
| 102 | 112 | } |
| 103 | 113 | |
| 114 | static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { |
| 115 | return IrInstructionIdDeclVar; |
| 116 | } |
| 117 | |
| 104 | 118 | static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadVar *) { |
| 105 | 119 | return IrInstructionIdLoadVar; |
| 106 | 120 | } |
| ... | ... | @@ -295,6 +309,9 @@ static IrInstruction *ir_build_load_var(IrBuilder *irb, AstNode *source_node, Va |
| 295 | 309 | IrInstructionLoadVar *load_var_instruction = ir_build_instruction<IrInstructionLoadVar>(irb, source_node); |
| 296 | 310 | load_var_instruction->base.type_entry = var->type; |
| 297 | 311 | load_var_instruction->var = var; |
| 312 | |
| 313 | ir_ref_var(var); |
| 314 | |
| 298 | 315 | return &load_var_instruction->base; |
| 299 | 316 | } |
| 300 | 317 | |
| ... | ... | @@ -443,6 +460,36 @@ static IrInstruction *ir_build_unreachable_from(IrBuilder *irb, IrInstruction *o |
| 443 | 460 | return new_instruction; |
| 444 | 461 | } |
| 445 | 462 | |
| 463 | //static IrInstruction *ir_build_store(IrBuilder *irb, AstNode *source_node, |
| 464 | // VariableTableEntry *var, IrInstruction *value) |
| 465 | //{ |
| 466 | // IrInstructionStoreVar *store_instruction = ir_build_instruction<IrInstructionStoreVar>(irb, source_node); |
| 467 | // store_instruction->base.static_value.ok = true; |
| 468 | // store_instruction->base.type_entry = irb->codegen->builtin_types.entry_void; |
| 469 | // store_instruction->var = var; |
| 470 | // store_instruction->value = value; |
| 471 | // return &store_instruction->base; |
| 472 | //} |
| 473 | |
| 474 | static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node, |
| 475 | VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value) |
| 476 | { |
| 477 | IrInstructionDeclVar *decl_var_instruction = ir_build_instruction<IrInstructionDeclVar>(irb, source_node); |
| 478 | decl_var_instruction->base.static_value.ok = true; |
| 479 | decl_var_instruction->base.type_entry = irb->codegen->builtin_types.entry_void; |
| 480 | decl_var_instruction->var = var; |
| 481 | decl_var_instruction->var_type = var_type; |
| 482 | decl_var_instruction->init_value = init_value; |
| 483 | return &decl_var_instruction->base; |
| 484 | } |
| 485 | |
| 486 | static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 487 | VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value) |
| 488 | { |
| 489 | IrInstruction *new_instruction = ir_build_var_decl(irb, old_instruction->source_node, var, var_type, init_value); |
| 490 | ir_link_new_instruction(new_instruction, old_instruction); |
| 491 | return new_instruction; |
| 492 | } |
| 446 | 493 | |
| 447 | 494 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { |
| 448 | 495 | // size_t result = 0; |
| ... | ... | @@ -497,6 +544,58 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { |
| 497 | 544 | irb->current_basic_block = basic_block; |
| 498 | 545 | } |
| 499 | 546 | |
| 547 | // Set name to nullptr to make the variable anonymous (not visible to programmer). |
| 548 | static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *name, |
| 549 | bool is_const, bool is_shadowable) |
| 550 | { |
| 551 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 552 | variable_entry->block_context = node->block_context; |
| 553 | variable_entry->import = node->owner; |
| 554 | variable_entry->shadowable = is_shadowable; |
| 555 | variable_entry->slot_index = exec_next_var_slot(irb->exec); |
| 556 | |
| 557 | if (name) { |
| 558 | buf_init_from_buf(&variable_entry->name, name); |
| 559 | |
| 560 | VariableTableEntry *existing_var = find_variable(irb->codegen, node->block_context, name); |
| 561 | if (existing_var && !existing_var->shadowable) { |
| 562 | ErrorMsg *msg = add_node_error(irb->codegen, node, |
| 563 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| 564 | add_error_note(irb->codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); |
| 565 | variable_entry->type = irb->codegen->builtin_types.entry_invalid; |
| 566 | } else { |
| 567 | auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(name); |
| 568 | if (primitive_table_entry) { |
| 569 | TypeTableEntry *type = primitive_table_entry->value; |
| 570 | add_node_error(irb->codegen, node, |
| 571 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); |
| 572 | variable_entry->type = irb->codegen->builtin_types.entry_invalid; |
| 573 | } else { |
| 574 | AstNode *decl_node = find_decl(node->block_context, name); |
| 575 | if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { |
| 576 | ErrorMsg *msg = add_node_error(irb->codegen, node, |
| 577 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| 578 | add_error_note(irb->codegen, msg, decl_node, buf_sprintf("previous definition is here")); |
| 579 | variable_entry->type = irb->codegen->builtin_types.entry_invalid; |
| 580 | } |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | node->block_context->var_table.put(&variable_entry->name, variable_entry); |
| 585 | } else { |
| 586 | // TODO replace _anon with @anon and make sure all tests still pass |
| 587 | buf_init_from_str(&variable_entry->name, "_anon"); |
| 588 | } |
| 589 | if (node->block_context->fn_entry) { |
| 590 | node->block_context->fn_entry->variable_list.append(variable_entry); |
| 591 | } |
| 592 | |
| 593 | variable_entry->is_const = is_const; |
| 594 | variable_entry->decl_node = node; |
| 595 | |
| 596 | return variable_entry; |
| 597 | } |
| 598 | |
| 500 | 599 | static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) { |
| 501 | 600 | assert(block_node->type == NodeTypeBlock); |
| 502 | 601 | |
| ... | ... | @@ -883,6 +982,38 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node) |
| 883 | 982 | } |
| 884 | 983 | } |
| 885 | 984 | |
| 985 | static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) { |
| 986 | assert(node->type == NodeTypeVariableDeclaration); |
| 987 | |
| 988 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; |
| 989 | |
| 990 | IrInstruction *type_instruction; |
| 991 | if (variable_declaration->type != nullptr) { |
| 992 | type_instruction = ir_gen_node(irb, variable_declaration->type, node->block_context); |
| 993 | if (type_instruction == irb->codegen->invalid_instruction) |
| 994 | return type_instruction; |
| 995 | } else { |
| 996 | type_instruction = nullptr; |
| 997 | } |
| 998 | |
| 999 | IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, node->block_context); |
| 1000 | if (init_value == irb->codegen->invalid_instruction) |
| 1001 | return init_value; |
| 1002 | |
| 1003 | bool is_shadowable = false; |
| 1004 | bool is_const = variable_declaration->is_const; |
| 1005 | bool is_extern = variable_declaration->is_extern; |
| 1006 | VariableTableEntry *var = ir_add_local_var(irb, node, variable_declaration->symbol, is_const, is_shadowable); |
| 1007 | |
| 1008 | if (!is_extern && !variable_declaration->expr) { |
| 1009 | var->type = irb->codegen->builtin_types.entry_invalid; |
| 1010 | add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); |
| 1011 | return irb->codegen->invalid_instruction; |
| 1012 | } |
| 1013 | |
| 1014 | return ir_build_var_decl(irb, node, var, type_instruction, init_value); |
| 1015 | } |
| 1016 | |
| 886 | 1017 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, |
| 887 | 1018 | bool pointer_only) |
| 888 | 1019 | { |
| ... | ... | @@ -906,10 +1037,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont |
| 906 | 1037 | return ir_gen_prefix_op_expr(irb, node); |
| 907 | 1038 | case NodeTypeContainerInitExpr: |
| 908 | 1039 | return ir_gen_container_init_expr(irb, node); |
| 1040 | case NodeTypeVariableDeclaration: |
| 1041 | return ir_gen_var_decl(irb, node); |
| 909 | 1042 | case NodeTypeUnwrapErrorExpr: |
| 910 | 1043 | case NodeTypeReturnExpr: |
| 911 | 1044 | case NodeTypeDefer: |
| 912 | | case NodeTypeVariableDeclaration: |
| 913 | 1045 | case NodeTypeArrayAccessExpr: |
| 914 | 1046 | case NodeTypeSliceExpr: |
| 915 | 1047 | case NodeTypeFieldAccessExpr: |
| ... | ... | @@ -1553,6 +1685,26 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 1553 | 1685 | return ira->codegen->invalid_instruction; |
| 1554 | 1686 | } |
| 1555 | 1687 | |
| 1688 | static TypeTableEntry *ir_get_canonical_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 1689 | if (type_value == ira->codegen->invalid_instruction) |
| 1690 | return ira->codegen->builtin_types.entry_invalid; |
| 1691 | |
| 1692 | if (type_value->type_entry->id == TypeTableEntryIdInvalid) |
| 1693 | return ira->codegen->builtin_types.entry_invalid; |
| 1694 | |
| 1695 | if (type_value->type_entry->id != TypeTableEntryIdMetaType) { |
| 1696 | add_node_error(ira->codegen, type_value->source_node, buf_sprintf("expected type, found expression")); |
| 1697 | return ira->codegen->builtin_types.entry_invalid; |
| 1698 | } |
| 1699 | |
| 1700 | if (!type_value->static_value.ok) { |
| 1701 | add_node_error(ira->codegen, type_value->source_node, buf_sprintf("unable to evaluate constant expression")); |
| 1702 | return ira->codegen->builtin_types.entry_invalid; |
| 1703 | } |
| 1704 | |
| 1705 | return get_underlying_type(type_value->static_value.data.x_type); |
| 1706 | } |
| 1707 | |
| 1556 | 1708 | static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type) { |
| 1557 | 1709 | assert(value); |
| 1558 | 1710 | assert(value != ira->codegen->invalid_instruction); |
| ... | ... | @@ -1915,6 +2067,119 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi |
| 1915 | 2067 | zig_unreachable(); |
| 1916 | 2068 | } |
| 1917 | 2069 | |
| 2070 | static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) { |
| 2071 | VariableTableEntry *var = decl_var_instruction->var; |
| 2072 | AstNodeVariableDeclaration *variable_declaration = &var->decl_node->data.variable_declaration; |
| 2073 | bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport); |
| 2074 | bool is_extern = variable_declaration->is_extern; |
| 2075 | |
| 2076 | var->ref_count = 0; |
| 2077 | |
| 2078 | TypeTableEntry *explicit_type = nullptr; |
| 2079 | IrInstruction *var_type = nullptr; |
| 2080 | if (decl_var_instruction->var_type != nullptr) { |
| 2081 | var_type = decl_var_instruction->var_type->other; |
| 2082 | explicit_type = ir_get_canonical_type(ira, var_type); |
| 2083 | switch (explicit_type->id) { |
| 2084 | case TypeTableEntryIdTypeDecl: |
| 2085 | zig_unreachable(); |
| 2086 | case TypeTableEntryIdInvalid: |
| 2087 | explicit_type = ira->codegen->builtin_types.entry_invalid; |
| 2088 | break; |
| 2089 | case TypeTableEntryIdUnreachable: |
| 2090 | case TypeTableEntryIdVar: |
| 2091 | case TypeTableEntryIdNumLitFloat: |
| 2092 | case TypeTableEntryIdNumLitInt: |
| 2093 | case TypeTableEntryIdUndefLit: |
| 2094 | case TypeTableEntryIdNullLit: |
| 2095 | case TypeTableEntryIdBlock: |
| 2096 | add_node_error(ira->codegen, var_type->source_node, |
| 2097 | buf_sprintf("variable of type '%s' not allowed", buf_ptr(&explicit_type->name))); |
| 2098 | explicit_type = ira->codegen->builtin_types.entry_invalid; |
| 2099 | break; |
| 2100 | case TypeTableEntryIdNamespace: |
| 2101 | case TypeTableEntryIdMetaType: |
| 2102 | case TypeTableEntryIdVoid: |
| 2103 | case TypeTableEntryIdBool: |
| 2104 | case TypeTableEntryIdInt: |
| 2105 | case TypeTableEntryIdFloat: |
| 2106 | case TypeTableEntryIdPointer: |
| 2107 | case TypeTableEntryIdArray: |
| 2108 | case TypeTableEntryIdStruct: |
| 2109 | case TypeTableEntryIdMaybe: |
| 2110 | case TypeTableEntryIdErrorUnion: |
| 2111 | case TypeTableEntryIdPureError: |
| 2112 | case TypeTableEntryIdEnum: |
| 2113 | case TypeTableEntryIdUnion: |
| 2114 | case TypeTableEntryIdFn: |
| 2115 | case TypeTableEntryIdGenericFn: |
| 2116 | // OK |
| 2117 | break; |
| 2118 | } |
| 2119 | } |
| 2120 | |
| 2121 | IrInstruction *init_value = decl_var_instruction->init_value->other; |
| 2122 | IrInstruction *casted_init_value = ir_get_casted_value(ira, init_value, explicit_type); |
| 2123 | TypeTableEntry *result_type = get_underlying_type(casted_init_value->type_entry); |
| 2124 | switch (result_type->id) { |
| 2125 | case TypeTableEntryIdTypeDecl: |
| 2126 | zig_unreachable(); |
| 2127 | case TypeTableEntryIdInvalid: |
| 2128 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 2129 | break; |
| 2130 | case TypeTableEntryIdNumLitFloat: |
| 2131 | case TypeTableEntryIdNumLitInt: |
| 2132 | if (is_export || is_extern || !casted_init_value->static_value.ok) { |
| 2133 | add_node_error(ira->codegen, var_type->source_node, buf_sprintf("unable to infer variable type")); |
| 2134 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 2135 | } |
| 2136 | break; |
| 2137 | case TypeTableEntryIdUnreachable: |
| 2138 | case TypeTableEntryIdVar: |
| 2139 | case TypeTableEntryIdBlock: |
| 2140 | add_node_error(ira->codegen, var_type->source_node, |
| 2141 | buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name))); |
| 2142 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 2143 | break; |
| 2144 | case TypeTableEntryIdMetaType: |
| 2145 | case TypeTableEntryIdNamespace: |
| 2146 | if (!casted_init_value->static_value.ok) { |
| 2147 | add_node_error(ira->codegen, var_type->source_node, |
| 2148 | buf_sprintf("variable of type '%s' must be constant", buf_ptr(&result_type->name))); |
| 2149 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 2150 | } |
| 2151 | break; |
| 2152 | case TypeTableEntryIdUndefLit: |
| 2153 | case TypeTableEntryIdNullLit: |
| 2154 | case TypeTableEntryIdVoid: |
| 2155 | case TypeTableEntryIdBool: |
| 2156 | case TypeTableEntryIdInt: |
| 2157 | case TypeTableEntryIdFloat: |
| 2158 | case TypeTableEntryIdPointer: |
| 2159 | case TypeTableEntryIdArray: |
| 2160 | case TypeTableEntryIdStruct: |
| 2161 | case TypeTableEntryIdMaybe: |
| 2162 | case TypeTableEntryIdErrorUnion: |
| 2163 | case TypeTableEntryIdPureError: |
| 2164 | case TypeTableEntryIdEnum: |
| 2165 | case TypeTableEntryIdUnion: |
| 2166 | case TypeTableEntryIdFn: |
| 2167 | case TypeTableEntryIdGenericFn: |
| 2168 | // OK |
| 2169 | break; |
| 2170 | } |
| 2171 | |
| 2172 | var->type = result_type; |
| 2173 | assert(var->type != nullptr); // should have been caught by the parser |
| 2174 | |
| 2175 | if (casted_init_value->static_value.ok) { |
| 2176 | // TODO set the variable in the IrVarSlot |
| 2177 | } |
| 2178 | ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, casted_init_value); |
| 2179 | |
| 2180 | return ira->codegen->builtin_types.entry_void; |
| 2181 | } |
| 2182 | |
| 1918 | 2183 | static TypeTableEntry *ir_analyze_instruction_load_var(IrAnalyze *ira, IrInstructionLoadVar *load_var_instruction) { |
| 1919 | 2184 | ir_build_load_var_from(&ira->new_irb, &load_var_instruction->base, load_var_instruction->var); |
| 1920 | 2185 | return load_var_instruction->var->type; |
| ... | ... | @@ -3473,6 +3738,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 3473 | 3738 | return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction); |
| 3474 | 3739 | case IrInstructionIdBinOp: |
| 3475 | 3740 | return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); |
| 3741 | case IrInstructionIdDeclVar: |
| 3742 | return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction); |
| 3476 | 3743 | case IrInstructionIdLoadVar: |
| 3477 | 3744 | return ir_analyze_instruction_load_var(ira, (IrInstructionLoadVar *)instruction); |
| 3478 | 3745 | case IrInstructionIdCall: |
| ... | ... | @@ -3612,6 +3879,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 3612 | 3879 | case IrInstructionIdBr: |
| 3613 | 3880 | case IrInstructionIdCondBr: |
| 3614 | 3881 | case IrInstructionIdSwitchBr: |
| 3882 | case IrInstructionIdDeclVar: |
| 3615 | 3883 | case IrInstructionIdStoreVar: |
| 3616 | 3884 | case IrInstructionIdCall: |
| 3617 | 3885 | case IrInstructionIdReturn: |