checker: infer generic interface type in `i := Interface(Struct<u32>{})`
parent
ae036b6146
commit
b10ff1e41b
|
@ -3369,13 +3369,14 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
|||
// node.expr_type: `Inside`
|
||||
// node.typ: `Outside`
|
||||
node.expr_type = c.expr(node.expr) // type to be casted
|
||||
mut from_type := node.expr_type
|
||||
to_type := node.typ
|
||||
|
||||
mut from_type := node.expr_type
|
||||
from_sym := c.table.sym(from_type)
|
||||
final_from_sym := c.table.final_sym(from_type)
|
||||
to_sym := c.table.sym(to_type) // type to be used as cast
|
||||
final_to_sym := c.table.final_sym(to_type)
|
||||
|
||||
mut to_type := node.typ
|
||||
mut to_sym := c.table.sym(to_type) // type to be used as cast
|
||||
mut final_to_sym := c.table.final_sym(to_type)
|
||||
|
||||
if (to_sym.is_number() && from_sym.name == 'JS.Number')
|
||||
|| (to_sym.is_number() && from_sym.name == 'JS.BigInt')
|
||||
|
@ -3435,6 +3436,14 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
|||
&& !c.inside_unsafe {
|
||||
c.mark_as_referenced(mut &node.expr, true)
|
||||
}
|
||||
if (to_sym.info as ast.Interface).is_generic {
|
||||
inferred_type := c.resolve_generic_interface(from_type, to_type, node.pos)
|
||||
if inferred_type != 0 {
|
||||
to_type = inferred_type
|
||||
to_sym = c.table.sym(to_type)
|
||||
final_to_sym = c.table.final_sym(to_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe {
|
||||
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
|
||||
|
|
|
@ -186,11 +186,27 @@ fn (mut c Checker) resolve_generic_interface(typ ast.Type, interface_type ast.Ty
|
|||
}
|
||||
for imethod in inter_sym.info.methods {
|
||||
method := typ_sym.find_method(imethod.name) or {
|
||||
typ_sym.find_method_with_generic_parent(imethod.name) or { ast.Fn{} }
|
||||
typ_sym.find_method_with_generic_parent(imethod.name) or {
|
||||
c.error('can not find method `$imethod.name` on `$typ_sym.name`, needed for interface: `$inter_sym.name`',
|
||||
pos)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if imethod.return_type.has_flag(.generic) {
|
||||
imret_sym := c.table.sym(imethod.return_type)
|
||||
mret_sym := c.table.sym(method.return_type)
|
||||
if method.return_type == ast.void_type
|
||||
&& imethod.return_type != method.return_type {
|
||||
c.error('interface method `$imethod.name` returns `$imret_sym.name`, but implementation method `$method.name` returns no value',
|
||||
pos)
|
||||
return 0
|
||||
}
|
||||
if imethod.return_type == ast.void_type
|
||||
&& imethod.return_type != method.return_type {
|
||||
c.error('interface method `$imethod.name` returns no value, but implementation method `$method.name` returns `$mret_sym.name`',
|
||||
pos)
|
||||
return 0
|
||||
}
|
||||
if imret_sym.info is ast.MultiReturn && mret_sym.info is ast.MultiReturn {
|
||||
for i, mr_typ in imret_sym.info.types {
|
||||
if mr_typ.has_flag(.generic)
|
||||
|
@ -215,7 +231,8 @@ fn (mut c Checker) resolve_generic_interface(typ ast.Type, interface_type ast.Ty
|
|||
}
|
||||
}
|
||||
if inferred_type == ast.void_type {
|
||||
c.error('could not infer generic type `$gt_name` in interface', pos)
|
||||
c.error('could not infer generic type `$gt_name` in interface `$inter_sym.name`',
|
||||
pos)
|
||||
return interface_type
|
||||
}
|
||||
inferred_types << inferred_type
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
vlib/v/checker/tests/generic_interface_err.vv:9:6: error: generic struct init must specify type parameter, e.g. Foo<int>
|
||||
7 | }
|
||||
8 |
|
||||
9 | s := Struct{7}
|
||||
| ~~~~~~~~~
|
||||
10 | i := Interface(s)
|
||||
vlib/v/checker/tests/generic_interface_err.vv:10:6: error: can not find method `method` on `Struct`, needed for interface: `Interface`
|
||||
8 |
|
||||
9 | s := Struct{7}
|
||||
10 | i := Interface(s)
|
||||
| ~~~~~~~~~~~~
|
|
@ -0,0 +1,10 @@
|
|||
struct Struct<T> {
|
||||
value int
|
||||
}
|
||||
|
||||
interface Interface<T> {
|
||||
method() T
|
||||
}
|
||||
|
||||
s := Struct{7}
|
||||
i := Interface(s)
|
|
@ -4,7 +4,7 @@ vlib/v/checker/tests/interface_generic_err.vv:7:9: error: generic struct init mu
|
|||
7 | what := What{}
|
||||
| ~~~~~~
|
||||
8 | why := Why(what)
|
||||
vlib/v/checker/tests/interface_generic_err.vv:8:8: error: could not infer generic type `T` in interface
|
||||
vlib/v/checker/tests/interface_generic_err.vv:8:8: error: could not infer generic type `T` in interface `Why`
|
||||
6 | // no segfault without generic
|
||||
7 | what := What{}
|
||||
8 | why := Why(what)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
struct Struct<T> {
|
||||
value int
|
||||
x T
|
||||
}
|
||||
|
||||
fn (s Struct<T>) method() T {
|
||||
return s.x + s.x
|
||||
}
|
||||
|
||||
interface Interface<T> {
|
||||
method() T
|
||||
}
|
||||
|
||||
fn test_infer_generic_interface() {
|
||||
s := Struct<u32>{7, 5}
|
||||
println(s)
|
||||
i := Interface(s)
|
||||
println(i)
|
||||
assert i.method() == 10
|
||||
}
|
Loading…
Reference in New Issue