From: "Mauricio Fernández" Date: 2005-08-10T18:38:19+09:00 Subject: Re: [BUG] bug in variable assignment On Wed, Aug 10, 2005 at 10:40:15AM +0900, Yukihiro Matsumoto wrote: > In message "Re: [BUG] bug in variable assignment" > on Wed, 10 Aug 2005 09:52:12 +0900, Yukihiro Matsumoto writes: > > |You shouldn't _fix_ this. Formal arguments to the anonymous function > |would not modify the external variables even when they are used outside. > > Instead we should fix optional arguments and rest arguments NOT to > modify outside variables. I see, I picked the wrong semantics. The above should also apply to block arguments then. $ ./ruby -ve "b=1; ->(&b){}.call; p b" ruby 1.9.0 (2005-08-10) [i686-linux] nil Index: parse.y =================================================================== RCS file: /src/ruby/parse.y,v retrieving revision 1.402 diff -p -u -r1.402 parse.y --- parse.y 10 Aug 2005 01:39:23 -0000 1.402 +++ parse.y 10 Aug 2005 09:18:04 -0000 @@ -4205,7 +4205,15 @@ f_block_arg : blkarg_mark tIDENTIFIER yyerror("block argument must be local variable"); else if (!dyna_in_block() && local_id($2)) yyerror("duplicated block argument name"); - $$ = dyna_in_block() ? assignable($2, 0) : NEW_BLOCK_ARG($2); + + if (dyna_in_block()) { + shadowing_lvar($2); + dyna_var($2); + $$ = assignable($2, 0); + } + else { + $$ = NEW_BLOCK_ARG($2); + } /*% $$ = $2; %*/ Index: test/ruby/test_lambda.rb =================================================================== RCS file: /src/ruby/test/ruby/test_lambda.rb,v retrieving revision 1.1 diff -p -u -r1.1 test_lambda.rb --- test/ruby/test_lambda.rb 8 Aug 2005 23:24:29 -0000 1.1 +++ test/ruby/test_lambda.rb 10 Aug 2005 09:18:04 -0000 @@ -36,9 +36,9 @@ class TestLambdaParameters < Test::Unit: assert_equal(nil, ->(&b){ b }.call) foo { puts "bogus block " } assert_equal(1, ->(&b){ b.call }.call { 1 }) - b = nil + b = 2 assert_equal(1, ->(&b){ b.call }.call { 1 }) - assert_not_nil(b) + assert_equal(2, b) end def foo @@ -50,4 +50,16 @@ class TestLambdaParameters < Test::Unit: 2.times ->(_){ a += 1 } assert_equal(a, 2) end + + def test_var_shadowing + a = 0 + _a, _b, _c, _d, _e, _f = lambda do + b = c = d = e = 0 + f = ->(a, b, c=1, *d, &e){ } + [->(){a}, ->(){b}, ->(){c}, ->(){d}, ->(){e}, f] + end.call + assert_equal([0,0,0,0,0], [_a[], _b[], _c[], _d[], _e[]]) + _f.call(1,2,3,4,5) { } + assert_equal([0,0,0,0,0], [_a[], _b[], _c[], _d[], _e[]]) + end end $ ./ruby -we "b=1; ->(&b){}.call; p b" -e:1: warning: shadowing outer local variable - b 1 $ ./ruby -w test/ruby/test_lambda.rb test/ruby/test_lambda.rb:40: warning: shadowing outer local variable - b test/ruby/test_lambda.rb:58: warning: shadowing outer local variable - a test/ruby/test_lambda.rb:58: warning: shadowing outer local variable - b test/ruby/test_lambda.rb:58: warning: shadowing outer local variable - c test/ruby/test_lambda.rb:58: warning: shadowing outer local variable - d test/ruby/test_lambda.rb:58: warning: shadowing outer local variable - e Loaded suite test/ruby/test_lambda Started ....... Finished in 0.008198 seconds. 7 tests, 26 assertions, 0 failures, 0 errors -- Mauricio Fernandez