From 9e7bce4efea255c1ba7ed0c4c7884f0ee9a0bee6 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 05:24:00 +0300 Subject: [PATCH] vfmt: fix format error on types (fixes #25496) --- vlib/v/fmt/fmt.v | 24 +++++++++++++++++++++++- vlib/v/fmt/tests/types_expected.vv | 6 ++++++ vlib/v/fmt/tests/types_input.vv | 6 ++++++ vlib/v/parser/parse_type.v | 27 +++++++++++++++++++++++---- 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 38ae54431..172368637 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1847,6 +1847,28 @@ struct Variant { id int } +fn (mut f Fmt) sum_type_variant_comments(variant ast.TypeNode) { + if variant.end_comments.len == 0 { + return + } + mut same_line_comments := []ast.Comment{} + mut follow_up_comments := []ast.Comment{} + for comment in variant.end_comments { + if comment.pos.line_nr == variant.pos.last_line { + same_line_comments << comment + } else { + follow_up_comments << comment + } + } + if same_line_comments.len > 0 { + f.comments(same_line_comments, has_nl: false) + } + if follow_up_comments.len > 0 { + f.writeln('') + f.comments(follow_up_comments, has_nl: false, level: .indent) + } +} + pub fn (mut f Fmt) sum_type_decl(node ast.SumTypeDecl) { f.attrs(node.attrs) start_pos := f.out.len @@ -1886,7 +1908,7 @@ pub fn (mut f Fmt) sum_type_decl(node ast.SumTypeDecl) { } f.write(variant.name) if node.variants[variant.id].end_comments.len > 0 && is_multiline { - f.comments(node.variants[variant.id].end_comments, has_nl: false) + f.sum_type_variant_comments(node.variants[variant.id]) } } if !is_multiline { diff --git a/vlib/v/fmt/tests/types_expected.vv b/vlib/v/fmt/tests/types_expected.vv index e70f2ac52..b868ee776 100644 --- a/vlib/v/fmt/tests/types_expected.vv +++ b/vlib/v/fmt/tests/types_expected.vv @@ -11,6 +11,12 @@ pub type Callback = ConnectedCallback // connected callback | DisconnectedCallback // disconnected callback | LoggedOffCallback // logged off callback +type SumResp = string + | int + // | f64 + | map[string]int + | map[string]bool + struct ConnectedCallback {} struct DisconnectedCallback {} diff --git a/vlib/v/fmt/tests/types_input.vv b/vlib/v/fmt/tests/types_input.vv index 97028fe5f..f73e6e5ac 100644 --- a/vlib/v/fmt/tests/types_input.vv +++ b/vlib/v/fmt/tests/types_input.vv @@ -11,6 +11,12 @@ pub type Callback = ConnectedCallback // connected callback | DisconnectedCallback // disconnected callback | LoggedOffCallback // logged off callback +type SumResp = string + | int + // | f64 + | map[string]int + | map[string]bool + struct ConnectedCallback{} struct DisconnectedCallback{} struct LoggedOnCallback{} diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 0206d9162..bbbe3d883 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -494,6 +494,23 @@ fn (mut p Parser) parse_inline_sum_type() ast.Type { // parse_sum_type_variants parses several types separated with a pipe and returns them as a list with at least one node. // If there is less than one node, it will add an error to the error list. +fn (p &Parser) has_follow_up_sum_type_pipe() bool { + mut line := p.prev_tok.line_nr + p.prev_tok.lit.count('\n') + if p.tok.kind != .comment || p.tok.line_nr > line + 1 { + return false + } + mut tok := p.tok + mut next_tok := p.peek_tok + mut peek_idx := 2 + for tok.kind == .comment && tok.line_nr <= line + 1 { + line = tok.line_nr + tok.lit.count('\n') + tok = next_tok + next_tok = p.peek_token(peek_idx) + peek_idx++ + } + return tok.kind == .pipe && tok.line_nr <= line + 1 +} + fn (mut p Parser) parse_sum_type_variants() []ast.TypeNode { p.inside_sum_type = true defer { @@ -503,10 +520,12 @@ fn (mut p Parser) parse_sum_type_variants() []ast.TypeNode { for { type_start_pos := p.tok.pos() typ := p.parse_type() - end_comments := p.eat_comments(same_line: true) - // TODO: needs to be its own var, otherwise TCC fails because of a known stack error - prev_tok := p.prev_tok - type_end_pos := prev_tok.pos() + // Keep the type node position on the variant itself; trailing comments are stored separately. + type_end_pos := p.prev_tok.pos() + mut end_comments := p.eat_comments(same_line: true) + if p.has_follow_up_sum_type_pipe() { + end_comments << p.eat_comments(follow_up: true) + } type_pos := type_start_pos.extend(type_end_pos) types << ast.TypeNode{ typ: typ -- 2.39.5