Skip to content

Commit 914169e

Browse files
authored
checker: fix missing check for generic array type without concrete types (fix #22414) (#22416)
1 parent 0073f09 commit 914169e

File tree

4 files changed

+72
-9
lines changed

4 files changed

+72
-9
lines changed

vlib/v/checker/checker.v

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4988,7 +4988,7 @@ fn (mut c Checker) fetch_field_name(field ast.StructField) string {
49884988
return name
49894989
}
49904990

4991-
fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos) bool {
4991+
fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos, is_container bool) bool {
49924992
if typ == 0 {
49934993
c.error('unknown type', pos)
49944994
return false
@@ -5014,39 +5014,47 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke
50145014
match sym.kind {
50155015
.function {
50165016
fn_info := sym.info as ast.FnType
5017-
if !c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos) {
5017+
if !c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos,
5018+
is_container) {
50185019
return false
50195020
}
50205021
for param in fn_info.func.params {
5021-
if !c.ensure_generic_type_specify_type_names(param.typ, param.type_pos) {
5022+
if !c.ensure_generic_type_specify_type_names(param.typ, param.type_pos,
5023+
is_container) {
50225024
return false
50235025
}
50245026
}
5027+
if fn_info.func.generic_names.len > 0 && !typ.has_flag(.generic) {
5028+
c.error('`${sym.name}` type is generic fn type, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',
5029+
pos)
5030+
return false
5031+
}
50255032
}
50265033
.array {
50275034
if !c.ensure_generic_type_specify_type_names((sym.info as ast.Array).elem_type,
5028-
pos) {
5035+
pos, true) {
50295036
return false
50305037
}
50315038
}
50325039
.array_fixed {
50335040
if !c.ensure_generic_type_specify_type_names((sym.info as ast.ArrayFixed).elem_type,
5034-
pos) {
5041+
pos, true) {
50355042
return false
50365043
}
50375044
}
50385045
.map {
50395046
info := sym.info as ast.Map
5040-
if !c.ensure_generic_type_specify_type_names(info.key_type, pos) {
5047+
if !c.ensure_generic_type_specify_type_names(info.key_type, pos, true) {
50415048
return false
50425049
}
5043-
if !c.ensure_generic_type_specify_type_names(info.value_type, pos) {
5050+
if !c.ensure_generic_type_specify_type_names(info.value_type, pos, true) {
50445051
return false
50455052
}
50465053
}
50475054
.sum_type {
50485055
info := sym.info as ast.SumType
5049-
if info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 {
5056+
if info.generic_types.len > 0 && (is_container || !typ.has_flag(.generic))
5057+
&& info.concrete_types.len == 0 {
50505058
c.error('`${sym.name}` type is generic sumtype, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',
50515059
pos)
50525060
return false
@@ -5068,6 +5076,12 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke
50685076
return false
50695077
}
50705078
}
5079+
.alias {
5080+
info := sym.info as ast.Alias
5081+
if !c.ensure_generic_type_specify_type_names(info.parent_type, pos, is_container) {
5082+
return false
5083+
}
5084+
}
50715085
else {}
50725086
}
50735087
return true

vlib/v/checker/struct.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
158158
if !c.ensure_type_exists(field.typ, field.type_pos) {
159159
continue
160160
}
161-
if !c.ensure_generic_type_specify_type_names(field.typ, field.type_pos) {
161+
if !c.ensure_generic_type_specify_type_names(field.typ, field.type_pos, false) {
162162
continue
163163
}
164164
if field.typ.has_flag(.generic) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
vlib/v/checker/tests/generics_field_struct_arr_err.vv:26:7: error: `Callback` type is generic sumtype, must specify the generic type names, e.g. Callback[T], Callback[int]
2+
24 | v T
3+
25 | prev T
4+
26 | cb []Callback // sumtype
5+
| ~~~~~~~~~~
6+
27 | cb2 []CBvret2 // alias
7+
28 | cb3 []Test // struct
8+
vlib/v/checker/tests/generics_field_struct_arr_err.vv:27:7: error: `CBvret2` type is generic fn type, must specify the generic type names, e.g. CBvret2[T], CBvret2[int]
9+
25 | prev T
10+
26 | cb []Callback // sumtype
11+
27 | cb2 []CBvret2 // alias
12+
| ~~~~~~~~~
13+
28 | cb3 []Test // struct
14+
29 | }
15+
vlib/v/checker/tests/generics_field_struct_arr_err.vv:28:7: error: `Test` type is generic struct, must specify the generic type names, e.g. Test[T], Test[int]
16+
26 | cb []Callback // sumtype
17+
27 | cb2 []CBvret2 // alias
18+
28 | cb3 []Test // struct
19+
| ~~~~~~
20+
29 | }
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// callback types
2+
type CBnoret[T] = fn (val T)
3+
4+
type CBnoret2[T] = fn (val T, prev T)
5+
6+
type CBvret[T] = fn (val T) T
7+
8+
type CBvret2[T] = fn (val T, prev T) T
9+
10+
type Callback[T] = CBnoret[T] | CBnoret2[T] | CBvret[T] | CBvret2[T]
11+
12+
interface IObv[T] {
13+
v T
14+
prev T
15+
cb []Callback[T]
16+
}
17+
18+
struct Test[T] {
19+
a T
20+
}
21+
22+
struct Obv[T] {
23+
mut:
24+
v T
25+
prev T
26+
cb []Callback // sumtype
27+
cb2 []CBvret2 // alias
28+
cb3 []Test // struct
29+
}

0 commit comments

Comments
 (0)