| ... | ... | @@ -1731,7 +1731,13 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o |
| 1731 | 1731 | } |
| 1732 | 1732 | } |
| 1733 | 1733 | |
| 1734 | | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 1734 | static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { |
| 1735 | assert(basic_block); |
| 1736 | |
| 1737 | irb->current_basic_block = basic_block; |
| 1738 | } |
| 1739 | |
| 1740 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) { |
| 1735 | 1741 | assert(node->type == NodeTypeReturnExpr); |
| 1736 | 1742 | |
| 1737 | 1743 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); |
| ... | ... | @@ -1740,6 +1746,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) |
| 1740 | 1746 | return irb->codegen->invalid_instruction; |
| 1741 | 1747 | } |
| 1742 | 1748 | |
| 1749 | Scope *outer_scope = fn_entry->child_scope; |
| 1750 | bool is_inline = ir_should_inline(irb); |
| 1751 | |
| 1743 | 1752 | AstNode *expr_node = node->data.return_expr.expr; |
| 1744 | 1753 | switch (node->data.return_expr.kind) { |
| 1745 | 1754 | case ReturnKindUnconditional: |
| ... | ... | @@ -1747,28 +1756,46 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node) |
| 1747 | 1756 | IrInstruction *return_value; |
| 1748 | 1757 | if (expr_node) { |
| 1749 | 1758 | return_value = ir_gen_node(irb, expr_node, scope); |
| 1759 | if (return_value == irb->codegen->invalid_instruction) |
| 1760 | return irb->codegen->invalid_instruction; |
| 1750 | 1761 | } else { |
| 1751 | 1762 | return_value = ir_build_const_void(irb, scope, node); |
| 1752 | 1763 | } |
| 1753 | 1764 | |
| 1754 | | Scope *outer_scope = fn_entry->child_scope; |
| 1765 | // TODO conditionally gen maybe defers and error defers |
| 1755 | 1766 | ir_gen_defers_for_block(irb, scope, outer_scope, false, false); |
| 1756 | 1767 | return ir_build_return(irb, scope, node, return_value); |
| 1757 | 1768 | } |
| 1758 | 1769 | case ReturnKindError: |
| 1759 | 1770 | zig_panic("TODO gen IR for %%return"); |
| 1760 | 1771 | case ReturnKindMaybe: |
| 1761 | | zig_panic("TODO gen IR for ?return"); |
| 1772 | { |
| 1773 | assert(expr_node); |
| 1774 | IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf); |
| 1775 | if (maybe_val_ptr == irb->codegen->invalid_instruction) |
| 1776 | return irb->codegen->invalid_instruction; |
| 1777 | IrInstruction *is_nonnull_val = ir_build_test_null(irb, scope, node, maybe_val_ptr); |
| 1778 | |
| 1779 | IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn"); |
| 1780 | IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue"); |
| 1781 | ir_build_cond_br(irb, scope, node, is_nonnull_val, continue_block, return_block, is_inline); |
| 1782 | |
| 1783 | ir_set_cursor_at_end(irb, return_block); |
| 1784 | ir_gen_defers_for_block(irb, scope, outer_scope, false, true); |
| 1785 | IrInstruction *null = ir_build_const_null(irb, scope, node); |
| 1786 | ir_build_return(irb, scope, node, null); |
| 1787 | |
| 1788 | ir_set_cursor_at_end(irb, continue_block); |
| 1789 | IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false); |
| 1790 | if (lval != LValPurposeNone) |
| 1791 | return unwrapped_ptr; |
| 1792 | else |
| 1793 | return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); |
| 1794 | } |
| 1762 | 1795 | } |
| 1763 | 1796 | zig_unreachable(); |
| 1764 | 1797 | } |
| 1765 | 1798 | |
| 1766 | | static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { |
| 1767 | | assert(basic_block); |
| 1768 | | |
| 1769 | | irb->current_basic_block = basic_block; |
| 1770 | | } |
| 1771 | | |
| 1772 | 1799 | static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, |
| 1773 | 1800 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, bool is_inline) |
| 1774 | 1801 | { |
| ... | ... | @@ -3606,7 +3633,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 3606 | 3633 | case NodeTypeArrayAccessExpr: |
| 3607 | 3634 | return ir_gen_array_access(irb, scope, node, lval); |
| 3608 | 3635 | case NodeTypeReturnExpr: |
| 3609 | | return ir_lval_wrap(irb, scope, ir_gen_return(irb, scope, node), lval); |
| 3636 | return ir_gen_return(irb, scope, node, lval); |
| 3610 | 3637 | case NodeTypeFieldAccessExpr: |
| 3611 | 3638 | return ir_gen_field_access(irb, scope, node, lval); |
| 3612 | 3639 | case NodeTypeThisLiteral: |
| ... | ... | @@ -3827,6 +3854,7 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3827 | 3854 | return ira->codegen->builtin_types.entry_invalid; |
| 3828 | 3855 | } |
| 3829 | 3856 | bool any_are_pure_error = (prev_inst->type_entry->id == TypeTableEntryIdPureError); |
| 3857 | bool any_are_null = (prev_inst->type_entry->id == TypeTableEntryIdNullLit); |
| 3830 | 3858 | for (size_t i = 1; i < instruction_count; i += 1) { |
| 3831 | 3859 | IrInstruction *cur_inst = instructions[i]; |
| 3832 | 3860 | TypeTableEntry *cur_type = cur_inst->type_entry; |
| ... | ... | @@ -3836,9 +3864,15 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3836 | 3864 | } else if (prev_type->id == TypeTableEntryIdPureError) { |
| 3837 | 3865 | prev_inst = cur_inst; |
| 3838 | 3866 | continue; |
| 3867 | } else if (prev_type->id == TypeTableEntryIdNullLit) { |
| 3868 | prev_inst = cur_inst; |
| 3869 | continue; |
| 3839 | 3870 | } else if (cur_type->id == TypeTableEntryIdPureError) { |
| 3840 | 3871 | any_are_pure_error = true; |
| 3841 | 3872 | continue; |
| 3873 | } else if (cur_type->id == TypeTableEntryIdNullLit) { |
| 3874 | any_are_null = true; |
| 3875 | continue; |
| 3842 | 3876 | } else if (types_match_const_cast_only(prev_type, cur_type)) { |
| 3843 | 3877 | continue; |
| 3844 | 3878 | } else if (types_match_const_cast_only(cur_type, prev_type)) { |
| ... | ... | @@ -3889,9 +3923,13 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3889 | 3923 | return ira->codegen->builtin_types.entry_invalid; |
| 3890 | 3924 | } |
| 3891 | 3925 | } else { |
| 3892 | | add_node_error(ira->codegen, source_node, |
| 3926 | ErrorMsg *msg = add_node_error(ira->codegen, source_node, |
| 3893 | 3927 | buf_sprintf("incompatible types: '%s' and '%s'", |
| 3894 | 3928 | buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); |
| 3929 | add_error_note(ira->codegen, msg, prev_inst->source_node, |
| 3930 | buf_sprintf("type '%s' here", buf_ptr(&prev_type->name))); |
| 3931 | add_error_note(ira->codegen, msg, cur_inst->source_node, |
| 3932 | buf_sprintf("type '%s' here", buf_ptr(&cur_type->name))); |
| 3895 | 3933 | |
| 3896 | 3934 | return ira->codegen->builtin_types.entry_invalid; |
| 3897 | 3935 | } |
| ... | ... | @@ -3903,9 +3941,23 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n |
| 3903 | 3941 | add_node_error(ira->codegen, source_node, |
| 3904 | 3942 | buf_sprintf("unable to make error union out of number literal")); |
| 3905 | 3943 | return ira->codegen->builtin_types.entry_invalid; |
| 3944 | } else if (prev_inst->type_entry->id == TypeTableEntryIdNullLit) { |
| 3945 | add_node_error(ira->codegen, source_node, |
| 3946 | buf_sprintf("unable to make error union out of null literal")); |
| 3947 | return ira->codegen->builtin_types.entry_invalid; |
| 3906 | 3948 | } else { |
| 3907 | 3949 | return get_error_type(ira->codegen, prev_inst->type_entry); |
| 3908 | 3950 | } |
| 3951 | } else if (any_are_null && prev_inst->type_entry->id != TypeTableEntryIdNullLit) { |
| 3952 | if (prev_inst->type_entry->id == TypeTableEntryIdNumLitInt || |
| 3953 | prev_inst->type_entry->id == TypeTableEntryIdNumLitFloat) |
| 3954 | { |
| 3955 | add_node_error(ira->codegen, source_node, |
| 3956 | buf_sprintf("unable to make maybe out of number literal")); |
| 3957 | return ira->codegen->builtin_types.entry_invalid; |
| 3958 | } else { |
| 3959 | return get_maybe_type(ira->codegen, prev_inst->type_entry); |
| 3960 | } |
| 3909 | 3961 | } else { |
| 3910 | 3962 | return prev_inst->type_entry; |
| 3911 | 3963 | } |
| ... | ... | @@ -9053,16 +9105,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9053 | 9105 | //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 9054 | 9106 | // TypeTableEntry *expected_type, AstNode *node) |
| 9055 | 9107 | //{ |
| 9056 | | // if (!node->data.return_expr.expr) { |
| 9057 | | // node->data.return_expr.expr = create_ast_void_node(g, import, node); |
| 9058 | | // normalize_parent_ptrs(node); |
| 9059 | | // } |
| 9060 | | // |
| 9061 | 9108 | // TypeTableEntry *expected_return_type = get_return_type(context); |
| 9062 | 9109 | // |
| 9063 | 9110 | // switch (node->data.return_expr.kind) { |
| 9064 | | // case ReturnKindUnconditional: |
| 9065 | | // zig_panic("TODO moved to ir.cpp"); |
| 9066 | 9111 | // case ReturnKindError: |
| 9067 | 9112 | // { |
| 9068 | 9113 | // TypeTableEntry *expected_err_type; |
| ... | ... | @@ -9093,34 +9138,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9093 | 9138 | // return g->builtin_types.entry_invalid; |
| 9094 | 9139 | // } |
| 9095 | 9140 | // } |
| 9096 | | // case ReturnKindMaybe: |
| 9097 | | // { |
| 9098 | | // TypeTableEntry *expected_maybe_type; |
| 9099 | | // if (expected_type) { |
| 9100 | | // expected_maybe_type = get_maybe_type(g, expected_type); |
| 9101 | | // } else { |
| 9102 | | // expected_maybe_type = nullptr; |
| 9103 | | // } |
| 9104 | | // TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type, |
| 9105 | | // node->data.return_expr.expr); |
| 9106 | | // if (resolved_type->id == TypeTableEntryIdInvalid) { |
| 9107 | | // return resolved_type; |
| 9108 | | // } else if (resolved_type->id == TypeTableEntryIdMaybe) { |
| 9109 | | // if (expected_return_type->id != TypeTableEntryIdMaybe) { |
| 9110 | | // ErrorMsg *msg = add_node_error(g, node, |
| 9111 | | // buf_sprintf("?return statement in function with return type '%s'", |
| 9112 | | // buf_ptr(&expected_return_type->name))); |
| 9113 | | // AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type; |
| 9114 | | // add_error_note(g, msg, return_type_node, buf_sprintf("function return type here")); |
| 9115 | | // } |
| 9116 | | // |
| 9117 | | // return resolved_type->data.maybe.child_type; |
| 9118 | | // } else { |
| 9119 | | // add_node_error(g, node->data.return_expr.expr, |
| 9120 | | // buf_sprintf("expected maybe type, found '%s'", buf_ptr(&resolved_type->name))); |
| 9121 | | // return g->builtin_types.entry_invalid; |
| 9122 | | // } |
| 9123 | | // } |
| 9124 | 9141 | // } |
| 9125 | 9142 | // zig_unreachable(); |
| 9126 | 9143 | //} |
| ... | ... | @@ -9344,43 +9361,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 9344 | 9361 | // return nullptr; |
| 9345 | 9362 | // } |
| 9346 | 9363 | // } |
| 9347 | | // case ReturnKindMaybe: |
| 9348 | | // { |
| 9349 | | // assert(value_type->id == TypeTableEntryIdMaybe); |
| 9350 | | // TypeTableEntry *child_type = value_type->data.maybe.child_type; |
| 9351 | | // |
| 9352 | | // LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn"); |
| 9353 | | // LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue"); |
| 9354 | | // |
| 9355 | | // LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); |
| 9356 | | // LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, ""); |
| 9357 | | // |
| 9358 | | // LLVMValueRef zero = LLVMConstNull(LLVMInt1Type()); |
| 9359 | | // LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, is_non_null, zero, ""); |
| 9360 | | // LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block); |
| 9361 | | // |
| 9362 | | // LLVMPositionBuilderAtEnd(g->builder, return_block); |
| 9363 | | // TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; |
| 9364 | | // assert(return_type->id == TypeTableEntryIdMaybe); |
| 9365 | | // if (handle_is_ptr(return_type)) { |
| 9366 | | // assert(g->cur_ret_ptr); |
| 9367 | | // |
| 9368 | | // LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, ""); |
| 9369 | | // LLVMBuildStore(g->builder, zero, maybe_bit_ptr); |
| 9370 | | // LLVMBuildRetVoid(g->builder); |
| 9371 | | // } else { |
| 9372 | | // LLVMValueRef ret_zero_value = LLVMConstNull(return_type->type_ref); |
| 9373 | | // gen_return(g, node, ret_zero_value, ReturnKnowledgeKnownNull); |
| 9374 | | // } |
| 9375 | | // |
| 9376 | | // LLVMPositionBuilderAtEnd(g->builder, continue_block); |
| 9377 | | // if (type_has_bits(child_type)) { |
| 9378 | | // LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, ""); |
| 9379 | | // return get_handle_value(g, val_ptr, child_type); |
| 9380 | | // } else { |
| 9381 | | // return nullptr; |
| 9382 | | // } |
| 9383 | | // } |
| 9384 | 9364 | // } |
| 9385 | 9365 | // zig_unreachable(); |
| 9386 | 9366 | //} |