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 {
|
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 {
|
// typ := c.table.find_type(struct_init.typ.typ.name) or {
|
||||||
// c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
|
// 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
|
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 {}
|
c.ensure_type_exists(utyp, struct_init.pos) or {}
|
||||||
type_sym := c.table.get_type_symbol(utyp)
|
type_sym := c.table.get_type_symbol(utyp)
|
||||||
if !c.inside_unsafe && type_sym.kind == .sum_type {
|
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 {
|
if is_embed {
|
||||||
expected_type = embed_type
|
expected_type = embed_type
|
||||||
c.expected_type = expected_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)
|
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||||
if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
|
if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
|
||||||
c.check_expected(expr_type, embed_type) or {
|
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)
|
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||||
expected_type = info_field.typ
|
expected_type = info_field.typ
|
||||||
c.expected_type = expected_type
|
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) {
|
if !info_field.typ.has_flag(.optional) {
|
||||||
expr_type = c.check_expr_opt_call(field.expr, expr_type)
|
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())
|
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) {
|
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
|
// TODO: non deferred
|
||||||
pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
||||||
c.expected_type = c.table.cur_fn.return_type
|
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)
|
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 {
|
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())
|
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")
|
33 | println("hi")
|
||||||
34 | }
|
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{
|
14 | d := GenericChannelStruct{
|
||||||
15 | ch: chan T{}
|
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