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
pub fn (mut list DoublyLinkedList<T>) push_back(item T) {
mut new_node := &DoublyListNode{
mut new_node := &DoublyListNode<T>{
data: item
}
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
pub fn (mut list DoublyLinkedList<T>) push_front(item T) {
mut new_node := &DoublyListNode{
mut new_node := &DoublyListNode<T>{
data: item
}
if list.is_empty() {
@ -149,7 +149,7 @@ fn (mut list DoublyLinkedList<T>) insert_back(idx int, item T) {
// |next|---->|next|
// |prev|<----|prev|
// ------ ------
new := &DoublyListNode{
new := &DoublyListNode<T>{
data: item
next: node
prev: prev
@ -176,7 +176,7 @@ fn (mut list DoublyLinkedList<T>) insert_front(idx int, item T) {
// |next|---->|next|
// |prev|<----|prev|
// ------ ------
new := &DoublyListNode{
new := &DoublyListNode<T>{
data: item
next: next
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
pub fn (mut list LinkedList<T>) push(item T) {
new_node := &ListNode{
new_node := &ListNode<T>{
data: item
}
if list.head == 0 {
@ -124,7 +124,7 @@ pub fn (mut list LinkedList<T>) insert(idx int, item T) ? {
if idx == 0 {
// first node case
list.head = &ListNode{
list.head = &ListNode<T>{
data: item
next: node
}
@ -132,7 +132,7 @@ pub fn (mut list LinkedList<T>) insert(idx int, item T) ? {
for i := 0; i < idx - 1; i++ {
node = node.next
}
node.next = &ListNode{
node.next = &ListNode<T>{
data: item
next: node.next
}

View File

@ -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

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)
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<int>',
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<int>',
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 {
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")
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> {
g := Generic{
g := Generic<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{
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
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
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
}

View File

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