From: Yusuke Endoh Date: 2011-07-22T01:36:11+09:00 Subject: [ruby-core:38351] [Ruby 1.9 - Bug #5068][Assigned] Issue with "duplicated when clause is ignored" Issue #5068 has been updated by Yusuke Endoh. Status changed from Open to Assigned Assignee set to Yusuke Endoh Target version set to 1.9.x Here is a patch. It became bigger than expected... I'll commit it unless there is objection. diff --git a/compile.c b/compile.c index 53149ca..c1012f7 100644 --- a/compile.c +++ b/compile.c @@ -1275,6 +1275,18 @@ static const struct st_hash_type cdhash_type = { cdhash_hash, }; +static int +translate_cdhash(st_data_t key, st_data_t val, st_data_t arg) +{ + VALUE lit = (VALUE)key; + LABEL *lobj = (LABEL *)(val & ~1); + VALUE *p = (VALUE *)arg; + + rb_hash_aset(p[0], key, INT2FIX(lobj->position - FIX2INT(p[1]))); + return ST_CONTINUE; +} + + /** ruby insn object list -> raw instruction sequence */ @@ -1402,30 +1414,11 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor) * [obj, label, ...] */ int i; - VALUE lits = operands[j]; - VALUE map = rb_hash_new(); - RHASH_TBL(map)->type = &cdhash_type; - - for (i=0; i < RARRAY_LEN(lits); i+=2) { - VALUE obj = rb_ary_entry(lits, i); - VALUE lv = rb_ary_entry(lits, i+1); - lobj = (LABEL *)(lv & ~1); - - if (!lobj->set) { - rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no, - "unknown label"); - } - if (!st_lookup(rb_hash_tbl(map), obj, 0)) { - rb_hash_aset(map, obj, INT2FIX(lobj->position - (pos+len))); - } - else { - rb_compile_warning(RSTRING_PTR(iseq->filename), iobj->line_no, - "duplicated when clause is ignored"); - } - } - hide_obj(map); - generated_iseq[pos + 1 + j] = map; - iseq_add_mark_object(iseq, map); + VALUE lits = operands[j], arg[2] = { lits, INT2FIX(pos+len) }; + st_foreach(RHASH_TBL(lits), translate_cdhash, (st_data_t)arg); + hide_obj(lits); + generated_iseq[pos + 1 + j] = lits; + iseq_add_mark_object(iseq, lits); break; } case TS_LINDEX: @@ -2345,7 +2338,7 @@ case_when_optimizable_literal(NODE * node) } static VALUE -when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE special_literals) +when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE special_literal_opt, VALUE special_literals) { while (vals) { VALUE lit; @@ -2353,13 +2346,17 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE s val = vals->nd_head; - if (special_literals && - (lit = case_when_optimizable_literal(val)) != Qfalse) { - rb_ary_push(special_literals, lit); - rb_ary_push(special_literals, (VALUE)(l1) | 1); + if ((lit = case_when_optimizable_literal(val)) != Qfalse) { + if (!st_lookup(rb_hash_tbl(special_literals), lit, 0)) { + rb_hash_aset(special_literals, lit, (VALUE)(l1) | 1); + } + else { + rb_compile_warning(RSTRING_PTR(iseq->filename), nd_line(val), + "duplicated when clause is ignored"); + } } else { - special_literals = Qfalse; + special_literal_opt = Qfalse; } if (nd_type(val) == NODE_STR) { @@ -2375,7 +2372,7 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE s ADD_INSNL(cond_seq, nd_line(val), branchif, l1); vals = vals->nd_next; } - return special_literals; + return special_literal_opt; } static int @@ -3049,13 +3046,14 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) break; } case NODE_CASE:{ + VALUE special_literals; NODE *vals; NODE *tempnode = node; LABEL *endlabel, *elselabel; DECL_ANCHOR(head); DECL_ANCHOR(body_seq); DECL_ANCHOR(cond_seq); - VALUE special_literals = rb_ary_tmp_new(1); + VALUE special_literal_opt = Qtrue; INIT_ANCHOR(head); INIT_ANCHOR(body_seq); @@ -3068,6 +3066,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) node = node->nd_body; type = nd_type(node); + special_literals = rb_hash_new(); + RHASH_TBL(special_literals)->type = &cdhash_type; if (type != NODE_WHEN) { COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type))); @@ -3091,12 +3091,12 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) if (vals) { switch (nd_type(vals)) { case NODE_ARRAY: - special_literals = when_vals(iseq, cond_seq, vals, l1, special_literals); + special_literal_opt = when_vals(iseq, cond_seq, vals, l1, special_literal_opt, special_literals); break; case NODE_SPLAT: case NODE_ARGSCAT: case NODE_ARGSPUSH: - special_literals = 0; + special_literal_opt = 0; COMPILE(cond_seq, "when/cond splat", vals); ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue); ADD_INSNL(cond_seq, nd_line(vals), branchif, l1); @@ -3133,7 +3133,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel); } - if (special_literals) { + if (special_literal_opt) { ADD_INSN(ret, nd_line(tempnode), dup); ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch, special_literals, elselabel); @@ -5381,16 +5381,17 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor, case TS_CDHASH: { int i; + VALUE map = rb_hash_new(); op = rb_convert_type(op, T_ARRAY, "Array", "to_ary"); op = rb_ary_dup(op); for (i=0; i ---------------------------------------- Bug #5068: Issue with "duplicated when clause is ignored" http://redmine.ruby-lang.org/issues/5068 Author: Stefano Mioli Status: Assigned Priority: Normal Assignee: Yusuke Endoh Category: Target version: 1.9.x ruby -v: 1.9.2-p{180,290} I'm filing this ticket as suggested by Ryan Davis here: http://www.ruby-forum.com/topic/2154866#1011303 Let's consider this snippet: x = 0 case x when 1 when 0 when 1 end Executing a file containing this code with ruby -w, the interpreter will print out this warning: warning: duplicated when clause is ignored Let's consider this one instead: x = 0 case x when 1 when 0 + 1 when 1 end This will *not* print out the same warning, even though we still have a duplicated 'when'. -- http://redmine.ruby-lang.org