From 4be3c926407bdbd27b9ac5989dbd24aab9c19041 Mon Sep 17 00:00:00 2001 From: yuyi Date: Wed, 9 Feb 2022 20:06:45 +0800 Subject: [PATCH] checker: check generic struct init without type parameter (#13404) --- vlib/datatypes/doubly_linked_list.v | 8 ++-- vlib/datatypes/linked_list.v | 6 +-- vlib/v/ast/ast.v | 7 ++-- vlib/v/checker/struct.v | 11 +++-- ...eric_fn_decl_without_generic_names_err.out | 8 +--- ...neric_fn_decl_without_generic_names_err.vv | 2 +- .../generics_fn_return_generic_struct_err.out | 7 ++++ .../tests/generics_struct_init_err.out | 42 +++++++++++++++++++ vlib/v/parser/struct.v | 1 + .../tests/generics_struct_anon_fn_type_test.v | 12 +++--- 10 files changed, 77 insertions(+), 27 deletions(-) diff --git a/vlib/datatypes/doubly_linked_list.v b/vlib/datatypes/doubly_linked_list.v index 450e31420c..d489b807d0 100644 --- a/vlib/datatypes/doubly_linked_list.v +++ b/vlib/datatypes/doubly_linked_list.v @@ -46,7 +46,7 @@ pub fn (list DoublyLinkedList) last() ?T { // push_back adds an element to the end of the linked list pub fn (mut list DoublyLinkedList) push_back(item T) { - mut new_node := &DoublyListNode{ + mut new_node := &DoublyListNode{ data: item } if list.is_empty() { @@ -63,7 +63,7 @@ pub fn (mut list DoublyLinkedList) push_back(item T) { // push_front adds an element to the beginning of the linked list pub fn (mut list DoublyLinkedList) push_front(item T) { - mut new_node := &DoublyListNode{ + mut new_node := &DoublyListNode{ data: item } if list.is_empty() { @@ -149,7 +149,7 @@ fn (mut list DoublyLinkedList) insert_back(idx int, item T) { // |next|---->|next| // |prev|<----|prev| // ------ ------ - new := &DoublyListNode{ + new := &DoublyListNode{ data: item next: node prev: prev @@ -176,7 +176,7 @@ fn (mut list DoublyLinkedList) insert_front(idx int, item T) { // |next|---->|next| // |prev|<----|prev| // ------ ------ - new := &DoublyListNode{ + new := &DoublyListNode{ data: item next: next prev: node diff --git a/vlib/datatypes/linked_list.v b/vlib/datatypes/linked_list.v index a3b7dc4564..739d027d29 100644 --- a/vlib/datatypes/linked_list.v +++ b/vlib/datatypes/linked_list.v @@ -61,7 +61,7 @@ pub fn (list LinkedList) index(idx int) ?T { // push adds an element to the end of the linked list pub fn (mut list LinkedList) push(item T) { - new_node := &ListNode{ + new_node := &ListNode{ data: item } if list.head == 0 { @@ -124,7 +124,7 @@ pub fn (mut list LinkedList) insert(idx int, item T) ? { if idx == 0 { // first node case - list.head = &ListNode{ + list.head = &ListNode{ data: item next: node } @@ -132,7 +132,7 @@ pub fn (mut list LinkedList) insert(idx int, item T) ? { for i := 0; i < idx - 1; i++ { node = node.next } - node.next = &ListNode{ + node.next = &ListNode{ data: item next: node.next } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 31c947bcd5..0b0dafc78a 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -397,9 +397,10 @@ pub mut: pub struct StructInit { pub: - pos token.Pos - name_pos token.Pos - is_short bool + pos token.Pos + name_pos token.Pos + is_short bool + is_short_syntax bool pub mut: unresolved bool pre_comments []Comment diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index c87f24cd68..316c27356c 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -131,9 +131,14 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type { struct_sym := c.table.sym(node.typ) if struct_sym.info is ast.Struct { if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0 - && c.table.cur_concrete_types.len == 0 { - c.error('generic struct init must specify type parameter, e.g. Foo', - node.pos) + && !node.is_short_syntax { + if c.table.cur_concrete_types.len == 0 { + c.error('generic struct init must specify type parameter, e.g. Foo', + node.pos) + } else if node.generic_types.len == 0 { + c.error('generic struct init must specify type parameter, e.g. Foo', + node.pos) + } } if node.generic_types.len > 0 && struct_sym.info.generic_types != node.generic_types { c.table.replace_generic_type(node.typ, node.generic_types) diff --git a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out index 70150abf0e..f94fd49448 100644 --- a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out +++ b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.out @@ -12,10 +12,4 @@ 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:23:9: error: cannot use `Generic` as type `Generic` in return argument - 21 | go g_worker(g) - 22 | - 23 | return g - | ^ - 24 | } - 25 | + diff --git a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv index cc001e9412..f455a3da05 100644 --- a/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv +++ b/vlib/v/checker/tests/generic_fn_decl_without_generic_names_err.vv @@ -14,7 +14,7 @@ fn main() { } fn create_generic_t() Generic { - g := Generic{ + g := Generic{ ch: chan T{} } diff --git a/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out b/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out index 12a579c300..e311bd4f40 100644 --- a/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out +++ b/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out @@ -5,3 +5,10 @@ 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:14:7: error: generic struct init must specify type parameter, e.g. Foo + 12 | + 13 | pub fn new_channel_struct() GenericChannelStruct { + 14 | d := GenericChannelStruct{ + | ~~~~~~~~~~~~~~~~~~~~~ + 15 | ch: chan T{} + 16 | } diff --git a/vlib/v/checker/tests/generics_struct_init_err.out b/vlib/v/checker/tests/generics_struct_init_err.out index c55c33618d..62402f8129 100644 --- a/vlib/v/checker/tests/generics_struct_init_err.out +++ b/vlib/v/checker/tests/generics_struct_init_err.out @@ -12,3 +12,45 @@ vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: generic struct ini | ~~~~~~~~~~~~~~ 68 | assert ret == -6 69 | } +vlib/v/checker/tests/generics_struct_init_err.vv:22:7: error: generic struct init must specify type parameter, e.g. Foo + 20 | + 21 | fn holder_call_1(func T, a int) int { + 22 | h := FnHolder1{func} + | ~~~~~~~~~~~~~~~ + 23 | return h.call(a) + 24 | } +vlib/v/checker/tests/generics_struct_init_err.vv:27:7: error: generic struct init must specify type parameter, e.g. Foo + 25 | + 26 | fn holder_call_2(func T, a int) int { + 27 | h := FnHolder2{func} + | ~~~~~~~~~~~~~~~ + 28 | return h.call(a) + 29 | } +vlib/v/checker/tests/generics_struct_init_err.vv:33:7: error: generic struct init must specify type parameter, e.g. Foo + 31 | fn holder_call_11(func T, a int) int { + 32 | f := func + 33 | h := FnHolder1{f} + | ~~~~~~~~~~~~ + 34 | return h.call(a) + 35 | } +vlib/v/checker/tests/generics_struct_init_err.vv:39:7: error: generic struct init must specify type parameter, e.g. Foo + 37 | fn holder_call_21(func T, a int) int { + 38 | f := func + 39 | h := FnHolder2{f} + | ~~~~~~~~~~~~ + 40 | return h.call(a) + 41 | } +vlib/v/checker/tests/generics_struct_init_err.vv:44:9: error: generic struct init must specify type parameter, e.g. Foo + 42 | + 43 | fn holder_call_12(func T, a int) int { + 44 | return FnHolder1{func}.call(a) + | ~~~~~~~~~~~~~~~ + 45 | } + 46 | +vlib/v/checker/tests/generics_struct_init_err.vv:48:9: error: generic struct init must specify type parameter, e.g. Foo + 46 | + 47 | fn holder_call_22(func T, a int) int { + 48 | return FnHolder2{func}.call(a) + | ~~~~~~~~~~~~~~~ + 49 | } + 50 | diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 12d7ceae57..bce008fa67 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -426,6 +426,7 @@ fn (mut p Parser) struct_init(typ_str string, short_syntax bool) ast.StructInit name_pos: first_pos pos: first_pos.extend(if short_syntax { p.tok.pos() } else { p.prev_tok.pos() }) is_short: no_keys + is_short_syntax: short_syntax pre_comments: pre_comments generic_types: p.struct_init_generic_types } diff --git a/vlib/v/tests/generics_struct_anon_fn_type_test.v b/vlib/v/tests/generics_struct_anon_fn_type_test.v index 0da23114f0..3bdd3d4349 100644 --- a/vlib/v/tests/generics_struct_anon_fn_type_test.v +++ b/vlib/v/tests/generics_struct_anon_fn_type_test.v @@ -19,33 +19,33 @@ fn (self FnHolder2) call(a int) int { } fn holder_call_1(func T, a int) int { - h := FnHolder1{func} + h := FnHolder1{func} return h.call(a) } fn holder_call_2(func T, a int) int { - h := FnHolder2{func} + h := FnHolder2{func} return h.call(a) } fn holder_call_11(func T, a int) int { f := func - h := FnHolder1{f} + h := FnHolder1{f} return h.call(a) } fn holder_call_21(func T, a int) int { f := func - h := FnHolder2{f} + h := FnHolder2{f} return h.call(a) } fn holder_call_12(func T, a int) int { - return FnHolder1{func}.call(a) + return FnHolder1{func}.call(a) } fn holder_call_22(func T, a int) int { - return FnHolder2{func}.call(a) + return FnHolder2{func}.call(a) } fn test_generic_struct_with_anon_fn_parameter() {