| author | |
| committer | |
| log | afc5507b6469c9963db8e00efc5648f8e682cf02 |
| tree | 4474b3bc4f036dfbfa29ecceb338b54b7de06926 |
| parent | 8e2804efa1d23696a476ab3f88c6b9852370cf8b |
5 files changed, 188 insertions(+), 72 deletions(-)
src/analyze.cpp+129-8| ... | @@ -49,6 +49,9 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte | ... | @@ -49,6 +49,9 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte |
| 49 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); | 49 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); |
| 50 | static void resolve_use_decl(CodeGen *g, AstNode *node); | 50 | static void resolve_use_decl(CodeGen *g, AstNode *node); |
| 51 | static void preview_use_decl(CodeGen *g, AstNode *node); | 51 | static void preview_use_decl(CodeGen *g, AstNode *node); |
| 52 | static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import, | ||
| 53 | BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, | ||
| 54 | AstNode *val_node); | ||
| 52 | 55 | ||
| 53 | AstNode *first_executing_node(AstNode *node) { | 56 | AstNode *first_executing_node(AstNode *node) { |
| 54 | switch (node->type) { | 57 | switch (node->type) { |
| ... | @@ -1677,6 +1680,129 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) { | ... | @@ -1677,6 +1680,129 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) { |
| 1677 | node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk; | 1680 | node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk; |
| 1678 | } | 1681 | } |
| 1679 | 1682 | ||
| 1683 | TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) { | ||
| 1684 | TypeTableEntry *underlying_type = get_underlying_type(type_entry); | ||
| 1685 | switch (underlying_type->id) { | ||
| 1686 | case TypeTableEntryIdTypeDecl: | ||
| 1687 | zig_unreachable(); | ||
| 1688 | case TypeTableEntryIdInvalid: | ||
| 1689 | return g->builtin_types.entry_invalid; | ||
| 1690 | case TypeTableEntryIdUnreachable: | ||
| 1691 | case TypeTableEntryIdVar: | ||
| 1692 | case TypeTableEntryIdNumLitFloat: | ||
| 1693 | case TypeTableEntryIdNumLitInt: | ||
| 1694 | case TypeTableEntryIdUndefLit: | ||
| 1695 | case TypeTableEntryIdNullLit: | ||
| 1696 | case TypeTableEntryIdBlock: | ||
| 1697 | add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed", | ||
| 1698 | buf_ptr(&underlying_type->name))); | ||
| 1699 | return g->builtin_types.entry_invalid; | ||
| 1700 | case TypeTableEntryIdNamespace: | ||
| 1701 | case TypeTableEntryIdMetaType: | ||
| 1702 | case TypeTableEntryIdVoid: | ||
| 1703 | case TypeTableEntryIdBool: | ||
| 1704 | case TypeTableEntryIdInt: | ||
| 1705 | case TypeTableEntryIdFloat: | ||
| 1706 | case TypeTableEntryIdPointer: | ||
| 1707 | case TypeTableEntryIdArray: | ||
| 1708 | case TypeTableEntryIdStruct: | ||
| 1709 | case TypeTableEntryIdMaybe: | ||
| 1710 | case TypeTableEntryIdErrorUnion: | ||
| 1711 | case TypeTableEntryIdPureError: | ||
| 1712 | case TypeTableEntryIdEnum: | ||
| 1713 | case TypeTableEntryIdUnion: | ||
| 1714 | case TypeTableEntryIdFn: | ||
| 1715 | case TypeTableEntryIdGenericFn: | ||
| 1716 | return type_entry; | ||
| 1717 | } | ||
| 1718 | zig_unreachable(); | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { | ||
| 1722 | assert(node->type == NodeTypeVariableDeclaration); | ||
| 1723 | |||
| 1724 | AstNodeVariableDeclaration *var_decl = &node->data.variable_declaration; | ||
| 1725 | BlockContext *scope = node->block_context; | ||
| 1726 | bool is_const = var_decl->is_const; | ||
| 1727 | bool is_export = (var_decl->top_level_decl.visib_mod == VisibModExport); | ||
| 1728 | bool is_extern = var_decl->is_extern; | ||
| 1729 | |||
| 1730 | assert(!scope->fn_entry); | ||
| 1731 | |||
| 1732 | TypeTableEntry *explicit_type = nullptr; | ||
| 1733 | if (var_decl->type) { | ||
| 1734 | TypeTableEntry *proposed_type = analyze_type_expr(g, import, scope, var_decl->type); | ||
| 1735 | explicit_type = validate_var_type(g, var_decl->type, proposed_type); | ||
| 1736 | } | ||
| 1737 | |||
| 1738 | TypeTableEntry *implicit_type = nullptr; | ||
| 1739 | if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) { | ||
| 1740 | implicit_type = explicit_type; | ||
| 1741 | } else if (var_decl->expr) { | ||
| 1742 | IrExecutable ir_executable = {0}; | ||
| 1743 | IrExecutable analyzed_executable = {0}; | ||
| 1744 | IrInstruction *result = ir_gen(g, var_decl->expr, scope, &ir_executable); | ||
| 1745 | if (result == g->invalid_instruction) { | ||
| 1746 | // ignore the poison value | ||
| 1747 | implicit_type = g->builtin_types.entry_invalid; | ||
| 1748 | } else { | ||
| 1749 | if (g->verbose) { | ||
| 1750 | fprintf(stderr, "var %s = {\n", buf_ptr(var_decl->symbol)); | ||
| 1751 | ir_print(stderr, &ir_executable, 4); | ||
| 1752 | fprintf(stderr, "}\n"); | ||
| 1753 | } | ||
| 1754 | implicit_type = ir_analyze(g, &ir_executable, &analyzed_executable, | ||
| 1755 | explicit_type, var_decl->type); | ||
| 1756 | if (g->verbose) { | ||
| 1757 | fprintf(stderr, "var %s = { // (analyzed)\n", buf_ptr(var_decl->symbol)); | ||
| 1758 | ir_print(stderr, &analyzed_executable, 4); | ||
| 1759 | fprintf(stderr, "}\n"); | ||
| 1760 | } | ||
| 1761 | |||
| 1762 | if (implicit_type->id == TypeTableEntryIdUnreachable) { | ||
| 1763 | add_node_error(g, node, | ||
| 1764 | buf_sprintf("variable initialization is unreachable")); | ||
| 1765 | implicit_type = g->builtin_types.entry_invalid; | ||
| 1766 | } else if ((!is_const || is_export) && | ||
| 1767 | (implicit_type->id == TypeTableEntryIdNumLitFloat || | ||
| 1768 | implicit_type->id == TypeTableEntryIdNumLitInt)) | ||
| 1769 | { | ||
| 1770 | add_node_error(g, node, buf_sprintf("unable to infer variable type")); | ||
| 1771 | implicit_type = g->builtin_types.entry_invalid; | ||
| 1772 | } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) { | ||
| 1773 | add_node_error(g, node, buf_sprintf("variable of type 'type' must be constant")); | ||
| 1774 | implicit_type = g->builtin_types.entry_invalid; | ||
| 1775 | } | ||
| 1776 | if (implicit_type->id != TypeTableEntryIdInvalid) { | ||
| 1777 | Expr *expr = get_resolved_expr(var_decl->expr); | ||
| 1778 | IrInstruction *result = ir_exec_const_result(&analyzed_executable); | ||
| 1779 | if (result) { | ||
| 1780 | assert(result->static_value.ok); | ||
| 1781 | expr->const_val = result->static_value; | ||
| 1782 | expr->type_entry = result->type_entry; | ||
| 1783 | } else { | ||
| 1784 | add_node_error(g, first_executing_node(var_decl->expr), | ||
| 1785 | buf_sprintf("global variable initializer requires constant expression")); | ||
| 1786 | implicit_type = g->builtin_types.entry_invalid; | ||
| 1787 | } | ||
| 1788 | } | ||
| 1789 | } | ||
| 1790 | } else if (!is_extern) { | ||
| 1791 | add_node_error(g, node, buf_sprintf("variables must be initialized")); | ||
| 1792 | implicit_type = g->builtin_types.entry_invalid; | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | TypeTableEntry *type = explicit_type ? explicit_type : implicit_type; | ||
| 1796 | assert(type != nullptr); // should have been caught by the parser | ||
| 1797 | |||
| 1798 | VariableTableEntry *var = add_local_var(g, node, import, scope, | ||
| 1799 | var_decl->symbol, type, is_const, var_decl->expr); | ||
| 1800 | |||
| 1801 | var_decl->variable = var; | ||
| 1802 | |||
| 1803 | g->global_vars.append(var); | ||
| 1804 | } | ||
| 1805 | |||
| 1680 | void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) { | 1806 | void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) { |
| 1681 | TopLevelDecl *tld = get_as_top_level_decl(node); | 1807 | TopLevelDecl *tld = get_as_top_level_decl(node); |
| 1682 | if (tld->resolution != TldResolutionUnresolved) { | 1808 | if (tld->resolution != TldResolutionUnresolved) { |
| ... | @@ -1705,14 +1831,8 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) { | ... | @@ -1705,14 +1831,8 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) { |
| 1705 | resolve_struct_decl(g, import, node); | 1831 | resolve_struct_decl(g, import, node); |
| 1706 | break; | 1832 | break; |
| 1707 | case NodeTypeVariableDeclaration: | 1833 | case NodeTypeVariableDeclaration: |
| 1708 | { | 1834 | resolve_var_decl(g, import, node); |
| 1709 | AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; | 1835 | break; |
| 1710 | VariableTableEntry *var = analyze_variable_declaration_raw(g, import, node->block_context, | ||
| 1711 | node, variable_declaration, false, node, false); | ||
| 1712 | |||
| 1713 | g->global_vars.append(var); | ||
| 1714 | break; | ||
| 1715 | } | ||
| 1716 | case NodeTypeTypeDecl: | 1836 | case NodeTypeTypeDecl: |
| 1717 | { | 1837 | { |
| 1718 | AstNode *type_node = node->data.type_decl.child_type; | 1838 | AstNode *type_node = node->data.type_decl.child_type; |
| ... | @@ -3566,6 +3686,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3566,6 +3686,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3566 | } | 3686 | } |
| 3567 | 3687 | ||
| 3568 | // Set name to nullptr to make the variable anonymous (not visible to programmer). | 3688 | // Set name to nullptr to make the variable anonymous (not visible to programmer). |
| 3689 | // TODO merge with definition of add_local_var in ir.cpp | ||
| 3569 | static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import, | 3690 | static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import, |
| 3570 | BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node, | 3691 | BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node, |
| 3571 | bool shadowable) | 3692 | bool shadowable) |
src/analyze.hpp+1| ... | @@ -58,5 +58,6 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only); | ... | @@ -58,5 +58,6 @@ void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only); |
| 58 | TopLevelDecl *get_as_top_level_decl(AstNode *node); | 58 | TopLevelDecl *get_as_top_level_decl(AstNode *node); |
| 59 | void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node); | 59 | void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node); |
| 60 | bool type_is_codegen_pointer(TypeTableEntry *type); | 60 | bool type_is_codegen_pointer(TypeTableEntry *type); |
| 61 | TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry); | ||
| 61 | 62 | ||
| 62 | #endif | 63 | #endif |
src/codegen.cpp+1-1| ... | @@ -2885,7 +2885,7 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn | ... | @@ -2885,7 +2885,7 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn |
| 2885 | VariableTableEntry *var = instruction->var; | 2885 | VariableTableEntry *var = instruction->var; |
| 2886 | if (type_has_bits(var->type)) { | 2886 | if (type_has_bits(var->type)) { |
| 2887 | assert(var->value_ref); | 2887 | assert(var->value_ref); |
| 2888 | return get_handle_value(g, var->value_ref, var->type); | 2888 | return var->value_ref; |
| 2889 | } else { | 2889 | } else { |
| 2890 | return nullptr; | 2890 | return nullptr; |
| 2891 | } | 2891 | } |
src/ir.cpp+55-63| ... | @@ -617,39 +617,38 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { | ... | @@ -617,39 +617,38 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { |
| 617 | irb->current_basic_block = basic_block; | 617 | irb->current_basic_block = basic_block; |
| 618 | } | 618 | } |
| 619 | 619 | ||
| 620 | // Set name to nullptr to make the variable anonymous (not visible to programmer). | 620 | static VariableTableEntry *add_local_var(CodeGen *codegen, AstNode *node, Buf *name, |
| 621 | static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *name, | ||
| 622 | bool is_const, bool is_shadowable) | 621 | bool is_const, bool is_shadowable) |
| 623 | { | 622 | { |
| 624 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); | 623 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 625 | variable_entry->block_context = node->block_context; | 624 | variable_entry->block_context = node->block_context; |
| 626 | variable_entry->import = node->owner; | 625 | variable_entry->import = node->owner; |
| 627 | variable_entry->shadowable = is_shadowable; | 626 | variable_entry->shadowable = is_shadowable; |
| 628 | variable_entry->mem_slot_index = exec_next_mem_slot(irb->exec); | 627 | variable_entry->mem_slot_index = SIZE_MAX; |
| 629 | 628 | ||
| 630 | if (name) { | 629 | if (name) { |
| 631 | buf_init_from_buf(&variable_entry->name, name); | 630 | buf_init_from_buf(&variable_entry->name, name); |
| 632 | 631 | ||
| 633 | VariableTableEntry *existing_var = find_variable(irb->codegen, node->block_context, name); | 632 | VariableTableEntry *existing_var = find_variable(codegen, node->block_context, name); |
| 634 | if (existing_var && !existing_var->shadowable) { | 633 | if (existing_var && !existing_var->shadowable) { |
| 635 | ErrorMsg *msg = add_node_error(irb->codegen, node, | 634 | ErrorMsg *msg = add_node_error(codegen, node, |
| 636 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); | 635 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| 637 | add_error_note(irb->codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); | 636 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); |
| 638 | variable_entry->type = irb->codegen->builtin_types.entry_invalid; | 637 | variable_entry->type = codegen->builtin_types.entry_invalid; |
| 639 | } else { | 638 | } else { |
| 640 | auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(name); | 639 | auto primitive_table_entry = codegen->primitive_type_table.maybe_get(name); |
| 641 | if (primitive_table_entry) { | 640 | if (primitive_table_entry) { |
| 642 | TypeTableEntry *type = primitive_table_entry->value; | 641 | TypeTableEntry *type = primitive_table_entry->value; |
| 643 | add_node_error(irb->codegen, node, | 642 | add_node_error(codegen, node, |
| 644 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); | 643 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); |
| 645 | variable_entry->type = irb->codegen->builtin_types.entry_invalid; | 644 | variable_entry->type = codegen->builtin_types.entry_invalid; |
| 646 | } else { | 645 | } else { |
| 647 | AstNode *decl_node = find_decl(node->block_context, name); | 646 | AstNode *decl_node = find_decl(node->block_context, name); |
| 648 | if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { | 647 | if (decl_node && decl_node->type != NodeTypeVariableDeclaration) { |
| 649 | ErrorMsg *msg = add_node_error(irb->codegen, node, | 648 | ErrorMsg *msg = add_node_error(codegen, node, |
| 650 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | 649 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| 651 | add_error_note(irb->codegen, msg, decl_node, buf_sprintf("previous definition is here")); | 650 | add_error_note(codegen, msg, decl_node, buf_sprintf("previous definition is here")); |
| 652 | variable_entry->type = irb->codegen->builtin_types.entry_invalid; | 651 | variable_entry->type = codegen->builtin_types.entry_invalid; |
| 653 | } | 652 | } |
| 654 | } | 653 | } |
| 655 | } | 654 | } |
| ... | @@ -666,6 +665,15 @@ static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf * | ... | @@ -666,6 +665,15 @@ static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf * |
| 666 | return variable_entry; | 665 | return variable_entry; |
| 667 | } | 666 | } |
| 668 | 667 | ||
| 668 | // Set name to nullptr to make the variable anonymous (not visible to programmer). | ||
| 669 | static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf *name, | ||
| 670 | bool is_const, bool is_shadowable) | ||
| 671 | { | ||
| 672 | VariableTableEntry *var = add_local_var(irb->codegen, node, name, is_const, is_shadowable); | ||
| 673 | var->mem_slot_index = exec_next_mem_slot(irb->exec); | ||
| 674 | return var; | ||
| 675 | } | ||
| 676 | |||
| 669 | static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) { | 677 | static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) { |
| 670 | assert(block_node->type == NodeTypeBlock); | 678 | assert(block_node->type == NodeTypeBlock); |
| 671 | 679 | ||
| ... | @@ -1224,6 +1232,13 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont | ... | @@ -1224,6 +1232,13 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont |
| 1224 | return ir_gen_array_access(irb, node, lval); | 1232 | return ir_gen_array_access(irb, node, lval); |
| 1225 | case NodeTypeUnwrapErrorExpr: | 1233 | case NodeTypeUnwrapErrorExpr: |
| 1226 | case NodeTypeReturnExpr: | 1234 | case NodeTypeReturnExpr: |
| 1235 | // TODO | ||
| 1236 | //if (!scope->fn_entry) { | ||
| 1237 | // add_node_error(ira->codegen, source_node, | ||
| 1238 | // buf_sprintf("return expression outside function definition")); | ||
| 1239 | // return ira->codegen->builtin_types.entry_invalid; | ||
| 1240 | //} | ||
| 1241 | |||
| 1227 | case NodeTypeDefer: | 1242 | case NodeTypeDefer: |
| 1228 | case NodeTypeSliceExpr: | 1243 | case NodeTypeSliceExpr: |
| 1229 | case NodeTypeFieldAccessExpr: | 1244 | case NodeTypeFieldAccessExpr: |
| ... | @@ -1933,20 +1948,12 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, | ... | @@ -1933,20 +1948,12 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, |
| 1933 | zig_unreachable(); | 1948 | zig_unreachable(); |
| 1934 | } | 1949 | } |
| 1935 | 1950 | ||
| 1936 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *return_instruction) { | 1951 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, |
| 1937 | AstNode *source_node = return_instruction->base.source_node; | 1952 | IrInstructionReturn *return_instruction) |
| 1938 | BlockContext *scope = source_node->block_context; | 1953 | { |
| 1939 | if (!scope->fn_entry) { | 1954 | IrInstruction *value = ir_get_casted_value(ira, return_instruction->value->other, ira->explicit_return_type); |
| 1940 | add_node_error(ira->codegen, source_node, buf_sprintf("return expression outside function definition")); | 1955 | if (value == ira->codegen->invalid_instruction) |
| 1941 | return ira->codegen->builtin_types.entry_invalid; | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | TypeTableEntry *expected_return_type = scope->fn_entry->type_entry->data.fn.fn_type_id.return_type; | ||
| 1945 | |||
| 1946 | IrInstruction *value = ir_get_casted_value(ira, return_instruction->value->other, expected_return_type); | ||
| 1947 | if (value == ira->codegen->invalid_instruction) { | ||
| 1948 | return ira->codegen->builtin_types.entry_invalid; | 1956 | return ira->codegen->builtin_types.entry_invalid; |
| 1949 | } | ||
| 1950 | ira->implicit_return_type_list.append(value); | 1957 | ira->implicit_return_type_list.append(value); |
| 1951 | 1958 | ||
| 1952 | IrInstruction *new_instruction = ir_build_return_from(&ira->new_irb, &return_instruction->base, value); | 1959 | IrInstruction *new_instruction = ir_build_return_from(&ira->new_irb, &return_instruction->base, value); |
| ... | @@ -2333,43 +2340,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc | ... | @@ -2333,43 +2340,10 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 2333 | IrInstruction *var_type = nullptr; | 2340 | IrInstruction *var_type = nullptr; |
| 2334 | if (decl_var_instruction->var_type != nullptr) { | 2341 | if (decl_var_instruction->var_type != nullptr) { |
| 2335 | var_type = decl_var_instruction->var_type->other; | 2342 | var_type = decl_var_instruction->var_type->other; |
| 2336 | explicit_type = ir_get_canonical_type(ira, var_type); | 2343 | TypeTableEntry *proposed_type = ir_get_canonical_type(ira, var_type); |
| 2337 | switch (explicit_type->id) { | 2344 | explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); |
| 2338 | case TypeTableEntryIdTypeDecl: | 2345 | if (explicit_type->id == TypeTableEntryIdInvalid) |
| 2339 | zig_unreachable(); | 2346 | return explicit_type; |
| 2340 | case TypeTableEntryIdInvalid: | ||
| 2341 | explicit_type = ira->codegen->builtin_types.entry_invalid; | ||
| 2342 | break; | ||
| 2343 | case TypeTableEntryIdUnreachable: | ||
| 2344 | case TypeTableEntryIdVar: | ||
| 2345 | case TypeTableEntryIdNumLitFloat: | ||
| 2346 | case TypeTableEntryIdNumLitInt: | ||
| 2347 | case TypeTableEntryIdUndefLit: | ||
| 2348 | case TypeTableEntryIdNullLit: | ||
| 2349 | case TypeTableEntryIdBlock: | ||
| 2350 | add_node_error(ira->codegen, var_type->source_node, | ||
| 2351 | buf_sprintf("variable of type '%s' not allowed", buf_ptr(&explicit_type->name))); | ||
| 2352 | explicit_type = ira->codegen->builtin_types.entry_invalid; | ||
| 2353 | break; | ||
| 2354 | case TypeTableEntryIdNamespace: | ||
| 2355 | case TypeTableEntryIdMetaType: | ||
| 2356 | case TypeTableEntryIdVoid: | ||
| 2357 | case TypeTableEntryIdBool: | ||
| 2358 | case TypeTableEntryIdInt: | ||
| 2359 | case TypeTableEntryIdFloat: | ||
| 2360 | case TypeTableEntryIdPointer: | ||
| 2361 | case TypeTableEntryIdArray: | ||
| 2362 | case TypeTableEntryIdStruct: | ||
| 2363 | case TypeTableEntryIdMaybe: | ||
| 2364 | case TypeTableEntryIdErrorUnion: | ||
| 2365 | case TypeTableEntryIdPureError: | ||
| 2366 | case TypeTableEntryIdEnum: | ||
| 2367 | case TypeTableEntryIdUnion: | ||
| 2368 | case TypeTableEntryIdFn: | ||
| 2369 | case TypeTableEntryIdGenericFn: | ||
| 2370 | // OK | ||
| 2371 | break; | ||
| 2372 | } | ||
| 2373 | } | 2347 | } |
| 2374 | 2348 | ||
| 2375 | IrInstruction *init_value = decl_var_instruction->init_value->other; | 2349 | IrInstruction *init_value = decl_var_instruction->init_value->other; |
| ... | @@ -4306,3 +4280,21 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -4306,3 +4280,21 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 4306 | } | 4280 | } |
| 4307 | zig_unreachable(); | 4281 | zig_unreachable(); |
| 4308 | } | 4282 | } |
| 4283 | |||
| 4284 | IrInstruction *ir_exec_const_result(IrExecutable *exec) { | ||
| 4285 | if (exec->basic_block_list.length != 1) | ||
| 4286 | return nullptr; | ||
| 4287 | |||
| 4288 | IrBasicBlock *bb = exec->basic_block_list.at(0); | ||
| 4289 | if (bb->instruction_list.length != 1) | ||
| 4290 | return nullptr; | ||
| 4291 | |||
| 4292 | IrInstruction *only_inst = bb->instruction_list.at(0); | ||
| 4293 | if (only_inst->id != IrInstructionIdReturn) | ||
| 4294 | return nullptr; | ||
| 4295 | |||
| 4296 | IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst; | ||
| 4297 | IrInstruction *value = ret_inst->value; | ||
| 4298 | assert(value->static_value.ok); | ||
| 4299 | return value; | ||
| 4300 | } |
src/ir.hpp+2| ... | @@ -16,6 +16,8 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry); | ... | @@ -16,6 +16,8 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry); |
| 16 | TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, | 16 | TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, |
| 17 | TypeTableEntry *expected_type, AstNode *expected_type_source_node); | 17 | TypeTableEntry *expected_type, AstNode *expected_type_source_node); |
| 18 | 18 | ||
| 19 | IrInstruction *ir_exec_const_result(IrExecutable *exec); | ||
| 20 | |||
| 19 | bool ir_has_side_effects(IrInstruction *instruction); | 21 | bool ir_has_side_effects(IrInstruction *instruction); |
| 20 | 22 | ||
| 21 | #endif | 23 | #endif |