@@ -315,6 +315,8 @@ class ResolveVisitor : public AstVisitorBase {
315315
316316 const absl::Status& status () const { return status_; }
317317
318+ int error_count () const { return error_count_; }
319+
318320 void AssertExpectedType (const Expr& expr, const Type& expected_type) {
319321 Type observed = GetTypeOrDyn (&expr);
320322 if (!inference_context_->IsAssignable (observed, expected_type)) {
@@ -364,24 +366,31 @@ class ResolveVisitor : public AstVisitorBase {
364366 void ResolveSelectOperation (const Expr& expr, absl::string_view field,
365367 const Expr& operand);
366368
369+ void ReportIssue (TypeCheckIssue issue) {
370+ if (issue.severity () == Severity::kError ) {
371+ error_count_++;
372+ }
373+ issues_->push_back (std::move (issue));
374+ }
375+
367376 void ReportMissingReference (const Expr& expr, absl::string_view name) {
368- issues_-> push_back (TypeCheckIssue::CreateError (
377+ ReportIssue (TypeCheckIssue::CreateError (
369378 ComputeSourceLocation (*ast_, expr.id ()),
370379 absl::StrCat (" undeclared reference to '" , name, " ' (in container '" ,
371380 container_, " ')" )));
372381 }
373382
374383 void ReportUndefinedField (int64_t expr_id, absl::string_view field_name,
375384 absl::string_view struct_name) {
376- issues_-> push_back (TypeCheckIssue::CreateError (
385+ ReportIssue (TypeCheckIssue::CreateError (
377386 ComputeSourceLocation (*ast_, expr_id),
378387 absl::StrCat (" undefined field '" , field_name, " ' not found in struct '" ,
379388 struct_name, " '" )));
380389 }
381390
382391 void ReportTypeMismatch (int64_t expr_id, const Type& expected,
383392 const Type& actual) {
384- issues_-> push_back (TypeCheckIssue::CreateError (
393+ ReportIssue (TypeCheckIssue::CreateError (
385394 ComputeSourceLocation (*ast_, expr_id),
386395 absl::StrCat (" expected type '" ,
387396 inference_context_->FinalizeType (expected).DebugString (),
@@ -412,7 +421,7 @@ class ResolveVisitor : public AstVisitorBase {
412421 }
413422 if (!inference_context_->IsAssignable (value_type, field_type) &&
414423 !IsPbNullFieldAssignable (value_type, field_type)) {
415- issues_-> push_back (TypeCheckIssue::CreateError (
424+ ReportIssue (TypeCheckIssue::CreateError (
416425 ComputeSourceLocation (*ast_, field.id ()),
417426 absl::StrCat (
418427 " expected type of field '" , field_info->name (), " ' is '" ,
@@ -461,6 +470,7 @@ class ResolveVisitor : public AstVisitorBase {
461470 std::vector<std::unique_ptr<VariableScope>> comprehension_vars_;
462471 std::vector<ComprehensionScope> comprehension_scopes_;
463472 absl::Status status_;
473+ int error_count_ = 0 ;
464474
465475 // References that were resolved and may require AST rewrites.
466476 absl::flat_hash_map<const Expr*, FunctionResolution> functions_;
@@ -546,7 +556,7 @@ void ResolveVisitor::PostVisitConst(const Expr& expr,
546556 types_[&expr] = TimestampType ();
547557 break ;
548558 default :
549- issues_-> push_back (TypeCheckIssue::CreateError (
559+ ReportIssue (TypeCheckIssue::CreateError (
550560 ComputeSourceLocation (*ast_, expr.id ()),
551561 absl::StrCat (" unsupported constant type: " ,
552562 constant.kind ().index ())));
@@ -597,7 +607,7 @@ void ResolveVisitor::PostVisitMap(const Expr& expr, const MapExpr& map) {
597607 //
598608 // To match the Go implementation, we just warn here, but in the future
599609 // we should consider making this an error.
600- issues_-> push_back (TypeCheckIssue (
610+ ReportIssue (TypeCheckIssue (
601611 Severity::kWarning , ComputeSourceLocation (*ast_, key->id ()),
602612 absl::StrCat (
603613 " unsupported map key type: " ,
@@ -702,7 +712,7 @@ void ResolveVisitor::PostVisitStruct(const Expr& expr,
702712
703713 if (resolved_type.kind () != TypeKind::kStruct &&
704714 !IsWellKnownMessageType (resolved_name)) {
705- issues_-> push_back (TypeCheckIssue::CreateError (
715+ ReportIssue (TypeCheckIssue::CreateError (
706716 ComputeSourceLocation (*ast_, expr.id ()),
707717 absl::StrCat (" type '" , resolved_name,
708718 " ' does not support message creation" )));
@@ -849,7 +859,7 @@ void ResolveVisitor::PostVisitComprehensionSubexpression(
849859 case TypeKind::kDyn :
850860 break ;
851861 default :
852- issues_-> push_back (TypeCheckIssue::CreateError (
862+ ReportIssue (TypeCheckIssue::CreateError (
853863 ComputeSourceLocation (*ast_, comprehension.iter_range ().id ()),
854864 absl::StrCat (
855865 " expression of type '" ,
@@ -923,7 +933,7 @@ void ResolveVisitor::ResolveFunctionOverloads(const Expr& expr,
923933 inference_context_->ResolveOverload (decl, arg_types, is_receiver);
924934
925935 if (!resolution.has_value ()) {
926- issues_-> push_back (TypeCheckIssue::CreateError (
936+ ReportIssue (TypeCheckIssue::CreateError (
927937 ComputeSourceLocation (*ast_, expr.id ()),
928938 absl::StrCat (" found no matching overload for '" , decl.name (),
929939 " ' applied to '(" ,
@@ -1085,7 +1095,7 @@ absl::optional<Type> ResolveVisitor::CheckFieldType(int64_t id,
10851095 break ;
10861096 }
10871097
1088- issues_-> push_back (TypeCheckIssue::CreateError (
1098+ ReportIssue (TypeCheckIssue::CreateError (
10891099 ComputeSourceLocation (*ast_, id),
10901100 absl::StrCat (" expression of type '" ,
10911101 inference_context_->FinalizeType (operand_type).DebugString (),
@@ -1252,25 +1262,34 @@ absl::StatusOr<ValidationResult> TypeCheckerImpl::Check(
12521262
12531263 TraversalOptions opts;
12541264 opts.use_comprehension_callbacks = true ;
1255-
1265+ bool error_limit_reached = false ;
12561266 auto traversal = AstTraversal::Create (ast_impl.root_expr (), opts);
1267+
12571268 for (int step = 0 ; step < options_.max_expression_node_count * 2 ; ++step) {
12581269 bool has_next = traversal.Step (visitor);
12591270 if (!visitor.status ().ok ()) {
12601271 return visitor.status ();
12611272 }
1273+ if (visitor.error_count () > options_.max_error_issues ) {
1274+ error_limit_reached = true ;
1275+ break ;
1276+ }
12621277 if (!has_next) {
12631278 break ;
12641279 }
12651280 }
12661281
1267- if (!traversal.IsDone ()) {
1282+ if (!traversal.IsDone () && !error_limit_reached ) {
12681283 return absl::InvalidArgumentError (
1269- absl::StrCat (" Max expression node count exceeded: " ,
1284+ absl::StrCat (" Maximum expression node count exceeded: " ,
12701285 options_.max_expression_node_count ));
12711286 }
12721287
1273- if (env_.expected_type ().has_value ()) {
1288+ if (error_limit_reached) {
1289+ issues.push_back (TypeCheckIssue::CreateError (
1290+ {}, absl::StrCat (" maximum number of ERROR issues exceeded: " ,
1291+ options_.max_error_issues )));
1292+ } else if (env_.expected_type ().has_value ()) {
12741293 visitor.AssertExpectedType (ast_impl.root_expr (), *env_.expected_type ());
12751294 }
12761295
0 commit comments