diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 5c5cd3943d..6c52ca292c 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1166,6 +1166,7 @@ pub: name string is_pub bool pos token.Pos + name_pos token.Pos comments []Comment typ Type generic_types []Type diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 28a24fb855..fb47ebc287 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -493,9 +493,26 @@ pub fn (mut c Checker) sum_type_decl(node ast.SumTypeDecl) { } else if sym.kind == .struct_ && sym.language == .js { c.error('sum type cannot hold an JS struct', variant.pos) } else if mut sym.info is ast.Struct { - if sym.info.is_generic && !variant.typ.has_flag(.generic) { - c.error('generic struct `$sym.name` must specify generic type names, e.g. Foo', - variant.pos) + if sym.info.is_generic { + if !variant.typ.has_flag(.generic) { + c.error('generic struct `$sym.name` must specify generic type names, e.g. Foo', + variant.pos) + } + if node.generic_types.len == 0 { + c.error('generic sumtype `$node.name` must specify generic type names, e.g. Foo', + node.name_pos) + } else { + for typ in sym.info.generic_types { + if typ !in node.generic_types { + sumtype_type_names := node.generic_types.map(c.table.type_to_str(it)).join(', ') + generic_sumtype_name := '$node.name<$sumtype_type_names>' + variant_type_names := sym.info.generic_types.map(c.table.type_to_str(it)).join(', ') + generic_variant_name := '$sym.name<$variant_type_names>' + c.error('generic type name `${c.table.sym(typ).name}` of generic struct `$generic_variant_name` is not mentioned in sumtype `$generic_sumtype_name`', + variant.pos) + } + } + } } } diff --git a/vlib/v/checker/tests/generic_sumtype_decl_err.out b/vlib/v/checker/tests/generic_sumtype_decl_err_a.out similarity index 50% rename from vlib/v/checker/tests/generic_sumtype_decl_err.out rename to vlib/v/checker/tests/generic_sumtype_decl_err_a.out index 7d3ce8f664..12fac1ed81 100644 --- a/vlib/v/checker/tests/generic_sumtype_decl_err.out +++ b/vlib/v/checker/tests/generic_sumtype_decl_err_a.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/generic_sumtype_decl_err.vv:7:24: error: generic struct `Just` must specify generic type names, e.g. Foo +vlib/v/checker/tests/generic_sumtype_decl_err_a.vv:7:24: error: generic struct `Just` must specify generic type names, e.g. Foo 5 | struct Nothing {} 6 | 7 | type Maybe = Nothing | Just diff --git a/vlib/v/checker/tests/generic_sumtype_decl_err.vv b/vlib/v/checker/tests/generic_sumtype_decl_err_a.vv similarity index 100% rename from vlib/v/checker/tests/generic_sumtype_decl_err.vv rename to vlib/v/checker/tests/generic_sumtype_decl_err_a.vv diff --git a/vlib/v/checker/tests/generic_sumtype_decl_err_b.out b/vlib/v/checker/tests/generic_sumtype_decl_err_b.out new file mode 100644 index 0000000000..4920a990c7 --- /dev/null +++ b/vlib/v/checker/tests/generic_sumtype_decl_err_b.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generic_sumtype_decl_err_b.vv:7:6: error: generic sumtype `Maybe` must specify generic type names, e.g. Foo + 5 | struct Nothing {} + 6 | + 7 | type Maybe = Nothing | Just + | ~~~~~ + 8 | + 9 | fn main() { diff --git a/vlib/v/checker/tests/generic_sumtype_decl_err_b.vv b/vlib/v/checker/tests/generic_sumtype_decl_err_b.vv new file mode 100644 index 0000000000..49873c3b4c --- /dev/null +++ b/vlib/v/checker/tests/generic_sumtype_decl_err_b.vv @@ -0,0 +1,10 @@ +struct Just { + value T +} + +struct Nothing {} + +type Maybe = Nothing | Just + +fn main() { +} diff --git a/vlib/v/checker/tests/generic_sumtype_decl_err_c.out b/vlib/v/checker/tests/generic_sumtype_decl_err_c.out new file mode 100644 index 0000000000..e0965959b9 --- /dev/null +++ b/vlib/v/checker/tests/generic_sumtype_decl_err_c.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generic_sumtype_decl_err_c.vv:7:27: error: generic type name `T` of generic struct `Just` is not mentioned in sumtype `Maybe` + 5 | struct Nothing {} + 6 | + 7 | type Maybe = Nothing | Just + | ~~~~~~~ + 8 | + 9 | fn main() { diff --git a/vlib/v/checker/tests/generic_sumtype_decl_err_c.vv b/vlib/v/checker/tests/generic_sumtype_decl_err_c.vv new file mode 100644 index 0000000000..99ec38cf7c --- /dev/null +++ b/vlib/v/checker/tests/generic_sumtype_decl_err_c.vv @@ -0,0 +1,10 @@ +struct Just { + value T +} + +struct Nothing {} + +type Maybe = Nothing | Just + +fn main() { +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index bde17cebc7..0656b53624 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -3672,6 +3672,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl { generic_types: generic_types attrs: p.attrs pos: decl_pos + name_pos: name_pos comments: comments } }