checker: check generic struct init without type parameter (#13404)

pull/13422/head
yuyi 2022-02-09 20:06:45 +08:00 committed by GitHub
parent 356ccf247f
commit 4be3c92640
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 77 additions and 27 deletions

View File

@ -46,7 +46,7 @@ pub fn (list DoublyLinkedList<T>) last() ?T {
// push_back adds an element to the end of the linked list // push_back adds an element to the end of the linked list
pub fn (mut list DoublyLinkedList<T>) push_back(item T) { pub fn (mut list DoublyLinkedList<T>) push_back(item T) {
mut new_node := &DoublyListNode{ mut new_node := &DoublyListNode<T>{
data: item data: item
} }
if list.is_empty() { if list.is_empty() {
@ -63,7 +63,7 @@ pub fn (mut list DoublyLinkedList<T>) push_back(item T) {
// push_front adds an element to the beginning of the linked list // push_front adds an element to the beginning of the linked list
pub fn (mut list DoublyLinkedList<T>) push_front(item T) { pub fn (mut list DoublyLinkedList<T>) push_front(item T) {
mut new_node := &DoublyListNode{ mut new_node := &DoublyListNode<T>{
data: item data: item
} }
if list.is_empty() { if list.is_empty() {
@ -149,7 +149,7 @@ fn (mut list DoublyLinkedList<T>) insert_back(idx int, item T) {
// |next|---->|next| // |next|---->|next|
// |prev|<----|prev| // |prev|<----|prev|
// ------ ------ // ------ ------
new := &DoublyListNode{ new := &DoublyListNode<T>{
data: item data: item
next: node next: node
prev: prev prev: prev
@ -176,7 +176,7 @@ fn (mut list DoublyLinkedList<T>) insert_front(idx int, item T) {
// |next|---->|next| // |next|---->|next|
// |prev|<----|prev| // |prev|<----|prev|
// ------ ------ // ------ ------
new := &DoublyListNode{ new := &DoublyListNode<T>{
data: item data: item
next: next next: next
prev: node prev: node

View File

@ -61,7 +61,7 @@ pub fn (list LinkedList<T>) index(idx int) ?T {
// push adds an element to the end of the linked list // push adds an element to the end of the linked list
pub fn (mut list LinkedList<T>) push(item T) { pub fn (mut list LinkedList<T>) push(item T) {
new_node := &ListNode{ new_node := &ListNode<T>{
data: item data: item
} }
if list.head == 0 { if list.head == 0 {
@ -124,7 +124,7 @@ pub fn (mut list LinkedList<T>) insert(idx int, item T) ? {
if idx == 0 { if idx == 0 {
// first node case // first node case
list.head = &ListNode{ list.head = &ListNode<T>{
data: item data: item
next: node next: node
} }
@ -132,7 +132,7 @@ pub fn (mut list LinkedList<T>) insert(idx int, item T) ? {
for i := 0; i < idx - 1; i++ { for i := 0; i < idx - 1; i++ {
node = node.next node = node.next
} }
node.next = &ListNode{ node.next = &ListNode<T>{
data: item data: item
next: node.next next: node.next
} }

View File

@ -400,6 +400,7 @@ pub:
pos token.Pos pos token.Pos
name_pos token.Pos name_pos token.Pos
is_short bool is_short bool
is_short_syntax bool
pub mut: pub mut:
unresolved bool unresolved bool
pre_comments []Comment pre_comments []Comment

View File

@ -131,9 +131,14 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
struct_sym := c.table.sym(node.typ) struct_sym := c.table.sym(node.typ)
if struct_sym.info is ast.Struct { if struct_sym.info is ast.Struct {
if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0 if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0
&& c.table.cur_concrete_types.len == 0 { && !node.is_short_syntax {
if c.table.cur_concrete_types.len == 0 {
c.error('generic struct init must specify type parameter, e.g. Foo<int>', c.error('generic struct init must specify type parameter, e.g. Foo<int>',
node.pos) node.pos)
} else if node.generic_types.len == 0 {
c.error('generic struct init must specify type parameter, e.g. Foo<T>',
node.pos)
}
} }
if node.generic_types.len > 0 && struct_sym.info.generic_types != node.generic_types { if node.generic_types.len > 0 && struct_sym.info.generic_types != node.generic_types {
c.table.replace_generic_type(node.typ, node.generic_types) c.table.replace_generic_type(node.typ, node.generic_types)

View File

@ -12,10 +12,4 @@ 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:23:9: error: cannot use `Generic` as type `Generic<Concrete>` in return argument
21 | go g_worker(g)
22 |
23 | return g
| ^
24 | }
25 |

View File

@ -14,7 +14,7 @@ fn main() {
} }
fn create_generic_t<T>() Generic<T> { fn create_generic_t<T>() Generic<T> {
g := Generic{ g := Generic<T>{
ch: chan T{} ch: chan T{}
} }

View File

@ -5,3 +5,10 @@ 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:14:7: error: generic struct init must specify type parameter, e.g. Foo<T>
12 |
13 | pub fn new_channel_struct<T>() GenericChannelStruct {
14 | d := GenericChannelStruct{
| ~~~~~~~~~~~~~~~~~~~~~
15 | ch: chan T{}
16 | }

View File

@ -12,3 +12,45 @@ vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: generic struct ini
| ~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~
68 | assert ret == -6 68 | assert ret == -6
69 | } 69 | }
vlib/v/checker/tests/generics_struct_init_err.vv:22:7: error: generic struct init must specify type parameter, e.g. Foo<T>
20 |
21 | fn holder_call_1<T>(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<T>
25 |
26 | fn holder_call_2<T>(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<T>
31 | fn holder_call_11<T>(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<T>
37 | fn holder_call_21<T>(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<T>
42 |
43 | fn holder_call_12<T>(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<T>
46 |
47 | fn holder_call_22<T>(func T, a int) int {
48 | return FnHolder2{func}.call(a)
| ~~~~~~~~~~~~~~~
49 | }
50 |

View File

@ -426,6 +426,7 @@ fn (mut p Parser) struct_init(typ_str string, short_syntax bool) ast.StructInit
name_pos: first_pos name_pos: first_pos
pos: first_pos.extend(if short_syntax { p.tok.pos() } else { p.prev_tok.pos() }) pos: first_pos.extend(if short_syntax { p.tok.pos() } else { p.prev_tok.pos() })
is_short: no_keys is_short: no_keys
is_short_syntax: short_syntax
pre_comments: pre_comments pre_comments: pre_comments
generic_types: p.struct_init_generic_types generic_types: p.struct_init_generic_types
} }

View File

@ -19,33 +19,33 @@ fn (self FnHolder2<T>) call(a int) int {
} }
fn holder_call_1<T>(func T, a int) int { fn holder_call_1<T>(func T, a int) int {
h := FnHolder1{func} h := FnHolder1<T>{func}
return h.call(a) return h.call(a)
} }
fn holder_call_2<T>(func T, a int) int { fn holder_call_2<T>(func T, a int) int {
h := FnHolder2{func} h := FnHolder2<T>{func}
return h.call(a) return h.call(a)
} }
fn holder_call_11<T>(func T, a int) int { fn holder_call_11<T>(func T, a int) int {
f := func f := func
h := FnHolder1{f} h := FnHolder1<T>{f}
return h.call(a) return h.call(a)
} }
fn holder_call_21<T>(func T, a int) int { fn holder_call_21<T>(func T, a int) int {
f := func f := func
h := FnHolder2{f} h := FnHolder2<T>{f}
return h.call(a) return h.call(a)
} }
fn holder_call_12<T>(func T, a int) int { fn holder_call_12<T>(func T, a int) int {
return FnHolder1{func}.call(a) return FnHolder1<T>{func}.call(a)
} }
fn holder_call_22<T>(func T, a int) int { fn holder_call_22<T>(func T, a int) int {
return FnHolder2{func}.call(a) return FnHolder2<T>{func}.call(a)
} }
fn test_generic_struct_with_anon_fn_parameter() { fn test_generic_struct_with_anon_fn_parameter() {