From 9983501ff2cccf828bb357dddefb21e36813046d Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Tue, 24 Sep 2019 17:53:05 -0400 Subject: [PATCH] add VarDecl support for struct-method call syntax implements #3306 --- src/ir.cpp | 40 +++++++++++++++++++------- test/stage1/behavior.zig | 1 + test/stage1/behavior/fn_delegation.zig | 39 +++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 test/stage1/behavior/fn_delegation.zig diff --git a/src/ir.cpp b/src/ir.cpp index b3906d8b61..14adf6fbd6 100644 --- a/src/ir.cpp +++ b/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); + 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; + + 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; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 9b7f4305c2..569e6e2b51 100644 --- a/test/stage1/behavior.zig +++ b/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"); diff --git a/test/stage1/behavior/fn_delegation.zig b/test/stage1/behavior/fn_delegation.zig new file mode 100644 index 0000000000..57006805c8 --- /dev/null +++ b/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); +}