From 0d5a6d936a8387aa83e1bd68c19dd2ab7e55fcd7 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Mon, 1 Apr 2024 13:57:38 -0400 Subject: [PATCH] Do not track locals starting with _ --- src/prism.c | 7 +++++ test/prism/errors_test.rb | 63 ++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/prism.c b/src/prism.c index 15c7e4568d5..2a288cae934 100644 --- a/src/prism.c +++ b/src/prism.c @@ -14605,6 +14605,9 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, bool top_pat */ static void parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_constant_id_t capture, const pm_location_t *location) { + // Skip this capture if it starts with an underscore. + if (*location->start == '_') return; + if (pm_constant_id_list_includes(captures, capture)) { pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_DUPLICATE); } else { @@ -14828,6 +14831,10 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *ca return (pm_node_t *) pm_implicit_node_create(parser, (pm_node_t *) target); } +/** + * Add a node to the list of keys for a hash pattern, and if it is a duplicate + * then add an error to the parser. + */ static void parse_pattern_hash_key(pm_parser_t *parser, pm_static_literals_t *keys, pm_node_t *node) { if (pm_static_literals_add(parser, keys, node) != NULL) { diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index 856e46fb769..cfe4ea41bec 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -2075,7 +2075,7 @@ def test_it_with_ordinary_parameter source = "proc { || it }" errors = [["`it` is not allowed when an ordinary parameter is defined", 10..12]] - assert_errors expression(source), source, errors + assert_errors expression(source), source, errors, check_valid_syntax: RUBY_VERSION >= "3.4.0" end def test_regular_expression_with_unknown_regexp_options @@ -2170,47 +2170,56 @@ def test_assignment_to_literal_in_conditionals def test_duplicate_pattern_capture source = <<~RUBY - () => [a, a] - () => [a, *a] - () => {a: a, b: a} - () => {a: a, **a} - () => [a, {a:}] - () => [a, {a: {a: {a: [a]}}}] - () => a => a - () => [A => a, {a: b => a}] + case (); in [a, a]; end + case (); in [a, *a]; end + case (); in {a: a, b: a}; end + case (); in {a: a, **a}; end + case (); in [a, {a:}]; end + case (); in [a, {a: {a: {a: [a]}}}]; end + case (); in a => a; end + case (); in [A => a, {a: b => a}]; end RUBY assert_error_messages source, Array.new(source.lines.length, "duplicated variable name") + refute_error_messages "case (); in [_a, _a]; end" end def test_duplicate_pattern_hash_key - assert_error_messages "() => {a:, a:}", ["duplicated key name", "duplicated variable name"] - assert_error_messages "() => {a:1, a:2}", ["duplicated key name"] + assert_error_messages "case (); in {a:, a:}; end", ["duplicated key name", "duplicated variable name"] + assert_error_messages "case (); in {a:1, a:2}; end", ["duplicated key name"] refute_error_messages "case (); in [{a:1}, {a:2}]; end" end private - def check_syntax(source) - $VERBOSE, previous = nil, $VERBOSE + if RUBY_ENGINE == "ruby" + def check_syntax(source) + $VERBOSE, previous = nil, $VERBOSE - begin - RubyVM::InstructionSequence.compile(source) - ensure - $VERBOSE = previous + begin + RubyVM::InstructionSequence.compile(source) + ensure + $VERBOSE = previous + end end - end - def assert_valid_syntax(source) - check_syntax(source) - end + def assert_valid_syntax(source) + check_syntax(source) + end - def refute_valid_syntax(source) - assert_raise(SyntaxError) { check_syntax(source) } + def refute_valid_syntax(source) + assert_raise(SyntaxError) { check_syntax(source) } + end + else + def assert_valid_syntax(source) + end + + def refute_valid_syntax(source) + end end - def assert_errors(expected, source, errors) - refute_valid_syntax(source) if RUBY_ENGINE == "ruby" + def assert_errors(expected, source, errors, check_valid_syntax: true) + refute_valid_syntax(source) if check_valid_syntax result = Prism.parse(source) node = result.value.statements.body.last @@ -2220,13 +2229,13 @@ def assert_errors(expected, source, errors) end def assert_error_messages(source, errors) - refute_valid_syntax(source) if RUBY_ENGINE == "ruby" + refute_valid_syntax(source) result = Prism.parse(source) assert_equal(errors, result.errors.map(&:message)) end def refute_error_messages(source) - assert_valid_syntax(source) if RUBY_ENGINE == "ruby" + assert_valid_syntax(source) assert Prism.parse_success?(source) end