checker: fix generic structs init (#10134)
parent
906b207e58
commit
492d264d08
|
@ -609,6 +609,56 @@ pub fn (mut c Checker) struct_decl(mut decl ast.StructDecl) {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) unwrap_generics_struct_init(struct_type ast.Type) ast.Type {
|
||||
ts := c.table.get_type_symbol(struct_type)
|
||||
if ts.info is ast.Struct {
|
||||
if ts.info.is_generic {
|
||||
mut nrt := '$ts.name<'
|
||||
mut c_nrt := '${ts.name}_T_'
|
||||
for i in 0 .. ts.info.generic_types.len {
|
||||
gts := c.table.get_type_symbol(c.unwrap_generic(ts.info.generic_types[i]))
|
||||
nrt += gts.name
|
||||
c_nrt += gts.name
|
||||
if i != ts.info.generic_types.len - 1 {
|
||||
nrt += ','
|
||||
c_nrt += '_'
|
||||
}
|
||||
}
|
||||
nrt += '>'
|
||||
idx := c.table.type_idxs[nrt]
|
||||
if idx != 0 && c.table.type_symbols[idx].kind != .placeholder {
|
||||
return ast.new_type(idx).derive(struct_type).clear_flag(.generic)
|
||||
} else {
|
||||
mut fields := ts.info.fields.clone()
|
||||
if ts.info.generic_types.len == c.cur_concrete_types.len {
|
||||
generic_names := ts.info.generic_types.map(c.table.get_type_symbol(it).name)
|
||||
for i in 0 .. fields.len {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(fields[i].typ,
|
||||
generic_names, c.cur_concrete_types, true)
|
||||
{
|
||||
fields[i].typ = t_typ
|
||||
}
|
||||
}
|
||||
mut info := ts.info
|
||||
info.is_generic = false
|
||||
info.concrete_types = c.cur_concrete_types.clone()
|
||||
info.parent_type = struct_type
|
||||
info.fields = fields
|
||||
stru_idx := c.table.register_type_symbol(ast.TypeSymbol{
|
||||
kind: .struct_
|
||||
name: nrt
|
||||
cname: util.no_dots(c_nrt)
|
||||
mod: c.mod
|
||||
info: info
|
||||
})
|
||||
return ast.new_type(stru_idx).derive(struct_type).clear_flag(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return struct_type
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
||||
// typ := c.table.find_type(struct_init.typ.typ.name) or {
|
||||
// c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
|
||||
|
@ -627,7 +677,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
|||
struct_init.typ = c.expected_type
|
||||
}
|
||||
}
|
||||
utyp := c.unwrap_generic(struct_init.typ)
|
||||
utyp := c.unwrap_generics_struct_init(struct_init.typ)
|
||||
c.ensure_type_exists(utyp, struct_init.pos) or {}
|
||||
type_sym := c.table.get_type_symbol(utyp)
|
||||
if !c.inside_unsafe && type_sym.kind == .sum_type {
|
||||
|
@ -757,7 +807,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
|||
if is_embed {
|
||||
expected_type = embed_type
|
||||
c.expected_type = expected_type
|
||||
expr_type = c.expr(field.expr)
|
||||
expr_type = c.unwrap_generic(c.expr(field.expr))
|
||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||
if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
|
||||
c.check_expected(expr_type, embed_type) or {
|
||||
|
@ -772,7 +822,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
|||
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||
expected_type = info_field.typ
|
||||
c.expected_type = expected_type
|
||||
expr_type = c.expr(field.expr)
|
||||
expr_type = c.unwrap_generic(c.expr(field.expr))
|
||||
if !info_field.typ.has_flag(.optional) {
|
||||
expr_type = c.check_expr_opt_call(field.expr, expr_type)
|
||||
}
|
||||
|
@ -882,7 +932,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
|||
c.error('expression is not an lvalue', struct_init.update_expr.position())
|
||||
}
|
||||
}
|
||||
return struct_init.typ
|
||||
return utyp
|
||||
}
|
||||
|
||||
fn (mut c Checker) check_div_mod_by_zero(expr ast.Expr, op_kind token.Kind) {
|
||||
|
@ -2930,7 +2980,14 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) ast.Typ
|
|||
// TODO: non deferred
|
||||
pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
||||
c.expected_type = c.table.cur_fn.return_type
|
||||
expected_type := c.unwrap_generic(c.expected_type)
|
||||
mut expected_type := c.unwrap_generic(c.expected_type)
|
||||
if expected_type.has_flag(.generic) && c.table.get_type_symbol(expected_type).kind == .struct_ {
|
||||
if t_typ := c.table.resolve_generic_to_concrete(expected_type, c.table.cur_fn.generic_names,
|
||||
c.cur_concrete_types, true)
|
||||
{
|
||||
expected_type = t_typ
|
||||
}
|
||||
}
|
||||
expected_type_sym := c.table.get_type_symbol(expected_type)
|
||||
if return_stmt.exprs.len > 0 && c.table.cur_fn.return_type == ast.void_type {
|
||||
c.error('unexpected argument, current function does not return anything', return_stmt.exprs[0].position())
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
vlib/v/checker/tests/check_generic_int_init.vv:2:9: error: type `int` is private
|
||||
1 | fn test<T>() T {
|
||||
2 | return T{}
|
||||
| ~~~
|
||||
3 | }
|
||||
4 |
|
|
@ -1,7 +0,0 @@
|
|||
fn test<T>() T {
|
||||
return T{}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
_ := test<int>()
|
||||
}
|
|
@ -12,3 +12,10 @@ vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:32:1: error: g
|
|||
| ~~~~~~~~~~~~~~
|
||||
33 | println("hi")
|
||||
34 | }
|
||||
vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv:21:14: error: cannot use `Generic<Concrete>` as `Generic<T>` in argument 1 to `g_worker`
|
||||
19 | }
|
||||
20 |
|
||||
21 | go g_worker(g)
|
||||
| ^
|
||||
22 |
|
||||
23 | return g
|
||||
|
|
|
@ -5,3 +5,9 @@ vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv:13:32: error: retu
|
|||
| ~~~~~~~~~~~~~~~~~~~~
|
||||
14 | d := GenericChannelStruct{
|
||||
15 | ch: chan T{}
|
||||
vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv:17:9: error: cannot use `GenericChannelStruct<Simple>` as type `GenericChannelStruct` in return argument
|
||||
15 | ch: chan T{}
|
||||
16 | }
|
||||
17 | return d
|
||||
| ^
|
||||
18 | }
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
struct List<T> {
|
||||
mut:
|
||||
count u32
|
||||
first &ListNode<T>
|
||||
last &ListNode<T>
|
||||
}
|
||||
|
||||
struct ListNode<T> {
|
||||
mut:
|
||||
val T
|
||||
next &ListNode<T> = 0
|
||||
}
|
||||
|
||||
fn create<T>(arr []T) &List<T> {
|
||||
assert arr.len > 0
|
||||
mut n := &ListNode{
|
||||
val: arr[0]
|
||||
next: 0
|
||||
}
|
||||
mut l := &List{
|
||||
first: n
|
||||
last: n
|
||||
count: 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
fn test_generics_with_generic_structs_init() {
|
||||
n := create([1, 2, 3])
|
||||
println(n)
|
||||
assert n.count == 1
|
||||
}
|
Loading…
Reference in New Issue