Commit 42db468dcb

Veikka Tuominen <git@vexu.eu>
2022-11-04 17:13:49
Sema: make method call work with optionals and error unions
Closes #13414
1 parent 35afa3f
Changed files (2)
src
test
behavior
src/Sema.zig
@@ -22833,6 +22833,7 @@ fn fieldCallBind(
                     {
                         const first_param_type = decl_type.fnParamType(0);
                         const first_param_tag = first_param_type.tag();
+                        var opt_buf: Type.Payload.ElemType = undefined;
                         // zig fmt: off
                         if (first_param_tag == .var_args_param or
                             first_param_tag == .generic_poison or (
@@ -22851,7 +22852,27 @@ fn fieldCallBind(
                             });
                             return sema.addConstant(ty, value);
                         } else if (first_param_type.eql(concrete_ty, sema.mod)) {
-                            var deref = try sema.analyzeLoad(block, src, object_ptr, src);
+                            const deref = try sema.analyzeLoad(block, src, object_ptr, src);
+                            const ty = Type.Tag.bound_fn.init();
+                            const value = try Value.Tag.bound_fn.create(arena, .{
+                                .func_inst = decl_val,
+                                .arg0_inst = deref,
+                            });
+                            return sema.addConstant(ty, value);
+                        } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .Optional and
+                            first_param_type.optionalChild(&opt_buf).eql(concrete_ty, sema.mod))
+                        {
+                            const deref = try sema.analyzeLoad(block, src, object_ptr, src);
+                            const ty = Type.Tag.bound_fn.init();
+                            const value = try Value.Tag.bound_fn.create(arena, .{
+                                .func_inst = decl_val,
+                                .arg0_inst = deref,
+                            });
+                            return sema.addConstant(ty, value);
+                        } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .ErrorUnion and
+                            first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))
+                        {
+                            const deref = try sema.analyzeLoad(block, src, object_ptr, src);
                             const ty = Type.Tag.bound_fn.init();
                             const value = try Value.Tag.bound_fn.create(arena, .{
                                 .func_inst = decl_val,
test/behavior/fn.zig
@@ -434,3 +434,22 @@ test "implicit cast function to function ptr" {
     var fnPtr2: *const fn () callconv(.C) c_int = S2.someFunctionThatReturnsAValue;
     try expect(fnPtr2() == 123);
 }
+
+test "method call with optional and error union first param" {
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+    const S = struct {
+        x: i32 = 1234,
+
+        fn opt(s: ?@This()) !void {
+            try expect(s.?.x == 1234);
+        }
+        fn errUnion(s: anyerror!@This()) !void {
+            try expect((try s).x == 1234);
+        }
+    };
+    var s: S = .{};
+    try s.opt();
+    try s.errUnion();
+}