Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

Conversation

@amomchilov
Copy link
Collaborator

@amomchilov amomchilov commented Dec 12, 2025

Motivation

Benefits:

  • def foo(**) is confusing in dusugar tree output

    • Looks like an anonymous kwarg splat
    • The two asterisk have totally different meanings. The first is a *splat, the second is the name
  • Improves consistency with implicit block rest args:

    # Desugar of `def foo(a, *)`
    -def foo(a, **, &<blk>)
    +def foo(a, *<restargs>, &<blk>)
    
    # Desugar of `call { |a, *| }`
    -<self>.call() do |a, **|
    +<self>.call() do |a, *<restargs>|
    
    # Desugar of `call { |a,| }`, no change
    <self>.call() do |a, *<restargs>|
    • As a result, the "Anonymous rest parameter in block args" will now be correctly applied to implicit rest arguments, which previously didn't have it (only explicit anonymous rest args did)

I have follow-up PRs that make similar changes to ** (#9766) and & (#9762).

Test plan

Covered by existing tests.

call do |m, a,| # error: Method `call` does not exist
stuff # error: Method `stuff` does not exist
call do |m, a,|
# error: Anonymous rest parameter in block args
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If it was call do |m, a, *| it would have been caught.

This error should have been here all along, but wasn't detected. Now it is.

# error: Anonymous rest parameter in block args
T.reveal_type(k) # error: `String`
end
opts.each do |k, _|
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This might be a mistake. This isn't a block rest arg, just another named positional argument that happens to be called _.

I suspect this was intended:

Suggested change
opts.each do |k, _|
opts.each do |k, *|
# error: Anonymous rest parameter in block args

@amomchilov amomchilov marked this pull request as ready for review December 13, 2025 02:47
@amomchilov amomchilov requested a review from a team as a code owner December 13, 2025 02:47
@amomchilov amomchilov requested review from froydnj and removed request for a team December 13, 2025 02:47
@jez jez self-requested a review December 13, 2025 02:52
Copy link
Collaborator

@jez jez left a comment

Choose a reason for hiding this comment

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

This is a breaking change. Sorbet currently permits this code.

→ View on sorbet.run

# typed: true
extend T::Sig

sig {params("*": T.untyped).void}
def foo(*)
end
No errors! Great job.

(If we don't have a test for that, we should.)

We should not regress this for an appeal to internal consistency: parameter names have meaning.

@amomchilov
Copy link
Collaborator Author

amomchilov commented Dec 15, 2025

@jez Agreed, Sorbet should have a test for that.

How about we rewrite the sig to continue supporting the ”*” syntax, while still having a clear internal name (which also fixes the implicit rest bug)

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.

2 participants