-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Fix "stack level too deep" error when overriding Warning.warn
#3987
Fix "stack level too deep" error when overriding Warning.warn
#3987
Conversation
Looks good to me @eregon.
Regarding this, sure, definitely better to have safer code than to have nicer looking code. Let's add an extra test that fails with the prepend / extend approach to justify it. |
Test added.
That is, the original Kernel#warn is used and not RubyGems version, which is unintended. |
b7c176e
to
c63d5be
Compare
test/rubygems/test_require.rb
Outdated
end | ||
assert_match(/^Foo Bar\n/, err) | ||
assert_match(/^warn comes from/, err) | ||
refute_match(%r{^warn comes from .+rubygems/core_ext/kernel_warn.rb}, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for this refute
vs asserting it comes from core is that's it's not easy to assert it comes from core, because methods defined in Ruby will have a source_location. In Ruby 2.7:
$ ruby --disable-gems -e 'p method(:warn).source_location'
["<internal:warning>", 42]
Should be ready for final review & merge when CI passed now. |
I'm not sure I understand this very well, but I'm not clear what the end user problem that this fixes is.
But this one I'm not totally sure. If not necessary for any end user behaviour, it seems nice to me that the original Could you split the new checks to a separate test, since they are unrelated to |
In short, it fixes #2588, without changing any other behavior or changing the ancestors of any class. I wish without RubyGems it would just be a SystemStackError because redefining Warning#warn is IMHO the mistake in the first place (documented in ruby/ruby#3621), but since there is a workaround in Ruby it sounds indeed nice that the RubyGems version of Kernel#warn behaves the same. I guess your question is mostly is there a case where we'd want RubyGems' |
c63d5be
to
584ce1a
Compare
@deivid-rodriguez I've updated the test with something more realistic, it should be clearer now. BTW it seems on Ruby 3,
We see warn uses It's kind of a shame that we need to redefine |
584ce1a
to
97def17
Compare
I didn't notice the lint failed, fixed now. |
I got a new idea, and it seems to work on Ruby 3 and on TruffleRuby, so there we wouldn't need to override The idea is we could set the "file" value for RubyGems' require as starting with eval <<RUBY, nil, '<internal:skip-me-for-warnings>', __LINE__+1
def mycaller
foo
end
RUBY
def foo
warn "WARNING", uplevel: 1
end
mycaller On Ruby 3 and on TruffleRuby it gives:
On Ruby 2 (I tried 2.7 and 2.6) it gives:
Anyway, we still need the fallback for Ruby 2, so I think we should first merge this PR. |
97def17
to
0f08040
Compare
@deivid-rodriguez The CI passes now, could you merge this? |
Regarding #3987 (comment) I got confused, Actually, CRuby's Kernel#warn does not seems to skip core library methods written in Ruby currently:
|
Issue on the CRuby tracker to automatically skip |
Only need to set `kw[:uplevel]` when not already set.
This fixes infinite recursion when monkey-patching Warning#warn, which is not recommended, but still should behave the same whether RubyGems is loaded or not.
0f08040
to
4b0f57f
Compare
self
when calling the original Kernel#warn methodWarning.warn
I rebased this PR, squashed some commits and slightly modified the test, and your commit attribution was accidentally lost in that process. I'm really sorry about that, it was completely unintentional. |
A bit unfortunate, but not a big deal, thanks for merging. |
Preserve `self` when calling the original Kernel#warn method (cherry picked from commit fac8d59)
Preserve `self` when calling the original Kernel#warn method (cherry picked from commit fac8d59)
Alternative to #3985 which does not require adding a new module next to Kernel, and also works if some class inherits from
BasicObject
andinclude Kernel
.Warning.warn
#2588.I will abide by the code of conduct.
cc @deivid-rodriguez