add: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Experimental/Misc/initialize_copy.rb
File: initialize_copy.rb
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Experimental/Misc/initialize_copy.rb;RhsArg
@@ -1,0 +1,27 @@
+class C
+  def initialize
+    @x = 1
+    @y = 2
+    puts "#{self.inspect}.initialize"
+  end
+  
+  def initialize_copy *c
+    puts "#{self.inspect}.initialize_copy(#{c.inspect})"
+  end
+
+  def allocate
+    puts "#{self.inspect}.allocate"
+  end
+end
+
+c = C.new
+c.taint
+c.freeze
+
+puts '-- dup:'
+dup_c = c.dup
+puts "frozen: #{dup_c.frozen?} tainted: #{dup_c.tainted?}"
+
+puts '-- clone:'
+clone_c = c.clone
+puts "frozen: #{clone_c.frozen?} tainted: #{clone_c.tainted?}"
===================================================================
add: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Experimental/Struct/struct_dup.rb
File: struct_dup.rb
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Experimental/Struct/struct_dup.rb;RhsArg
@@ -1,0 +1,17 @@
+p S = Struct.new(:foo)
+p S.dup
+p S.hash == S.dup.hash
+
+puts '---'
+
+p iS = S['f']
+p diS = iS.dup
+p iS.hash == diS.hash
+
+puts '---'
+
+p iS = S['f']
+p cis = iS.clone
+p iS.hash == cis.hash
+
+
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C556753
File: RubyTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C556753  (server)    9/9/2008 5:33 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;RhsArg
@@ -154,7 +154,9 @@
                 Scenario_RubyBlockArgs2,
                 Scenario_RubyBlockArgs3,
                 Scenario_RubyBlockArgs4,
-                // TODO (bug): Scenario_RubyBlockArgs5,
+                Scenario_RubyBlockArgs5,
+                Scenario_RubyBlockArgs6,
+                // TODO: Scenario_RubyBlockArgs7,
 
                 Scenario_RubyProcs1,
                 RubyProcArgConversion1,
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/BlockTests.cs;C540639
File: BlockTests.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/BlockTests.cs;C540639  (server)    9/9/2008 5:33 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/BlockTests.cs;RhsArg
@@ -538,24 +538,58 @@
         }
 
         /// <summary>
-        /// R(0,*,1)
+        /// L(M,*) := R(N,*,=) where M is less then N.
         /// </summary>
         public void Scenario_RubyBlockArgs5() {
-            // TODO:
             AssertOutput(delegate() {
                 CompilerTest(@"
 class C
-  define_method('[]=') { |*args|
-    p args
+  define_method('[]=') { |a,b,c,*p|
+    print a,b,c,'|',*p
   }
 end
 
 c = C.new
-c[1,*[2,3]] = 4
+c[1,2,3,4,5,6,7,*[8]] = 9
 ");
-            }, @"[1, 2, 3, 4]");
+            }, @"123|456789");
         }
 
