[ruby-core:117313] [Ruby master Bug#20392] Delegate super calls with a block

Issue #20392 has been reported by tenderlovemaking (Aaron Patterson). ---------------------------------------- Bug #20392: Delegate super calls with a block https://bugs.ruby-lang.org/issues/20392 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket. Using delegate `...` with an explicit block will cause an error: ```ruby # Example 1 def foo ... yield end def bar ... foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError) end ``` However, calling `super` and passing a block works: ``` # Example 2 class A def foo yield(3) end end class B < A def foo(...) super do |x| yield(2 + x) end end end p B.new.foo { |x| x } # 5 ``` In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`. However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored: ```ruby # Example 3 class A def foo yield(3) end end class B < A def foo(...) super(...) do |x| raise "should I be called?" end end end p B.new.foo { |x| x } # 3 ``` I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior. Is Example 3 intended behavior? If not, how should it behave? Thanks. -- https://bugs.ruby-lang.org/

Issue #20392 has been updated by Dan0042 (Daniel DeLorme). In Ruby 3.2, example 3 raised an exception "both block arg and actual block given" So this looks like a Ruby 3.3 regression. ---------------------------------------- Bug #20392: Delegate super calls with a block https://bugs.ruby-lang.org/issues/20392#change-107454 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket. Using delegate `...` with an explicit block will cause an error: ```ruby # Example 1 def foo ... yield end def bar ... foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError) end ``` However, calling `super` and passing a block works: ``` # Example 2 class A def foo yield(3) end end class B < A def foo(...) super do |x| yield(2 + x) end end end p B.new.foo { |x| x } # 5 ``` In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`. However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored: ```ruby # Example 3 class A def foo yield(3) end end class B < A def foo(...) super(...) do |x| raise "should I be called?" end end end p B.new.foo { |x| x } # 3 ``` I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior. Is Example 3 intended behavior? If not, how should it behave? Thanks. -- https://bugs.ruby-lang.org/

Issue #20392 has been updated by jeremyevans0 (Jeremy Evans). `super(...){}`should be a syntax error, just as `foo(...){}` is. `super` behavior in general is special. For example, `super(arg)` is not a zsuper, but still passes the block implicitly, you have to do `super(arg, &nil)` to avoid passing a block. `super{}` passes the args implicitly, but uses the block given. While I find that confusing, I don't think changing that behavior is worth it, as the backwards compatibility breakage is not worth the benefit IMO. ---------------------------------------- Bug #20392: Delegate super calls with a block https://bugs.ruby-lang.org/issues/20392#change-107455 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket. Using delegate `...` with an explicit block will cause an error: ```ruby # Example 1 def foo ... yield end def bar ... foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError) end ``` However, calling `super` and passing a block works: ``` # Example 2 class A def foo yield(3) end end class B < A def foo(...) super do |x| yield(2 + x) end end end p B.new.foo { |x| x } # 5 ``` In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`. However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored: ```ruby # Example 3 class A def foo yield(3) end end class B < A def foo(...) super(...) do |x| raise "should I be called?" end end end p B.new.foo { |x| x } # 3 ``` I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior. Is Example 3 intended behavior? If not, how should it behave? Thanks. -- https://bugs.ruby-lang.org/

Issue #20392 has been updated by tenderlovemaking (Aaron Patterson). Dan0042 (Daniel DeLorme) wrote in #note-1:
In Ruby 3.2, example 3 raised an exception "both block arg and actual block given" So this looks like a Ruby 3.3 regression.
Thanks, I should have checked older versions. According to git bisect, this was introduced in fdc329ea6f5bce922e95645a0c2118cfd3e1cdea (though I'm not sure how that commit caused this) jeremyevans0 (Jeremy Evans) wrote in #note-2:
`super(...){}`should be a syntax error, just as `foo(...){}` is.
`super` behavior in general is special. For example, `super(arg)` is not a zsuper, but still passes the block implicitly, you have to do `super(arg, &nil)` to avoid passing a block. `super{}` passes the args implicitly, but uses the block given. While I find that confusing, I don't think changing that behavior is worth it, as the backwards compatibility breakage is not worth the benefit IMO.
It's very odd behavior, but I definitely agree. ---------------------------------------- Bug #20392: Delegate super calls with a block https://bugs.ruby-lang.org/issues/20392#change-107456 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket. Using delegate `...` with an explicit block will cause an error: ```ruby # Example 1 def foo ... yield end def bar ... foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError) end ``` However, calling `super` and passing a block works: ``` # Example 2 class A def foo yield(3) end end class B < A def foo(...) super do |x| yield(2 + x) end end end p B.new.foo { |x| x } # 5 ``` In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`. However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored: ```ruby # Example 3 class A def foo yield(3) end end class B < A def foo(...) super(...) do |x| raise "should I be called?" end end end p B.new.foo { |x| x } # 3 ``` I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior. Is Example 3 intended behavior? If not, how should it behave? Thanks. -- https://bugs.ruby-lang.org/

Issue #20392 has been updated by jeremyevans0 (Jeremy Evans). tenderlovemaking (Aaron Patterson) wrote in #note-3:
Dan0042 (Daniel DeLorme) wrote in #note-1:
In Ruby 3.2, example 3 raised an exception "both block arg and actual block given" So this looks like a Ruby 3.3 regression.
Thanks, I should have checked older versions. According to git bisect, this was introduced in fdc329ea6f5bce922e95645a0c2118cfd3e1cdea (though I'm not sure how that commit caused this)
It's missing entries for `NODE_SUPER` and `NODE_ZSUPER` in `get_nd_args`, so the `nd_args` are ignored for those nodes. At least those node types should be fixed, and all other node types in the switch should be checked to see if this isn't swallowing other syntax errors. @yui-knk is my analysis correct? ---------------------------------------- Bug #20392: Delegate super calls with a block https://bugs.ruby-lang.org/issues/20392#change-107457 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket. Using delegate `...` with an explicit block will cause an error: ```ruby # Example 1 def foo ... yield end def bar ... foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError) end ``` However, calling `super` and passing a block works: ``` # Example 2 class A def foo yield(3) end end class B < A def foo(...) super do |x| yield(2 + x) end end end p B.new.foo { |x| x } # 5 ``` In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`. However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored: ```ruby # Example 3 class A def foo yield(3) end end class B < A def foo(...) super(...) do |x| raise "should I be called?" end end end p B.new.foo { |x| x } # 3 ``` I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior. Is Example 3 intended behavior? If not, how should it behave? Thanks. -- https://bugs.ruby-lang.org/

Issue #20392 has been updated by nobu (Nobuyoshi Nakada). Description updated https://github.com/ruby/ruby/pull/10361 ---------------------------------------- Bug #20392: Delegate super calls with a block https://bugs.ruby-lang.org/issues/20392#change-107458 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket. Using delegate `...` with an explicit block will cause an error: ```ruby # Example 1 def foo ... yield end def bar ... foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError) end ``` However, calling `super` and passing a block works: ```ruby # Example 2 class A def foo yield(3) end end class B < A def foo(...) super do |x| yield(2 + x) end end end p B.new.foo { |x| x } # 5 ``` In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`. However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored: ```ruby # Example 3 class A def foo yield(3) end end class B < A def foo(...) super(...) do |x| raise "should I be called?" end end end p B.new.foo { |x| x } # 3 ``` I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior. Is Example 3 intended behavior? If not, how should it behave? Thanks. -- https://bugs.ruby-lang.org/

Issue #20392 has been updated by nobu (Nobuyoshi Nakada). jeremyevans0 (Jeremy Evans) wrote in #note-4:
It's missing entries for `NODE_SUPER` and `NODE_ZSUPER` in `get_nd_args`, so the `nd_args` are ignored for those nodes. At least those node types should be fixed, and all other node types in the switch should be checked to see if this isn't swallowing other syntax errors. @yui-knk is my analysis correct?
I think that zsuper is special. ---------------------------------------- Bug #20392: Delegate super calls with a block https://bugs.ruby-lang.org/issues/20392#change-107459 * Author: tenderlovemaking (Aaron Patterson) * Status: Open * ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket. Using delegate `...` with an explicit block will cause an error: ```ruby # Example 1 def foo ... yield end def bar ... foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError) end ``` However, calling `super` and passing a block works: ```ruby # Example 2 class A def foo yield(3) end end class B < A def foo(...) super do |x| yield(2 + x) end end end p B.new.foo { |x| x } # 5 ``` In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`. However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored: ```ruby # Example 3 class A def foo yield(3) end end class B < A def foo(...) super(...) do |x| raise "should I be called?" end end end p B.new.foo { |x| x } # 3 ``` I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior. Is Example 3 intended behavior? If not, how should it behave? Thanks. -- https://bugs.ruby-lang.org/
participants (4)
-
Dan0042 (Daniel DeLorme)
-
jeremyevans0 (Jeremy Evans)
-
nobu (Nobuyoshi Nakada)
-
tenderlovemaking (Aaron Patterson)