diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 2ca1dba69d..938b39b355 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -346,6 +346,17 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type { call_expr.return_type = table.string_type return table.string_type } + // call struct field fn type + // TODO: can we use SelectorExpr for all? + if field := c.table.struct_find_field(left_type_sym, method_name) { + field_type_sym := c.table.get_type_symbol(field.typ) + if field_type_sym.kind == .function { + call_expr.is_method = false + info := field_type_sym.info as table.FnType + call_expr.return_type = info.func.return_type + return info.func.return_type + } + } c.error('unknown method: ${left_type_sym.name}.$method_name', call_expr.pos) return table.void_type } diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index fcbe562d9b..71cb8ea3d7 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -242,6 +242,19 @@ fn (g mut Gen) method_call(node ast.CallExpr) { } fn (g mut Gen) fn_call(node ast.CallExpr) { + // call struct field with fn type + // TODO: test node.left instead + // left & left_type will be `x` and `x type` in `x.fieldfn()` + // will be `0` for `foo()` + if node.left_type != 0 { + g.expr(node.left) + if table.type_is_ptr(node.left_type) { + g.write('->') + } + else { + g.write('.') + } + } mut name := node.name is_print := name == 'println' || name == 'print' print_method := if name == 'println' { 'println' } else { 'print' } diff --git a/vlib/v/tests/fn_test.v b/vlib/v/tests/fn_test.v index b617ee2fd9..1a563844d8 100644 --- a/vlib/v/tests/fn_test.v +++ b/vlib/v/tests/fn_test.v @@ -153,7 +153,11 @@ struct MySt { fn test_fn_type_call() { mut arr := []MyFn arr << MyFn(test) - assert arr[0](10) == 1010 + // TODO: `arr[0](10)` + // assert arr[0](10) == 1010 + x1 := arr[0] + x2 := x1(10) + assert x2 == 1010 st := MySt{f:test} assert st.f(10) == 1010