diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 81534a6848..1a6bb3c36f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4120,6 +4120,58 @@ fn (mut c Checker) trace(fbase string, message string) { } } +fn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos) ? { + if typ == 0 { + c.error('unknown type', pos) + return + } + sym := c.table.final_sym(typ) + match sym.kind { + .function { + fn_info := sym.info as ast.FnType + c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos)? + for param in fn_info.func.params { + c.ensure_generic_type_specify_type_names(param.typ, param.type_pos)? + } + } + .array { + c.ensure_generic_type_specify_type_names((sym.info as ast.Array).elem_type, + pos)? + } + .array_fixed { + c.ensure_generic_type_specify_type_names((sym.info as ast.ArrayFixed).elem_type, + pos)? + } + .map { + info := sym.info as ast.Map + c.ensure_generic_type_specify_type_names(info.key_type, pos)? + c.ensure_generic_type_specify_type_names(info.value_type, pos)? + } + .sum_type { + info := sym.info as ast.SumType + if info.generic_types.len > 0 && !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) + } + } + .struct_ { + info := sym.info as ast.Struct + if info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 { + c.error('`${sym.name}` type is generic struct, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]', + pos) + } + } + .interface_ { + info := sym.info as ast.Interface + if info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 { + c.error('`${sym.name}` type is generic interface, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]', + pos) + } + } + else {} + } +} + fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) ? { if typ == 0 { c.error('unknown type', pos) diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 0c021c6b3d..a60002c40e 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -52,6 +52,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { c.error('struct field does not support storing result', field.optional_pos) } c.ensure_type_exists(field.typ, field.type_pos) or { return } + c.ensure_generic_type_specify_type_names(field.typ, field.type_pos) or { return } if field.typ.has_flag(.generic) { has_generic_types = true } @@ -77,11 +78,6 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { if info.is_heap && !field.typ.is_ptr() { struct_sym.info.is_heap = true } - if info.generic_types.len > 0 && !field.typ.has_flag(.generic) - && info.concrete_types.len == 0 { - c.error('field `${field.name}` type is generic struct, must specify the generic type names, e.g. Foo[T], Foo[int]', - field.type_pos) - } } if sym.kind == .multi_return { c.error('cannot use multi return as field type', field.type_pos) diff --git a/vlib/v/checker/tests/generics_interface_field_type_err.out b/vlib/v/checker/tests/generics_interface_field_type_err.out new file mode 100644 index 0000000000..8edd2e6253 --- /dev/null +++ b/vlib/v/checker/tests/generics_interface_field_type_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generics_interface_field_type_err.vv:34:18: error: `IComponentStore` type is generic interface, must specify the generic type names, e.g. IComponentStore[T], IComponentStore[int] + 32 | struct Registry { + 33 | pub mut: + 34 | data map[string]IComponentStore + | ~~~~~~~~~~~~~~~ + 35 | } + 36 | diff --git a/vlib/v/checker/tests/generics_interface_field_type_err.vv b/vlib/v/checker/tests/generics_interface_field_type_err.vv new file mode 100644 index 0000000000..d63124ac13 --- /dev/null +++ b/vlib/v/checker/tests/generics_interface_field_type_err.vv @@ -0,0 +1,45 @@ +module main + +pub struct Entity { +pub: + id u16 +} + +pub struct Position { // other components ie Velocity +pub mut: + x f64 + y f64 + z f64 +} + +pub interface IComponentStore { +mut: + add(Entity, T) +} + +pub struct ComponentStore { +pub mut: + typ string + // data etc +} + +pub fn (mut cs ComponentStore) add(e Entity, value T) { + // index := cs.set.add(e.id) + // cs.instances[index] = value +} + +[heap] +struct Registry { +pub mut: + data map[string]IComponentStore +} + +pub fn registry() &Registry { + mut r := &Registry { + data: map[string]IComponentStore{} + } + return r +} + +fn main() { +} diff --git a/vlib/v/checker/tests/generics_struct_field_type_err.out b/vlib/v/checker/tests/generics_struct_field_type_err.out index ca8b4f5666..97c807a9c2 100644 --- a/vlib/v/checker/tests/generics_struct_field_type_err.out +++ b/vlib/v/checker/tests/generics_struct_field_type_err.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/generics_struct_field_type_err.vv:4:9: error: field `next` type is generic struct, must specify the generic type names, e.g. Foo[T], Foo[int] +vlib/v/checker/tests/generics_struct_field_type_err.vv:4:9: error: `LL` type is generic struct, must specify the generic type names, e.g. LL[T], LL[int] 2 | mut: 3 | value T 4 | next &LL = unsafe { 0 }