checker: fix generics fn return generic interface (fix #10818) (#10831)

pull/10851/head
yuyi 2021-07-18 13:55:19 +08:00 committed by GitHub
parent 11a7899690
commit 8b8f496762
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 9 deletions

View File

@ -2991,8 +2991,12 @@ fn (mut c Checker) resolve_generic_interface(typ ast.Type, interface_type ast.Ty
typ_sym.find_method_with_generic_parent(imethod.name) or { ast.Fn{} }
}
if imethod.return_type.has_flag(.generic) {
if method.return_type !in inferred_types {
inferred_types << method.return_type
mut inferred_type := method.return_type
if imethod.return_type.has_flag(.optional) {
inferred_type = inferred_type.clear_flag(.optional)
}
if inferred_type !in inferred_types {
inferred_types << inferred_type
}
}
for i, iparam in imethod.params {
@ -3362,6 +3366,33 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
}
}
}
if typ.has_flag(.generic) && !has_field {
gs := c.table.get_type_symbol(typ)
if f := c.table.find_field(gs, field_name) {
has_field = true
field = f
} else {
// look for embedded field
if gs.info is ast.Struct {
mut found_fields := []ast.StructField{}
mut embed_of_found_fields := []ast.Type{}
for embed in gs.info.embeds {
embed_sym := c.table.get_type_symbol(embed)
if f := c.table.find_field(embed_sym, field_name) {
found_fields << f
embed_of_found_fields << embed
}
}
if found_fields.len == 1 {
field = found_fields[0]
has_field = true
node.from_embed_type = embed_of_found_fields[0]
} else if found_fields.len > 1 {
c.error('ambiguous field `$field_name`', node.pos)
}
}
}
}
}
if has_field {
if sym.mod != c.mod && !field.is_pub && sym.language != .c {

View File

@ -5,13 +5,6 @@ vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:26:1: error: g
| ~~~~~~~~~~~~~~~~~~~~~~~~~
27 | t := <-g.ch
28 | handle(t)
vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:27:7: error: <- operator can only be used with `chan` types
25 |
26 | fn g_worker(g Generic<T>) {
27 | t := <-g.ch
| ~~
28 | handle(t)
29 | // println("${t.msg}")
vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:32:1: error: generic function declaration must specify generic type names, e.g. foo<T>
30 | }
31 |

View File

@ -0,0 +1,28 @@
interface Iter<T> {
next() ?T
}
struct ArrayIter<T> {
data []T
}
fn (mut i ArrayIter<T>) next<T>() ?T {
if i.data.len == 0 {
return none
}
return i.data[0]
}
fn iter<T>(arr []T) Iter<T> {
return ArrayIter<T>{
data: arr
}
}
fn test_generics_fn_return_generic_interface() {
x := iter([1, 2, 3])
println(x)
y := x.next() or { 0 }
println(y)
assert y == 1
}