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 has_method := false
|
||||
mut is_method_from_embed := false
|
||||
if m := c.table.type_find_method(left_type_sym, method_name) {
|
||||
method = m
|
||||
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 {
|
||||
method = found_methods[0]
|
||||
has_method = true
|
||||
is_method_from_embed = true
|
||||
call_expr.from_embed_type = embed_of_found_methods[0]
|
||||
} else if found_methods.len > 1 {
|
||||
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
|
||||
}
|
||||
}
|
||||
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.
|
||||
// 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)
|
||||
} else {
|
||||
// note: correct receiver type is automatically set here on struct embed calls
|
||||
call_expr.receiver_type = method.params[0].typ
|
||||
}
|
||||
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 {
|
||||
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
|
||||
mut is_optional := node.expr is ast.Ident && node.expr_type.has_flag(.optional)
|
||||
if is_optional {
|
||||
|
|
|
@ -116,3 +116,35 @@ fn test_embed_mutable() {
|
|||
mut a := field_publicity.App{}
|
||||
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