+        /// <summary>
+        /// L(M,*) := R(N,*,=) where M is greater then N.
+        /// </summary>
+        public void Scenario_RubyBlockArgs6() {
+            AssertOutput(delegate() {
+                CompilerTest(@"
+class C
+  define_method('[]=') { |a,b,c,*p|
+    print a,b,c,'|',*p
+  }
+end
+
+c = C.new
+c[1,*[2]] = 3
+");
+            }, @"123|");
+        }
+
+        /// <summary>
+        /// Wrong number of arguments.
+        /// </summary>
+        public void Scenario_RubyBlockArgs7() {
+            // TODO:
+            AssertExceptionThrown<ArgumentException>(delegate() {
+                CompilerTest(@"
+class C
+  define_method('[]=') { |a,b| }
+end
+
+c = C.new
+c[1,2,*[]] = 3
+");
+            });
+        }
+
         public void Scenario_RubyProcs1() {
             AssertOutput(delegate() {
                 CompilerTest(@"
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.cs;C556753
File: Proc.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.cs;C556753  (server)    9/9/2008 8:19 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.cs;RhsArg
@@ -26,6 +26,7 @@
 using IronRuby.Runtime.Calls;
 
 using Ast = System.Linq.Expressions.Expression;
+using AstFactory = IronRuby.Compiler.Ast.AstFactory;
 using System.Collections.Generic;
 
 namespace IronRuby.Builtins {
@@ -169,9 +170,6 @@
             var bfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc");
             var resultVariable = metaBuilder.GetTemporary(typeof(object), "#result");
 
-            var simpleArguments = args.GetSimpleArgumentExpressions();
-            var splattedArgument = args.GetSplattedArgumentExpression();
-
             metaBuilder.Result = Ast.Comma(
                 Ast.Assign(bfcVariable,
                     (callingMethodExpression != null) ?
@@ -183,7 +181,13 @@
                             Ast.ConvertHelper(procExpression, typeof(Proc))
                         )
                 ),
-                Ast.Assign(resultVariable, IronRuby.Compiler.Ast.AstFactory.YieldExpression(simpleArguments, splattedArgument, bfcVariable, selfExpression)),
+                Ast.Assign(resultVariable, AstFactory.YieldExpression(
+                    args.GetSimpleArgumentExpressions(), 
+                    args.GetSplattedArgumentExpression(), 
+                    args.GetRhsArgumentExpression(),
+                    bfcVariable, 
+                    selfExpression
+                )),
                 Ast.Call(RuntimeFlowControl.GetMethod("MethodProcCall"), bfcVariable, resultVariable),
                 resultVariable
             );
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Arguments.cs;C533798
File: Arguments.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Arguments.cs;C533798  (server)    9/9/2008 8:17 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Arguments.cs;RhsArg
@@ -119,7 +119,8 @@
 
             return AstFactory.YieldExpression(
                 args,
-                (_array != null) ? _array.TransformRead(gen) : null,
+                (_array != null) ? _array.TransformRead(gen) : null,         // splatted argument
+                null,                                                        // rhs argument
                 bfcVariable,
                 selfExpression
             );
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/AstFactory.cs;C540639
File: AstFactory.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/AstFactory.cs;C540639  (server)    9/9/2008 5:38 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/AstFactory.cs;RhsArg
@@ -355,13 +355,14 @@
         internal static MSA.Expression/*!*/ YieldExpression(
             IList<MSA.Expression>/*!*/ arguments, 
             MSA.Expression splattedArgument,
+            MSA.Expression rhsArgument,
             MSA.Expression/*!*/ bfcVariable,
             MSA.Expression/*!*/ selfArgument) {
 
             Assert.NotNull(arguments, bfcVariable, selfArgument);
 
             bool hasArgumentArray;
-            var opMethod = RubyOps.GetYieldMethod(arguments.Count, splattedArgument != null, out hasArgumentArray);
+            var opMethod = RubyOps.GetYieldMethod(arguments.Count, splattedArgument != null, rhsArgument != null, out hasArgumentArray);
 
             var args = new List<MSA.Expression>();
 
@@ -377,6 +378,10 @@
                 args.Add(Ast.ConvertHelper(splattedArgument, typeof(object)));
             }
 
+            if (rhsArgument != null) {
+                args.Add(Ast.ConvertHelper(rhsArgument, typeof(object)));
+            }
+
             args.Add(Ast.ConvertHelper(selfArgument, typeof(object)));
             args.Add(bfcVariable);
 
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.cs;C556753
File: BlockParam.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.cs;C556753  (server)    9/9/2008 8:18 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.cs;RhsArg
@@ -232,7 +232,7 @@
         /// </summary>
         internal void SetCallActionRule(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) {
             Assert.NotNull(metaBuilder, args);
-            Debug.Assert(!args.Signature.HasRhsArgument && !args.Signature.HasBlock);
+            Debug.Assert(!args.Signature.HasBlock);
 
             var convertedTarget = Ast.ConvertHelper(args.TargetExpression, typeof(BlockParam));
 
@@ -242,6 +242,7 @@
             metaBuilder.Result = AstFactory.YieldExpression(
                 args.GetSimpleArgumentExpressions(),
                 args.GetSplattedArgumentExpression(),
+                args.GetRhsArgumentExpression(),
                 convertedTarget,                              // block param
                 Ast.Property(convertedTarget, SelfProperty)   // self
             ); 
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;C556753
File: RubyOps.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;C556753  (server)    9/9/2008 5:54 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;RhsArg
@@ -238,7 +238,16 @@
 
         #region Yield: TODO: generate
 
-        internal static MethodInfo/*!*/ GetYieldMethod(int argumentCount, bool hasSplattedArgument, out bool hasArgumentArray) {
+        internal static MethodInfo/*!*/ GetYieldMethod(int argumentCount, bool hasSplattedArgument, bool hasRhsArgument, out bool hasArgumentArray) {
+            if (hasRhsArgument) {
+                if (hasSplattedArgument) {
+                    hasArgumentArray = true;
+                    return GetMethod("YieldSplatNRhs");
+                } else {
+                    argumentCount++;
+                }
+            }
+
             hasArgumentArray = argumentCount > BlockDispatcher.MaxBlockArity;
             return GetMethod((hasSplattedArgument ? "YieldSplat" : "Yield") + (hasArgumentArray ? "N" : argumentCount.ToString()));
         }
@@ -401,6 +410,18 @@
             return result;
         }
 
+        // emitted: 
+        public static object YieldSplatNRhs(object[]/*!*/ args, object splattee, object rhs, object self, BlockParam/*!*/ blockParam) {
+            object result;
+            var proc = blockParam.Proc;
+            try {
+                result = proc.Dispatcher.InvokeSplatRhs(blockParam, self, args, splattee, rhs);
+            } catch (EvalUnwinder evalUnwinder) {
+                result = blockParam.GetUnwinderResult(evalUnwinder);
+            }
+
+            return result;
+        }
         #endregion
 
         #region Methods
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcher.cs;C533798
File: BlockDispatcher.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcher.cs;C533798  (server)    9/9/2008 6:06 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcher.cs;RhsArg
@@ -62,6 +62,8 @@
         public abstract object InvokeSplat(BlockParam/*!*/ param, object self, object arg1, object arg2, object arg3, object arg4, object splattee);
         public abstract object InvokeSplat(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee);
 
+        public abstract object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs);
+
         internal const int MaxBlockArity = 4;
         internal const int HiddenParameterCount = 2;
 
@@ -98,42 +100,52 @@
             return typeof(BlockCallTargetUnsplatN);
         }
 
-#if UNUSED
-        internal static MethodInfo/*!*/ GetInvokeMethod(int plainArgumentCount, bool hasSplattedArgument, out bool hasArrayArguments) {
-            hasArrayArguments = plainArgumentCount <= MaxBlockArity;
-            
-            var parameterTypes = GetInvokeMethodParameterTypes(regularArgumentCount, hasSplattedArgument, hasArrayArguments);
-            var name = (hasSplattedArgument) ? "InvokeSplat" : "Invoke";
+        // starts with slot #nextArg in args array, returns the number of filled slots in args array in ref nextArg:
+        private static void CopyArgumentsFromSplattee(object[]/*!*/ args, int originalLength, int parameterCount, out int nextArg, out int nextItem, object splattee) {
+            int i = Math.Min(originalLength, parameterCount);
+            int j = 0;
+            var list = splattee as List<object>;
+            if (list != null) {
+                while (i < parameterCount && j < list.Count) {
+                    args[i++] = list[j++];
+                }
+            } else if (i < parameterCount) {
+                args[i++] = splattee;
+                j++;
+            }
 
-            return typeof(BlockDispatcher).GetMethod(name, parameterTypes);
+            nextArg = i;
+            nextItem = j;
         }
 
-        private static Type[]/*!*/ GetInvokeMethodParameterTypes(int regularArgumentCount, bool hasSplattedArgument, bool hasArrayArguments) {
-            var parameterTypes = new Type[
-                HiddenParameterCount +
-                (hasArrayArguments ? 1 : regularArgumentCount) +
-                (hasSplattedArgument ? 1 : 0)
-            ];
+        internal static object[]/*!*/ CopyArgumentsFromSplattee(object[]/*!*/ args, int parameterCount, object splattee) {
+            int nextArg, nextItem;
+            CopyArgumentsFromSplattee(args, args.Length, parameterCount, out nextArg, out nextItem, splattee);
+            return args;
+        }
 
-            // hidden parameters:
-            parameterTypes[0] = typeof(BlockParam);
-            parameterTypes[1] = typeof(object);
+        internal static void CreateArgumentsFromSplattee(int parameterCount, out int nextArg, out int nextItem, ref object[]/*!*/ args, object splattee) {
+            // the args array is passed to the block, we need at least space for all explicit parameters:
+            int originalLength = args.Length;
+            if (args.Length < parameterCount) {
+                Array.Resize(ref args, parameterCount);
+            }
 
-            // plain arguments, splatted argument:
-            if (hasArrayArguments) {
-                parameterTypes[HiddenParameterCount] = typeof(object[]);
-                if (hasSplattedArgument) {
-                    parameterTypes[HiddenParameterCount + 1] = typeof(object);
-                }
-            } else {
-                for (int i = HiddenParameterCount; i < parameterTypes.Length; i++) {
-                    parameterTypes[i] = typeof(object);
-                }
+            CopyArgumentsFromSplattee(args, originalLength, parameterCount, out nextArg, out nextItem, splattee);
+        }
+
+        internal static object[]/*!*/ CreateArgumentsFromSplatteeAndRhs(int parameterCount, object[]/*!*/ args, object splattee, object rhs) {
+            int nextArg, nextItem;
+
+            // the args array is passed to the block, we need at least space for all explicit parameters:
+            CreateArgumentsFromSplattee(parameterCount, out nextArg, out nextItem, ref args, splattee);
+
+            if (nextArg < args.Length) {
+                args[nextArg++] = rhs;
             }
 
-            return parameterTypes;
+            return args;
         }
-#endif
 
 #if OBSOLETE
         private Expression/*!*/ AddWarning(Expression/*!*/ codeContextExpression, Expression/*!*/ expression) {
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcherN.cs;C533798
File: BlockDispatcherN.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcherN.cs;C533798  (server)    9/9/2008 6:07 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcherN.cs;RhsArg
@@ -81,7 +81,7 @@
         
         // R(1, -)
         public override object Invoke(BlockParam/*!*/ param, object self, object arg1) {
-            return InvokeSplatInternal(param, self, new object[_parameterCount], 0, arg1);
+            return _block(param, self, CopyArgumentsFromSplattee(new object[_parameterCount], _parameterCount, arg1));
         }
 
         // R(2, -)
@@ -113,52 +113,40 @@
 
         // R(0, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object splattee) {
-            return InvokeSplatInternal(param, self, new object[_parameterCount], 0, splattee);
+            return _block(param, self, CopyArgumentsFromSplattee(new object[_parameterCount], _parameterCount, splattee));
         }
 
-        private object InvokeSplatInternal(BlockParam/*!*/ param, object self, object[]/*!*/ args, int i, object splattee) {
-            var list = splattee as List<object>;
-            if (list != null) {
-                while (i < Math.Min(args.Length, list.Count)) {
-                    args[i] = list[i];
-                    i++;
-                }
-            } else if (i < args.Length) {
-                args[i] = splattee;
-            }
-            return _block(param, self, args);
-        }
-
         // R(1, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object arg1, object splattee) {
-            return InvokeSplatInternal(param, self, MakeArray(arg1), 1, splattee);
+            return _block(param, self, CopyArgumentsFromSplattee(MakeArray(arg1), _parameterCount, splattee));
         }
 
         // R(2, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object arg1, object arg2, object splattee) {
-            return InvokeSplatInternal(param, self, MakeArray(arg1, arg2), 2, splattee);
+            return _block(param, self, CopyArgumentsFromSplattee(MakeArray(arg1, arg2), _parameterCount, splattee));
         }
 
         // R(3, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object arg1, object arg2, object arg3, object splattee) {
-            return InvokeSplatInternal(param, self, MakeArray(arg1, arg2, arg3), 3, splattee);
+            return _block(param, self, CopyArgumentsFromSplattee(MakeArray(arg1, arg2, arg3), _parameterCount, splattee));
         }
 
         // R(4, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object arg1, object arg2, object arg3, object arg4, object splattee) {
-            return InvokeSplatInternal(param, self, MakeArray(arg1, arg2, arg3, arg4), 4, splattee);
+            return _block(param, self, CopyArgumentsFromSplattee(MakeArray(arg1, arg2, arg3, arg4), _parameterCount, splattee));
         }
 
         // R(N, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee) {
-            Debug.Assert(args.Length > 4);
+            Debug.Assert(args.Length > MaxBlockArity);
+            int i, j;
+            CreateArgumentsFromSplattee(_parameterCount, out i, out j, ref args, splattee);
+            return _block(param, self, args);
+        }
 
-            int argsLength = args.Length;
-            if (argsLength < _parameterCount) {
-                Array.Resize(ref args, _parameterCount);
-            }
-
-            return InvokeSplatInternal(param, self, args, argsLength, splattee);
+        // R(N, *, =)
+        public override object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs) {
+            return _block(param, self, CreateArgumentsFromSplatteeAndRhs(_parameterCount, args, splattee, rhs));
         }
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatchers.cs;C533798
File: BlockDispatchers.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatchers.cs;C533798  (server)    9/9/2008 6:24 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatchers.cs;RhsArg
@@ -99,6 +99,11 @@
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee) {
             return _block(param, self);
         }
+
+        // R(N, *, =)
+        public override object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs) {
+            return _block(param, self);
+        }
     }
 
     // L(1, -)
