@@ -1005,14 +1005,18 @@ pm_locals_reads(pm_locals_t *locals, pm_constant_id_t name) {
1005
1005
* written but not read in certain contexts.
1006
1006
*/
1007
1007
static void
1008
- pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool warn_unused ) {
1008
+ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel ) {
1009
1009
pm_constant_id_list_init_capacity(list, locals->size);
1010
1010
1011
1011
// If we're still below the threshold for switching to a hash, then we only
1012
1012
// need to loop over the locals until we hit the size because the locals are
1013
1013
// stored in a list.
1014
1014
uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1015
1015
1016
+ // We will only warn for unused variables if we're not at the top level, or
1017
+ // if we're parsing a file outside of eval or -e.
1018
+ bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1019
+
1016
1020
for (uint32_t index = 0; index < capacity; index++) {
1017
1021
pm_local_t *local = &locals->locals[index];
1018
1022
@@ -12329,7 +12333,8 @@ static pm_node_t *
12329
12333
parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id);
12330
12334
12331
12335
/**
12332
- * This is a wrapper of parse_expression, which also checks whether the resulting node is value expression.
12336
+ * This is a wrapper of parse_expression, which also checks whether the
12337
+ * resulting node is a value expression.
12333
12338
*/
12334
12339
static pm_node_t *
12335
12340
parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
@@ -13217,7 +13222,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
13217
13222
pm_static_literals_t literals = { 0 };
13218
13223
pm_hash_key_static_literals_add(parser, &literals, argument);
13219
13224
13220
- // Finish parsing the one we are part way through
13225
+ // Finish parsing the one we are part way through.
13221
13226
pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE);
13222
13227
argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value);
13223
13228
@@ -14014,9 +14019,8 @@ parse_block_parameters(
14014
14019
pm_parser_local_add_token(parser, &parser->previous, 1);
14015
14020
14016
14021
pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->previous);
14017
- if (repeated) {
14018
- pm_node_flag_set_repeated_parameter((pm_node_t *)local);
14019
- }
14022
+ if (repeated) pm_node_flag_set_repeated_parameter((pm_node_t *) local);
14023
+
14020
14024
pm_block_parameters_node_append_local(block_parameters, local);
14021
14025
} while (accept1(parser, PM_TOKEN_COMMA));
14022
14026
}
@@ -14118,7 +14122,7 @@ parse_block(pm_parser_t *parser) {
14118
14122
}
14119
14123
14120
14124
pm_constant_id_list_t locals;
14121
- pm_locals_order(parser, &parser->current_scope->locals, &locals, ! pm_parser_scope_toplevel_p(parser));
14125
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
14122
14126
pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &opening, &parser->previous);
14123
14127
14124
14128
pm_parser_scope_pop(parser);
@@ -17442,7 +17446,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17442
17446
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
17443
17447
17444
17448
pm_constant_id_list_t locals;
17445
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true );
17449
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false );
17446
17450
17447
17451
pm_parser_scope_pop(parser);
17448
17452
pm_do_loop_stack_pop(parser);
@@ -17502,7 +17506,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17502
17506
}
17503
17507
17504
17508
pm_constant_id_list_t locals;
17505
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true );
17509
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false );
17506
17510
17507
17511
pm_parser_scope_pop(parser);
17508
17512
pm_do_loop_stack_pop(parser);
@@ -17767,7 +17771,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17767
17771
}
17768
17772
17769
17773
pm_constant_id_list_t locals;
17770
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true );
17774
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false );
17771
17775
pm_parser_scope_pop(parser);
17772
17776
17773
17777
/**
@@ -18029,7 +18033,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18029
18033
}
18030
18034
18031
18035
pm_constant_id_list_t locals;
18032
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true );
18036
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, false );
18033
18037
18034
18038
pm_parser_scope_pop(parser);
18035
18039
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
@@ -18795,7 +18799,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18795
18799
}
18796
18800
18797
18801
pm_constant_id_list_t locals;
18798
- pm_locals_order(parser, &parser->current_scope->locals, &locals, ! pm_parser_scope_toplevel_p(parser));
18802
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
18799
18803
pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &operator, &parser->previous);
18800
18804
18801
18805
pm_parser_scope_pop(parser);
@@ -18851,11 +18855,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18851
18855
}
18852
18856
}
18853
18857
18854
- static inline pm_node_t *
18858
+ /**
18859
+ * Parse a value that is going to be written to some kind of variable or method
18860
+ * call. We need to handle this separately because the rescue modifier is
18861
+ * permitted on the end of the these expressions, which is a deviation from its
18862
+ * normal binding power.
18863
+ *
18864
+ * Note that this will only be called after an operator write, as in &&=, ||=,
18865
+ * or any of the binary operators that can be written to a variable.
18866
+ */
18867
+ static pm_node_t *
18855
18868
parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
18856
18869
pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id);
18857
18870
18858
- // Contradicting binding powers, the right-hand-side value of rthe assignment allows the `rescue` modifier.
18871
+ // Contradicting binding powers, the right-hand-side value of the assignment
18872
+ // allows the `rescue` modifier.
18859
18873
if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18860
18874
context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18861
18875
@@ -18871,14 +18885,63 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_
18871
18885
return value;
18872
18886
}
18873
18887
18888
+ /**
18889
+ * When a local variable write node is the value being written in a different
18890
+ * write, the local variable is considered "used".
18891
+ */
18892
+ static void
18893
+ parse_assignment_value_local(pm_parser_t *parser, const pm_node_t *node) {
18894
+ switch (PM_NODE_TYPE(node)) {
18895
+ case PM_BEGIN_NODE: {
18896
+ const pm_begin_node_t *cast = (const pm_begin_node_t *) node;
18897
+ if (cast->statements != NULL) parse_assignment_value_local(parser, (const pm_node_t *) cast->statements);
18898
+ break;
18899
+ }
18900
+ case PM_LOCAL_VARIABLE_WRITE_NODE: {
18901
+ const pm_local_variable_write_node_t *cast = (const pm_local_variable_write_node_t *) node;
18902
+ pm_locals_read(&pm_parser_scope_find(parser, cast->depth)->locals, cast->name);
18903
+ break;
18904
+ }
18905
+ case PM_PARENTHESES_NODE: {
18906
+ const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
18907
+ if (cast->body != NULL) parse_assignment_value_local(parser, cast->body);
18908
+ break;
18909
+ }
18910
+ case PM_STATEMENTS_NODE: {
18911
+ const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
18912
+ const pm_node_t *statement;
18874
18913
18875
- static inline pm_node_t *
18914
+ PM_NODE_LIST_FOREACH(&cast->body, index, statement) {
18915
+ parse_assignment_value_local(parser, statement);
18916
+ }
18917
+ break;
18918
+ }
18919
+ default:
18920
+ break;
18921
+ }
18922
+ }
18923
+
18924
+ /**
18925
+ * Parse the value (or values, through an implicit array) that is going to be
18926
+ * written to some kind of variable or method call. We need to handle this
18927
+ * separately because the rescue modifier is permitted on the end of the these
18928
+ * expressions, which is a deviation from its normal binding power.
18929
+ *
18930
+ * Additionally, if the value is a local variable write node (e.g., a = a = 1),
18931
+ * the "a" is marked as being used so the parser should not warn on it.
18932
+ *
18933
+ * Note that this will only be called after an = operator, as that is the only
18934
+ * operator that allows multiple values after it.
18935
+ */
18936
+ static pm_node_t *
18876
18937
parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
18877
18938
pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id);
18878
- bool single_value = true ;
18939
+ parse_assignment_value_local(parser, value) ;
18879
18940
18941
+ bool single_value = true;
18880
18942
if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
18881
18943
single_value = false;
18944
+
18882
18945
pm_token_t opening = not_provided(parser);
18883
18946
pm_array_node_t *array = pm_array_node_create(parser, &opening);
18884
18947
@@ -18887,8 +18950,11 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
18887
18950
18888
18951
while (accept1(parser, PM_TOKEN_COMMA)) {
18889
18952
pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT);
18953
+
18890
18954
pm_array_node_elements_append(array, element);
18891
18955
if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
18956
+
18957
+ parse_assignment_value_local(parser, element);
18892
18958
}
18893
18959
}
18894
18960
@@ -19173,7 +19239,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19173
19239
pm_location_t *message_loc = &cast->message_loc;
19174
19240
pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
19175
19241
19176
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 0 );
19242
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1 );
19177
19243
pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
19178
19244
pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
19179
19245
@@ -19286,7 +19352,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19286
19352
pm_location_t *message_loc = &cast->message_loc;
19287
19353
pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
19288
19354
19289
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 0 );
19355
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1 );
19290
19356
pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
19291
19357
pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
19292
19358
@@ -19409,7 +19475,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
19409
19475
pm_location_t *message_loc = &cast->message_loc;
19410
19476
pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
19411
19477
19412
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 0 );
19478
+ pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1 );
19413
19479
pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
19414
19480
pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
19415
19481
@@ -20070,7 +20136,7 @@ parse_program(pm_parser_t *parser) {
20070
20136
}
20071
20137
20072
20138
pm_constant_id_list_t locals;
20073
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false );
20139
+ pm_locals_order(parser, &parser->current_scope->locals, &locals, true );
20074
20140
pm_parser_scope_pop(parser);
20075
20141
20076
20142
// If this is an empty file, then we're still going to parse all of the
0 commit comments