edit: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/super_spec.rb;C1086571 File: super_spec.rb =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/super_spec.rb;C1086571 (server) 12/1/2009 11:20 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/super_spec.rb;NewSuper6 @@ -95,23 +95,35 @@ sub.new.a.should == "a" end - ruby_version_is ""..."1.9" do - it "can be used with implicit arguments from a method defined with define_method" do - sup = Class.new do - def a; "a"; end + not_supported_on :ironruby do + ruby_version_is ""..."1.9" do + it "can be used with implicit arguments from a method defined with define_method" do + sup = Class.new do + def a; "a"; end + end + + sub = Class.new(sup) do + define_method :a do + super + end + end + + sub.new.a.should == "a" end + end + end - sub = Class.new(sup) do + ruby_version_is "1.9" do + it "can't be used with implicit arguments from a method defined with define_method" do + Class.new do define_method :a do super - end + end.should raise_error(RuntimeError) end - - sub.new.a.should == "a" end end - - ruby_version_is "1.9" do + + extended_on :ironruby do it "can't be used with implicit arguments from a method defined with define_method" do Class.new do define_method :a do =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C1264343 File: RubyTests.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C1264343 (server) 11/30/2009 12:45 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;NewSuper6 @@ -565,16 +565,20 @@ Super1, SuperParameterless1, - SuperParameterless2, + SuperParameterless2A, + SuperParameterless2B, SuperParameterless3, Super2, SuperToAttribute1, SuperAndMethodMissing1, SuperAndMethodMissing2, SuperCaching1, + SuperInBlocks1, SuperInDefineMethod1, SuperInDefineMethod2, - // TODO: SuperInDefineMethod3, + SuperInDefineMethod3, + SuperInDefineMethod4, + SuperInDefineMethod5, SuperInTopLevelCode1, SuperInAliasedDefinedMethod1, =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/SuperTests.cs;C966724 File: SuperTests.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/SuperTests.cs;C966724 (server) 11/30/2009 12:45 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/SuperTests.cs;NewSuper6 @@ -42,28 +42,33 @@ public void SuperParameterless1() { TestOutputWithEval(@" class C - def foo a + def foo *a puts 'C.foo' - puts a + p a end end class D < C - def foo a + def foo a, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8, j=9, k=a, *rest, &blck puts 'D.foo' - super # TODO: test with eval + p rest + y = 1 + z = 2 + # end end -D.new.foo 'arg' -",@" +D.new.foo 0 +", @" D.foo +[] C.foo -arg" +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0] +" ); } - public void SuperParameterless2() { + public void SuperParameterless2A() { TestOutputWithEval(@" class C def foo a @@ -76,7 +81,7 @@ class D < C def foo a puts 'D.foo' - super { puts 'block' } # TODO: test with eval + # end end @@ -90,6 +95,35 @@ ); } + /// + /// Super passes the most recent values of the parameter variables but keeps the original block value. + /// This is consistent with yield. + /// + public void SuperParameterless2B() { + TestOutputWithEval(@" +class C + def foo *a + p a + yield + end +end + +class D < C + def foo a, &b + a = 2 + b = lambda { puts '2' } + 1.times { # } + end +end + +D.new.foo(1) { puts '1' } +", @" +[2] +1 +" + ); + } + public void SuperParameterless3() { AssertOutput(delegate() { CompilerTest(@" @@ -268,7 +302,6 @@ "); } - // TODO: parameters public void SuperInDefineMethod1() { SuperInDefineMethod1_Test(false); } @@ -289,7 +322,7 @@ $p = lambda { 1.times { p self.class - # + # } } } @@ -318,9 +351,8 @@ /// /// Super in a proc invoked via "call" uses the self and parameters captured in closure by the block. /// - public void SuperInDefineMethod2() { - AssertOutput(delegate() { - CompilerTest(@" + public void SuperInBlocks1() { + TestOutput(@" class A def def_lambda a puts 'A.def_lambda' @@ -334,7 +366,7 @@ $p = lambda { 1.times { p self.class - super + super } } } @@ -343,8 +375,7 @@ B.new.def_lambda 'arg' $p.call 'foo' -"); - }, @" +", @" B A.def_lambda arg @@ -352,66 +383,180 @@ } /// - /// Super call in defined_method's proc: - /// 1.8: parameters are taken from block parameters - /// 1.9: not-supported exception is thrown + /// define_method returns a lambda that behaves like a method-block when called. + /// This behavior is not very well defined in CRuby (see http://redmine.ruby-lang.org/issues/show/2419). /// + public void SuperInDefineMethod2() { + TestOutput(@" +class B + def m + puts self.class.to_s + '::m' + end +end + +class C < B + q = nil + + C.new.instance_eval do # we need to close the block over self that is an instance of C + q = Proc.new do + super() + end + end + + mq = define_method :m, &q + puts mq.object_id == q.object_id + + q.call rescue p $! + mq.call +end +", @" +false +# +C::m +"); + } + + /// + /// Caching - a single super call site can be used for invocation of two different methods, + /// if it is defined in a block that is used in define_method. + /// public void SuperInDefineMethod3() { - // TODO: - AssertOutput(delegate() { - CompilerTest(@" + TestOutput(@" class B - def m *a - p a + def foo + puts 'B::foo' end + + def bar + puts 'B::bar' + end end class C < B - define_method :m do |*a| - p a - super + def foo + 1.times { $p = Proc.new { 1.times { 1.times { super() } } } } + 1.times(&$p) end end -C.new.m 1,2 +c = C.new +c.foo + +class C + define_method(:bar, &$p) +end + +c.bar +", @" +B::foo +B::bar "); - }, @" -[1, 2] -[1, 2] + } + + /// + /// Caching - The same as SuperInDefineMethod4 but with implicit arguments at super call site. + /// This should throw an exception as in Ruby 1.9. + /// + public void SuperInDefineMethod4() { + TestOutput(@" +class B + def foo + puts 'B::foo' + end + + def bar + puts 'B::bar' + end +end + +class C < B + def foo + 1.times { $p = Proc.new { 1.times { 1.times { super } } } } + 1.times(&$p) + end +end + +c = C.new +c.foo + +class C + define_method(:bar, &$p) +end + +c.bar rescue p $! +c.foo +", @" +B::foo +# +B::foo "); } + /// + /// Caching - the same super call site can be used to invoke different method names. + /// + public void SuperInDefineMethod5() { + TestOutput(@" +class C + def a; 'a'; end + def b; 'b'; end +end + +class D < C + $p = Proc.new do + super() + end + + [:a, :b].each do |name| + define_method(name, &$p) + end +end + +puts D.new.a, D.new.b, D.new.a +", @" +a +b +a +"); + } + public void SuperInTopLevelCode1() { - AssertOutput(delegate() { - CompilerTest(@" + TestOutput(@" class B def m puts 'B::m' end end +1.times do + $p = Proc.new do + 1.times do + super() + end + end +end + +$p.call rescue p $! + class C < B - define_method :m do - super - end + define_method(:m, &$p) end C.new.m -"); - }, @" +", @" +# B::m "); } /// /// Alias doesn't change DeclaringModule of the method => super call uses the class in which the method is defined. - /// Parameters /// public void SuperInAliasedDefinedMethod1() { AssertOutput(delegate() { CompilerTest(@" class B - def m *a + def m puts 'B::m' end end @@ -419,7 +564,7 @@ class C < B define_method :m do puts 'C::m' - super + super() end def n =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Exceptions.cs;C1044096 File: Exceptions.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Exceptions.cs;C1044096 (server) 11/30/2009 6:08 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Exceptions.cs;NewSuper6 @@ -58,18 +58,6 @@ #endif } - [RubyException("RuntimeError"), Serializable] - public class RuntimeError : SystemException { - public RuntimeError() : this(null, null) { } - public RuntimeError(string message): this(message, null) { } - public RuntimeError(string message, Exception inner) : base(message ?? String.Empty, inner) { } - -#if !SILVERLIGHT - protected RuntimeError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) - : base(info, context) { } -#endif - } - [RubyException("ThreadError"), Serializable] public class ThreadError : SystemException { public ThreadError() : this(null, null) { } @@ -206,6 +194,10 @@ public static class EncodingErrorOps { } + [RubyException("RuntimeError", Extends = typeof(RuntimeError), Inherits = typeof(SystemException))] + public static class RuntimeErrorOps { + } + // special one: [RubyException("SystemCallError", Extends = typeof(ExternalException), Inherits = typeof(SystemException))] public static class SystemCallErrorOps { =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs;C1286631 File: KernelOps.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs;C1286631 (server) 11/30/2009 6:13 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs;NewSuper6 @@ -264,8 +264,7 @@ throw RubyExceptions.CreateArgumentError("tried to create Proc object without a block"); } - // doesn't preserve the class: - return block.Proc.ToLambda(); + return block.Proc.ToLambda(null); } #endregion =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs;C1290543 File: ModuleOps.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs;C1290543 (server) 12/1/2009 12:31 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs;NewSuper6 @@ -322,19 +322,20 @@ // thread-safe: [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)] public static Proc/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self, - [DefaultProtocol, NotNull]string/*!*/ methodName, [NotNull]Proc/*!*/ method) { + [DefaultProtocol, NotNull]string/*!*/ methodName, [NotNull]Proc/*!*/ block) { var visibility = GetDefinedMethodVisibility(scope, self, methodName); - self.AddMethod(scope.RubyContext, methodName, Proc.ToLambdaMethodInfo(method.ToLambda(), methodName, visibility, self)); - return method; + var info = Proc.ToLambdaMethodInfo(block, methodName, visibility, self); + self.AddMethod(scope.RubyContext, methodName, info); + return info.Lambda; } // thread-safe: [RubyMethod("define_method", RubyMethodAttributes.PrivateInstance)] public static Proc/*!*/ DefineMethod(RubyScope/*!*/ scope, RubyModule/*!*/ self, - [NotNull]ClrName/*!*/ methodName, [NotNull]Proc/*!*/ method) { + [NotNull]ClrName/*!*/ methodName, [NotNull]Proc/*!*/ block) { - var result = DefineMethod(scope, self, methodName.MangledName, method); + var result = DefineMethod(scope, self, methodName.MangledName, block); if (methodName.HasMangledName) { self.AddMethodAlias(methodName.ActualName, methodName.MangledName); } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C1286631 File: MutableStringOps.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C1286631 (server) 11/30/2009 6:13 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;NewSuper6 @@ -1525,7 +1525,7 @@ RequireNoVersionChange(self); if (self.IsFrozen) { - throw new RuntimeError("string frozen"); + throw RubyExceptions.CreateRuntimeError("string frozen"); } // replace content of self with content of the builder: @@ -2623,7 +2623,7 @@ private static void RequireNoVersionChange(MutableString/*!*/ self) { if (self.HasChanged) { - throw new RuntimeError("string modified"); + throw RubyExceptions.CreateRuntimeError("string modified"); } } } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ObjectSpace.cs;C1093989 File: ObjectSpace.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ObjectSpace.cs;C1093989 (server) 11/30/2009 6:12 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ObjectSpace.cs;NewSuper6 @@ -34,7 +34,7 @@ [RubyMethod("each_object", RubyMethodAttributes.PublicSingleton)] public static object EachObject(BlockParam block, RubyModule/*!*/ self, [NotNull]RubyClass/*!*/ theClass) { if (!theClass.HasAncestor(self.Context.ModuleClass)) { - throw new RuntimeError("each_object only supported for objects of type Class or Module"); + throw RubyExceptions.CreateRuntimeError("each_object only supported for objects of type Class or Module"); } if (block == null) { =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/OpenSSL/OpenSSL.cs;C1286631 File: OpenSSL.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/OpenSSL/OpenSSL.cs;C1286631 (server) 11/30/2009 6:11 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/OpenSSL/OpenSSL.cs;NewSuper6 @@ -80,7 +80,7 @@ #endif if (algorithm == null) { - throw new RuntimeError(String.Format(CultureInfo.InvariantCulture, "Unsupported digest algorithm ({0}).", algorithmName)); + throw RubyExceptions.CreateRuntimeError("Unsupported digest algorithm ({0}).", algorithmName); } self._algorithm = algorithm; =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Thread/RubyConditionVariable.cs;C1286631 File: RubyConditionVariable.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Thread/RubyConditionVariable.cs;C1286631 (server) 12/1/2009 5:10 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Thread/RubyConditionVariable.cs;NewSuper6 @@ -22,6 +22,7 @@ public class RubyConditionVariable { private RubyMutex _mutex; private readonly AutoResetEvent _signal = new AutoResetEvent(false); + private readonly object _lock = new object(); private int _waits; public RubyConditionVariable() { @@ -40,18 +41,20 @@ public static RubyConditionVariable/*!*/ Broadcast(RubyConditionVariable/*!*/ self) { RubyMutex m = self._mutex; if (m != null) { - int waits = self._waits; - for (int i = 0; i < waits; i++) { - self._signal.Set(); - // - // WARNING - // - // There is no guarantee that every call to the Set method will release a waiting thread. - // If two calls are too close together, so that the second call occurs before a thread - // has been released, only one thread is released. - // We add a sleep to increase the chance that all waiting threads will be released. - // - Thread.CurrentThread.Join(1); + lock (self._lock) { + int waits = self._waits; + for (int i = 0; i < waits; i++) { + self._signal.Set(); + // + // WARNING + // + // There is no guarantee that every call to the Set method will release a waiting thread. + // If two calls are too close together, so that the second call occurs before a thread + // has been released, only one thread is released. + // We add a sleep to increase the chance that all waiting threads will be released. + // + Thread.CurrentThread.Join(1); + } } } return self; @@ -61,11 +64,11 @@ public static RubyConditionVariable/*!*/ Wait(RubyConditionVariable/*!*/ self, [NotNull]RubyMutex/*!*/ mutex) { self._mutex = mutex; RubyMutex.Unlock(mutex); - Interlocked.Increment(ref self._waits); + lock (self._lock) { self._waits++; } self._signal.WaitOne(); - Interlocked.Decrement(ref self._waits); + lock (self._lock) { self._waits--; } RubyMutex.Lock(mutex); return self; } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Win32API/Win32API.cs;C1286631 File: Win32API.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Win32API/Win32API.cs;C1286631 (server) 11/30/2009 6:11 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Win32API/Win32API.cs;NewSuper6 @@ -322,12 +322,12 @@ [Emitted] public static Exception/*!*/ UninitializedFunctionError() { - return new RuntimeError("uninitialized Win32 function"); + return RubyExceptions.CreateRuntimeError("uninitialized Win32 function"); } [Emitted] public static Exception/*!*/ InvalidParameterCountError(int expected, int actual) { - return new RuntimeError(String.Format(CultureInfo.InvariantCulture, "wrong number of parameters: expected {0}, got {1}", expected, actual)); + return RubyExceptions.CreateRuntimeError("wrong number of parameters: expected {0}, got {1}", expected, actual); } #endregion =================================================================== delete: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libs/hacks.rb;C966724 File: hacks.rb =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libs/hacks.rb;C966724 (server) 12/1/2009 4:36 PM +++ [no target file] @@ -1,55 +1,0 @@ -# **************************************************************************** -# -# Copyright (c) Microsoft Corporation. -# -# This source code is subject to terms and conditions of the Microsoft Public License. A -# copy of the license can be found in the License.html file at the root of this distribution. If -# you cannot locate the Microsoft Public License, please send an email to -# ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound -# by the terms of the Microsoft Public License. -# -# You must not remove this notice, or any other, from this software. -# -# -# **************************************************************************** - -# In non-iirb sessions, TOPLEVEL_BINDING isn't defined -unless defined?(TOPLEVEL_BINDING) - TOPLEVEL_BINDING = binding -end - -# IronRuby bug: IO#read seems to chop off the first char - -class TCPSocket - def read size - recv size - end -end - -# Subclass Tracking - -module SubclassTracking - class Holder < Array - def each_object(klass, &b) - self.each { |c| b[c] } - end - end - def self.extended(klass) - (class << klass; self; end).send :attr_accessor, :subclasses - (class << klass; self; end).send :define_method, :inherited do |klazz| - klass.subclasses << klazz - super - end - klass.subclasses = Holder.new - end -end - -class IO - def flush; end # nop -end - -class String - def hex - self.to_i(16) - end -end =================================================================== delete: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libs/test;C791094 edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Ruby.Build.csproj;C1240182 File: Ruby.Build.csproj =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Ruby.Build.csproj;C1240182 (server) 12/1/2009 10:33 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Ruby.Build.csproj;NewSuper6 @@ -102,6 +102,7 @@ + @@ -120,7 +121,7 @@ - + =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C1286631 File: Ruby.csproj =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C1286631 (server) 11/30/2009 3:18 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;NewSuper6 @@ -242,10 +242,11 @@ - + + =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/Exceptions.cs;C1175370 File: Exceptions.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/Exceptions.cs;C1175370 (server) 11/30/2009 6:10 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/Exceptions.cs;NewSuper6 @@ -161,6 +161,18 @@ } [Serializable] + public class RuntimeError : SystemException { + public RuntimeError() : this(null, null) { } + public RuntimeError(string message) : this(message, null) { } + public RuntimeError(string message, Exception inner) : base(message, inner) { } + +#if !SILVERLIGHT + protected RuntimeError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } +#endif + } + + [Serializable] public class SyntaxError : ScriptError { private readonly string _file; private readonly string _lineSourceCode; =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.cs;C1120203 File: Proc.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.cs;C1120203 (server) 12/1/2009 1:10 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.cs;NewSuper6 @@ -57,7 +57,10 @@ private readonly RubyScope/*!*/ _scope; private readonly BlockDispatcher/*!*/ _dispatcher; + + // TODO: can we remove _kind and use _method and Converter fields intead? private ProcKind _kind; + private RubyLambdaMethodInfo _method; // The frame that converted this block to a proc: internal RuntimeFlowControl Converter { get; set; } @@ -68,6 +71,10 @@ internal set { _kind = value; } } + internal RubyLambdaMethodInfo Method { + get { return _method; } + } + public BlockDispatcher/*!*/ Dispatcher { get { return _dispatcher; } } @@ -115,9 +122,10 @@ /// Creates a lambda Proc that has the same target, context and self object as this block. /// Doesn't preserve the class of the Proc. /// - public Proc/*!*/ ToLambda() { + public Proc/*!*/ ToLambda(RubyLambdaMethodInfo method) { Proc result = new Proc(this); result.Kind = ProcKind.Lambda; + result._method = method; return result; } @@ -137,9 +145,9 @@ return result; } - public static RubyMemberInfo/*!*/ ToLambdaMethodInfo(Proc/*!*/ lambda, string/*!*/ definitionName, RubyMethodVisibility visibility, + public static RubyLambdaMethodInfo/*!*/ ToLambdaMethodInfo(Proc/*!*/ block, string/*!*/ definitionName, RubyMethodVisibility visibility, RubyModule/*!*/ owner) { - return new RubyLambdaMethodInfo(lambda, definitionName, (RubyMemberFlags)visibility, owner); + return new RubyLambdaMethodInfo(block, definitionName, (RubyMemberFlags)visibility, owner); } #endregion @@ -158,7 +166,6 @@ metaBuilder, convertedTarget, // proc object Methods.GetProcSelf.OpCall(convertedTarget), // self captured by the block closure - null, args ); } @@ -170,23 +177,13 @@ MetaObjectBuilder/*!*/ metaBuilder, Expression/*!*/ procExpression, // proc object Expression/*!*/ selfExpression, // self passed to the proc - Expression callingMethodExpression, // RubyLambdaMethodInfo passed to the proc via BlockParam CallArguments/*!*/ args // user arguments passed to the proc ) { var bfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc"); var resultVariable = metaBuilder.GetTemporary(typeof(object), "#result"); metaBuilder.Result = AstFactory.Block( - Ast.Assign(bfcVariable, - (callingMethodExpression != null) ? - Methods.CreateBfcForMethodProcCall.OpCall( - AstUtils.Convert(procExpression, typeof(Proc)), - callingMethodExpression - ) : - Methods.CreateBfcForProcCall.OpCall( - AstUtils.Convert(procExpression, typeof(Proc)) - ) - ), + Ast.Assign(bfcVariable, Methods.CreateBfcForProcCall.OpCall(AstUtils.Convert(procExpression, typeof(Proc)))), Ast.Assign(resultVariable, AstFactory.YieldExpression( args.RubyContext, args.GetSimpleArgumentExpressions(), =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/AstBlock.cs;C1120203 File: AstBlock.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/AstBlock.cs;C1120203 (server) 11/30/2009 5:02 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/AstBlock.cs;NewSuper6 @@ -22,9 +22,6 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; -using Microsoft.Scripting; -using Microsoft.Scripting.Utils; -using AstUtils = Microsoft.Scripting.Ast.Utils; namespace IronRuby.Compiler { internal struct AstBlock : IEnumerable { =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/AstGenerator.cs;C1158858 File: AstGenerator.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/AstGenerator.cs;C1158858 (server) 11/30/2009 2:22 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/AstGenerator.cs;NewSuper6 @@ -313,14 +313,12 @@ set { _parentMethod = value; } } - // TODO: super call - // null for top-level code + // null for top-level code, used by block definition (to encode method name into stack frame) public string MethodName { get { return _methodName; } } - // TODO: super call - // null for top-level code + // null for code that is evaluated outside a method scope, used by super-call public Parameters Parameters { get { return _parameters; } } =================================================================== add: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/CollectionBuilder.cs File: CollectionBuilder.cs =================================================================== --- [no source file] +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/CollectionBuilder.cs;NewSuper6 @@ -1,0 +1,64 @@ +?/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Microsoft Public License. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Microsoft Public License, please send an email to + * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Microsoft Public License. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using Microsoft.Scripting; + +namespace IronRuby.Compiler { + internal abstract class CollectionBuilder : MutableTuple { + private int _count; + private ReadOnlyCollectionBuilder _items; + + public CollectionBuilder() { + } + + public int Count { + get { return _count; } + } + + public ReadOnlyCollectionBuilder Items { + get { return _items; } + } + + public void Add(TElement expression) { + if (expression == null) { + return; + } + + switch (_count) { + case 0: Item000 = expression; break; + case 1: Item001 = expression; break; + case 2: Item002 = expression; break; + case 3: Item003 = expression; break; + case 4: + _items = new ReadOnlyCollectionBuilder(); + _items.Add(Item000); + _items.Add(Item001); + _items.Add(Item002); + _items.Add(Item003); + _items.Add(expression); + break; + + default: + Debug.Assert(_items != null); + _items.Add(expression); + break; + } + + _count++; + } + } +} =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/ReflectionCache.Generated.cs;C1240182 File: ReflectionCache.Generated.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/ReflectionCache.Generated.cs;C1240182 (server) 11/30/2009 6:15 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/ReflectionCache.Generated.cs;NewSuper6 @@ -68,8 +68,6 @@ private static MethodInfo _CreateArgumentsErrorForProc; public static MethodInfo/*!*/ CreateBfcForLibraryMethod { get { return _CreateBfcForLibraryMethod ?? (_CreateBfcForLibraryMethod = GetMethod(typeof(RubyOps), "CreateBfcForLibraryMethod")); } } private static MethodInfo _CreateBfcForLibraryMethod; - public static MethodInfo/*!*/ CreateBfcForMethodProcCall { get { return _CreateBfcForMethodProcCall ?? (_CreateBfcForMethodProcCall = GetMethod(typeof(RubyOps), "CreateBfcForMethodProcCall")); } } - private static MethodInfo _CreateBfcForMethodProcCall; public static MethodInfo/*!*/ CreateBfcForProcCall { get { return _CreateBfcForProcCall ?? (_CreateBfcForProcCall = GetMethod(typeof(RubyOps), "CreateBfcForProcCall")); } } private static MethodInfo _CreateBfcForProcCall; public static MethodInfo/*!*/ CreateBfcForYield { get { return _CreateBfcForYield ?? (_CreateBfcForYield = GetMethod(typeof(RubyOps), "CreateBfcForYield")); } } @@ -262,6 +260,8 @@ private static MethodInfo _GetRetrySingleton; public static MethodInfo/*!*/ GetSelfClassVersionHandle { get { return _GetSelfClassVersionHandle ?? (_GetSelfClassVersionHandle = GetMethod(typeof(RubyOps), "GetSelfClassVersionHandle")); } } private static MethodInfo _GetSelfClassVersionHandle; + public static MethodInfo/*!*/ GetSuperCallTarget { get { return _GetSuperCallTarget ?? (_GetSuperCallTarget = GetMethod(typeof(RubyOps), "GetSuperCallTarget")); } } + private static MethodInfo _GetSuperCallTarget; public static MethodInfo/*!*/ GetUnqualifiedConstant { get { return _GetUnqualifiedConstant ?? (_GetUnqualifiedConstant = GetMethod(typeof(RubyOps), "GetUnqualifiedConstant")); } } private static MethodInfo _GetUnqualifiedConstant; public static MethodInfo/*!*/ HookupEvent { get { return _HookupEvent ?? (_HookupEvent = GetMethod(typeof(RubyOps), "HookupEvent")); } } @@ -326,8 +326,8 @@ private static MethodInfo _IsProcConverterTarget; public static MethodInfo/*!*/ IsRetrySingleton { get { return _IsRetrySingleton ?? (_IsRetrySingleton = GetMethod(typeof(RubyOps), "IsRetrySingleton")); } } private static MethodInfo _IsRetrySingleton; - public static MethodInfo/*!*/ IsSuperCallTarget { get { return _IsSuperCallTarget ?? (_IsSuperCallTarget = GetMethod(typeof(RubyOps), "IsSuperCallTarget")); } } - private static MethodInfo _IsSuperCallTarget; + public static MethodInfo/*!*/ IsSuperOutOfMethodScope { get { return _IsSuperOutOfMethodScope ?? (_IsSuperOutOfMethodScope = GetMethod(typeof(RubyOps), "IsSuperOutOfMethodScope")); } } + private static MethodInfo _IsSuperOutOfMethodScope; public static MethodInfo/*!*/ IsTrue { get { return _IsTrue ?? (_IsTrue = GetMethod(typeof(RubyOps), "IsTrue")); } } private static MethodInfo _IsTrue; public static MethodInfo/*!*/ LeaveLoop { get { return _LeaveLoop ?? (_LeaveLoop = GetMethod(typeof(RubyOps), "LeaveLoop")); } } @@ -368,6 +368,8 @@ private static MethodInfo _MakeHash; public static MethodInfo/*!*/ MakeHash0 { get { return _MakeHash0 ?? (_MakeHash0 = GetMethod(typeof(RubyOps), "MakeHash0")); } } private static MethodInfo _MakeHash0; + public static MethodInfo/*!*/ MakeImplicitSuperInBlockMethodError { get { return _MakeImplicitSuperInBlockMethodError ?? (_MakeImplicitSuperInBlockMethodError = GetMethod(typeof(RubyOps), "MakeImplicitSuperInBlockMethodError")); } } + private static MethodInfo _MakeImplicitSuperInBlockMethodError; public static MethodInfo/*!*/ MakeInvalidArgumentTypesError { get { return _MakeInvalidArgumentTypesError ?? (_MakeInvalidArgumentTypesError = GetMethod(typeof(RubyOps), "MakeInvalidArgumentTypesError")); } } private static MethodInfo _MakeInvalidArgumentTypesError; public static MethodInfo/*!*/ MakeMissingDefaultConstructorError { get { return _MakeMissingDefaultConstructorError ?? (_MakeMissingDefaultConstructorError = GetMethod(typeof(RubyOps), "MakeMissingDefaultConstructorError")); } } @@ -616,6 +618,8 @@ private static FieldInfo _IsDefinedConstantSiteCache_Value; public static FieldInfo/*!*/ IsDefinedConstantSiteCache_Version { get { return _IsDefinedConstantSiteCache_Version ?? (_IsDefinedConstantSiteCache_Version = GetField(typeof(IsDefinedConstantSiteCache), "Version")); } } private static FieldInfo _IsDefinedConstantSiteCache_Version; + public static FieldInfo/*!*/ NeedsUpdate { get { return _NeedsUpdate ?? (_NeedsUpdate = GetField(typeof(RubyOps), "NeedsUpdate")); } } + private static FieldInfo _NeedsUpdate; public static FieldInfo/*!*/ RubyContext_ConstantAccessVersion { get { return _RubyContext_ConstantAccessVersion ?? (_RubyContext_ConstantAccessVersion = GetField(typeof(RubyContext), "ConstantAccessVersion")); } } private static FieldInfo _RubyContext_ConstantAccessVersion; public static FieldInfo/*!*/ RubyModule_Version { get { return _RubyModule_Version ?? (_RubyModule_Version = GetField(typeof(RubyModule), "Version")); } } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/RubyCompilerOptions.cs;C1086496 File: RubyCompilerOptions.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/RubyCompilerOptions.cs;C1086496 (server) 11/30/2009 7:20 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/RubyCompilerOptions.cs;NewSuper6 @@ -74,11 +74,22 @@ } /// - /// Method name used by super in eval. + /// Method name used by blocks. /// internal string TopLevelMethodName { get; set; } + /// + /// Used by super-calls with implicit parameters. + /// + internal string[] TopLevelParameterNames { get; set; } + + internal bool TopLevelHasUnsplatParameter { get; set; } + + /// + /// Used by dynamic variable look-up. + /// internal List LocalNames { get; set; } + internal RubyCompatibility Compatibility { get; set; } public RubyCompilerOptions() { =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Arguments.cs;C1158858 File: Arguments.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Arguments.cs;C1158858 (server) 11/30/2009 3:17 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Arguments.cs;NewSuper6 @@ -95,19 +95,19 @@ return args; } - internal void TransformToCall(AstGenerator/*!*/ gen, CallBuilder callBuilder) { + internal void TransformToCall(AstGenerator/*!*/ gen, CallSiteBuilder/*!*/ siteBuilder) { if (_expressions != null) { foreach (var arg in _expressions) { - callBuilder.Add(arg.TransformRead(gen)); + siteBuilder.Add(arg.TransformRead(gen)); } } if (_maplets != null) { - callBuilder.Add(gen.TransformToHashConstructor(_maplets)); + siteBuilder.Add(gen.TransformToHashConstructor(_maplets)); } if (_array != null) { - callBuilder.SplattedArgument = + siteBuilder.SplattedArgument = Ast.Dynamic(SplatAction.Make(gen.Context), typeof(IList), _array.TransformRead(gen)); } } =================================================================== rename, edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/CallSiteBuilder.cs;C1107696 File: CallSiteBuilder.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/CallSiteBuilder.cs;C1107696 (server) 11/30/2009 2:43 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/CallSiteBuilder.cs;NewSuper6 @@ -19,9 +19,8 @@ using MSA = Microsoft.Scripting.Ast; #endif -using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Diagnostics; +using System.Runtime.CompilerServices; using IronRuby.Runtime.Calls; using IronRuby.Runtime; using Microsoft.Scripting.Utils; @@ -33,54 +32,83 @@ /// /// Simple helper for building up method call actions. /// - internal class CallBuilder { + internal sealed class CallSiteBuilder : CollectionBuilder { private readonly AstGenerator/*!*/ _gen; + private readonly bool _hasBlock; - private readonly List/*!*/ _args = new List(); - - // TODO: - public MSA.Expression Instance; - public MSA.Expression SplattedArgument; - public MSA.Expression Block; - public MSA.Expression RhsArgument; + public MSA.Expression SplattedArgument { get; set; } + public MSA.Expression RhsArgument { get; set; } - internal CallBuilder(AstGenerator/*!*/ gen) { - Assert.NotNull(gen); + internal CallSiteBuilder(AstGenerator/*!*/ gen, MSA.Expression/*!*/ instance, MSA.Expression block) { + Assert.NotNull(gen, instance); + _hasBlock = block != null; _gen = gen; + + // scope variable can be typed to a subclass of RubyScope: + Add(AstUtils.Convert(_gen.CurrentScopeVariable, typeof(RubyScope))); + Add(instance); + Add(block); } - public void Add(MSA.Expression/*!*/ expression) { - _args.Add(expression); + /// + /// [scope, instance, block?] + /// + private int HiddenArgumentCount { + get { return _hasBlock ? 3 : 2; } } - private RubyCallSignature MakeCallSignature(bool hasImplicitSelf) { - return new RubyCallSignature(true, hasImplicitSelf, _args.Count, SplattedArgument != null, Block != null, RhsArgument != null); + private RubyCallFlags GetSignatureFlags() { + var flags = RubyCallFlags.HasScope; + + if (_hasBlock) { + flags |= RubyCallFlags.HasBlock; + } + + if (SplattedArgument != null) { + flags |= RubyCallFlags.HasSplattedArgument; + } + + if (RhsArgument != null) { + flags |= RubyCallFlags.HasRhsArgument; + } + + return flags; } + public MSA.DynamicExpression/*!*/ MakeSuperCallAction(int lexicalScopeId, bool hasImplicitArguments) { + RubyCallFlags flags = GetSignatureFlags() | RubyCallFlags.HasImplicitSelf; + if (hasImplicitArguments) { + flags |= RubyCallFlags.HasImplicitArguments; + } + + return MakeCallSite(SuperCallAction.Make(_gen.Context, new RubyCallSignature(Count - HiddenArgumentCount, flags), lexicalScopeId)); + } + public MSA.DynamicExpression/*!*/ MakeCallAction(string/*!*/ name, bool hasImplicitSelf) { - return InvokeMethod(_gen.Context, name, MakeCallSignature(hasImplicitSelf), GetExpressions()); - } + RubyCallFlags flags = GetSignatureFlags(); + if (hasImplicitSelf) { + flags |= RubyCallFlags.HasImplicitSelf; + } - public MSA.Expression/*!*/ MakeSuperCallAction(int lexicalScopeId) { - return Ast.Dynamic( - SuperCallAction.Make(_gen.Context, MakeCallSignature(true), lexicalScopeId), - typeof(object), - GetExpressions() - ); + return MakeCallSite(RubyCallAction.Make(_gen.Context, name, new RubyCallSignature(Count - HiddenArgumentCount, flags))); } - internal static MSA.DynamicExpression/*!*/ InvokeMethod(RubyContext/*!*/ context, string/*!*/ name, RubyCallSignature signature, - params MSA.Expression[]/*!*/ args) { + internal MSA.DynamicExpression/*!*/ MakeCallSite(CallSiteBinder/*!*/ binder) { + if (SplattedArgument != null) { + Add(SplattedArgument); + } - Debug.Assert(args.Length >= 2); - var scope = args[0]; - var target = args[1]; + if (RhsArgument != null) { + Add(RhsArgument); + } - switch (args.Length) { - case 2: return InvokeMethod(context, name, signature, scope, target); - case 3: return InvokeMethod(context, name, signature, scope, target, args[2]); - case 4: return InvokeMethod(context, name, signature, scope, target, args[2], args[3]); - default: return InvokeMethod(context, name, signature, scope, target, args); + switch (Count) { + case 0: + case 1: throw Assert.Unreachable; + case 2: return Ast.Dynamic(binder, typeof(object), Item000, Item001); + case 3: return Ast.Dynamic(binder, typeof(object), Item000, Item001, Item002); + case 4: return Ast.Dynamic(binder, typeof(object), Item000, Item001, Item002, Item003); + default: return Ast.Dynamic(binder, typeof(object), Items); } } @@ -104,38 +132,5 @@ return Ast.Dynamic(RubyCallAction.Make(context, name, signature), typeof(object), AstUtils.Convert(scope, typeof(RubyScope)), target, arg0, arg1); } - - internal static MSA.DynamicExpression/*!*/ InvokeMethod(RubyContext/*!*/ context, string/*!*/ name, RubyCallSignature signature, - MSA.Expression/*!*/ scope, MSA.Expression/*!*/ target, MSA.Expression/*!*/[]/*!*/ args) { - Debug.Assert(signature.HasScope); - Debug.Assert(args.Length >= 2); - - args[0] = Ast.Convert(args[0], typeof(RubyScope)); - return Ast.Dynamic(RubyCallAction.Make(context, name, signature), typeof(object), args); - } - - private MSA.Expression/*!*/[]/*!*/ GetExpressions() { - var result = new List(); - result.Add(_gen.CurrentScopeVariable); - result.Add(Instance); - - if (Block != null) { - result.Add(Block); - } - - for (int i = 0; i < _args.Count; i++) { - result.Add(_args[i]); - } - - if (SplattedArgument != null) { - result.Add(SplattedArgument); - } - - if (RhsArgument != null) { - result.Add(RhsArgument); - } - - return result.ToArray(); - } } } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Parameters.cs;C1158858 File: Parameters.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Parameters.cs;C1158858 (server) 11/30/2009 4:08 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Parameters.cs;NewSuper6 @@ -95,5 +95,23 @@ AstUtils.Empty() ); } + + internal void TransformForSuperCall(AstGenerator/*!*/ gen, CallSiteBuilder/*!*/ siteBuilder) { + if (_mandatory != null) { + foreach (Variable v in _mandatory) { + siteBuilder.Add(v.TransformRead(gen)); + } + } + + if (_optional != null) { + foreach (SimpleAssignmentExpression s in _optional) { + siteBuilder.Add(s.Left.TransformRead(gen)); + } + } + + if (_array != null) { + siteBuilder.SplattedArgument = _array.TransformRead(gen); + } + } } } \ No newline at end of file =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs;C1107696 File: SourceUnitTree.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs;C1107696 (server) 11/30/2009 3:17 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs;NewSuper6 @@ -107,8 +107,8 @@ selfVariable, runtimeScopeVariable, blockParameter, - gen.CompilerOptions.TopLevelMethodName, // method name - null // parameters + gen.CompilerOptions.TopLevelMethodName, // method name for blocks + null // parameters for super calls ); MSA.Expression body; @@ -120,7 +120,7 @@ var epilogue = Methods.PrintInteractiveResult.OpCall(runtimeScopeVariable, Ast.Dynamic(ConvertToSAction.Make(gen.Context), typeof(MutableString), - CallBuilder.InvokeMethod(gen.Context, "inspect", RubyCallSignature.WithScope(0), + CallSiteBuilder.InvokeMethod(gen.Context, "inspect", RubyCallSignature.WithScope(0), gen.CurrentScopeVariable, resultVariable ) ) =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Declarations/MethodDeclaration.cs;C1107696 File: MethodDeclaration.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Declarations/MethodDeclaration.cs;C1107696 (server) 11/30/2009 2:07 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Declarations/MethodDeclaration.cs;NewSuper6 @@ -129,6 +129,15 @@ var selfParameter = parameters[0]; var blockParameter = parameters[1]; + // exclude block parameter even if it is explicitly specified: + int visiblePrameterCountAndSignatureFlags = (parameters.Length - 2) << 2; + if (_parameters.Block != null) { + visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasBlockFlag; + } + if (_parameters.Array != null) { + visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasUnsplatFlag; + } + gen.EnterMethodDefinition( scope, selfParameter, @@ -190,6 +199,7 @@ Methods.CreateMethodScope.OpCall( scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(), + Ast.Constant(visiblePrameterCountAndSignatureFlags), Ast.Constant(declaringScope, typeof(RubyScope)), Ast.Constant(declaringModule, typeof(RubyModule)), Ast.Constant(_name), =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/CaseExpression.cs;C1120203 File: CaseExpression.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/CaseExpression.cs;C1120203 (server) 11/30/2009 3:15 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/CaseExpression.cs;NewSuper6 @@ -87,7 +87,7 @@ // RubyOps.IsTrue(Call("===", , )) private static MSA.Expression/*!*/ MakeTest(AstGenerator/*!*/ gen, MSA.Expression/*!*/ expr, MSA.Expression value) { if (value != null) { - expr = CallBuilder.InvokeMethod(gen.Context, "===", RubyCallSignature.WithScope(1), + expr = CallSiteBuilder.InvokeMethod(gen.Context, "===", RubyCallSignature.WithScope(1), gen.CurrentScopeVariable, expr, value =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/ForLoopExpression.cs;C1107696 File: ForLoopExpression.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/ForLoopExpression.cs;C1107696 (server) 11/30/2009 3:17 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/ForLoopExpression.cs;NewSuper6 @@ -61,7 +61,7 @@ MSA.Expression blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#forloop-block", typeof(Proc)); - MSA.Expression result = CallBuilder.InvokeMethod(gen.Context, "each", RubyCallSignature.WithScopeAndBlock(0), + MSA.Expression result = CallSiteBuilder.InvokeMethod(gen.Context, "each", RubyCallSignature.WithScopeAndBlock(0), gen.CurrentScopeVariable, _list.TransformRead(gen), blockArgVariable =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/MethodCall.cs;C1202407 File: MethodCall.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/MethodCall.cs;C1202407 (server) 11/30/2009 3:17 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/MethodCall.cs;NewSuper6 @@ -90,31 +90,31 @@ // 3. passed args: normal args, maplets, array // 4. RHS of assignment (if present) - CallBuilder callBuilder = new CallBuilder(gen); - callBuilder.Instance = transformedTarget; - - MSA.Expression blockArgVariable = null; - MSA.Expression transformedBlock = null; + MSA.Expression blockArgVariable; + MSA.Expression transformedBlock; if (block != null) { blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#block-def", typeof(Proc)); transformedBlock = block.Transform(gen); - callBuilder.Block = blockArgVariable; + } else { + blockArgVariable = transformedBlock = null; } + var siteBuilder = new CallSiteBuilder(gen, transformedTarget, blockArgVariable); + if (arguments != null) { - arguments.TransformToCall(gen, callBuilder); + arguments.TransformToCall(gen, siteBuilder); } else if (singleArgument != null) { - callBuilder.Add(singleArgument); + siteBuilder.Add(singleArgument); } MSA.Expression rhsVariable = null; if (assignmentRhsArgument != null) { rhsVariable = gen.CurrentScope.DefineHiddenVariable("#rhs", assignmentRhsArgument.Type); - callBuilder.RhsArgument = Ast.Assign(rhsVariable, assignmentRhsArgument); + siteBuilder.RhsArgument = Ast.Assign(rhsVariable, assignmentRhsArgument); } - var dynamicSite = callBuilder.MakeCallAction(methodName, hasImplicitSelf); + var dynamicSite = siteBuilder.MakeCallAction(methodName, hasImplicitSelf); if (gen.Context.CallSiteCreated != null) { gen.Context.CallSiteCreated(node, dynamicSite); } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/StringConstructor.cs;C1107696 File: StringConstructor.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/StringConstructor.cs;C1107696 (server) 11/30/2009 3:17 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/StringConstructor.cs;NewSuper6 @@ -73,7 +73,7 @@ return TransformConcatentation(gen, _parts, Methods.CreateSymbol); case StringKind.Command: - return CallBuilder.InvokeMethod(gen.Context, "`", new RubyCallSignature(1, RubyCallFlags.HasScope | RubyCallFlags.HasImplicitSelf), + return CallSiteBuilder.InvokeMethod(gen.Context, "`", new RubyCallSignature(1, RubyCallFlags.HasScope | RubyCallFlags.HasImplicitSelf), gen.CurrentScopeVariable, gen.CurrentSelfVariable, TransformConcatentation(gen, _parts, Methods.CreateMutableString) =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/SuperCall.cs;C1202407 File: SuperCall.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/SuperCall.cs;C1202407 (server) 11/30/2009 1:12 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/SuperCall.cs;NewSuper6 @@ -34,31 +34,55 @@ /// super(args) /// super /// - /// The former case passes the arguments explicitly - /// The latter passes all of the arguments that were passed to the current method - /// (including the block, if any) + /// The former case passes the arguments explicitly. + /// The latter passes all of the arguments that were passed to the current method (including the block, if any) /// - /// Also works from a method defined using define_method (not supported yet!) + /// Also works from a method defined using define_method. /// public partial class SuperCall : CallExpression { + /// + /// All non-block arguments are passed implicitly. + /// + public bool HasImplicitArguments { + get { return Arguments == null; } + } + public SuperCall(Arguments args, Block block, SourceSpan location) : base(args, block, location) { } internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + // variable assigned to the transformed block in MakeCallWithBlockRetryable: + MSA.Expression blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#super-call-block", typeof(Proc)); + // invoke super member action: - CallBuilder callBuilder = new CallBuilder(gen); + var siteBuilder = new CallSiteBuilder(gen, gen.CurrentSelfVariable, blockArgVariable); - // self: - callBuilder.Instance = gen.CurrentSelfVariable; + // arguments: + if (HasImplicitArguments) { + // MRI 1.8: If a block is called via define_method stub its parameters are used here. + // MRI 1.9: This scenario is not supported. + // We don't support this either. Otherwise we would need to emit super call with dynamic parameters if gen.CurrentBlock != null. - // arguments: - if (Arguments != null) { - Arguments.TransformToCall(gen, callBuilder); + if (gen.CurrentMethod.Parameters != null) { + gen.CurrentMethod.Parameters.TransformForSuperCall(gen, siteBuilder); + } else if (gen.CompilerOptions.TopLevelParameterNames != null) { + bool hasUnsplat = gen.CompilerOptions.TopLevelHasUnsplatParameter; + string[] names = gen.CompilerOptions.TopLevelParameterNames; + + // dynamic lookup: + for (int i = 0; i < names.Length - (hasUnsplat ? 1 : 0); i++) { + siteBuilder.Add(Methods.GetLocalVariable.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(names[i]))); + } + if (hasUnsplat) { + siteBuilder.SplattedArgument = + Methods.GetLocalVariable.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(names[names.Length - 1])); + } + } else { + // this means we are not inside any method scope -> an exception will be thrown at the call site + } } else { - // copy parameters from the method: - // TODO: parameters in top-level eval - LexicalScope.TransformParametersToSuperCall(gen, callBuilder, gen.CurrentMethod.Parameters); + Arguments.TransformToCall(gen, siteBuilder); } // block: @@ -68,16 +92,10 @@ } else { transformedBlock = gen.MakeMethodBlockParameterRead(); } - - // variable assigned to the transformed block in MakeCallWithBlockRetryable: - MSA.Expression blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#super-call-block", typeof(Proc)); - callBuilder.Block = blockArgVariable; - - // TODO: this could be improved, currently the right method name and declaring module is always searched for at run-time (at the site): - + return gen.DebugMark( - MethodCall.MakeCallWithBlockRetryable(gen, - callBuilder.MakeSuperCallAction(gen.CurrentFrame.UniqueId), + MethodCall.MakeCallWithBlockRetryable(gen, + siteBuilder.MakeSuperCallAction(gen.CurrentFrame.UniqueId, HasImplicitArguments), blockArgVariable, transformedBlock, Block != null && Block.IsDefinition =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/LexicalScope.cs;C1107696 File: LexicalScope.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/LexicalScope.cs;C1107696 (server) 11/30/2009 2:50 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/LexicalScope.cs;NewSuper6 @@ -142,28 +142,6 @@ return localCount; } - internal static void TransformParametersToSuperCall(AstGenerator/*!*/ gen, CallBuilder/*!*/ callBuilder, Parameters parameters) { - if (parameters == null) { - return; - } - - if (parameters.Mandatory != null) { - foreach (Variable v in parameters.Mandatory) { - callBuilder.Add(v.TransformRead(gen)); - } - } - - if (parameters.Optional != null) { - foreach (SimpleAssignmentExpression s in parameters.Optional) { - callBuilder.Add(s.Left.TransformRead(gen)); - } - } - - if (parameters.Array != null) { - callBuilder.SplattedArgument = parameters.Array.TransformRead(gen); - } - } - #endregion } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/Parser.cs;C1286631 File: Parser.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/Parser.cs;C1286631 (server) 11/30/2009 1:35 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/Parser.cs;NewSuper6 @@ -406,6 +406,7 @@ } private static SuperCall/*!*/ MakeSuperCall(TokenValue args, SourceSpan location) { + Debug.Assert(args.Arguments != null); return new SuperCall(args.Arguments, args.Block, location); } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.cs;C1120203 File: BlockParam.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.cs;C1120203 (server) 12/1/2009 1:19 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.cs;NewSuper6 @@ -73,11 +73,8 @@ private readonly Proc/*!*/ _proc; private readonly BlockCallerKind _callerKind; - // filled by define_method, module_eval, load: if not null than method definition and method alias uses the module + // filled by module_eval: if not null than method definition uses the module private RubyModule _methodLookupModule; - - // filled by define_method: if not null then injects a scope in super call method lookup: - private readonly string _methodName; // Is the library method call taking this BlockParam a proc converter? // Used only for BlockParams that are passed to library method calls. @@ -89,16 +86,11 @@ private RuntimeFlowControl _targetFrame; private ProcKind _sourceProcKind; - private void ObjectInvariant() { - ContractUtils.Invariant(_methodName == null || _methodLookupModule != null); - } - internal BlockCallerKind CallerKind { get { return _callerKind; } } internal ProcKind SourceProcKind { get { return _sourceProcKind; } } internal BlockReturnReason ReturnReason { get { return _returnReason; } set { _returnReason = value; } } internal RuntimeFlowControl TargetFrame { get { return _targetFrame; } } internal RubyModule MethodLookupModule { get { return _methodLookupModule; } set { _methodLookupModule = value; } } - internal string MethodName { get { return _methodName; } } internal bool IsLibProcConverter { get { return _isLibProcConverter; } } public Proc/*!*/ Proc { get { return _proc; } } @@ -111,22 +103,17 @@ } public bool IsMethod { - get { - ObjectInvariant(); - return _methodName != null; - } + get { return _proc.Method != null; } } internal static PropertyInfo/*!*/ SelfProperty { get { return typeof(BlockParam).GetProperty("Self"); } } // friend: RubyOps - internal BlockParam(Proc/*!*/ proc, BlockCallerKind callerKind, bool isLibProcConverter, RubyModule moduleDeclaration, string methodName) { + internal BlockParam(Proc/*!*/ proc, BlockCallerKind callerKind, bool isLibProcConverter, RubyModule moduleDeclaration) { _callerKind = callerKind; _proc = proc; _isLibProcConverter = isLibProcConverter; _methodLookupModule = moduleDeclaration; - _methodName = methodName; - ObjectInvariant(); } internal void SetFlowControl(BlockReturnReason reason, RuntimeFlowControl targetFrame, ProcKind sourceProcKind) { @@ -234,22 +221,16 @@ [Emitted] public static BlockParam/*!*/ CreateBfcForYield(Proc proc) { if (proc != null) { - return new BlockParam(proc, BlockCallerKind.Yield, false, null, null); + return new BlockParam(proc, BlockCallerKind.Yield, false, null); } else { throw RubyExceptions.NoBlockGiven(); } } [Emitted] - public static BlockParam/*!*/ CreateBfcForMethodProcCall(Proc/*!*/ proc, RubyLambdaMethodInfo/*!*/ method) { - Assert.NotNull(proc, method); - return new BlockParam(proc, BlockCallerKind.Call, false, method.DeclaringModule, method.DefinitionName); - } - - [Emitted] public static BlockParam/*!*/ CreateBfcForProcCall(Proc/*!*/ proc) { Assert.NotNull(proc); - return new BlockParam(proc, BlockCallerKind.Call, false, null, null); + return new BlockParam(proc, BlockCallerKind.Call, false, null); } [Emitted] @@ -267,7 +248,7 @@ isProcConverter = false; } - return new BlockParam(proc, BlockCallerKind.Yield, isProcConverter, null, null); + return new BlockParam(proc, BlockCallerKind.Yield, isProcConverter, null); } [Emitted] =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExceptions.cs;C1286631 File: RubyExceptions.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExceptions.cs;C1286631 (server) 11/30/2009 6:10 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExceptions.cs;NewSuper6 @@ -212,6 +212,10 @@ return new LocalJumpError(FormatMessage(message, args)); } + public static Exception/*!*/ CreateRuntimeError(string/*!*/ message, params object[] args) { + return new RuntimeError(FormatMessage(message, args)); + } + public static Exception/*!*/ NoBlockGiven() { return CreateLocalJumpError("no block given"); } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;C1286631 File: RubyOps.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;C1286631 (server) 11/30/2009 11:46 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;NewSuper6 @@ -44,7 +44,6 @@ namespace IronRuby.Runtime { [ReflectionCached, CLSCompliant(false)] public static partial class RubyOps { - [Emitted] public static readonly object DefaultArgument = new object(); @@ -52,6 +51,13 @@ [Emitted] public static readonly object ForwardToBase = new object(); + // an instance of a dummy type that causes any rule based on instance type check to fail + private sealed class _NeedsUpdate { + } + + [Emitted] + public static readonly object NeedsUpdate = new _NeedsUpdate(); + #region Scopes [Emitted] @@ -128,12 +134,12 @@ } [Emitted] - public static RubyMethodScope/*!*/ CreateMethodScope(MutableTuple locals, SymbolId[] variableNames, - RubyScope/*!*/ parentScope, RubyModule/*!*/ declaringModule, string/*!*/ definitionName, + public static RubyMethodScope/*!*/ CreateMethodScope(MutableTuple locals, SymbolId[] variableNames, int visibleParameterCount, + RubyScope/*!*/ parentScope, RubyModule/*!*/ declaringModule, string/*!*/ definitionName, object selfObject, Proc blockParameter, InterpretedFrame interpretedFrame) { return new RubyMethodScope( - locals, variableNames ?? SymbolId.EmptySymbols, + locals, variableNames ?? SymbolId.EmptySymbols, visibleParameterCount, parentScope, declaringModule, definitionName, selfObject, blockParameter, interpretedFrame ); @@ -163,15 +169,17 @@ [Emitted] public static void TraceBlockCall(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) { - if (block.IsMethod) { - scope.RubyContext.ReportTraceEvent("call", scope, block.MethodLookupModule, block.MethodName, fileName, lineNumber); + var method = block.Proc.Method; + if (method != null) { + scope.RubyContext.ReportTraceEvent("call", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber); } } [Emitted] public static void TraceBlockReturn(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) { - if (block.IsMethod) { - scope.RubyContext.ReportTraceEvent("return", scope, block.MethodLookupModule, block.MethodName, fileName, lineNumber); + var method = block.Proc.Method; + if (method != null) { + scope.RubyContext.ReportTraceEvent("return", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber); } } @@ -1824,16 +1832,13 @@ ); } + [Emitted] + public static Exception/*!*/ MakeImplicitSuperInBlockMethodError() { + return RubyExceptions.CreateRuntimeError("implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly."); + } + #endregion - [Emitted] //RubyBinder - public static bool IsSuperCallTarget(RubyScope/*!*/ scope, RubyModule/*!*/ module, string/*!*/ methodName, out object self) { - RubyModule _currentDeclaringModule; - string _currentMethodName; - scope.GetSuperCallTarget(out _currentDeclaringModule, out _currentMethodName, out self); - return module == _currentDeclaringModule && methodName == _currentMethodName; - } - #region Ranges [Emitted] @@ -1909,6 +1914,45 @@ && !(context.TryGetClrTypeInstanceData(target, out data) && (immediate = data.ImmediateClass) != null && immediate.IsSingletonClass); } + // super call condition + [Emitted] + public static object GetSuperCallTarget(RubyScope/*!*/ scope, int targetId) { + while (true) { + switch (scope.Kind) { + case ScopeKind.Method: + return targetId == 0 ? scope.SelfObject : NeedsUpdate; + + case ScopeKind.BlockMethod: + return targetId == ((RubyBlockScope)scope).BlockFlowControl.Proc.Method.Id ? scope.SelfObject : NeedsUpdate; + + case ScopeKind.TopLevel: + // This method is only called if there was method or block-method scope in lexical scope chain. + // Once there is it cannot be undone. It can only be shadowed by a block scope that became block-method scope, or + // a block-method scope's target-id can be changed. + throw Assert.Unreachable; + } + + scope = scope.Parent; + } + } + + // super call condition + [Emitted] + public static bool IsSuperOutOfMethodScope(RubyScope/*!*/ scope) { + while (true) { + switch (scope.Kind) { + case ScopeKind.Method: + case ScopeKind.BlockMethod: + return false; + + case ScopeKind.TopLevel: + return true; + } + + scope = scope.Parent; + } + } + #endregion #region Conversions =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScope.cs;C1240527 File: RubyScope.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScope.cs;C1240527 (server) 11/30/2009 5:09 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyScope.cs;NewSuper6 @@ -24,6 +24,7 @@ using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; using System.Threading; +using IronRuby.Runtime.Calls; namespace IronRuby.Runtime { @@ -31,7 +32,17 @@ TopLevel, Method, Module, - Block + Block, + + /// + /// Block scope used by defined_method. + /// + BlockMethod, + + /// + /// Block scope used by module_eval. + /// + BlockModule } public class RuntimeFlowControl { @@ -370,6 +381,8 @@ while (scope != null) { switch (scope.Kind) { case ScopeKind.Block: + case ScopeKind.BlockMethod: + case ScopeKind.BlockModule: blockScope = (RubyBlockScope)scope; return; @@ -382,7 +395,13 @@ } } - internal void GetSuperCallTarget(out RubyModule declaringModule, out string/*!*/ methodName, out object self) { + /// + /// Returns + /// -1 if there is no method or block-method scope, + /// 0 if the target scope is a method scope, + /// id > 0 of the target lambda for block-method scopes. + /// + internal int GetSuperCallTarget(out RubyModule declaringModule, out string/*!*/ methodName, out RubyScope targetScope) { RubyScope scope = this; while (true) { Debug.Assert(scope != null); @@ -393,21 +412,22 @@ // See RubyOps.DefineMethod for why we can use Method here. declaringModule = methodScope.DeclaringModule; methodName = methodScope.DefinitionName; - self = scope.SelfObject; - return; + targetScope = scope; + return 0; - case ScopeKind.Block: - BlockParam blockParam = ((RubyBlockScope)scope).BlockFlowControl; - if (blockParam.MethodName != null) { - declaringModule = blockParam.MethodLookupModule; - methodName = blockParam.MethodName; - self = scope.SelfObject; - return; - } - break; + case ScopeKind.BlockMethod: + RubyLambdaMethodInfo info = ((RubyBlockScope)scope).BlockFlowControl.Proc.Method; + Debug.Assert(info != null); + declaringModule = info.DeclaringModule; + methodName = info.DefinitionName; + targetScope = scope; + return info.Id; case ScopeKind.TopLevel: - throw RubyOps.MakeTopLevelSuperException(); + declaringModule = null; + methodName = null; + targetScope = null; + return -1; } scope = scope.Parent; @@ -417,13 +437,13 @@ public RubyScope/*!*/ GetMethodAttributesDefinitionScope() { RubyScope scope = this; while (true) { - if (scope.Kind == ScopeKind.Block) { - BlockParam blockParam = ((RubyBlockScope)scope).BlockFlowControl; - if (blockParam.MethodLookupModule != null && blockParam.MethodName == null) { + switch (scope.Kind) { + case ScopeKind.Block: + case ScopeKind.BlockMethod: + break; + + default: return scope; - } - } else { - return scope; } scope = scope.Parent; @@ -454,12 +474,13 @@ case ScopeKind.Method: return scope.GetInnerMostModuleForMethodLookup(); - case ScopeKind.Block: + case ScopeKind.BlockMethod: + return ((RubyBlockScope)scope).BlockFlowControl.Proc.Method.DeclaringModule; + + case ScopeKind.BlockModule: BlockParam blockParam = ((RubyBlockScope)scope).BlockFlowControl; - if (blockParam.MethodLookupModule != null) { - return blockParam.MethodLookupModule; - } - break; + Debug.Assert(blockParam.MethodLookupModule != null); + return blockParam.MethodLookupModule; } scope = scope.Parent; @@ -695,6 +716,23 @@ private readonly string/*!*/ _definitionName; private readonly Proc _blockParameter; + // Lowest 2 bits are flags: + internal const int HasBlockFlag = 1; + internal const int HasUnsplatFlag = 2; + private readonly int _visibleParameterCountAndSignatureFlags; + + internal bool HasUnsplatParameter { + get { return (_visibleParameterCountAndSignatureFlags & HasUnsplatFlag) != 0; } + } + + internal bool HasBlockParameter { + get { return (_visibleParameterCountAndSignatureFlags & HasBlockFlag) != 0; } + } + + internal int VisibleParameterCount { + get { return _visibleParameterCountAndSignatureFlags >> 2; } + } + public override ScopeKind Kind { get { return ScopeKind.Method; } } public override bool InheritsLocalVariables { get { return false; } } @@ -711,7 +749,7 @@ get { return _blockParameter; } } - internal RubyMethodScope(MutableTuple locals, SymbolId[]/*!*/ variableNames, + internal RubyMethodScope(MutableTuple locals, SymbolId[]/*!*/ variableNames, int visibleParameterCountAndSignatureFlags, RubyScope/*!*/ parent, RubyModule/*!*/ declaringModule, string/*!*/ definitionName, object selfObject, Proc blockParameter, InterpretedFrame interpretedFrame) { Assert.NotNull(parent, declaringModule, definitionName); @@ -726,6 +764,7 @@ _methodAttributes = RubyMethodAttributes.PublicInstance; _locals = locals; _variableNames = variableNames; + _visibleParameterCountAndSignatureFlags = visibleParameterCountAndSignatureFlags; InterpretedFrame = interpretedFrame; // RubyMethodScope: @@ -736,6 +775,18 @@ InitializeRfc(blockParameter); SetDebugName("method " + definitionName + ((blockParameter != null) ? "&" : null)); } + + public string/*!*/[]/*!*/ GetVisibleParameterNames() { + int firstVisibleParameter = HasBlockParameter ? 1 : 0; + var result = new string[VisibleParameterCount]; + + // parameters precede other variables: + for (int i = 0; i < result.Length; i++) { + result[i] = SymbolTable.IdToString(_variableNames[firstVisibleParameter + i]); + } + + return result; + } } public sealed class RubyModuleScope : RubyClosureScope { @@ -817,9 +868,24 @@ public sealed class RubyBlockScope : RubyScope { private readonly BlockParam/*!*/ _blockFlowControl; - public override ScopeKind Kind { get { return ScopeKind.Block; } } - public override bool InheritsLocalVariables { get { return true; } } + public override ScopeKind Kind { + get { + if (_blockFlowControl.IsMethod) { + return ScopeKind.BlockMethod; + } + if (_blockFlowControl.MethodLookupModule == null) { + return ScopeKind.Block; + } + + return ScopeKind.BlockModule; + } + } + + public override bool InheritsLocalVariables { + get { return true; } + } + public BlockParam/*!*/ BlockFlowControl { get { return _blockFlowControl; } } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs;C1286631 File: RubyUtils.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs;C1286631 (server) 11/30/2009 7:22 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyUtils.cs;NewSuper6 @@ -764,6 +764,8 @@ FactoryKind = isModuleEval ? TopScopeFactoryKind.ModuleEval : TopScopeFactoryKind.None, LocalNames = targetScope.GetVisibleLocalNames(), TopLevelMethodName = (methodScope != null) ? methodScope.DefinitionName : null, + TopLevelParameterNames = (methodScope != null) ? methodScope.GetVisibleParameterNames() : null, + TopLevelHasUnsplatParameter = (methodScope != null) ? methodScope.HasUnsplatParameter : false, InitialLocation = new SourceLocation(0, line <= 0 ? 1 : line, 1), }; } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyCallSignature.cs;C1202407 File: RubyCallSignature.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyCallSignature.cs;C1202407 (server) 11/30/2009 1:09 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyCallSignature.cs;NewSuper6 @@ -44,16 +44,19 @@ // Interop calls can only see Ruby-public members. IsInteropCall = 32, - // If the resolved method is a Ruby method call it otherwise invoke #base# method on target's type. + // CallAction only: If the resolved method is a Ruby method call it otherwise invoke #base# method on target's type. // Used in method overrides defined in types emitted for Ruby classes that derive from CLR type. IsVirtualCall = 64, + + // SuperCallAction only: the super site dynamically loads its parameters from scope. + HasImplicitArguments = 128 } /// /// RubyScope/RubyContext, (self), (argument){ArgumentCount}, (splatted-argument)?, (block)? /// public struct RubyCallSignature : IEquatable { - private const int FlagsCount = 7; + private const int FlagsCount = 8; private const int ResolveOnlyArgumentCount = (int)(UInt32.MaxValue >> FlagsCount); private const int MaxArgumentCount = ResolveOnlyArgumentCount - 1; @@ -68,6 +71,7 @@ public bool HasRhsArgument { get { return (_countAndFlags & (uint)RubyCallFlags.HasRhsArgument) != 0; } } public bool IsInteropCall { get { return (_countAndFlags & (uint)RubyCallFlags.IsInteropCall) != 0; } } public bool IsVirtualCall { get { return (_countAndFlags & (uint)RubyCallFlags.IsVirtualCall) != 0; } } + public bool HasImplicitArguments { get { return (_countAndFlags & (uint)RubyCallFlags.HasImplicitArguments) != 0; } } // defined? ignores arguments hence we can use one argument number (max) to represent resolve only sites: public bool ResolveOnly { get { return ArgumentCount == ResolveOnlyArgumentCount; } } @@ -101,19 +105,6 @@ _countAndFlags = ((uint)argumentCount << FlagsCount) | (uint)flags; } - public RubyCallSignature(bool hasScope, bool hasImplicitSelf, int argumentCount, bool hasSplattedArgument, bool hasBlock, bool hasRhsArgument) { - Debug.Assert(argumentCount >= 0 && argumentCount <= MaxArgumentCount); - - var flags = RubyCallFlags.None; - if (hasImplicitSelf) flags |= RubyCallFlags.HasImplicitSelf; - if (hasScope) flags |= RubyCallFlags.HasScope; - if (hasSplattedArgument) flags |= RubyCallFlags.HasSplattedArgument; - if (hasBlock) flags |= RubyCallFlags.HasBlock; - if (hasRhsArgument) flags |= RubyCallFlags.HasRhsArgument; - - _countAndFlags = ((uint)argumentCount << FlagsCount) | (uint)flags; - } - [Emitted, Obsolete("Do not use from code"), CLSCompliant(false)] public RubyCallSignature(uint countAndFlags) { _countAndFlags = countAndFlags; @@ -179,12 +170,13 @@ public override string/*!*/ ToString() { return "(" + (HasImplicitSelf ? "." : "") + + (HasImplicitArguments ? "I" : "") + (IsVirtualCall ? "V" : "") + (HasScope ? "S" : "C") + (ResolveOnly ? "?" : "," + ArgumentCount.ToString()) + (HasSplattedArgument ? "*" : "") + (HasBlock ? "&" : "") + - (HasRhsArgument ? "=" : "") + + (HasRhsArgument ? "=" : "") + ")"; } } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyLambdaMethodInfo.cs;C1107696 File: RubyLambdaMethodInfo.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyLambdaMethodInfo.cs;C1107696 (server) 12/1/2009 1:14 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyLambdaMethodInfo.cs;NewSuper6 @@ -20,6 +20,7 @@ #endif using System; +using System.Threading; using System.Diagnostics; using System.Reflection; using Microsoft.Scripting; @@ -33,20 +34,28 @@ using Ast = Expression; public class RubyLambdaMethodInfo : RubyMemberInfo { + private static int _Id = 1; + + private readonly int _id; private readonly Proc/*!*/ _lambda; private readonly string/*!*/ _definitionName; - internal RubyLambdaMethodInfo(Proc/*!*/ lambda, string/*!*/ definitionName, RubyMemberFlags flags, RubyModule/*!*/ declaringModule) + internal RubyLambdaMethodInfo(Proc/*!*/ block, string/*!*/ definitionName, RubyMemberFlags flags, RubyModule/*!*/ declaringModule) : base(flags, declaringModule) { - Assert.NotNull(lambda, definitionName, declaringModule); - _lambda = lambda; + Assert.NotNull(block, definitionName, declaringModule); + _lambda = block.ToLambda(this); _definitionName = definitionName; + _id = Interlocked.Increment(ref _Id); } public Proc/*!*/ Lambda { get { return _lambda; } } + internal int Id { + get { return _id; } + } + public string/*!*/ DefinitionName { get { return _definitionName; } } @@ -68,8 +77,7 @@ Proc.BuildCall( metaBuilder, AstUtils.Constant(_lambda), // proc object - args.TargetExpression, // self - AstUtils.Constant(this), // this method for super and class_eval + args.TargetExpression, // self args ); } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/SuperCallAction.cs;C1202407 File: SuperCallAction.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/SuperCallAction.cs;C1202407 (server) 11/30/2009 4:28 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/SuperCallAction.cs;NewSuper6 @@ -40,6 +40,7 @@ internal SuperCallAction(RubyContext context, RubyCallSignature signature, int lexicalScopeId) : base(context) { + Debug.Assert(signature.HasImplicitSelf && signature.HasScope && (signature.HasBlock || signature.ResolveOnly)); _signature = signature; _lexicalScopeId = lexicalScopeId; } @@ -73,21 +74,33 @@ string currentMethodName; var scope = args.Scope; + var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)); - object target; - scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target); + RubyScope targetScope; + int scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope); + if (scopeNesting == -1) { + metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr)); + metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall()); + return true; + } + + object target = targetScope.SelfObject; var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); - - metaBuilder.AddCondition( - Methods.IsSuperCallTarget.OpCall( - AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)), - AstUtils.Constant(currentDeclaringModule), - AstUtils.Constant(currentMethodName), - targetExpression - ) + var assignTarget = Ast.Assign( + targetExpression, + Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting)) ); + if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod) { + metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate))); + metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall()); + return true; + } + + // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail: + metaBuilder.AddCondition(Ast.Block(assignTarget, Ast.Constant(true))); + args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); @@ -95,6 +108,9 @@ RubyMemberInfo method; RubyMemberInfo methodMissing = null; + // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C + // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419. + // we need to lock the hierarchy of the target class: var targetClass = scope.RubyContext.GetImmediateClassOf(target); using (targetClass.Context.ClassHierarchyLocker()) { ===================================================================