Commit bf7b6fbbdb

Andrew Kelley <andrew@ziglang.org>
2019-08-16 22:30:24
add missing compile error for fn call bad implicit cast
when the function's return type handle is a pointer but the result location's result value type handle is not a pointer closes #3055
1 parent cbca658
Changed files (2)
src/ir.cpp
@@ -9615,6 +9615,10 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
             return cur_type;
         }
 
+        if (prev_type == cur_type) {
+            continue;
+        }
+
         if (prev_type->id == ZigTypeIdUnreachable) {
             prev_inst = cur_inst;
             continue;
@@ -14921,7 +14925,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc
     ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry);
     IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
             frame_type, nullptr, true, true, false);
-    if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
+    if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
         return result_loc;
     }
     result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false));
@@ -15638,10 +15642,14 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
         if (handle_is_ptr(impl_fn_type_id->return_type)) {
             result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
                     impl_fn_type_id->return_type, nullptr, true, true, false);
-            if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) ||
-                        instr_is_unreachable(result_loc)))
-            {
-                return result_loc;
+            if (result_loc != nullptr) {
+                if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
+                    return result_loc;
+                }
+                if (!handle_is_ptr(result_loc->value.type->data.pointer.child_type)) {
+                    ir_reset_result(call_instruction->result_loc);
+                    result_loc = nullptr;
+                }
             }
         } else {
             result_loc = nullptr;
@@ -15791,8 +15799,14 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
     if (handle_is_ptr(return_type)) {
         result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
                 return_type, nullptr, true, true, false);
-        if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
-            return result_loc;
+        if (result_loc != nullptr) {
+            if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
+                return result_loc;
+            }
+            if (!handle_is_ptr(result_loc->value.type->data.pointer.child_type)) {
+                ir_reset_result(call_instruction->result_loc);
+                result_loc = nullptr;
+            }
         }
     } else {
         result_loc = nullptr;
test/compile_errors.zig
@@ -2,6 +2,40 @@ const tests = @import("tests.zig");
 const builtin = @import("builtin");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "result location incompatibility mismatching handle_is_ptr (generic call)",
+        \\export fn entry() void {
+        \\    var damn = Container{
+        \\        .not_optional = getOptional(i32),
+        \\    };
+        \\}
+        \\pub fn getOptional(comptime T: type) ?T {
+        \\    return 0;
+        \\}
+        \\pub const Container = struct {
+        \\    not_optional: i32,
+        \\};
+    ,
+        "tmp.zig:3:36: error: expected type 'i32', found '?i32'",
+    );
+
+    cases.add(
+        "result location incompatibility mismatching handle_is_ptr",
+        \\export fn entry() void {
+        \\    var damn = Container{
+        \\        .not_optional = getOptional(),
+        \\    };
+        \\}
+        \\pub fn getOptional() ?i32 {
+        \\    return 0;
+        \\}
+        \\pub const Container = struct {
+        \\    not_optional: i32,
+        \\};
+    ,
+        "tmp.zig:3:36: error: expected type 'i32', found '?i32'",
+    );
+
     cases.add(
         "const frame cast to anyframe",
         \\export fn a() void {