From b230d8ac117f788e22f8d40d8e29361eb6560c99 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:17 +0300 Subject: [PATCH] parser: move error/warning messages from parser to checker (fixes #26097) --- vlib/v/checker/struct.v | 8 ++++++-- vlib/v/checker/tests/import_symbol_type_err.out | 10 ++-------- vlib/v/checker/tests/struct_scope_err.out | 9 +-------- vlib/v/checker/tests/wrong_struct_init_err.out | 5 +++-- vlib/v/parser/parser.v | 11 +++++++++-- vlib/v/parser/struct.v | 7 ------- 6 files changed, 21 insertions(+), 29 deletions(-) diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 258bc7f49..7c8133efd 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -689,7 +689,10 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini } } if !is_field_zero_struct_init { - c.ensure_type_exists(concrete_node_typ, node.pos) + type_exists := c.ensure_type_exists(node.typ, node.pos) + if !type_exists && node.typ.idx() > 0 && c.table.sym(node.typ).kind == .placeholder { + return ast.void_type + } } // Make sure the first letter is capital, do not allow e.g. `x := string{}`, // but `x := T{}` is ok. @@ -881,9 +884,10 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini exp_type_sym } c.expected_type = exp_type + nr_errors_before := c.nr_errors got_type = c.expr(mut init_field.expr) got_type_sym := c.table.sym(got_type) - if got_type == ast.void_type { + if got_type == ast.void_type && c.nr_errors == nr_errors_before { c.error('`${init_field.expr}` (no value) used as value', init_field.pos) } exp_type_is_option := exp_type.has_flag(.option) diff --git a/vlib/v/checker/tests/import_symbol_type_err.out b/vlib/v/checker/tests/import_symbol_type_err.out index 45980d7dc..3e270479b 100644 --- a/vlib/v/checker/tests/import_symbol_type_err.out +++ b/vlib/v/checker/tests/import_symbol_type_err.out @@ -5,19 +5,13 @@ vlib/v/checker/tests/import_symbol_type_err.vv:1:17: error: module `crypto` has 3 | fn main() { vlib/v/checker/tests/import_symbol_type_err.vv:4:10: error: unknown type `crypto.Coin`. Did you mean `crypto.Hash`? - 2 | - 3 | fn main() { - 4 | println(Coin{}) - | ~~~~~~ - 5 | } -vlib/v/checker/tests/import_symbol_type_err.vv:4:10: error: unknown struct: crypto.Coin - 2 | + 2 | 3 | fn main() { 4 | println(Coin{}) | ~~~~~~ 5 | } vlib/v/checker/tests/import_symbol_type_err.vv:4:2: error: `println` can not print void expressions - 2 | + 2 | 3 | fn main() { 4 | println(Coin{}) | ~~~~~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/struct_scope_err.out b/vlib/v/checker/tests/struct_scope_err.out index 5aa90af53..6fc59d386 100644 --- a/vlib/v/checker/tests/struct_scope_err.out +++ b/vlib/v/checker/tests/struct_scope_err.out @@ -6,14 +6,7 @@ vlib/v/checker/tests/struct_scope_err.vv:8:5: notice: condition is always true 9 | fb := Foobar{5, 6} 10 | println(fb.foo) vlib/v/checker/tests/struct_scope_err.vv:16:8: error: unknown type `Foobar` - 14 | - 15 | fn x() { - 16 | fb := Foobar{7, 8} - | ~~~~~~~~~~~~ - 17 | println(fb.bar) - 18 | } -vlib/v/checker/tests/struct_scope_err.vv:16:8: error: unknown struct: Foobar - 14 | + 14 | 15 | fn x() { 16 | fb := Foobar{7, 8} | ~~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/wrong_struct_init_err.out b/vlib/v/checker/tests/wrong_struct_init_err.out index 097a4286a..620b5e218 100644 --- a/vlib/v/checker/tests/wrong_struct_init_err.out +++ b/vlib/v/checker/tests/wrong_struct_init_err.out @@ -1,6 +1,7 @@ -vlib/v/checker/tests/wrong_struct_init_err.vv:4:33: error: struct name must begin with capital letter +vlib/v/checker/tests/wrong_struct_init_err.vv:4:33: error: unknown type `net.http.new_header`. +Did you mean `http.Header`? 2 | 3 | import net.http 4 | _ := http.Response{header: http.new_header{} } - | ~~~~~~~~~~ + | ~~~~~~~~~~~~ 5 | diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index eb742d208..76c547ff7 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1515,6 +1515,13 @@ fn (mut p Parser) alias_array_type() ast.Type { return ast.void_type } +fn (p &Parser) is_known_non_placeholder_type(name string) bool { + if idx := p.table.type_idxs[name] { + return p.table.sym(ast.idx_to_type(idx)).kind != .placeholder + } + return false +} + @[direct_array_access] fn (mut p Parser) name_expr() ast.Expr { prev_tok_kind := p.prev_tok.kind @@ -1754,8 +1761,8 @@ fn (mut p Parser) name_expr() ast.Expr { if (is_option || p.peek_tok.kind in [.lsbr, .lpar]) && (is_mod_cast || is_c_pointer_cast || is_c_type_cast || is_js_cast || is_generic_cast || (language == .v && name != '' && (is_capital_after_last_dot - || name[0].is_capital() - || (!known_var && (name in p.table.type_idxs || name_w_mod in p.table.type_idxs))))) { + || name[0].is_capital() || (!known_var && (p.is_known_non_placeholder_type(name) + || p.is_known_non_placeholder_type(name_w_mod)))))) { // MainLetter(x) is *always* a cast, as long as it is not `C.` // TODO: handle C.stat() start_pos := p.tok.pos() diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index a5370dcdf..19ef1dd3a 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -587,13 +587,6 @@ fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind, is_option first_pos := (if kind == .short_syntax && p.prev_tok.kind == .lcbr { p.prev_tok } else { p.tok }).pos() p.init_generic_types = []ast.Type{} mut typ := if kind == .short_syntax { ast.void_type } else { p.parse_type() } - sym := p.table.sym(typ) - struct_name := sym.name.all_after_last('.') - if sym.kind == .placeholder && struct_name.len > 0 && !struct_name[0].is_capital() - && !sym.name.starts_with('C.') { - p.error_with_pos('struct name must begin with capital letter', first_pos) - return ast.StructInit{} - } struct_init_generic_types := p.init_generic_types.clone() if is_option { typ = typ.set_flag(.option) -- 2.39.5