diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 0cf8541d15..dec21f74e8 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -1045,7 +1045,7 @@ pub mut: pub struct GenericInst { pub mut: parent_idx int // idx of the base generic struct - concrete_types []Type // concrete types, e.g. + concrete_types []Type // concrete types, e.g. [int, string] } [minify] @@ -1148,7 +1148,7 @@ pub fn (mytable &Table) type_to_code(t Type) string { } } -// clean type name from generics form. From Type -> Type +// clean type name from generics form. From Type[int] -> Type pub fn (t &Table) clean_generics_type_str(typ Type) string { result := t.type_to_str(typ) return result.all_before('[') @@ -1436,12 +1436,12 @@ pub fn (t &Table) fn_signature_using_aliases(func &Fn, import_aliases map[string } // symbol_name_except_generic return the name of the complete qualified name of the type, -// but without the generic parts. For example, `main.Abc` -> `main.Abc` +// but without the generic parts. For example, `main.Abc[int]` -> `main.Abc` pub fn (t &TypeSymbol) symbol_name_except_generic() string { - // main.Abc + // main.Abc[int] mut embed_name := t.name // remove generic part from name - // main.Abc => main.Abc + // main.Abc[int] => main.Abc if embed_name.contains('[') { embed_name = embed_name.all_before('[') } @@ -1449,10 +1449,10 @@ pub fn (t &TypeSymbol) symbol_name_except_generic() string { } pub fn (t &TypeSymbol) embed_name() string { - // main.Abc => Abc + // main.Abc[int] => Abc[int] mut embed_name := t.name.split('.').last() // remove generic part from name - // Abc => Abc + // Abc[int] => Abc if embed_name.contains('[') { embed_name = embed_name.split('[')[0] } diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index e1c6bb59e7..a4e134156f 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -78,6 +78,12 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { if info.is_heap && !field.typ.is_ptr() { struct_sym.info.is_heap = true } + for ct in info.concrete_types { + ct_sym := c.table.sym(ct) + if ct_sym.kind == .placeholder { + c.error('unknown type `${ct_sym.name}`', 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/struct_field_generic_struct_unknown_type_err.out b/vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.out new file mode 100644 index 0000000000..f9aed83736 --- /dev/null +++ b/vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.vv:9:24: error: unknown type `UnknownType` + 7 | } + 8 | struct MyType { + 9 | a Maybe[UnknownType] + | ^ + 10 | } + 11 | diff --git a/vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.vv b/vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.vv new file mode 100644 index 0000000000..d6ff44c6de --- /dev/null +++ b/vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.vv @@ -0,0 +1,14 @@ +module main + + +pub struct Maybe[T] { + present bool + val T +} +struct MyType { + a Maybe[UnknownType] +} + +fn main() { + _ = MyType {} +}