cgen: fix embed generic field access & method call (#7725)
parent
b4c5fa8ca0
commit
9a31744255
|
@ -1258,6 +1258,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
}
|
}
|
||||||
mut method := table.Fn{}
|
mut method := table.Fn{}
|
||||||
mut has_method := false
|
mut has_method := false
|
||||||
|
mut is_method_from_embed := false
|
||||||
if m := c.table.type_find_method(left_type_sym, method_name) {
|
if m := c.table.type_find_method(left_type_sym, method_name) {
|
||||||
method = m
|
method = m
|
||||||
has_method = true
|
has_method = true
|
||||||
|
@ -1275,6 +1276,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
if found_methods.len == 1 {
|
if found_methods.len == 1 {
|
||||||
method = found_methods[0]
|
method = found_methods[0]
|
||||||
has_method = true
|
has_method = true
|
||||||
|
is_method_from_embed = true
|
||||||
call_expr.from_embed_type = embed_of_found_methods[0]
|
call_expr.from_embed_type = embed_of_found_methods[0]
|
||||||
} else if found_methods.len > 1 {
|
} else if found_methods.len > 1 {
|
||||||
c.error('ambiguous method `$method_name`', call_expr.pos)
|
c.error('ambiguous method `$method_name`', call_expr.pos)
|
||||||
|
@ -1374,12 +1376,13 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
||||||
call_expr.expected_arg_types << method.params[i].typ
|
call_expr.expected_arg_types << method.params[i].typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_generic {
|
if is_method_from_embed {
|
||||||
|
call_expr.receiver_type = call_expr.from_embed_type.derive(method.params[0].typ)
|
||||||
|
} else if is_generic {
|
||||||
// We need the receiver to be T in cgen.
|
// We need the receiver to be T in cgen.
|
||||||
// TODO: cant we just set all these to the concrete type in checker? then no need in gen
|
// TODO: cant we just set all these to the concrete type in checker? then no need in gen
|
||||||
call_expr.receiver_type = left_type.derive(method.params[0].typ).set_flag(.generic)
|
call_expr.receiver_type = left_type.derive(method.params[0].typ).set_flag(.generic)
|
||||||
} else {
|
} else {
|
||||||
// note: correct receiver type is automatically set here on struct embed calls
|
|
||||||
call_expr.receiver_type = method.params[0].typ
|
call_expr.receiver_type = method.params[0].typ
|
||||||
}
|
}
|
||||||
call_expr.return_type = method.return_type
|
call_expr.return_type = method.return_type
|
||||||
|
|
|
@ -2768,7 +2768,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||||
if node.expr_type == 0 {
|
if node.expr_type == 0 {
|
||||||
g.checker_bug('unexpected SelectorExpr.expr_type = 0', node.pos)
|
g.checker_bug('unexpected SelectorExpr.expr_type = 0', node.pos)
|
||||||
}
|
}
|
||||||
sym := g.table.get_type_symbol(node.expr_type)
|
sym := g.table.get_type_symbol(g.unwrap_generic(node.expr_type))
|
||||||
// if node expr is a root ident and an optional
|
// if node expr is a root ident and an optional
|
||||||
mut is_optional := node.expr is ast.Ident && node.expr_type.has_flag(.optional)
|
mut is_optional := node.expr is ast.Ident && node.expr_type.has_flag(.optional)
|
||||||
if is_optional {
|
if is_optional {
|
||||||
|
|
|
@ -116,3 +116,35 @@ fn test_embed_mutable() {
|
||||||
mut a := field_publicity.App{}
|
mut a := field_publicity.App{}
|
||||||
a.Context = field_publicity.Context{}
|
a.Context = field_publicity.Context{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
static_files string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (c Context) test() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
Context
|
||||||
|
}
|
||||||
|
|
||||||
|
fn embed_field_access_generic<T>(mut app T) {
|
||||||
|
app.Context = Context{
|
||||||
|
static_files: app.static_files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_embed_field_access_generic() {
|
||||||
|
mut app := App{}
|
||||||
|
embed_field_access_generic(mut app)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn embed_method_generic<T>(app T) bool {
|
||||||
|
return app.test()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_embed_method_generic() {
|
||||||
|
mut app := App{}
|
||||||
|
assert embed_method_generic(app)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue