checker: allow using methods as vars when expecting a ctx arg (#14414)

spaceface 2022-05-16 11:05:08 +02:00 committed by Jef Roosens
parent 9e179ab11f
commit 4179e1cac2
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 43 additions and 7 deletions

View File

@ -263,6 +263,7 @@ pub mut:
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.

View File

@ -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

View File

@ -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())

View File

@ -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
}