checker: allow using methods as vars when expecting a ctx arg (#14414)
parent
9e179ab11f
commit
4179e1cac2
|
@ -256,13 +256,14 @@ pub:
|
||||||
mut_pos token.Pos
|
mut_pos token.Pos
|
||||||
next_token token.Kind
|
next_token token.Kind
|
||||||
pub mut:
|
pub mut:
|
||||||
expr Expr // expr.field_name
|
expr Expr // expr.field_name
|
||||||
expr_type Type // type of `Foo` in `Foo.bar`
|
expr_type Type // type of `Foo` in `Foo.bar`
|
||||||
typ Type // type of the entire thing (`Foo.bar`)
|
typ Type // type of the entire thing (`Foo.bar`)
|
||||||
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
|
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
|
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
|
||||||
scope &Scope
|
scope &Scope
|
||||||
from_embed_types []Type // holds the type of the embed that the method is called from
|
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.
|
// 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
|
return field.typ
|
||||||
}
|
}
|
||||||
if mut method := c.table.find_method(sym, field_name) {
|
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
|
receiver := method.params[0].typ
|
||||||
if receiver.nr_muls() > 0 {
|
if receiver.nr_muls() > 0 {
|
||||||
if !c.inside_unsafe {
|
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..]
|
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,
|
fn_type := ast.new_type(c.table.find_or_register_fn_type(c.mod, method, false,
|
||||||
true))
|
true))
|
||||||
return fn_type
|
return fn_type
|
||||||
|
|
|
@ -3347,6 +3347,10 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !has_embeds {
|
if !has_embeds {
|
||||||
|
if !node.has_hidden_receiver {
|
||||||
|
g.write('${g.typ(node.expr_type.idx())}_$m.name')
|
||||||
|
return
|
||||||
|
}
|
||||||
receiver := m.params[0]
|
receiver := m.params[0]
|
||||||
expr_styp := g.typ(node.expr_type.idx())
|
expr_styp := g.typ(node.expr_type.idx())
|
||||||
data_styp := g.typ(receiver.typ.idx())
|
data_styp := g.typ(receiver.typ.idx())
|
||||||
|
|
|
@ -95,3 +95,25 @@ fn test_methods_as_fields_ref() {
|
||||||
new := set_val(5)
|
new := set_val(5)
|
||||||
assert old == new && old == 1
|
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