From 37279d15468ec5d5873e9a5fea49cd6323891fa6 Mon Sep 17 00:00:00 2001 From: nobu Date: Tue, 14 Aug 2018 11:58:17 +0000 Subject: non-symbol keys in kwargs * class.c (separate_symbol): [EXPERIMENTAL] non-symbol key in keyword arguments hash causes an exception now. c.f. https://twitter.com/yukihiro_matz/status/1022287578995646464 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64358 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- class.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) (limited to 'class.c') diff --git a/class.c b/class.c index cb47849e96..b77974fdf2 100644 --- a/class.c +++ b/class.c @@ -1814,33 +1814,57 @@ unknown_keyword_error(VALUE hash, const ID *table, int keywords) rb_keyword_error("unknown", rb_hash_keys(hash)); } +struct extract_keywords { + VALUE kwdhash, nonsymkey; +}; + static int separate_symbol(st_data_t key, st_data_t value, st_data_t arg) { - VALUE *kwdhash = (VALUE *)arg; + struct extract_keywords *argp = (struct extract_keywords *)arg; + VALUE k = (VALUE)key, v = (VALUE)value; - if (!SYMBOL_P(key)) kwdhash++; - if (!*kwdhash) *kwdhash = rb_hash_new(); - rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value); + if (argp->kwdhash) { + if (UNLIKELY(!SYMBOL_P(k))) { + argp->nonsymkey = k; + return ST_STOP; + } + } + else if (SYMBOL_P(k)) { + if (UNLIKELY(argp->nonsymkey != Qundef)) { + argp->kwdhash = Qnil; + return ST_STOP; + } + argp->kwdhash = rb_hash_new(); + } + else { + if (argp->nonsymkey == Qundef) + argp->nonsymkey = k; + return ST_CONTINUE; + } + rb_hash_aset(argp->kwdhash, k, v); return ST_CONTINUE; } VALUE rb_extract_keywords(VALUE *orighash) { - VALUE parthash[2] = {0, 0}; + struct extract_keywords arg = {0, Qundef}; VALUE hash = *orighash; if (RHASH_EMPTY_P(hash)) { *orighash = 0; return hash; } - st_foreach(rb_hash_tbl_raw(hash), separate_symbol, (st_data_t)&parthash); - *orighash = parthash[1]; - if (parthash[1] && RBASIC_CLASS(hash) != rb_cHash) { - RBASIC_SET_CLASS(parthash[1], RBASIC_CLASS(hash)); + st_foreach(rb_hash_tbl_raw(hash), separate_symbol, (st_data_t)&arg); + if (arg.kwdhash) { + if (arg.nonsymkey != Qundef) { + rb_raise(rb_eArgError, "non-symbol key in keyword arguments: %+"PRIsVALUE, + arg.nonsymkey); + } + *orighash = 0; } - return parthash[0]; + return arg.kwdhash; } int -- cgit v1.2.3