8000 Fix a parser crash with empty match vars by elliottt · Pull Request #8911 · sorbet/sorbet · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix a parser crash with empty match vars #8911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 23, 2025
Merged

Conversation

elliottt
Copy link
Collaborator
@elliottt elliottt commented May 22, 2025

Sorbet is crashing when encountering an unterminated string symbol in a match expression. This PR fixes the problem by catching the empty case, and entering it manually.

This introduces a new parser error, with text that mirrors the error from the ruby parser:

irb(main):002:0> case nil; in {"":} then true end
/Users/trevor/.rbenv/versions/3.1.2/lib/ruby/3.1.0/irb/workspace.rb:119:in `eval': (irb):2: key must be valid as local variables (SyntaxError)
case nil; in {"":} then true end
              ^~~
(irb):2: identifier  is not valid to set
        from /Users/trevor/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
        from /Users/trevor/.rbenv/versions/3.1.2/bin/irb:25:in `load'
        from /Users/trevor/.rbenv/versions/3.1.2/bin/irb:25:in `<main>'

and from Sorbet after this change:

% ./bazel-bin/main/sorbet test/testdata/parser/crash_case_empty_var.rb
👋 Hey there! Heads up that this is not a release build of sorbet.
Release builds are faster and more well-supported by the Sorbet team.
Check out the README to learn how to build Sorbet in release mode.
To forcibly silence this error, either pass --silence-dev-message,
or set SORBET_SILENCE_DEV_MESSAGE=1 in your shell environment.

test/testdata/parser/crash_case_empty_var.rb:4: key must be valid as local variables https://srb.help/2001
     4 |case T.unsafe(nil); in {"":} then true; end
                                ^^^
Errors: 1

Motivation

Fixes #8903

Test plan

See included automated tests.

@elliottt elliottt force-pushed the trevor/fix-parser-case-crash branch from b51668f to 063c087 Compare May 22, 2025 22:37
@elliottt elliottt force-pushed the trevor/fix-parser-case-crash branch from 063c087 to 740819c Compare May 22, 2025 22:39
@elliottt elliottt force-pushed the trevor/fix-parser-case-crash branch from 740819c to fb49bd2 Compare May 22, 2025 22:47
@elliottt elliottt marked this pull request as ready for review May 22, 2025 22:49
@elliottt elliottt requested a review from a team as a code owner May 22, 2025 22:49
@elliottt elliottt requested review from jez and removed request for a team May 22, 2025 22:49
@elliottt elliottt changed the title Fix a parser crash with match vars Fix a parser crash with empty match vars May 22, 2025
@@ -1206,6 +1206,10 @@ class Builder::Impl {
// Label key is a symbol `sym: val`
return match_var_h 8000 ash(label->loc, key->val.show(gs_));
} else if (auto *key = parser::cast_node<DSymbol>(pair->key.get())) {
if (key->nodes.empty()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth, it looks like all string-quoted keys are not allowed in the punned hash key/val pairs

 ruby -e '{"x":}'
-e:1: syntax error, unexpected '}'
{"x":}

not just empty strings.

@@ -78,6 +78,7 @@ tuple<string, string> MESSAGES[] = {
{"NoAnonymousBlockArg", "no anonymous block parameter"},
{"NoAnonymousRestArg", "no anonymous rest parameter"},
{"NoAnonymousKwrestArg", "no anonymous keyword rest parameter"},
{"InvalidKey", "key must be valid as local variables"},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how important this is but both the whitequark parser and the ruby parser seem to report an unexpected token error:

❯ ruby-parse -e '{"x":}'
warning: parser/current is loading parser/ruby31, which recognizes 3.1.4-compliant syntax, but you are running 3.1.2.
Please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
(fragment:0):1:6: error: unexpected token tRCURLY
(fragment:0):1: {"x":}
(fragment:0):1:      ^

~/sorbet (jez-package-namespaces-with-owner)
❯ ruby -e '{"x":}'
-e:1: syntax error, unexpected '}'
{"x":}

all else being equal it's probably better to have our own custom error for this if it means that we can provide better parse error recovery for it, so I'm fine with the new dclass but I'm curious to know what's different about our parser vs those parsers that is going through a different code path.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it seems like this is actually specific to pattern matching, and the error message is the same as upstream.

~/sorbet (jez-package-namespaces-with-owner)
❯ ruby -e 'case {}; in {"":} then true; end'
-e:1: key must be valid as local variables
case {}; in {"":} then true; end
-e:1: identifier  is not valid to set

~/sorbet (jez-package-namespaces-with-owner)
❯ ruby -e 'case {}; in {"x":} then true; end'
-e:1:in `<main>': {}: key not found: :x (NoMatchingPatternKeyError)

~/sorbet (jez-package-namespaces-with-owner)
❯ ruby -e 'case {}; in {"x y":} then true; end'
-e:1: key must be valid as local variables
case {}; in {"x y":} then true; end
-e:1: identifier x y is not valid to set

but in any case, it's not just empty string that's invalid

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, true. I don't think that we can handle the second case, as it's a dynamic property of the value being examined, but the third case is definitely something we could raise an error for.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, the second case I was just trying to show that the logic is not "are there quotes around the name" which I suspected might be the case, like maybe {x:} was fine but {"x":} was not fine because it had quotes (which would be easier to detect in Builder.cc than trying to check valid variable names)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the plan to merge this and handle the non-empty "key must be valid as local variable" in a follow up change / an open issue?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll timebox investigating the local variable name validation, and if I run out I'll ping you for an approval and make an issue to track it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know whether there's an easy helper for this. Might be best to just over-eagerly allow things—I don't think that having {"x y":} causes problems for Sorbet.

Might want to add a test case and defer solving in Prism.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My timebox ran out, and I agree that this will be easier to handle when we upgrade to prism 👍

@elliottt elliottt requested a review from jez May 23, 2025 00:24
@elliottt elliottt merged commit 32c619f into master May 23, 2025
14 checks passed
@elliottt elliottt deleted the trevor/fix-parser-case-crash branch May 23, 2025 23:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

LSP crashes at typedruby_release_bison.cc:8124:9
2 participants
0