@@ -222,6 +227,18 @@
             return _block(param, self, arg1);
         }
 
+        private object InvokeSplatInternal(BlockParam/*!*/ param, object self, RubyArray/*!*/ array, object splattee) {
+            Debug.Assert(array.Count >= 2);
+
+            RubyOps.SplatAppend(array, splattee);
+
+            if (!FirstArgumentIsNestedLValue) {
+                param.MultipleValuesForBlockParameterWarning(array.Count);
+            }
+
+            return _block(param, self, array);
+        }
+
         // R(2, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object arg1, object arg2, object splattee) {
             return InvokeSplatInternal(param, self, RubyOps.MakeArray2(arg1, arg2), splattee);
@@ -239,17 +256,22 @@
         
         // R(N, *)
         public override object InvokeSplat(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee) {
+            Debug.Assert(args.Length > MaxBlockArity);
             return InvokeSplatInternal(param, self, RubyOps.MakeArray(args), splattee);
         }
 
-        private object InvokeSplatInternal(BlockParam/*!*/ param, object self, RubyArray/*!*/ array, object splattee) {
-            var arg = RubyOps.SplatAppend(array, splattee);
-            
-            if (!FirstArgumentIsNestedLValue) {
-                param.MultipleValuesForBlockParameterWarning(arg.Count);
+        // R(N, *, =)
+        public override object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs) {
+            var array = new RubyArray(args);
+            RubyOps.SplatAppend(array, splattee);
+            array.Add(rhs);
+
+            if (array.Count != 1 && !FirstArgumentIsNestedLValue) {
+                param.MultipleValuesForBlockParameterWarning(array.Count);
             }
 
-            return _block(param, self, arg);
+            Debug.Assert(array.Count >= 2);
+            return _block(param, self, array);
         }
     }
 
