From fa66183f432119c9d8fdac1e755d3eb1ea190205 Mon Sep 17 00:00:00 2001 From: yuyi Date: Mon, 11 Apr 2022 15:07:23 +0800 Subject: [PATCH] checker: check error for map of generic struct init (#13999) --- vlib/v/checker/containers.v | 16 ++++++++++++++++ .../tests/map_of_generic_struct_init_err.out | 6 ++++++ .../tests/map_of_generic_struct_init_err.vv | 7 +++++++ vlib/v/parser/parser.v | 4 +++- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 vlib/v/checker/tests/map_of_generic_struct_init_err.out create mode 100644 vlib/v/checker/tests/map_of_generic_struct_init_err.vv diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index bee64cdb80..754b1ef6cd 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -260,6 +260,22 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type { // `x := map[string]string` - set in parser if node.typ != 0 { info := c.table.sym(node.typ).map_info() + if info.value_type != 0 { + val_sym := c.table.sym(info.value_type) + if val_sym.kind == .struct_ { + val_info := val_sym.info as ast.Struct + if val_info.generic_types.len > 0 && val_info.concrete_types.len == 0 + && !info.value_type.has_flag(.generic) { + if c.table.cur_concrete_types.len == 0 { + c.error('generic struct `$val_sym.name` must specify type parameter, e.g. Foo', + node.pos) + } else { + c.error('generic struct `$val_sym.name` must specify type parameter, e.g. Foo', + node.pos) + } + } + } + } c.ensure_type_exists(info.key_type, node.pos) or {} c.ensure_type_exists(info.value_type, node.pos) or {} node.key_type = info.key_type diff --git a/vlib/v/checker/tests/map_of_generic_struct_init_err.out b/vlib/v/checker/tests/map_of_generic_struct_init_err.out new file mode 100644 index 0000000000..f9d68ef1c3 --- /dev/null +++ b/vlib/v/checker/tests/map_of_generic_struct_init_err.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/map_of_generic_struct_init_err.vv:6:11: error: generic struct `Item` must specify type parameter, e.g. Foo + 4 | + 5 | fn main() { + 6 | mut m := map[string]Item{} + | ~~~~~~~~~~~~~~~~~ + 7 | } diff --git a/vlib/v/checker/tests/map_of_generic_struct_init_err.vv b/vlib/v/checker/tests/map_of_generic_struct_init_err.vv new file mode 100644 index 0000000000..27d3e72596 --- /dev/null +++ b/vlib/v/checker/tests/map_of_generic_struct_init_err.vv @@ -0,0 +1,7 @@ +struct Item{ + val T +} + +fn main() { + mut m := map[string]Item{} +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 91afa31779..61886980c0 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -2140,10 +2140,12 @@ pub fn (mut p Parser) name_expr() ast.Expr { p.expr_mod = '' // `map[string]int` initialization if p.tok.lit == 'map' && p.peek_tok.kind == .lsbr { + mut pos := p.tok.pos() map_type := p.parse_map_type() if p.tok.kind == .lcbr { p.next() if p.tok.kind == .rcbr { + pos = pos.extend(p.tok.pos()) p.next() } else { if p.pref.is_fmt { @@ -2156,7 +2158,7 @@ pub fn (mut p Parser) name_expr() ast.Expr { } return ast.MapInit{ typ: map_type - pos: p.prev_tok.pos() + pos: pos } } // `chan typ{...}`