From 914169ed4b5ecf2c7fe3e156b8c5ec38b0b7bcda Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Mon, 7 Oct 2024 13:49:47 -0300 Subject: [PATCH] checker: fix missing check for generic array type without concrete types (fix #22414) (#22416) --- vlib/v/checker/checker.v | 30 ++++++++++++++----- vlib/v/checker/struct.v | 2 +- .../tests/generics_field_struct_arr_err.out | 20 +++++++++++++ .../tests/generics_field_struct_arr_err.vv | 29 ++++++++++++++++++ 4 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 vlib/v/checker/tests/generics_field_struct_arr_err.out create mode 100644 vlib/v/checker/tests/generics_field_struct_arr_err.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 7b798cbbb..877310773 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4988,7 +4988,7 @@ fn (mut c Checker) fetch_field_name(field ast.StructField) string { return name } -fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos) bool { +fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos, is_container bool) bool { if typ == 0 { c.error('unknown type', pos) return false @@ -5014,39 +5014,47 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke match sym.kind { .function { fn_info := sym.info as ast.FnType - if !c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos) { + if !c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos, + is_container) { return false } for param in fn_info.func.params { - if !c.ensure_generic_type_specify_type_names(param.typ, param.type_pos) { + if !c.ensure_generic_type_specify_type_names(param.typ, param.type_pos, + is_container) { return false } } + if fn_info.func.generic_names.len > 0 && !typ.has_flag(.generic) { + c.error('`${sym.name}` type is generic fn type, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]', + pos) + return false + } } .array { if !c.ensure_generic_type_specify_type_names((sym.info as ast.Array).elem_type, - pos) { + pos, true) { return false } } .array_fixed { if !c.ensure_generic_type_specify_type_names((sym.info as ast.ArrayFixed).elem_type, - pos) { + pos, true) { return false } } .map { info := sym.info as ast.Map - if !c.ensure_generic_type_specify_type_names(info.key_type, pos) { + if !c.ensure_generic_type_specify_type_names(info.key_type, pos, true) { return false } - if !c.ensure_generic_type_specify_type_names(info.value_type, pos) { + if !c.ensure_generic_type_specify_type_names(info.value_type, pos, true) { return false } } .sum_type { info := sym.info as ast.SumType - if info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 { + if info.generic_types.len > 0 && (is_container || !typ.has_flag(.generic)) + && info.concrete_types.len == 0 { c.error('`${sym.name}` type is generic sumtype, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]', pos) return false @@ -5068,6 +5076,12 @@ fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos toke return false } } + .alias { + info := sym.info as ast.Alias + if !c.ensure_generic_type_specify_type_names(info.parent_type, pos, is_container) { + return false + } + } else {} } return true diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index a2e22efb3..7643ce34e 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -158,7 +158,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { if !c.ensure_type_exists(field.typ, field.type_pos) { continue } - if !c.ensure_generic_type_specify_type_names(field.typ, field.type_pos) { + if !c.ensure_generic_type_specify_type_names(field.typ, field.type_pos, false) { continue } if field.typ.has_flag(.generic) { diff --git a/vlib/v/checker/tests/generics_field_struct_arr_err.out b/vlib/v/checker/tests/generics_field_struct_arr_err.out new file mode 100644 index 000000000..04ba01c85 --- /dev/null +++ b/vlib/v/checker/tests/generics_field_struct_arr_err.out @@ -0,0 +1,20 @@ +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] + 24 | v T + 25 | prev T + 26 | cb []Callback // sumtype + | ~~~~~~~~~~ + 27 | cb2 []CBvret2 // alias + 28 | cb3 []Test // struct +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] + 25 | prev T + 26 | cb []Callback // sumtype + 27 | cb2 []CBvret2 // alias + | ~~~~~~~~~ + 28 | cb3 []Test // struct + 29 | } +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] + 26 | cb []Callback // sumtype + 27 | cb2 []CBvret2 // alias + 28 | cb3 []Test // struct + | ~~~~~~ + 29 | } diff --git a/vlib/v/checker/tests/generics_field_struct_arr_err.vv b/vlib/v/checker/tests/generics_field_struct_arr_err.vv new file mode 100644 index 000000000..58c651f83 --- /dev/null +++ b/vlib/v/checker/tests/generics_field_struct_arr_err.vv @@ -0,0 +1,29 @@ +// callback types +type CBnoret[T] = fn (val T) + +type CBnoret2[T] = fn (val T, prev T) + +type CBvret[T] = fn (val T) T + +type CBvret2[T] = fn (val T, prev T) T + +type Callback[T] = CBnoret[T] | CBnoret2[T] | CBvret[T] | CBvret2[T] + +interface IObv[T] { + v T + prev T + cb []Callback[T] +} + +struct Test[T] { + a T +} + +struct Obv[T] { +mut: + v T + prev T + cb []Callback // sumtype + cb2 []CBvret2 // alias + cb3 []Test // struct +} -- 2.39.5