From 497bfade251b0a4d0e75e1a1d1d6bba23e6aa60b Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 23 Apr 2026 21:11:11 +0300 Subject: [PATCH] all: fix "too many errors/warnings/notices" should not result in a build error (fixes #20242) --- vlib/v/builder/builder.v | 6 +++--- vlib/v/builder/builder_test.v | 29 +++++++++++++++++++++++++++++ vlib/v/checker/checker.v | 2 +- vlib/v/checker/errors.v | 12 +++++------- vlib/v/help/build/build.txt | 2 +- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index e159675cf..1ca8ab479 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -890,9 +890,9 @@ pub fn (b &Builder) show_total_warns_and_errors_stats() { return } if b.pref.is_stats { - mut nr_errors := b.checker.errors.len - mut nr_warnings := b.checker.warnings.len - mut nr_notices := b.checker.notices.len + mut nr_errors := b.checker.nr_errors + mut nr_warnings := b.checker.nr_warnings + mut nr_notices := b.checker.nr_notices if b.pref.check_only { nr_errors = b.nr_errors diff --git a/vlib/v/builder/builder_test.v b/vlib/v/builder/builder_test.v index 27d163e3b..6b248d3bf 100644 --- a/vlib/v/builder/builder_test.v +++ b/vlib/v/builder/builder_test.v @@ -246,6 +246,35 @@ fn test_windows_host_c_compiler_probe_is_skipped_for_non_windows_targets() { backend: .js_browser os: .windows }) +fn test_message_limit_notices_do_not_fail_build() { + os.chdir(test_path)! + src_file := os.join_path(test_path, 'message_limit_notices.v') + mut exe_file := os.join_path(test_path, 'message_limit_notices') + $if windows { + exe_file += '.exe' + } + + mut lines := []string{} + for i in 0 .. 10 { + lines << '@[deprecated]' + lines << "@[deprecated_after: '3000-12-30']" + lines << 'fn future_${i}() {}' + } + lines << 'fn main() {' + for i in 0 .. 10 { + lines << '\tfuture_${i}()' + } + lines << '}' + os.write_file(src_file, lines.join('\n') + '\n')! + + res := + os.execute('${os.quoted_path(vexe)} -stats -message-limit 5 -o ${os.quoted_path(exe_file)} ${os.quoted_path(src_file)}') + normalized_output := res.output.replace('\r\n', '\n') + + assert res.exit_code == 0, normalized_output + assert os.exists(exe_file), normalized_output + assert !normalized_output.contains('builder error: too many errors/warnings/notices') + assert normalized_output.contains('checker summary: 0 V errors, 0 V warnings, 10 V notices'), normalized_output } fn test_run_with_obscure_source_filenames() { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 825450a76..d34b51458 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -65,7 +65,7 @@ pub mut: warning_lines map[string]bool // dedup warns notice_lines map[string]bool // dedup notices error_details []string - should_abort bool // when too many errors/warnings/notices are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time. + should_abort bool // when too many errors are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time. expected_type ast.Type expected_or_type ast.Type // fn() or { 'this type' } eg. string. expected or block type diff --git a/vlib/v/checker/errors.v b/vlib/v/checker/errors.v index 04ef6498c..3d3ed737d 100644 --- a/vlib/v/checker/errors.v +++ b/vlib/v/checker/errors.v @@ -81,10 +81,6 @@ fn (mut c Checker) fatal(message string, pos token.Pos, options MessageOptions) } fn (mut c Checker) note(message string, pos token.Pos) { - if c.pref.message_limit >= 0 && c.nr_notices >= c.pref.message_limit { - c.should_abort = true - return - } if c.is_generated { return } @@ -101,6 +97,10 @@ fn (mut c Checker) note(message string, pos token.Pos) { kpos := '${file_path}:${pos.line_nr}:${message}' if kpos !in c.notice_lines { c.notice_lines[kpos] = true + c.nr_notices++ + if c.pref.message_limit >= 0 && c.notices.len >= c.pref.message_limit { + return + } note := errors.Notice{ reporter: errors.Reporter.checker pos: pos @@ -110,7 +110,6 @@ fn (mut c Checker) note(message string, pos token.Pos) { } c.file.notices << note c.notices << note - c.nr_notices++ } } @@ -133,8 +132,7 @@ fn (mut c Checker) warn_or_error(message string, pos token.Pos, warn bool, optio file_path := if pos.file_idx < 0 { c.file.path } else { c.table.filelist[pos.file_idx] } if warn && !c.pref.skip_warnings { c.nr_warnings++ - if c.pref.message_limit >= 0 && c.nr_warnings >= c.pref.message_limit { - c.should_abort = true + if c.pref.message_limit >= 0 && c.warnings.len >= c.pref.message_limit { return } // deduplicate warnings for the same line diff --git a/vlib/v/help/build/build.txt b/vlib/v/help/build/build.txt index a70861de0..92ede6d19 100644 --- a/vlib/v/help/build/build.txt +++ b/vlib/v/help/build/build.txt @@ -187,7 +187,7 @@ NB: the build flags are shared with the run command too: -message-limit The maximum amount of warnings / errors / notices, that will be accumulated (defaults to 200). - The parser and checker, will return prematurely, once this limit has been reached. + The compiler may stop accumulating additional diagnostics, once this limit has been reached. Setting this to a negative value like -1, will disable the limit. Setting this to 0, will stop showing errors, but the compiler will still exit with a non zero exit code, if there are any. -- 2.39.5