From 80ba21b83cd13849c1d1d9cdebfa070b03f334d3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 8 Feb 2020 14:59:33 -0500 Subject: properly spill optional payload capture value --- src/ir.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index ef3426d111..dc24fcef0c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8874,7 +8874,9 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo AstNode *else_node = node->data.test_expr.else_node; bool var_is_ptr = node->data.test_expr.var_is_ptr; - IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, expr_node, scope); + + IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, &spill_scope->base, LValPtr, nullptr); if (maybe_val_ptr == irb->codegen->invalid_inst_src) return maybe_val_ptr; @@ -8899,7 +8901,7 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo ir_set_cursor_at_end_and_append_block(irb, then_block); - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); Scope *var_scope; if (var_symbol) { bool is_shadowable = false; -- cgit v1.2.3 From d80db3546cf49b8af434005de0e74509d07b4855 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 8 Feb 2020 15:07:12 -0500 Subject: Revert "properly spill optional payload capture value" This reverts commit 80ba21b83cd13849c1d1d9cdebfa070b03f334d3. --- src/analyze.cpp | 3 +-- src/ir.cpp | 6 ++---- test/stage1/behavior/async_fn.zig | 24 ------------------------ 3 files changed, 3 insertions(+), 30 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index e5b90aa7b1..70352a2c18 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6104,12 +6104,11 @@ static void mark_suspension_point(Scope *scope) { continue; } case ScopeIdExpr: { - ScopeExpr *parent_expr_scope = reinterpret_cast(scope); if (!looking_for_exprs) { - parent_expr_scope->need_spill = MemoizedBoolTrue; // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) continue; } + ScopeExpr *parent_expr_scope = reinterpret_cast(scope); if (child_expr_scope != nullptr) { for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { assert(i < parent_expr_scope->children_len); diff --git a/src/ir.cpp b/src/ir.cpp index dc24fcef0c..ef3426d111 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8874,9 +8874,7 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo AstNode *else_node = node->data.test_expr.else_node; bool var_is_ptr = node->data.test_expr.var_is_ptr; - ScopeExpr *spill_scope = create_expr_scope(irb->codegen, expr_node, scope); - - IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, &spill_scope->base, LValPtr, nullptr); + IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (maybe_val_ptr == irb->codegen->invalid_inst_src) return maybe_val_ptr; @@ -8901,7 +8899,7 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo ir_set_cursor_at_end_and_append_block(irb, then_block); - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); Scope *var_scope; if (var_symbol) { bool is_shadowable = false; diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index fb17d5740c..4bfc4f4ee4 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1416,27 +1416,3 @@ test "async function call resolves target fn frame, runtime func" { resume S.global_frame; expect(S.global_int == 10); } - -test "properly spill optional payload capture value" { - const S = struct { - var global_frame: anyframe = undefined; - var global_int: usize = 2; - - fn foo() void { - var opt: ?usize = 1234; - if (opt) |x| { - bar(); - global_int += x; - } - } - - fn bar() void { - global_frame = @frame(); - suspend; - global_int += 1; - } - }; - _ = async S.foo(); - resume S.global_frame; - expect(S.global_int == 1237); -} -- cgit v1.2.3 From 24d197b037f93d57e5c9b7d1c84cdc9ec7313081 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 8 Feb 2020 15:27:45 -0500 Subject: solve previous commit a better way --- src/all_types.hpp | 3 +++ src/analyze.cpp | 5 ++++- src/ir.cpp | 7 +++++-- test/stage1/behavior/async_fn.zig | 24 ++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 58a753c545..5eb569263c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2490,6 +2490,9 @@ struct ScopeExpr { size_t children_len; MemoizedBool need_spill; + // This is a hack. I apologize for this, I need this to work so that I + // can make progress on other fronts. I'll pay off this tech debt eventually. + bool spill_harder; }; // synchronized with code in define_builtin_compile_vars diff --git a/src/analyze.cpp b/src/analyze.cpp index 70352a2c18..7d99ca92da 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6104,11 +6104,14 @@ static void mark_suspension_point(Scope *scope) { continue; } case ScopeIdExpr: { + ScopeExpr *parent_expr_scope = reinterpret_cast(scope); if (!looking_for_exprs) { + if (parent_expr_scope->spill_harder) { + parent_expr_scope->need_spill = MemoizedBoolTrue; + } // Now we're only looking for a block, to see if it's in a loop (see the case ScopeIdBlock) continue; } - ScopeExpr *parent_expr_scope = reinterpret_cast(scope); if (child_expr_scope != nullptr) { for (size_t i = 0; parent_expr_scope->children_ptr[i] != child_expr_scope; i += 1) { assert(i < parent_expr_scope->children_len); diff --git a/src/ir.cpp b/src/ir.cpp index ef3426d111..2f0c52347c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8874,7 +8874,10 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo AstNode *else_node = node->data.test_expr.else_node; bool var_is_ptr = node->data.test_expr.var_is_ptr; - IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, expr_node, scope); + spill_scope->spill_harder = true; + + IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, &spill_scope->base, LValPtr, nullptr); if (maybe_val_ptr == irb->codegen->invalid_inst_src) return maybe_val_ptr; @@ -8899,7 +8902,7 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo ir_set_cursor_at_end_and_append_block(irb, then_block); - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); Scope *var_scope; if (var_symbol) { bool is_shadowable = false; diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 4bfc4f4ee4..fb17d5740c 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1416,3 +1416,27 @@ test "async function call resolves target fn frame, runtime func" { resume S.global_frame; expect(S.global_int == 10); } + +test "properly spill optional payload capture value" { + const S = struct { + var global_frame: anyframe = undefined; + var global_int: usize = 2; + + fn foo() void { + var opt: ?usize = 1234; + if (opt) |x| { + bar(); + global_int += x; + } + } + + fn bar() void { + global_frame = @frame(); + suspend; + global_int += 1; + } + }; + _ = async S.foo(); + resume S.global_frame; + expect(S.global_int == 1237); +} -- cgit v1.2.3 From 04ee3b01a159a25894f93d8448fb766ae545ab53 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 9 Feb 2020 17:19:28 -0500 Subject: fix defer interfering with return value spill --- src/analyze.cpp | 4 +++- src/codegen.cpp | 31 +++++++++++++++++++-------- src/ir.cpp | 45 ++++++++++++++++++++++++--------------- test/stage1/behavior/async_fn.zig | 41 +++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 27 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 7d99ca92da..d13b62bcfd 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6367,7 +6367,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { IrInstGen *instruction = block->instruction_list.at(instr_i); if (instruction->id == IrInstGenIdAwait || instruction->id == IrInstGenIdVarPtr || - instruction->id == IrInstGenIdAlloca) + instruction->id == IrInstGenIdAlloca || + instruction->id == IrInstGenIdSpillBegin || + instruction->id == IrInstGenIdSpillEnd) { // This instruction does its own spilling specially, or otherwise doesn't need it. continue; diff --git a/src/codegen.cpp b/src/codegen.cpp index 15a3ca7e95..5a831819a5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2561,7 +2561,12 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir LLVMBuildRet(g->builder, by_val_value); } } else if (instruction->operand == nullptr) { - LLVMBuildRetVoid(g->builder); + if (g->cur_ret_ptr == nullptr) { + LLVMBuildRetVoid(g->builder); + } else { + LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, ""); + LLVMBuildRet(g->builder, by_val_value); + } } else { LLVMValueRef value = ir_llvm_value(g, instruction->operand); LLVMBuildRet(g->builder, value); @@ -5715,18 +5720,24 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) && g->errors_by_index.length > 1; - bool value_has_bits; - if ((err = type_has_bits2(g, instruction->base.value->type, &value_has_bits))) - codegen_report_errors_and_exit(g); - - if (!want_safety && !value_has_bits) - return nullptr; - ZigType *ptr_type = instruction->value->value->type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; ZigType *payload_type = err_union_type->data.error_union.payload_type; LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); + + LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); + bool value_has_bits; + if ((err = type_has_bits2(g, instruction->base.value->type, &value_has_bits))) + codegen_report_errors_and_exit(g); + if (!want_safety && !value_has_bits) { + if (instruction->initializing) { + gen_store_untyped(g, zero, err_union_ptr, 0, false); + } + return nullptr; + } + + LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); if (!type_has_bits(err_union_type->data.error_union.err_set_type)) { @@ -5741,7 +5752,6 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex } else { err_val = err_union_handle; } - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError"); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk"); @@ -5761,6 +5771,9 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex } return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); } else { + if (instruction->initializing) { + gen_store_untyped(g, zero, err_union_ptr, 0, false); + } return nullptr; } } diff --git a/src/ir.cpp b/src/ir.cpp index 2f0c52347c..82fce395b0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5252,6 +5252,7 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, return irb->codegen->invalid_inst_src; } else { return_value = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, return_value, &result_loc_ret->base); } ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value, result_loc_ret)); @@ -5262,7 +5263,7 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { // only generate unconditional defers ir_gen_defers_for_block(irb, scope, outer_scope, false); - IrInstSrc *result = ir_build_return_src(irb, scope, node, return_value); + IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); result_loc_ret->base.source_instruction = result; return result; } @@ -5271,10 +5272,6 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBasicBlockSrc *err_block = ir_create_basic_block(irb, scope, "ErrRetErr"); IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk"); - if (!have_err_defers) { - ir_gen_defers_for_block(irb, scope, outer_scope, false); - } - IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true); IrInstSrc *is_comptime; @@ -5288,22 +5285,18 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); ir_set_cursor_at_end_and_append_block(irb, err_block); - if (have_err_defers) { - ir_gen_defers_for_block(irb, scope, outer_scope, true); - } + ir_gen_defers_for_block(irb, scope, outer_scope, true); if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr_src(irb, scope, node); } ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ok_block); - if (have_err_defers) { - ir_gen_defers_for_block(irb, scope, outer_scope, false); - } + ir_gen_defers_for_block(irb, scope, outer_scope, false); ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); - IrInstSrc *result = ir_build_return_src(irb, scope, node, return_value); + IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); result_loc_ret->base.source_instruction = result; return result; } @@ -9622,7 +9615,10 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode * } - IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr, nullptr); + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, op1_node, parent_scope); + spill_scope->spill_harder = true; + + IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, op1_node, &spill_scope->base, LValPtr, nullptr); if (err_union_ptr == irb->codegen->invalid_inst_src) return irb->codegen->invalid_inst_src; @@ -9644,7 +9640,7 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode * is_comptime); ir_set_cursor_at_end_and_append_block(irb, err_block); - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, parent_scope, is_comptime); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); Scope *err_scope; if (var_node) { assert(var_node->type == NodeTypeSymbol); @@ -15497,6 +15493,12 @@ static IrInstGen *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira } static IrInstGen *ir_analyze_instruction_return(IrAnalyze *ira, IrInstSrcReturn *instruction) { + if (instruction->operand == nullptr) { + // result location mechanism took care of it. + IrInstGen *result = ir_build_return_gen(ira, &instruction->base.base, nullptr); + return ir_finish_anal(ira, result); + } + IrInstGen *operand = instruction->operand->child; if (type_is_invalid(operand->value->type)) return ir_unreach_error(ira); @@ -29551,8 +29553,13 @@ static IrInstGen *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstSrcSp if (!type_has_bits(operand->value->type)) return ir_const_void(ira, &instruction->base.base); - ir_assert(instruction->spill_id == SpillIdRetErrCode, &instruction->base.base); - ira->new_irb.exec->need_err_code_spill = true; + switch (instruction->spill_id) { + case SpillIdInvalid: + zig_unreachable(); + case SpillIdRetErrCode: + ira->new_irb.exec->need_err_code_spill = true; + break; + } return ir_build_spill_begin_gen(ira, &instruction->base.base, operand, instruction->spill_id); } @@ -29562,8 +29569,12 @@ static IrInstGen *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstSrcSpil if (type_is_invalid(operand->value->type)) return ira->codegen->invalid_inst_gen; - if (ir_should_inline(ira->old_irb.exec, instruction->base.base.scope) || !type_has_bits(operand->value->type)) + if (ir_should_inline(ira->old_irb.exec, instruction->base.base.scope) || + !type_has_bits(operand->value->type) || + instr_is_comptime(operand)) + { return operand; + } ir_assert(instruction->begin->base.child->id == IrInstGenIdSpillBegin, &instruction->base.base); IrInstGenSpillBegin *begin = reinterpret_cast(instruction->begin->base.child); diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index fb17d5740c..dcd5102ff8 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -2,6 +2,7 @@ const std = @import("std"); const builtin = @import("builtin"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; +const expectError = std.testing.expectError; var global_x: i32 = 1; @@ -1440,3 +1441,43 @@ test "properly spill optional payload capture value" { resume S.global_frame; expect(S.global_int == 1237); } + +test "handle defer interfering with return value spill" { + const S = struct { + var global_frame1: anyframe = undefined; + var global_frame2: anyframe = undefined; + var finished = false; + var baz_happened = false; + + fn doTheTest() void { + _ = async testFoo(); + resume global_frame1; + resume global_frame2; + expect(baz_happened); + expect(finished); + } + + fn testFoo() void { + expectError(error.Bad, foo()); + finished = true; + } + + fn foo() anyerror!void { + defer baz(); + return bar() catch |err| return err; + } + + fn bar() anyerror!void { + global_frame1 = @frame(); + suspend; + return error.Bad; + } + + fn baz() void { + global_frame2 = @frame(); + suspend; + baz_happened = true; + } + }; + S.doTheTest(); +} -- cgit v1.2.3 From 5ea79bfc4a0a1269930d98faee36a8f6cb0b0401 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 9 Feb 2020 22:34:34 -0500 Subject: fix not checking type of return pointer Thanks to Vexu for the test cases. Closes #3422 Closes #3646 Closes #3224 Closes #3327 Closes #3269 --- src/ir.cpp | 12 ++++++++++++ test/compile_errors.zig | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 82fce395b0..4716b91b5d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19591,6 +19591,12 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { return result_loc; } + IrInstGen *dummy_value = ir_const(ira, source_instr, impl_fn_type_id->return_type); + dummy_value->value->special = ConstValSpecialRuntime; + IrInstGen *dummy_result = ir_implicit_cast2(ira, source_instr, + dummy_value, result_loc->value->type->data.pointer.child_type); + if (type_is_invalid(dummy_result->value->type)) + return ira->codegen->invalid_inst_gen; ZigType *res_child_type = result_loc->value->type->data.pointer.child_type; if (res_child_type == ira->codegen->builtin_types.entry_var) { res_child_type = impl_fn_type_id->return_type; @@ -19723,6 +19729,12 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { return result_loc; } + IrInstGen *dummy_value = ir_const(ira, source_instr, return_type); + dummy_value->value->special = ConstValSpecialRuntime; + IrInstGen *dummy_result = ir_implicit_cast2(ira, source_instr, + dummy_value, result_loc->value->type->data.pointer.child_type); + if (type_is_invalid(dummy_result->value->type)) + return ira->codegen->invalid_inst_gen; ZigType *res_child_type = result_loc->value->type->data.pointer.child_type; if (res_child_type == ira->codegen->builtin_types.entry_var) { res_child_type = return_type; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 341062e161..85491fa0f2 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3,6 +3,30 @@ const builtin = @import("builtin"); const Target = @import("std").Target; pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add("function call assigned to incorrect type", + \\export fn entry() void { + \\ var arr: [4]f32 = undefined; + \\ arr = concat(); + \\} + \\fn concat() [16]f32 { + \\ return [1]f32{0}**16; + \\} + , &[_][]const u8{ + "tmp.zig:3:17: error: expected type '[4]f32', found '[16]f32'", + }); + + cases.add("generic function call assigned to incorrect type", + \\pub export fn entry() void { + \\ var res: []i32 = undefined; + \\ res = myAlloc(i32); + \\} + \\fn myAlloc(comptime arg: type) anyerror!arg{ + \\ unreachable; + \\} + , &[_][]const u8{ + "tmp.zig:3:18: error: expected type '[]i32', found 'anyerror!i32", + }); + cases.addTest("dependency loop in top-level decl with @TypeInfo", \\export const foo = @typeInfo(@This()); , &[_][]const u8{ -- cgit v1.2.3