From b1633b9ebb68cb682a656f1026056f77afcdfb45 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 11 Feb 2026 14:05:06 +0000 Subject: [PATCH] Require all values from a procedure iterator if the procedure is marked with `@(require_results)` --- src/check_stmt.cpp | 19 +++++++++++++++++-- src/parser.cpp | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1f433df36..66283d3da 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1724,6 +1724,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) bool is_range = false; bool is_possibly_addressable = true; isize max_val_count = 2; + if (is_ast_range(expr)) { ast_node(ie, BinaryExpr, expr); Operand x = {}; @@ -1884,7 +1885,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error_line("\tMultiple return valued parameters in a range statement are limited to a minimum of 1 usable values with a trailing boolean for the conditional, got %td\n", count); break; } - enum : isize {MAXIMUM_COUNT = 100}; + enum : isize {MAXIMUM_COUNT = 20}; if (count > MAXIMUM_COUNT) { ERROR_BLOCK(); check_not_tuple(ctx, &operand); @@ -1900,7 +1901,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) break; } - max_val_count = count; + max_val_count = count-1; for (Entity *e : t->Tuple.variables) { array_add(&vals, e->type); @@ -1920,6 +1921,20 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) if (is_reverse) { error(node, "#reverse for is not supported for multiple return valued parameters"); } + + Ast *expr = unparen_expr(operand.expr); + if (expr->kind == Ast_CallExpr) { + Type *p = base_type(type_of_expr(expr->CallExpr.proc)); + if (p != nullptr && p->kind == Type_Proc) { + if (p->Proc.require_results) { + if (rs->vals.count < max_val_count) { + TokenPos start = ast_token(rs->vals[0]).pos; + TokenPos end = ast_end_pos(rs->vals[rs->vals.count-1]); + error_range(start, end, "Expected a %td identifier%s, got %td", max_val_count, max_val_count == 1 ? "" : "s", rs->vals.count); + } + } + } + } } break; diff --git a/src/parser.cpp b/src/parser.cpp index 0efe2714a..159eb65f8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -514,6 +514,22 @@ gb_internal void error(Ast *node, char const *fmt, ...) { } } +gb_internal void error_range(TokenPos start, TokenPos end, char const *fmt, ...) { + GB_ASSERT(start.file_id == end.file_id); + GB_ASSERT(start.line == end.line); + GB_ASSERT(start.column <= end.column); + GB_ASSERT(start.offset <= end.offset); + + va_list va; + va_start(va, fmt); + error_va(start, end, fmt, va); + va_end(va); + if (start.file_id != 0) { + AstFile *f = thread_safe_get_ast_file_from_id(start.file_id); + f->error_count += 1; + } +} + gb_internal void syntax_error_with_verbose(Ast *node, char const *fmt, ...) { Token token = {}; TokenPos end_pos = {};