1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check generic interface type specifing type names (fix #16576) (#16591)

This commit is contained in:
yuyi 2022-12-05 16:05:32 +08:00 committed by GitHub
parent 349ce08a11
commit 59c979c8d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 6 deletions

View File

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

View File

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

View File

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

View File

@ -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<T> {
mut:
add(Entity, T)
}
pub struct ComponentStore<T> {
pub mut:
typ string
// data etc
}
pub fn (mut cs ComponentStore<T>) 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() {
}

View File

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