internal override void BuildMethodMissingCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) { var globalScope = args.TargetClass.GlobalScope; var context = globalScope.Context; if (name.LastCharacter() == '=') { var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1); if (!metaBuilder.Error) { var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); var interopSetter = context.MetaBinderFactory.InteropSetMember(name.Substring(0, name.Length - 1)); metaBuilder.SetMetaResult( interopSetter.Bind( new DynamicMetaObject( scopeVar, BindingRestrictions.Empty, globalScope.Scope ), new[] { normalizedArgs[0] } ), true ); } } else { RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0); Expression errorExpr = metaBuilder.Error ? Ast.Throw(metaBuilder.Result, typeof(object)) : null; var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); var scopeLookupResultVar = metaBuilder.GetTemporary(typeof(object), "#result"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); Expression scopeLookupResultExpr = errorExpr ?? scopeLookupResultVar; Expression fallbackExp; if (name == "scope") { fallbackExp = errorExpr ?? args.TargetExpression; } else { // super(methodName, ...args...) - ignore argument error: args.InsertMethodName(name); fallbackExp = AstUtils.LightDynamic( context.MetaBinderFactory.Call(Symbols.MethodMissing, new RubyCallSignature( args.Signature.ArgumentCount + 1, args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall ) ), typeof(object), args.GetCallSiteArguments(args.TargetExpression) ); } var scopeLookup = Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(RubyMetaBinderFactory.InteropTryGetMemberExact(name), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ); string unmanagled = RubyUtils.TryUnmangleMethodName(name); if (unmanagled != null) { scopeLookup = Ast.OrElse( scopeLookup, Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(RubyMetaBinderFactory.InteropTryGetMemberExact(unmanagled), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ) ); } metaBuilder.Result = Ast.Condition( scopeLookup, scopeLookupResultExpr, fallbackExp ); } }
internal override void BuildMethodMissingCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { var globalScope = args.TargetClass.GlobalScope; var context = globalScope.Context; if (name.LastCharacter() == '=') { var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1); if (!metaBuilder.Error) { var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); var interopSetter = context.MetaBinderFactory.InteropSetMember(name.Substring(0, name.Length - 1)); metaBuilder.SetMetaResult( interopSetter.Bind( new DynamicMetaObject( scopeVar, BindingRestrictions.Empty, globalScope.Scope ), new[] { normalizedArgs[0] } ), true ); } } else { RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0); Expression errorExpr = metaBuilder.Error ? Ast.Throw(metaBuilder.Result, typeof(object)) : null; var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); var scopeLookupResultVar = metaBuilder.GetTemporary(typeof(object), "#result"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); Expression scopeLookupResultExpr = errorExpr ?? scopeLookupResultVar; Expression fallbackExp; if (name == "scope") { fallbackExp = errorExpr ?? args.TargetExpression; } else { // super(methodName, ...args...) - ignore argument error: args.InsertMethodName(name); fallbackExp = AstUtils.LightDynamic( context.MetaBinderFactory.Call(Symbols.MethodMissing, new RubyCallSignature( args.Signature.ArgumentCount + 1, args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall ) ), typeof(object), args.GetCallSiteArguments(args.TargetExpression) ); } var scopeLookup = Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(context.MetaBinderFactory.InteropTryGetMemberExact(name), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ); string unmanagled = RubyUtils.TryUnmangleMethodName(name); if (unmanagled != null) { scopeLookup = Ast.OrElse( scopeLookup, Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(context.MetaBinderFactory.InteropTryGetMemberExact(unmanagled), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ) ); } metaBuilder.Result = Ast.Condition( scopeLookup, scopeLookupResultExpr, fallbackExp ); } }
protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)); 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"); 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.AddInitialization(assignTarget); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); 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()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (_signature.ResolveOnly) { metaBuilder.Result = AstUtils.Constant(method != null); return true; } if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback); } return true; }
protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)); 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"); 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.AddInitialization(assignTarget); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); 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()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (_signature.ResolveOnly) { metaBuilder.Result = AstUtils.Constant(method != null); return(true); } if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return(RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback)); } return(true); }