From ba31a3c0c8c37f8ed3352787cd9a23d2941d2b1d Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 12 Jun 2026 05:58:07 +0300 Subject: [PATCH] checker: require common fields for match aggregates (#27428) --- vlib/v/ast/table.v | 31 +++++++++++++++++-- vlib/v/checker/checker.v | 2 +- .../tests/match_sumtype_multiple_types.out | 14 +++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index c78b797ed..0f2fe99aa 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -824,12 +824,37 @@ pub fn (t &Table) find_field_from_embeds(sym &TypeSymbol, field_name string) !(S return error('ambiguous field `${field_name}`') } } else if sym.info is Aggregate { + mut found_once := false + mut new_field := StructField{} + mut found_embed_types := []Type{} for typ in sym.info.types { agg_sym := t.sym(typ) - field, embed_types := t.find_field_from_embeds(agg_sym, field_name) or { continue } - if embed_types.len > 0 { - return field, embed_types + mut field := StructField{} + mut embed_types := []Type{} + if type_field := t.find_field(agg_sym, field_name) { + field = type_field + } else { + field, embed_types = t.find_field_from_embeds(agg_sym, field_name) or { + return error('type `${t.type_to_str(typ)}` has no field or method `${field_name}`') + } + if found_embed_types.len == 0 { + found_embed_types = embed_types.clone() + } + } + if !found_once { + found_once = true + new_field = field + } else if new_field.typ != field.typ { + return error('field `${t.type_to_str(typ)}.${field_name}` type is different') } + new_field = StructField{ + ...new_field + is_mut: new_field.is_mut && field.is_mut + is_pub: new_field.is_pub && field.is_pub + } + } + if found_once { + return new_field, found_embed_types } } else if sym.info is Alias { unalias_sym := t.sym(sym.info.parent_type) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c1d7ddcc8..5f198b62f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3172,7 +3172,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { } else { first_err := err has_field = false - if final_sym.kind in [.aggregate, .sum_type] { + if final_sym.kind == .sum_type { if variant_typ, variant_field, variant_embed_types := c.table.find_single_field_variant(final_sym, field_name) { diff --git a/vlib/v/checker/tests/match_sumtype_multiple_types.out b/vlib/v/checker/tests/match_sumtype_multiple_types.out index 0a84394db..a156c11e1 100644 --- a/vlib/v/checker/tests/match_sumtype_multiple_types.out +++ b/vlib/v/checker/tests/match_sumtype_multiple_types.out @@ -1,3 +1,17 @@ +vlib/v/checker/tests/match_sumtype_multiple_types.vv:26:13: error: type `Charlie` has no field or method `char` + 24 | match l { + 25 | Alfa, Charlie { + 26 | assert l.char == `a` + | ~~~~ + 27 | assert l.letter() == 'a' + 28 | } +vlib/v/checker/tests/match_sumtype_multiple_types.vv:26:11: error: assert can be used only with `bool` expressions, but found `void` instead + 24 | match l { + 25 | Alfa, Charlie { + 26 | assert l.char == `a` + | ~~~~~~~~~~~~~ + 27 | assert l.letter() == 'a' + 28 | } vlib/v/checker/tests/match_sumtype_multiple_types.vv:27:13: error: unknown method: `Charlie.letter` 25 | Alfa, Charlie { 26 | assert l.char == `a` -- 2.39.5