diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index ab3b1f62a2..c65994e35b 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -932,6 +932,8 @@ pub fn (mut c Checker) generic_insts_to_concrete() { typ.is_public = true typ.kind = parent.kind typ.methods = all_methods + } else { + util.verror('generic error', 'the number of generic types of interface `$parent.name` is inconsistent with the concrete types') } } ast.SumType { @@ -968,6 +970,8 @@ pub fn (mut c Checker) generic_insts_to_concrete() { } typ.is_public = true typ.kind = parent.kind + } else { + util.verror('generic error', 'the number of generic types of sumtype `$parent.name` is inconsistent with the concrete types') } } else {} diff --git a/vlib/v/checker/tests/generics_inst_non_generic_struct_err.out b/vlib/v/checker/tests/generics_inst_non_generic_struct_err.out index 8d09c8f676..51e73e1f98 100644 --- a/vlib/v/checker/tests/generics_inst_non_generic_struct_err.out +++ b/vlib/v/checker/tests/generics_inst_non_generic_struct_err.out @@ -1 +1,6 @@ -generic error: struct `main.Test` is not a generic struct, cannot instantiate to the concrete types +vlib/v/checker/tests/generics_inst_non_generic_struct_err.vv:5:14: error: struct `Test` is not a generic struct, cannot instantiate to the concrete types + 3 | + 4 | fn main() { + 5 | println(Test{}) + | ~~~~~~~~ + 6 | } diff --git a/vlib/v/checker/tests/generics_struct_type_mismatch_err.out b/vlib/v/checker/tests/generics_struct_type_mismatch_err.out index 2c7760d6ea..cfbe202aa6 100644 --- a/vlib/v/checker/tests/generics_struct_type_mismatch_err.out +++ b/vlib/v/checker/tests/generics_struct_type_mismatch_err.out @@ -1 +1,7 @@ -generic error: the number of generic types of struct `main.Example` is inconsistent with the concrete types +vlib/v/checker/tests/generics_struct_type_mismatch_err.vv:7:20: error: the number of generic types of struct `Example` is inconsistent with the concrete types + 5 | + 6 | fn main() { + 7 | example := Example{ + | ~~~~~~~~ + 8 | key: 'key' + 9 | value: 'value' diff --git a/vlib/v/fmt/tests/generics_keep.vv b/vlib/v/fmt/tests/generics_keep.vv index 4fe55e76b3..303029a962 100644 --- a/vlib/v/fmt/tests/generics_keep.vv +++ b/vlib/v/fmt/tests/generics_keep.vv @@ -14,12 +14,6 @@ fn (_ Foo) simple() T { return T{} } -struct NonGenericStruct {} - -fn use_as_generic(ngs NonGenericStruct) NonGenericStruct { - return NonGenericStruct{} -} - struct GenericStruct {} fn proper_generics(gs GenericStruct) GenericStruct { diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 201ac927fc..33255a28f6 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -539,6 +539,7 @@ pub fn (mut p Parser) parse_generic_type(name string) ast.Type { pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type { mut bs_name := name mut bs_cname := name + start_pos := p.tok.position() p.next() p.in_generic_params = true bs_name += '<' @@ -561,6 +562,7 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type { bs_name += ', ' bs_cname += '_' } + concrete_types_pos := start_pos.extend(p.tok.position()) p.check(.gt) p.in_generic_params = false bs_name += '>' @@ -575,6 +577,38 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type { if parent_idx == 0 { parent_idx = p.table.add_placeholder_type(name, .v) } + parent_sym := p.table.get_type_symbol(ast.new_type(parent_idx)) + match parent_sym.info { + ast.Struct { + if parent_sym.info.generic_types.len == 0 { + p.error_with_pos('struct `$parent_sym.name` is not a generic struct, cannot instantiate to the concrete types', + concrete_types_pos) + } else if parent_sym.info.generic_types.len != concrete_types.len { + p.error_with_pos('the number of generic types of struct `$parent_sym.name` is inconsistent with the concrete types', + concrete_types_pos) + } + } + ast.Interface { + if parent_sym.info.generic_types.len == 0 { + p.error_with_pos('interface `$parent_sym.name` is not a generic interface, cannot instantiate to the concrete types', + concrete_types_pos) + } else if parent_sym.info.generic_types.len != concrete_types.len { + p.error_with_pos('the number of generic types of interfce `$parent_sym.name` is inconsistent with the concrete types', + concrete_types_pos) + } + } + ast.SumType { + if parent_sym.info.generic_types.len == 0 { + p.error_with_pos('sumtype `$parent_sym.name` is not a generic sumtype, cannot instantiate to the concrete types', + concrete_types_pos) + } else if parent_sym.info.generic_types.len != concrete_types.len { + p.error_with_pos('the number of generic types of sumtype `$parent_sym.name` is inconsistent with the concrete types', + concrete_types_pos) + } + } + else {} + } + idx := p.table.register_type_symbol(ast.TypeSymbol{ kind: .generic_inst name: bs_name