diff options
author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2021-06-03 12:32:44 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2021-06-03 15:11:18 +0900 |
commit | 37eb5e74395f148782f7d67b5218fb2e66b113d7 (patch) | |
tree | f92f0414ab29ff9ff6b6dca6a13b600574d165b0 | |
parent | a023db49bfbbbe119638bae6abf8113f0de371de (diff) |
Warn more duplicate literal hash keys
Following non-special_const literals:
* T_BIGNUM
* T_FLOAT (non-flonum)
* T_RATIONAL
* T_COMPLEX
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4548
-rw-r--r-- | compile.c | 16 | ||||
-rw-r--r-- | internal/compile.h | 2 | ||||
-rw-r--r-- | parse.y | 34 | ||||
-rw-r--r-- | test/ruby/test_literal.rb | 4 |
4 files changed, 47 insertions, 9 deletions
@@ -1967,8 +1967,8 @@ iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl) return COMPILE_OK; } -static int -cdhash_cmp(VALUE val, VALUE lit) +int +rb_iseq_cdhash_cmp(VALUE val, VALUE lit) { int tval, tlit; @@ -2004,20 +2004,20 @@ cdhash_cmp(VALUE val, VALUE lit) else if (tlit == T_RATIONAL) { const struct RRational *rat1 = RRATIONAL(val); const struct RRational *rat2 = RRATIONAL(lit); - return cdhash_cmp(rat1->num, rat2->num) || cdhash_cmp(rat1->den, rat2->den); + return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den); } else if (tlit == T_COMPLEX) { const struct RComplex *comp1 = RCOMPLEX(val); const struct RComplex *comp2 = RCOMPLEX(lit); - return cdhash_cmp(comp1->real, comp2->real) || cdhash_cmp(comp1->imag, comp2->imag); + return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag); } else { UNREACHABLE_RETURN(-1); } } -static st_index_t -cdhash_hash(VALUE a) +st_index_t +rb_iseq_cdhash_hash(VALUE a) { switch (OBJ_BUILTIN_TYPE(a)) { case -1: @@ -2039,8 +2039,8 @@ cdhash_hash(VALUE a) } static const struct st_hash_type cdhash_type = { - cdhash_cmp, - cdhash_hash, + rb_iseq_cdhash_cmp, + rb_iseq_cdhash_hash, }; struct cdhash_set_label_struct { diff --git a/internal/compile.h b/internal/compile.h index c1f2a36685..99c15d6a44 100644 --- a/internal/compile.h +++ b/internal/compile.h @@ -20,6 +20,8 @@ int rb_dvar_defined(ID, const struct rb_iseq_struct *); int rb_local_defined(ID, const struct rb_iseq_struct *); const char *rb_insns_name(int i); VALUE rb_insns_name_array(void); +int rb_iseq_cdhash_cmp(VALUE val, VALUE lit); +st_index_t rb_iseq_cdhash_hash(VALUE a); /* iseq.c */ int rb_vm_insn_addr2insn(const void *); @@ -12184,10 +12184,42 @@ append_literal_keys(st_data_t k, st_data_t v, st_data_t h) return ST_CONTINUE; } +static bool +hash_literal_key_p(VALUE k) +{ + switch (OBJ_BUILTIN_TYPE(k)) { + case T_NODE: + case T_REGEXP: + return false; + default: + return true; + } +} + +static int +literal_cmp(VALUE val, VALUE lit) +{ + if (val == lit) return 0; + if (!hash_literal_key_p(val) || !hash_literal_key_p(lit)) return -1; + return rb_iseq_cdhash_cmp(val, lit); +} + +static st_index_t +literal_hash(VALUE a) +{ + if (!hash_literal_key_p(a)) return (st_index_t)a; + return rb_iseq_cdhash_hash(a); +} + +static const struct st_hash_type literal_type = { + literal_cmp, + literal_hash, +}; + static NODE * remove_duplicate_keys(struct parser_params *p, NODE *hash) { - st_table *literal_keys = st_init_numtable_with_size(hash->nd_alen / 2); + st_table *literal_keys = st_init_table_with_size(&literal_type, hash->nd_alen / 2); NODE *result = 0; rb_code_location_t loc = hash->nd_loc; while (hash && hash->nd_head && hash->nd_next) { diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb index 10cb09b833..ed93b74cff 100644 --- a/test/ruby/test_literal.rb +++ b/test/ruby/test_literal.rb @@ -480,6 +480,10 @@ class TestRubyLiteral < Test::Unit::TestCase '"a"', '1000', '1.0', + '1_000_000_000_000_000_000_000', + '1.0r', + '1.0i', + '1.72723e-77', ) do |key| assert_warning(/key #{Regexp.quote(eval(key).inspect)} is duplicated/) do eval("{#{key} => :bar, #{key} => :foo}") |