cgen: fix embed generic field access & method call (#7725)

pull/7766/head
Daniel Däschle 2020-12-30 23:49:02 +01:00 committed by GitHub
parent b4c5fa8ca0
commit 9a31744255
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 3 deletions

View File

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

View File

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

View File

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