@@ -354,6 +376,12 @@
             Debug.Assert(args.Length > MaxBlockArity);
             return _block(param, self, args[0], args[1]);
         }
+
+        // R(N, *, =)
+        public override object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs) {
+            args = CreateArgumentsFromSplatteeAndRhs(2, args, splattee, rhs);
+            return _block(param, self, args[0], args[1]);
+        }
     }
 
     // L(3, -)
@@ -467,6 +495,12 @@
             Debug.Assert(args.Length > MaxBlockArity);
             return _block(param, self, args[0], args[1], args[2]);
         }
+
+        // R(N, *, =)
+        public override object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs) {
+            args = CreateArgumentsFromSplatteeAndRhs(3, args, splattee, rhs);
+            return _block(param, self, args[0], args[1], args[2]);
+        }
     }
 
     // L(4, -)
@@ -591,5 +625,11 @@
             Debug.Assert(args.Length > MaxBlockArity);
             return _block(param, self, args[0], args[1], args[2], args[3]);
         }
+
+        // R(N, *, =)
+        public override object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs) {
+            args = CreateArgumentsFromSplatteeAndRhs(4, args, splattee, rhs);
+            return _block(param, self, args[0], args[1], args[2], args[3]);
+        }
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcherUnsplatN.cs;C533798
File: BlockDispatcherUnsplatN.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcherUnsplatN.cs;C533798  (server)    9/9/2008 7:58 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/BlockDispatcherUnsplatN.cs;RhsArg
@@ -130,35 +130,49 @@
             return InvokeSplatInternal(param, self, args, splattee);
         }
 
