Bug #2226

case 文の式が省略され when 節に配列展開があるときの挙動

Added by _ wanabe over 2 years ago. Updated 10 months ago.

[ruby-dev:39506]
Status:Closed Start date:
Priority:Low Due date:
Assignee:Yukihiro Matsumoto % Done:

100%

Category:core
Target version:1.9.2
ruby -v:ruby 1.9.2dev (2009-10-22 trunk 25433) [x86_64-freebsd8.0]

Description

ワナベと申します。

case 文の式が省略され、かつ when 節に配列展開があるときの挙動、
より具体的には NODE_ARGSCAT, NODE_ARGSPUSH の
コンパイル結果が正しくないように思います。
通常の NODE_CASE と同じように処理するのはどうでしょうか。

$ cat test.rb
case
when *[], false
  p :ng1
else
  p :ok
end

case
when *false, []
  p :ok
else
  p :ng2
end

begin
  case
  when false, *nonexistent_var, false
    p :ng3
  else
    p :ng4
  end
rescue NameError
  p :ok
end

$ ruby -v test.rb
ruby 1.9.2dev (2009-10-17 trunk 25387) [i386-mingw32]
:ng1
:ng2
:ng3


Index: compile.c
===================================================================
--- compile.c	(revision 25387)
+++ compile.c	(working copy)
@@ -3116,41 +3116,31 @@
 	    ADD_INSNL(body_seq, nd_line(node), jump, endlabel);

 	    vals = node->nd_head;
-	    if (vals && nd_type(vals) == NODE_ARRAY) {
+	    if (!vals) {
+		rb_bug("NODE_WHEN: must be NODE_ARRAY, but 0");
+	    }
+	    switch (nd_type(vals)) {
+	      case NODE_ARRAY:
 		while (vals) {
 		    val = vals->nd_head;
 		    COMPILE(ret, "when2", val);
 		    ADD_INSNL(ret, nd_line(val), branchif, l1);
 		    vals = vals->nd_next;
 		}
+		break;
+	      case NODE_SPLAT:
+	      case NODE_ARGSCAT:
+	      case NODE_ARGSPUSH:
+		ADD_INSN(ret, nd_line(vals), putnil);
+		COMPILE(ret, "when2/cond splat", vals);
+		ADD_INSN1(ret, nd_line(vals), checkincludearray, Qfalse);
+		ADD_INSN(ret, nd_line(vals), pop);
+		ADD_INSNL(ret, nd_line(vals), branchif, l1);
+		break;
+	      default:
+		rb_bug("NODE_WHEN: unknown node (%s)",
+		       ruby_node_name(nd_type(vals)));
 	    }
-	    else if (nd_type(vals) == NODE_SPLAT ||
-		     nd_type(vals) == NODE_ARGSCAT ||
-		     nd_type(vals) == NODE_ARGSPUSH) {
-
-		NODE *val = vals->nd_head;
-
-		if (nd_type(vals) == NODE_ARGSCAT || nd_type(vals) == NODE_ARGSPUSH) {
-		    NODE *vs = vals->nd_head;
-		    val = vals->nd_body;
-
-		    while (vs) {
-			NODE* val = vs->nd_head;
-			COMPILE(ret, "when/argscat", val);
-			ADD_INSNL(ret, nd_line(val), branchif, l1);
-			vs = vs->nd_next;
-		    }
-		}
-
-		ADD_INSN(ret, nd_line(val), putnil);
-		COMPILE(ret, "when2/splat", val);
-		ADD_INSN1(ret, nd_line(val), checkincludearray, Qfalse);
-		ADD_INSN(ret, nd_line(val), pop);
-		ADD_INSNL(ret, nd_line(val), branchif, l1);
-	    }
-	    else {
-		rb_bug("err");
-	    }
 	    node = node->nd_next;
 	}
 	/* else */


-- 
ワナベ

Related issues

related to Ruby 1.8 - Bug #2468: Array expansion inside case/when gives unexpected results Closed 12/10/2009

Associated revisions

Revision 27376
Added by _ wanabe almost 2 years ago

* compile.c (iseq_compile_each): fix splat condition in NODE_WHEN. [Bug #2226]

Revision 27376
Added by _ wanabe almost 2 years ago

* compile.c (iseq_compile_each): fix splat condition in NODE_WHEN. [Bug #2226]

History

Updated by Yui NARUSE over 2 years ago

  • Category set to core
  • Status changed from Open to Assigned
  • Assignee set to Yukihiro Matsumoto
  • Target version set to 1.9.2
  • ruby -v set to ruby 1.9.2dev (2009-10-22 trunk 25433) [x86_64-freebsd8.0]

Updated by _ wanabe about 2 years ago

まつもとさん(あるいはささださん?)
このチケットについて、よろしければ意見をお聞きしたいのですがどうでしょうか。
(バグではない、バグだがパッチが正しくない、コミットしてよい、など)
催促するようで申し訳ありません。

Updated by Yusuke Endoh almost 2 years ago

wanabe さん
遠藤です。

2009年10月18日6:16 wanabe <s.wanabe@gmail.com>:
> case 文の式が省略され、かつ when 節に配列展開があるときの挙動、
> より具体的には NODE_ARGSCAT, NODE_ARGSPUSH の
> コンパイル結果が正しくないように思います。
> 通常の NODE_CASE と同じように処理するのはどうでしょうか。

2010年1月29日2:37 _ wanabe <redmine@ruby-lang.org>:
> まつもとさん(あるいはささださん?)
> このチケットについて、よろしければ意見をお聞きしたいのですがどうでしょうか。
> (バグではない、バグだがパッチが正しくない、コミットしてよい、など)


確かにバグだと思いますし、ワナベさんのパッチで正しいと思います。
反対もないようなので、コミットしちゃってください。


ただ、一応、以下の点が非互換になるようです。

  $ ruby -ve 'case; when true, *x; p :ok; end'
  ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
  :ok

  $ ./ruby -ve 'case; when true, *x; p :ok; end'
  ruby 1.9.2dev (2010-04-16 trunk 27359) [i686-linux]
  -e:1:in `<main>': undefined local variable or method `x' for
main:Object (NameError)

といっても、NODE_CASE の方ではワナベさんのパッチの前から非互換な
ようです。

  $ ruby -ve 'case "foo"; when "foo", *x; p :ok; end'
  ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
  :ok

  $ ./ruby -ve 'case "foo"; when "foo", *x; p :ok; end'
  ruby 1.9.2dev (2010-04-16 trunk 27359) [i686-linux]
  -e:1:in `<main>': undefined local variable or method `x' for
main:Object (NameError)

実害はほぼないと思うのですが、もし暇だったら見てやってください。

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Updated by _ wanabe almost 2 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100
This issue was solved with changeset r27376.
_, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

Also available in: Atom PDF