Bug #20478
closedCircular parameter syntax error rules
Description
I would like to revisit https://bugs.ruby-lang.org/issues/16343.
These cases are syntax errors:
def foo(bar = -> { bar }) end # no lambda parameters
def foo(bar = ->() { bar }) end # no lambda parameters
def foo(bar = baz { bar }) end # no block parameters
def foo(bar = baz { _1 + bar }) end # parameters, but no pipes
def foo(bar = baz { it + bar }) end # parameters, but no pipes
These cases are not syntax errors:
def foo(bar = ->(baz) { bar }) end # lambda parameters
def foo(bar = baz { || bar }) end # no block parameters but empty pipes
def foo(bar = baz { |qux| bar }) end # block parameters
I don't think these rules are very intuitive, and they feel somewhat arbitrary. I would like to suggest we change them to be either:
- Syntax error is raised if the parameter is ever read in its default value at any scope depth
- Syntax error is raised if the parameter is ever read in its default value at depth 0
Either one is fine by me, but gating the syntax error based on the presence of pipes is really confusing.
Updated by nobu (Nobuyoshi Nakada) 6 months ago
Given that these Proc
s are only created if the argument bar
is not assigned, should they all be syntax errors?
Updated by kddnewton (Kevin Newton) 6 months ago
Yes, I very much think they should all be syntax errors.
Updated by nobu (Nobuyoshi Nakada) 6 months ago
Even this should be a syntax error?
def foo(bar = ->(baz = bar) {}) end
That means it needs to manage the list of yet-unusable variables, not only tracking single variable.
Updated by kddnewton (Kevin Newton) 6 months ago
I figured that was already happening for the "unused" warning.
Updated by byroot (Jean Boussier) 6 months ago
- Related to Bug #16343: Inconsistent behavior of 'circular argument reference' error added
Updated by kddnewton (Kevin Newton) 6 months ago
@nobu (Nobuyoshi Nakada) another option would be to delete those tests and leave it up to the parser instead of forcing parse.y to implement it. Specifically I'm talking about:
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var: bar {| | var}) var end")
end
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var: bar {|| var}) var end")
end
and
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var = bar {| | var}) var end")
end
o = Object.new
assert_warn("") do
o.instance_eval("def foo(var = bar {|| var}) var end")
end
If it's too complicated to implement in parse.y, then removing these tests would be a good compromise. These tests themselves are the issue blocking me.
Updated by kddnewton (Kevin Newton) 6 months ago
If we go with only syntax errors at depth 0, then this:
def foo(bar = baz { bar }) end
should not be a syntax error either. I think that makes sense, because the baz
method could use instance_exec
/instance_eval
so we don't know if bar
is going to be the same variable here or not.
Updated by kddnewton (Kevin Newton) 6 months ago
Also:
def foo(bar = -> { bar }) end
def foo(bar = ->( ) { bar }) end
def foo(bar = ->(_) { bar }) end
Two of these are a syntax error, but I think either all of them should be or none of them should be.
Updated by mame (Yusuke Endoh) 5 months ago
Discussed at the dev meeting. @matz (Yukihiro Matsumoto) said all cases should be accepted with no syntax error. So def foo(bar = bar) = bar; foo
will return nil
with no warning and error.