Commit 9983501ff2

Michael Dusan <michael.dusan@gmail.com>
2019-09-24 23:53:05
add VarDecl support for struct-method call syntax
implements #3306
1 parent 56b1818
Changed files (3)
src
test
src/ir.cpp
@@ -17675,18 +17675,36 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
         assert(container_scope != nullptr);
         auto entry = container_scope->decl_table.maybe_get(field_name);
         Tld *tld = entry ? entry->value : nullptr;
-        if (tld && tld->id == TldIdFn) {
-            resolve_top_level_decl(ira->codegen, tld, source_instr->source_node, false);
-            if (tld->resolution == TldResolutionInvalid)
-                return ira->codegen->invalid_instruction;
-            TldFn *tld_fn = (TldFn *)tld;
-            ZigFn *fn_entry = tld_fn->fn_entry;
-            if (type_is_invalid(fn_entry->type_entry))
-                return ira->codegen->invalid_instruction;
+        if (tld) {
+            if (tld->id == TldIdFn) {
+                resolve_top_level_decl(ira->codegen, tld, source_instr->source_node, false);
+                if (tld->resolution == TldResolutionInvalid)
+                    return ira->codegen->invalid_instruction;
+                TldFn *tld_fn = (TldFn *)tld;
+                ZigFn *fn_entry = tld_fn->fn_entry;
+                if (type_is_invalid(fn_entry->type_entry))
+                    return ira->codegen->invalid_instruction;
+
+                IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, source_instr->scope,
+                    source_instr->source_node, fn_entry, container_ptr);
+                return ir_get_ref(ira, source_instr, bound_fn_value, true, false);
+            } else if (tld->id == TldIdVar) {
+                resolve_top_level_decl(ira->codegen, tld, source_instr->source_node, false);
+                if (tld->resolution == TldResolutionInvalid)
+                    return ira->codegen->invalid_instruction;
+                TldVar *tld_var = (TldVar *)tld;
+                ZigVar *var = tld_var->var;
+                if (type_is_invalid(var->var_type))
+                    return ira->codegen->invalid_instruction;
 
-            IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, source_instr->scope,
-                source_instr->source_node, fn_entry, container_ptr);
-            return ir_get_ref(ira, source_instr, bound_fn_value, true, false);
+                if (var->const_value->type->id == ZigTypeIdFn) {
+                    ir_assert(var->const_value->data.x_ptr.special == ConstPtrSpecialFunction, source_instr);
+                    ZigFn *fn = var->const_value->data.x_ptr.data.fn.fn_entry;
+                    IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, source_instr->scope,
+                        source_instr->source_node, fn, container_ptr);
+                    return ir_get_ref(ira, source_instr, bound_fn_value, true, false);
+                }
+            }
         }
     }
     const char *prefix_name;
test/stage1/behavior/fn_delegation.zig
@@ -0,0 +1,39 @@
+const expect = @import("std").testing.expect;
+
+const Foo = struct {
+    a: u64 = 10,
+
+    fn one(self: Foo) u64 {
+        return self.a + 1;
+    }
+
+    const two = __two;
+
+    fn __two(self: Foo) u64 {
+        return self.a + 2;
+    }
+
+    const three = __three;
+
+    const four = custom(Foo, 4);
+};
+
+fn __three(self: Foo) u64 {
+    return self.a + 3;
+}
+
+fn custom(comptime T: type, comptime num: u64) fn (T) u64 {
+    return struct {
+        fn function(self: T) u64 {
+            return self.a + num;
+        }
+    }.function;
+}
+
+test "fn delegation" {
+    const foo = Foo{};
+    expect(foo.one() == 11);
+    expect(foo.two() == 12);
+    expect(foo.three() == 13);
+    expect(foo.four() == 14);
+}
test/stage1/behavior.zig
@@ -58,6 +58,7 @@ comptime {
     _ = @import("behavior/floatop.zig");
     _ = @import("behavior/fn.zig");
     _ = @import("behavior/fn_in_struct_in_comptime.zig");
+    _ = @import("behavior/fn_delegation.zig");
     _ = @import("behavior/for.zig");
     _ = @import("behavior/generics.zig");
     _ = @import("behavior/hasdecl.zig");