checker: allow using methods as vars when expecting a ctx arg (#14414)
parent
c2b763655d
commit
36bec823c2
|
@ -256,13 +256,14 @@ pub:
|
|||
mut_pos token.Pos
|
||||
next_token token.Kind
|
||||
pub mut:
|
||||
expr Expr // expr.field_name
|
||||
expr_type Type // type of `Foo` in `Foo.bar`
|
||||
typ Type // type of the entire thing (`Foo.bar`)
|
||||
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
|
||||
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
|
||||
scope &Scope
|
||||
from_embed_types []Type // holds the type of the embed that the method is called from
|
||||
expr Expr // expr.field_name
|
||||
expr_type Type // type of `Foo` in `Foo.bar`
|
||||
typ Type // type of the entire thing (`Foo.bar`)
|
||||
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
|
||||
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
|
||||
scope &Scope
|
||||
from_embed_types []Type // holds the type of the embed that the method is called from
|
||||
has_hidden_receiver bool
|
||||
}
|
||||
|
||||
// root_ident returns the origin ident where the selector started.
|
||||
|
|
|
@ -1851,6 +1851,14 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
|||
return field.typ
|
||||
}
|
||||
if mut method := c.table.find_method(sym, field_name) {
|
||||
if c.expected_type != 0 && c.expected_type != ast.none_type {
|
||||
fn_type := ast.new_type(c.table.find_or_register_fn_type(c.mod, method, false,
|
||||
true))
|
||||
// if the expected type includes the receiver, don't hide it behind a closure
|
||||
if c.check_types(fn_type, c.expected_type) {
|
||||
return fn_type
|
||||
}
|
||||
}
|
||||
receiver := method.params[0].typ
|
||||
if receiver.nr_muls() > 0 {
|
||||
if !c.inside_unsafe {
|
||||
|
@ -1867,6 +1875,7 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
|||
}
|
||||
}
|
||||
method.params = method.params[1..]
|
||||
node.has_hidden_receiver = true
|
||||
fn_type := ast.new_type(c.table.find_or_register_fn_type(c.mod, method, false,
|
||||
true))
|
||||
return fn_type
|
||||
|
|
|
@ -3347,6 +3347,10 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
|||
}
|
||||
}
|
||||
if !has_embeds {
|
||||
if !node.has_hidden_receiver {
|
||||
g.write('${g.typ(node.expr_type.idx())}_$m.name')
|
||||
return
|
||||
}
|
||||
receiver := m.params[0]
|
||||
expr_styp := g.typ(node.expr_type.idx())
|
||||
data_styp := g.typ(receiver.typ.idx())
|
||||
|
|
|
@ -95,3 +95,25 @@ fn test_methods_as_fields_ref() {
|
|||
new := set_val(5)
|
||||
assert old == new && old == 1
|
||||
}
|
||||
|
||||
struct GG_Ctx {
|
||||
frame_fn fn (voidptr) int
|
||||
}
|
||||
|
||||
[heap]
|
||||
struct App {
|
||||
msg string = 'hello'
|
||||
}
|
||||
|
||||
fn (app &App) frame() int {
|
||||
return app.msg.len
|
||||
}
|
||||
|
||||
fn test_ctx_arg_expected() {
|
||||
mut app := &App{}
|
||||
mut ctx := &GG_Ctx{
|
||||
frame_fn: app.frame
|
||||
}
|
||||
assert typeof(ctx.frame_fn).str() == 'fn (voidptr) int'
|
||||
assert ctx.frame_fn(app) == 5
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue