Preserve Ruby call syntax on print instead of canonicalizing it - #8510
Open
jkschneider wants to merge 1 commit into
Open
Preserve Ruby call syntax on print instead of canonicalizing it#8510jkschneider wants to merge 1 commit into
jkschneider wants to merge 1 commit into
Conversation
Three ways of writing a call round-tripped as a different, canonical
spelling of the same call, so `requirePrintEqualsInput` rejected the file
and it was dropped as a parse error. In each case Prism reports the
desugared call and the printer wrote that back out instead of what the
source says.
- `Foo.()` is shorthand for `Foo.call()`, and Prism names the call `call`
either way. A new `ImplicitCall` marker records that the message was
elided, and the printer omits it (unless a recipe has since renamed the
method, which does have to be written out).
- `WEBrick::Log::new(path)` printed as `WEBrick::Log.new(path)`. The
`Colon2` marker was already parsed and already honoured for ordinary
invocations; `J.NewClass` just never consulted it.
- `eq({} => 0)` failed with a cursor desync. A brace-less hash whose first
key is itself a hash also starts with `{`, and that brace was consumed as
if it opened the outer hash. The brace only belongs to the hash when it
sits ahead of the first pair.
Bug 1 alone accounted for roughly 85% of Ruby parse errors over a corpus of
105 Rails applications; exercism/website goes from 1,064 failures to 1 (a
file Prism itself rejects as a syntax error).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's changed
Three ways of writing a Ruby call parsed fine but printed back as a different, canonical spelling of the same call.
Parser.requirePrintEqualsInputthen rejected the file and it was dropped as a parse error. The shared root cause is the printer normalizing Ruby call syntax rather than preserving what the source actually wrote — in each case Prism reports the desugared call and the printer wrote that out.Foo.()printed asFoo.call().()is sugar for.call(), and Prism names the callcalleither way. A newImplicitCallmarker records that the message was elided, andRubyPrinteromits it. The one nuance: if a recipe has since renamed the method, the new name does have to be written out, so the printer only elides while the name is stillcall.Foo::method()printed asFoo.method()Ruby permits
::as a method-call delimiter, not only as constant scope resolution. TheColon2marker was already parsed and already honoured for ordinary invocations —J.NewClassjust never consulted it, so only the::newform was affected.Cursor desync on
eq({} => 0)A brace-less hash whose first key is itself a hash also starts with
{, and that brace was consumed as if it opened the outer hash. The brace only belongs to the hash when it sits ahead of the first pair.Impact
Found empirically by building a corpus of 105 real Rails applications. The first case alone accounted for roughly 85% of all Ruby parse errors across that corpus and also affects discourse, gumroad, both Basecamp apps, cyberark/conjur, diaspora and dradis-ce. Measured with
RubyCorpusTestonexercism/website:The one remaining failure is
scripts/setup_part_2.rb, which Prism itself rejects as a syntax error.The three real-world files that produced these reports —
exercism/website/test/test_helper.rb,alphagov/e-petitions/features/support/ssl_server.rbandalphagov/email-alert-api/spec/lib/collectors/global_prometheus_collector_spec.rb— all parse and round-trip.Tests
MethodInvocationTest#callSugar,#callSugarWithBlock,#explicitCall,#colon2CallandHashTest#hashKey, all asserting the source round-trips unchanged.explicitCallpins the explicitly-written.callform so eliding the message can't overreach. Full:rewrite-ruby:testis green (452 tests).