commit f54d3f94a396dab00f2b2a5258d95cb368e4dcdd (tree)
parent 1c1407adb89ef594c0d264a9506c371eb6070ecd
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Fri, 13 Feb 2026 22:16:41 +0000
astgen: fix rlExpr bugs for inline while/for labels, assign_destructure, and @-quoted identifiers
Fix three issues in the RL annotation pre-pass (rlExpr):
1. Label detection for `inline while`/`inline for` now accounts for
the `keyword_inline` token before checking for `identifier colon`,
matching upstream fullWhileComponents/fullForComponents logic.
2. `assign_destructure` now recurses into variable nodes and the value
expression with RL_RI_NONE, matching upstream behavior instead of
returning false without visiting sub-expressions.
3. `rlTokenIdentEqual` now handles @"..."-quoted identifiers by comparing
the quoted content rather than stopping at the `@` character, which
previously caused all @-quoted identifiers to compare as equal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
| M | astgen.c | | | 54 | +++++++++++++++++++++++++++++++++++++++++++++--------- |
1 file changed, 45 insertions(+), 9 deletions(-)
diff --git a/astgen.c b/astgen.c
@@ -9547,11 +9547,33 @@ static bool nodesNeedRlContains(const AstGenCtx* ag, uint32_t node) {
}
// Compare two identifier tokens by their source text.
+// Handles both regular identifiers and @"..."-quoted identifiers.
static bool rlTokenIdentEqual(
const Ast* tree, uint32_t tok_a, uint32_t tok_b) {
const char* src = tree->source;
uint32_t a_start = tree->tokens.starts[tok_a];
uint32_t b_start = tree->tokens.starts[tok_b];
+ bool a_quoted = (src[a_start] == '@');
+ bool b_quoted = (src[b_start] == '@');
+ if (a_quoted != b_quoted)
+ return false;
+ if (a_quoted) {
+ // Both are @"..."-quoted: skip '@"' prefix, compare up to '"'.
+ uint32_t ai = a_start + 2;
+ uint32_t bi = b_start + 2;
+ for (;;) {
+ char ca = src[ai];
+ char cb = src[bi];
+ if (ca == '"' && cb == '"')
+ return true;
+ if (ca == '"' || cb == '"')
+ return false;
+ if (ca != cb)
+ return false;
+ ai++;
+ bi++;
+ }
+ }
for (uint32_t i = 0;; i++) {
char ca = src[a_start + i];
char cb = src[b_start + i];
@@ -9998,10 +10020,13 @@ static bool rlExpr(
else_node = tree->extra_data.arr[nd.rhs + 2];
}
uint32_t main_tok = tree->nodes.main_tokens[node];
+ uint32_t tok_i = main_tok;
+ if (tok_i >= 1 && tree->tokens.tags[tok_i - 1] == TOKEN_KEYWORD_INLINE)
+ tok_i = tok_i - 1;
bool is_labeled
- = (main_tok >= 2 && tree->tokens.tags[main_tok - 1] == TOKEN_COLON
- && tree->tokens.tags[main_tok - 2] == TOKEN_IDENTIFIER);
- uint32_t label_token = is_labeled ? main_tok - 2 : UINT32_MAX;
+ = (tok_i >= 2 && tree->tokens.tags[tok_i - 1] == TOKEN_COLON
+ && tree->tokens.tags[tok_i - 2] == TOKEN_IDENTIFIER);
+ uint32_t label_token = is_labeled ? tok_i - 2 : UINT32_MAX;
// Detect payload/error.
uint32_t last_cond_tok = lastToken(tree, cond_node);
@@ -10069,10 +10094,14 @@ static bool rlExpr(
}
uint32_t main_tok = tree->nodes.main_tokens[node];
- bool is_labeled
- = (main_tok >= 2 && tree->tokens.tags[main_tok - 1] == TOKEN_COLON
- && tree->tokens.tags[main_tok - 2] == TOKEN_IDENTIFIER);
- uint32_t label_token = is_labeled ? main_tok - 2 : UINT32_MAX;
+ uint32_t for_tok_i = main_tok;
+ if (for_tok_i >= 1
+ && tree->tokens.tags[for_tok_i - 1] == TOKEN_KEYWORD_INLINE)
+ for_tok_i = for_tok_i - 1;
+ bool is_labeled = (for_tok_i >= 2
+ && tree->tokens.tags[for_tok_i - 1] == TOKEN_COLON
+ && tree->tokens.tags[for_tok_i - 2] == TOKEN_IDENTIFIER);
+ uint32_t label_token = is_labeled ? for_tok_i - 2 : UINT32_MAX;
for (uint32_t i = 0; i < num_inputs; i++) {
uint32_t input = inputs[i];
@@ -10646,8 +10675,15 @@ static bool rlExpr(
case AST_NODE_AWAIT:
(void)rlExpr(ag, nd.lhs, block, RL_RI_NONE);
return false;
- case AST_NODE_ASSIGN_DESTRUCTURE:
- return false; // TODO if needed
+ case AST_NODE_ASSIGN_DESTRUCTURE: {
+ uint32_t extra_start = nd.lhs;
+ uint32_t variable_count = tree->extra_data.arr[extra_start];
+ for (uint32_t i = 0; i < variable_count; i++)
+ (void)rlExpr(ag, tree->extra_data.arr[extra_start + 1 + i], block,
+ RL_RI_NONE);
+ (void)rlExpr(ag, nd.rhs, block, RL_RI_NONE);
+ return false;
+ }
case AST_NODE_ASYNC_CALL_ONE:
case AST_NODE_ASYNC_CALL_ONE_COMMA:
case AST_NODE_ASYNC_CALL: