From: "nobu (Nobuyoshi Nakada)" Date: 2022-03-15T08:56:44+00:00 Subject: [ruby-core:107908] [Ruby master Bug#18632] Struct.new wrongly treats a positional Hash as keyword arguments Issue #18632 has been updated by nobu (Nobuyoshi Nakada). `rb_check_arity` with unlimited arguments are: ``` array.c:2420: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); array.c:7602: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); eval.c:1138: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); eval.c:1195: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); eval.c:1649: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); eval.c:1754: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); ext/-test-/iter/yield.c:6: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); ext/io/console/console.c:1456: rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS); ext/syslog/syslog.c:304: rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS); ext/win32ole/win32ole.c:3353: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); ext/zlib/zlib.c:3225: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); file.c:374:#define apply2args(n) (rb_check_arity(argc, n, UNLIMITED_ARGUMENTS), argc-=n) hash.c:4579: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); proc.c:2615: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); process.c:2584: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); signal.c:432: rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS); string.c:8179: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); string.c:8438: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); struct.c:580: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); struct.c:1517: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); vm_eval.c:2193: rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS); vm_method.c:2393: rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); ``` Probably only these two. ```diff diff --git i/eval.c w/eval.c index d91440676fb..cb2b3779fe4 100644 --- i/eval.c +++ w/eval.c @@ -704,6 +704,9 @@ extract_raise_opts(int argc, const VALUE *argv, VALUE *opts) if (!RHASH_EMPTY_P(opt)) { ID keywords[1]; CONST_ID(keywords[0], "cause"); + if (!rb_scan_args_keyword_p(RB_SCAN_ARGS_PASS_CALLED_KEYWORDS, opt)) { + rb_warn_deprecated_to_remove("3.3", "passing non-keywords Hash", "**"); + } rb_get_kwargs(opt, keywords, 0, -1-raise_max_opt, opts); if (RHASH_EMPTY_P(opt)) --argc; return argc; diff --git i/struct.c w/struct.c index 8b19266e62d..c3af0830105 100644 --- i/struct.c +++ w/struct.c @@ -589,11 +589,15 @@ rb_struct_s_def(int argc, VALUE *argv, VALUE klass) if (RB_TYPE_P(argv[argc-1], T_HASH)) { static ID keyword_ids[1]; + VALUE opt = argv[argc-1]; if (!keyword_ids[0]) { keyword_ids[0] = rb_intern("keyword_init"); } - rb_get_kwargs(argv[argc-1], keyword_ids, 0, 1, &keyword_init); + if (!rb_scan_args_keyword_p(RB_SCAN_ARGS_PASS_CALLED_KEYWORDS, opt)) { + rb_warn_deprecated_to_remove("3.3", "passing non-keywords Hash", "**"); + } + rb_get_kwargs(opt, keyword_ids, 0, 1, &keyword_init); if (keyword_init == Qundef) { keyword_init = Qnil; } ``` ---------------------------------------- Bug #18632: Struct.new wrongly treats a positional Hash as keyword arguments https://bugs.ruby-lang.org/issues/18632#change-96846 * Author: Eregon (Benoit Daloze) * Status: Open * Priority: Normal * ruby -v: ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux] * Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- ``` $ ruby -e 'Struct.new(:a, name: "b")' -e:1:in `new': unknown keyword: :name (ArgumentError) from -e:1:in `
' ^ expected $ ruby -e 'Struct.new(:a, { name: "b" })' -e:1:in `new': unknown keyword: :name (ArgumentError) from -e:1:in `
' ^ wrong ``` It shouldn't be such an error for the 2nd command since it's a positional Hash. It should be a TypeError, like when passing e.g. `nil` instead of the positional Hash. Also: ``` $ ruby -e 'p Struct.new(:a, {}).members' [:a] ``` But it should be an error to pass a positional Hash. I think this is worth fixing, because it basically breaks the separation of positional and keyword arguments for this method. Also Struct.new does take a keyword argument, `keyword_init: true`. -- https://bugs.ruby-lang.org/ Unsubscribe: