checker, cgen: fix generics interface method (#10858)
parent
dbba46b349
commit
8e99a018df
vlib/v
|
@ -1470,8 +1470,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
// `array << elm`
|
// `array << elm`
|
||||||
c.check_expr_opt_call(node.right, right_type)
|
c.check_expr_opt_call(node.right, right_type)
|
||||||
node.auto_locked, _ = c.fail_if_immutable(node.left)
|
node.auto_locked, _ = c.fail_if_immutable(node.left)
|
||||||
left_value_type := c.table.value_type(left_type)
|
left_value_type := c.table.value_type(c.unwrap_generic(left_type))
|
||||||
left_value_sym := c.table.get_type_symbol(left_value_type)
|
left_value_sym := c.table.get_type_symbol(c.unwrap_generic(left_value_type))
|
||||||
if left_value_sym.kind == .interface_ {
|
if left_value_sym.kind == .interface_ {
|
||||||
if right_final.kind != .array {
|
if right_final.kind != .array {
|
||||||
// []Animal << Cat
|
// []Animal << Cat
|
||||||
|
@ -1489,8 +1489,9 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
// []T << T or []T << []T
|
// []T << T or []T << []T
|
||||||
if c.check_types(right_type, left_value_type)
|
unwrapped_right_type := c.unwrap_generic(right_type)
|
||||||
|| c.check_types(right_type, left_type) {
|
if c.check_types(unwrapped_right_type, left_value_type)
|
||||||
|
|| c.check_types(unwrapped_right_type, left_type) {
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
c.error('cannot append `$right_sym.name` to `$left_sym.name`', right_pos)
|
c.error('cannot append `$right_sym.name` to `$left_sym.name`', right_pos)
|
||||||
|
|
|
@ -548,7 +548,23 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
if node.receiver_type == 0 {
|
if node.receiver_type == 0 {
|
||||||
g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos)
|
g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos)
|
||||||
}
|
}
|
||||||
unwrapped_rec_type := g.unwrap_generic(node.receiver_type)
|
mut unwrapped_rec_type := node.receiver_type
|
||||||
|
if g.table.cur_fn.generic_names.len > 0 { // in generic fn
|
||||||
|
unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
|
||||||
|
} else { // in non-generic fn
|
||||||
|
sym := g.table.get_type_symbol(node.receiver_type)
|
||||||
|
match sym.info {
|
||||||
|
ast.Struct, ast.Interface, ast.SumType {
|
||||||
|
generic_names := sym.info.generic_types.map(g.table.get_type_symbol(it).name)
|
||||||
|
if utyp := g.table.resolve_generic_to_concrete(node.receiver_type, generic_names,
|
||||||
|
sym.info.concrete_types)
|
||||||
|
{
|
||||||
|
unwrapped_rec_type = utyp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
typ_sym := g.table.get_type_symbol(unwrapped_rec_type)
|
typ_sym := g.table.get_type_symbol(unwrapped_rec_type)
|
||||||
rec_cc_type := g.cc_type(unwrapped_rec_type, false)
|
rec_cc_type := g.cc_type(unwrapped_rec_type, false)
|
||||||
mut receiver_type_name := util.no_dots(rec_cc_type)
|
mut receiver_type_name := util.no_dots(rec_cc_type)
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
interface Iter<T> {
|
||||||
|
next() ?T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut it Iter<T>) collect<T>() []T {
|
||||||
|
mut data := []T{}
|
||||||
|
for {
|
||||||
|
val := it.next() or { break }
|
||||||
|
data << val
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ArrayIter<T> {
|
||||||
|
data []T
|
||||||
|
mut:
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut it ArrayIter<T>) next<T>() ?T {
|
||||||
|
if it.index >= it.data.len {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
defer {
|
||||||
|
it.index++
|
||||||
|
}
|
||||||
|
return it.data[it.index]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generics_interface_method() {
|
||||||
|
mut iter := Iter<int>(ArrayIter<int>{
|
||||||
|
data: [1, 2, 3]
|
||||||
|
})
|
||||||
|
assert iter.collect() == [1, 2, 3]
|
||||||
|
}
|
Loading…
Reference in New Issue