Skip to content

Commit

Permalink
Do not track locals starting with _
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton committed Apr 1, 2024
1 parent ddec1c1 commit 0d5a6d9
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 27 deletions.
7 changes: 7 additions & 0 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
63 changes: 36 additions & 27 deletions test/prism/errors_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down

0 comments on commit 0d5a6d9

Please sign in to comment.