From 9184983d06c103c470ace35390066fb017c66b11 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 23 Apr 2026 21:55:42 +0300 Subject: [PATCH] =?UTF-8?q?fmt:=20fix=20`parser`:=20anonymous=20struct=20t?= =?UTF-8?q?ype=20literal=20not=20accepted=20as=20a=20generic=20type=20argu?= =?UTF-8?q?ment=20(`fn[struct=20{=20=E2=80=A6=20}](=E2=80=A6)`)=20(fixes?= =?UTF-8?q?=20#26894)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vlib/v/fmt/fmt.v | 26 +++++++++++++++----------- vlib/v/fmt/struct.v | 11 +++++++++++ vlib/v/parser/checks.v | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index f8d7b03b4..ae82c1529 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -2245,17 +2245,19 @@ fn (mut f Fmt) write_generic_call_if_require(node ast.CallExpr) { if node.concrete_types.len > 0 { f.write('[') for i, concrete_type in node.concrete_types { - mut name := f.type_to_str_using_aliases(concrete_type, f.mod2alias) tsym := f.table.sym(concrete_type) - if tsym.language != .js && !tsym.name.starts_with('JS.') { - name = f.short_module(name) - } else if tsym.language == .js && !tsym.name.starts_with('JS.') { - name = 'JS.' + name - } - if tsym.language == .c { - name = 'C.' + name + if !f.write_anon_struct_type(concrete_type) { + mut name := f.type_to_str_using_aliases(concrete_type, f.mod2alias) + if tsym.language != .js && !tsym.name.starts_with('JS.') { + name = f.short_module(name) + } else if tsym.language == .js && !tsym.name.starts_with('JS.') { + name = 'JS.' + name + } + if tsym.language == .c { + name = 'C.' + name + } + f.write(name) } - f.write(name) if i != node.concrete_types.len - 1 { f.write(', ') } @@ -2504,8 +2506,10 @@ pub fn (mut f Fmt) ident(node ast.Ident) { if node.concrete_types.len > 0 { f.write('[') for i, concrete_type in node.concrete_types { - typ_name := f.type_to_str_using_aliases(concrete_type, f.mod2alias) - f.write(typ_name) + if !f.write_anon_struct_type(concrete_type) { + typ_name := f.type_to_str_using_aliases(concrete_type, f.mod2alias) + f.write(typ_name) + } if i != node.concrete_types.len - 1 { f.write(', ') } diff --git a/vlib/v/fmt/struct.v b/vlib/v/fmt/struct.v index d0e462aa2..01157db45 100644 --- a/vlib/v/fmt/struct.v +++ b/vlib/v/fmt/struct.v @@ -198,6 +198,17 @@ fn (mut f Fmt) write_anon_struct_field_decl(field_typ ast.Type, field_anon_decl return false } +fn (mut f Fmt) write_anon_struct_type(typ ast.Type) bool { + sym := f.table.sym(typ) + if sym.info is ast.Struct && sym.info.is_anon { + f.struct_decl(ast.StructDecl{ + fields: sym.info.fields + }, true) + return true + } + return false +} + pub fn (mut f Fmt) struct_init(node ast.StructInit) { struct_init_save := f.is_struct_init f.is_struct_init = true diff --git a/vlib/v/parser/checks.v b/vlib/v/parser/checks.v index 9480df2b3..3e8bc1bc6 100644 --- a/vlib/v/parser/checks.v +++ b/vlib/v/parser/checks.v @@ -117,12 +117,48 @@ fn (mut p Parser) is_following_concrete_types() bool { return true } +@[direct_array_access] +fn (p &Parser) is_anon_struct_generic_arg(next_kind token.Kind) bool { + mut i := 2 + mut nested_sbr_count := 0 + mut nested_cbr_count := 0 + for { + cur_tok := p.peek_token(i) + if cur_tok.kind == .eof { + return false + } + if cur_tok.kind == .lsbr { + nested_sbr_count++ + } else if cur_tok.kind == .rsbr { + if nested_cbr_count == 0 && nested_sbr_count == 0 { + return p.peek_token(i + 1).kind == next_kind + } + if nested_sbr_count == 0 { + return false + } + nested_sbr_count-- + } else if cur_tok.kind == .lcbr { + nested_cbr_count++ + } else if cur_tok.kind == .rcbr { + if nested_cbr_count == 0 { + return false + } + nested_cbr_count-- + } + i++ + } + return false +} + @[direct_array_access] fn (p &Parser) is_generic_struct_init() bool { lit0_is_capital := p.tok.kind != .eof && p.tok.lit.len > 0 && p.tok.lit[0].is_capital() if !lit0_is_capital || p.peek_tok.kind != .lsbr { return false } + if p.peek_token(2).kind == .key_struct { + return p.is_anon_struct_generic_arg(.lcbr) + } mut i := 2 mut nested_sbr_count := 0 for { @@ -191,6 +227,9 @@ fn (p &Parser) is_generic_call() bool { // case 1 (array or fixed array type) return tok3.kind == .rsbr || (tok4.kind == .rsbr && p.is_typename(tok5)) } + if kind2 == .key_struct { + return p.is_anon_struct_generic_arg(.lpar) + } if kind2 == .name { if kind3 == .lsbr && tok2.lit == 'map' { -- 2.39.5