Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp committed Dec 16, 2024
1 parent 75928d1 commit a58d3a6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 2 deletions.
1 change: 1 addition & 0 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,7 @@ pub mut:
is_return_used bool // return value is used for another expr
//
is_expand_simple_interpolation bool // true, when the function/method is marked as @[expand_simple_interpolation]
is_unwrapped_fn_selector bool // true, when the call is from an unwrapped selector (e.g. if t.foo != none { t.foo() })
// Calls to it with an interpolation argument like `b.f('x ${y}')`, will be converted to `b.f('x ')` followed by `b.f(y)`.
// The same type, has to support also a .write_decimal(n i64) method.
}
Expand Down
13 changes: 11 additions & 2 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -2364,10 +2364,19 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
// call struct field fn type
// TODO: can we use SelectorExpr for all? this dosent really belong here
if field := c.table.find_field_with_embeds(left_sym, method_name) {
mut field_typ := field.typ
if field.typ.has_flag(.option) {
c.error('Option function field must be unwrapped first', node.pos)
// unwrapped callback (if f.func != none {})
if scope_field := node.scope.find_struct_field(node.left.str(), node.left_type,
method_name)
{
field_typ = scope_field.smartcasts.last()
node.is_unwrapped_fn_selector = true
} else {
c.error('Option function field must be unwrapped first', node.pos)
}
}
field_sym := c.table.sym(c.unwrap_generic(field.typ))
field_sym := c.table.sym(c.unwrap_generic(field_typ))
if field_sym.kind == .function {
node.is_method = false
node.is_field = true
Expand Down
12 changes: 12 additions & 0 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -2077,11 +2077,20 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
if field := g.table.find_field_with_embeds(left_sym, node.name) {
fn_typ = field.typ
}
if node.is_unwrapped_fn_selector {
fn_typ = fn_typ.clear_option_and_result()
}
}
if left_sym.kind == .interface || fn_typ.is_ptr() {
is_interface_call = true
g.write('(*')
}
if node.is_unwrapped_fn_selector {
callback_sym := g.table.final_sym(fn_typ)
if callback_sym.info is ast.FnType {
g.write('(*(${g.styp(fn_typ)}*)')
}
}
g.expr(node.left)
if node.left_type.is_ptr() {
g.write('->')
Expand Down Expand Up @@ -2387,6 +2396,9 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.write(g.get_ternary_name(name))
}
}
if node.is_unwrapped_fn_selector {
g.write('.data)')
}
if is_interface_call {
g.write(')')
}
Expand Down
29 changes: 29 additions & 0 deletions vlib/v/tests/options/option_method_selector_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
struct Foo {
mut:
func ?fn (voidptr) bool = unsafe { nil }
}

fn callback(foo &Foo) bool {
return foo.func? == callback
}

type OptFn = fn (&Foo) bool

fn test_main() {
t := Foo{
func: callback
}
assert t.func? == callback
if t.func != none {
assert t.func(&t)
} else {
assert false
}

a := ?OptFn(callback)
if a != none {
assert a(&t)
} else {
assert false
}
}

0 comments on commit a58d3a6

Please sign in to comment.