Feature #16954
closedA new mode `Warning[:deprecated] = :error` for 2.7
Description
Problem¶
(This is what I already wrote in rubyonrails discourse but I repeat this to make this discussion easy.)
The plan of 3.0 keyword change (#14183) will prohibit the automatic conversion from the last Hash positional argument to keyword arguments, but will keep one from keywords to a positional argument. This asymmetry made it difficult to fix code of argument forwarding. @kamipo and @matsuda (Akira Matsuda), Rails developers who did much work to support the 3.0 keyword change, found the following (simplified) case where a warning is emitted within Rails code although Rails is innocent.
Rails code:
def target(**opt) # warning: The called method `foo' is defined here
end
ruby2_keywords def lib_proxy(*args)
target(*args) # warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
end
User application code (or gem code other than Rails):
def app_proxy(*args) # actually, ruby2_keywords is required here
lib_proxy(*args)
end
app_proxy(k: 42)
The user code attempts to pass keywords to Rails' target
method via argument forwarding methods app_proxy
and lib_proxy
. Rails appropriately annotates lib_proxy
with ruby2_keywords, but user code does not yet for app_proxy
. Calling app_proxy
converts the keywords to a normal Hash, so the final target
method accepts them as a positional Hash, which leads to the warning. Unfortunately, the warning points only Rails code. So, the user sends a bug report to Rails and there is no good way for Rails developer to diagnose the issue.
@kamipo said that actual cases include rails/rails #39562 and #39227.
Proposal¶
We can think of two solutions for this issue:
- Make the warning print a full backtrace (including
app_proxy
in the above case) so that they can debug the issue. - Warn an event of automatic conversion from keywords to a positional one, This will point the call of
app_proxy
, though it brings false positives.
Focus on the first solution in this ticket. (I'll create another ticket for the second one.)
There are two (orthogonal) approaches to make the first solution:
-
Warning[:deprecated] = :error
, to make the warning into an error which produces a full backtrace (and stops the execution). -
Warning[:deprecated] = :debug
, to make the warning print a full backtrace (and continues the execution).
The former one is like Thread.abort_on_exception = true
, and the latter is like Thread.report_on_exception = true
.
A patch is not availrable yet. (I'm asking @nobu (Nobuyoshi Nakada) to create a patch.)
Discussion points¶
- We need to add this change into Ruby 2.7.2. Is it acceptable? (Matz has already agreed with this change, but we need to get approval from @nagachika (Tomoyuki Chikanaga), the 2.7 branch maintainer.)
- Which approach is preferrable? Both?
- Are the names
:error
and:debug
okay? Or:abort
and:report
likeThread.*_on_exception
? Or other names? - Should the commandline option
-W:deprecated
support the new modes? Like-W:deprecated=error
?