Bug #19132
closed`**` を引数に指定すると no anonymous keyword rest parameter になる
Added by tommy (Masahiro Tomita) about 2 years ago. Updated about 2 years ago.
Description
Ruby 3.2.0-preview3 で次のスクリプトを実行するとエラーになります。
def hoge(a, *, k: nil, **)
foo(*, **)
end
% ruby hoge.rb
hoge.rb:2: no anonymous keyword rest parameter
次のようにキーワードパラメータが **
だけであればエラーになりませんでした。
def hoge(a, *, **)
foo(*, **)
end
Updated by shugo (Shugo Maeda) about 2 years ago
new_args_tail()でkw_argsがある時にANON_KEYWORD_REST_IDがローカル変数のテーブルから削られてしまうようです。
f_kwrestの値をinternal_idからANON_KEYWORD_REST_IDに変えると動くようになりました。
https://github.com/ruby/ruby/pull/6743
内部的な変数名が変わってtest/ruby/test_ast.rbが失敗するようになったのでその部分は対処しましたが、この修正方法だと他にも問題があるかもしれません。
Updated by shugo (Shugo Maeda) about 2 years ago
shugo (Shugo Maeda) wrote in #note-1:
内部的な変数名が変わってtest/ruby/test_ast.rbが失敗するようになったのでその部分は対処しましたが、この修正方法だと他にも問題があるかもしれません。
案の定RBSのテストで失敗したのでANON_KEYWORD_REST_IDを内部IDに変えてみたのですが、今度はUnboundMethod#parametersなどで :**
が返ることを期待しているテストがコケるようになってしまいました。
https://github.com/ruby/ruby/pull/6743#issuecomment-1317787459
内部IDか :**
のどちらかに統一して、必要ならこれらのテストかRBSを修正した方がいい気がするのですが、どうするのがいいでしょう。
Updated by nobu (Nobuyoshi Nakada) about 2 years ago
- Backport changed from 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN to 2.7: DONTNEED, 3.0: DONTNEED, 3.1: DONTNEED
Updated by nobu (Nobuyoshi Nakada) about 2 years ago
:**
に統一でいいのではないでしょうか。
Updated by shugo (Shugo Maeda) about 2 years ago
nobu (Nobuyoshi Nakada) wrote in #note-4:
:**
に統一でいいのではないでしょうか。
Rubyレベルで公開されている情報が :**
なので私もそちらに合わせる方がよいように思います。
Updated by shugo (Shugo Maeda) about 2 years ago
shugo (Shugo Maeda) wrote in #note-5:
nobu (Nobuyoshi Nakada) wrote in #note-4:
:**
に統一でいいのではないでしょうか。Rubyレベルで公開されている情報が
:**
なので私もそちらに合わせる方がよいように思います。
上記の修正でRBSのテストがこけるのを調べてみたのですが、RubyVM::ASTのテストが通るように以下の修正をしたせいでした。
--- a/ast.c
+++ b/ast.c
@@ -348,6 +348,7 @@ static VALUE
var_name(ID id)
{
if (!id) return Qnil;
+ if (!rb_is_local_id(id)) return Qnil;
if (!rb_id2str(id)) return Qnil;
return ID2SYM(id);
}
変数名が **
の時に名前なし扱いするためでしたが、これが def foo(...)
とかで定義される *
なども隠してしまっていたようです。
**
の時だけ隠すという修正もできますが、UnboundMethod#parametersなどでは **
という変数名が見えているので、RubyVM::ASTも合わせた方がいいように思います。
Updated by yui-knk (Kaneko Yuichiro) about 2 years ago
- UnboundMethod#parametersなどでは ** という変数名が見えている
-
DVAR@1:6-1:8 nil
で**
を表現するよりは、kwrest: (DVAR@1:6-1:8 :**)
で表現したほうが理解がしやすい
という点からRubyVM::AST側でも **
が取得できるというふうに修正し test/ruby/test_ast.rb のexpectationを更新するのがよいと思います。
また調べたところ、議論になっているtest caseが追加されたのが https://github.com/ruby/ruby/commit/fa41a7b2608#diff-7db75141987f9cf709ba4cb68969d3bc97b0de8dfe175d845df2f3de2b91cae6R320 で、 Add support for anonymous rest and keyword rest argument forwarding (https://github.com/ruby/ruby/commit/f53dfab95c3) のほうがあとであることもあり、expectationを更新することに前向きです。
anonymousでない場合:
pp RubyVM::AbstractSyntaxTree.parse("def a(**a) end")
#=> (SCOPE@1:0-1:14
tbl: []
args: nil
body:
(DEFN@1:0-1:14
mid: :a
body:
(SCOPE@1:0-1:14
tbl: [:a]
args:
(ARGS@1:6-1:9
pre_num: 0
pre_init: nil
opt: nil
first_post: nil
post_num: 0
post_init: nil
rest: nil
kw: nil
kwrest: (DVAR@1:6-1:9 :a)
block: nil)
body: nil)))
anonymousで、**
を隠す場合:
pp RubyVM::AbstractSyntaxTree.parse("def a(**) end")
#=> (SCOPE@1:0-1:13
tbl: []
args: nil
body:
(DEFN@1:0-1:13
mid: :a
body:
(SCOPE@1:0-1:13
tbl: [nil]
args:
(ARGS@1:6-1:8
pre_num: 0
pre_init: nil
opt: nil
first_post: nil
post_num: 0
post_init: nil
rest: nil
kw: nil
kwrest: (DVAR@1:6-1:8 nil)
block: nil)
body: nil)))
anonymousで、**
を隠さない場合:
pp RubyVM::AbstractSyntaxTree.parse("def a(**) end")
#=> (SCOPE@1:0-1:13
tbl: []
args: nil
body:
(DEFN@1:0-1:13
mid: :a
body:
(SCOPE@1:0-1:13
tbl: [:**]
args:
(ARGS@1:6-1:8
pre_num: 0
pre_init: nil
opt: nil
first_post: nil
post_num: 0
post_init: nil
rest: nil
kw: nil
kwrest: (DVAR@1:6-1:8 :**)
block: nil)
body: nil)))
Updated by shugo (Shugo Maeda) about 2 years ago
- Status changed from Open to Closed
Applied in changeset git|ddd62fadaf91418cd259593285bc59358fb0b166.
Allow anonymous keyword rest parameter with other keyword parameters
Fixes [Bug #19132]