+        // R(N, *, =)
+        public override object InvokeSplatRhs(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, object rhs) {
+            var list = splattee as List<object>;
+            if (list != null) {
+                var l = new RubyArray(list.Count + 1);
+                l.AddRange(list);
+                l.Add(rhs);
+                list = l;
+            } else {
+                list = RubyOps.MakeArray2(splattee, rhs);
+            }
+
+            return InvokeSplatInternal(param, self, args, list, list);
+        }
+
         private object InvokeSplatInternal(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee) {
-            var list = splattee as List<object>;
-            var listCount = list != null ? list.Count : 1;
+            return InvokeSplatInternal(param, self, args, splattee, splattee as List<object>);
+        }
 
-            var actualArgs = new object[_parameterCount];
-            int j = 0;
-            for (int i = 0; i < _parameterCount; i++) {
-                if (i < args.Length) {
-                    actualArgs[i] = args[i];
-                } else if (j < listCount) {
-                    actualArgs[i] = (list != null) ? list[j] : splattee;
-                    j++;
-                }
-            }
+        private object InvokeSplatInternal(BlockParam/*!*/ param, object self, object[]/*!*/ args, object splattee, List<object> list) {
+            int argsLength = args.Length;
 
+            int nextArg, nextItem;
+            CreateArgumentsFromSplattee(_parameterCount, out nextArg, out nextItem, ref args, splattee);
+
             var array = new RubyArray();
-            for (int i = _parameterCount; i < args.Length; i++) {
-                array.Add(args[i]);
+
+            // remaining args:
+            while (nextArg < argsLength) {
+                array.Add(args[nextArg++]);
             }
 
+            // remaining items:
             if (list != null) {
-                while (j < listCount) {
-                    array.Add(list[j++]);
+                while (nextItem < list.Count) {
+                    array.Add(list[nextItem++]);
                 }
-            } else if (j < listCount) {
+            } else if (nextItem < 1) {
+                // splattee hasn't been added yet:
                 array.Add(splattee);
             }
 
-            return _block(param, self, actualArgs, array);
+            return _block(param, self, args, array);
         }
     }
 }
===================================================================
edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyLambdaMethodInfo.cs;C533798
File: RubyLambdaMethodInfo.cs
===================================================================
--- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyLambdaMethodInfo.cs;C533798  (server)    9/9/2008 5:36 PM
+++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyLambdaMethodInfo.cs;RhsArg
@@ -44,18 +44,8 @@
 
         internal override void SetInvocationRule(string name, MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) {
 
-            Debug.Assert(!args.Signature.HasRhsArgument && !args.Signature.HasBlock);
+            Debug.Assert(!args.Signature.HasBlock);
 
-#if TODO // this is broken:
-class C
-  define_method("[]=") { |a,b,c,d|
-    p a,b,c,d
-  }
-end
-
-c = C.new
-c[1,*[2,3]] = 4
-#endif
             Proc.SetProcCallRule(
                 metaBuilder,
                 Ast.Constant(_lambda),            // proc object
===================================================================
