SetError() public method

public SetError ( Expression expression ) : void
expression Expression
return void
Beispiel #1
0
        private static MethodMissingBinding BindToKernelMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName,
                                                                      RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall)
        {
            // TODO: better specialization of method_missing methods
            if (methodMissing == null ||
                methodMissing.DeclaringModule == methodMissing.Context.KernelModule && methodMissing is RubyLibraryMethodInfo)
            {
                if (isSuperCall)
                {
                    metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName)));
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Private)
                {
                    metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Protected)
                {
                    metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else
                {
                    return(MethodMissingBinding.Fallback);
                }

                return(MethodMissingBinding.Error);
            }

            return(MethodMissingBinding.Custom);
        }
Beispiel #2
0
        // Returns true if the call was bound (with success or failure), false if fallback should be performed.
        internal static bool BuildMethodMissingAccess(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName,
                                                      RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall, bool defaultFallback)
        {
            switch (BindToKernelMethodMissing(metaBuilder, args, methodName, methodMissing, incompatibleVisibility, isSuperCall))
            {
            case MethodMissingBinding.Custom:
                // we pretend we found the member and return a method that calls method_missing:
                Debug.Assert(!metaBuilder.Error);
                metaBuilder.Result = Methods.CreateBoundMissingMember.OpCall(
                    AstUtils.Convert(args.TargetExpression, typeof(object)),
                    Ast.Constant(methodMissing, typeof(RubyMemberInfo)),
                    Ast.Constant(methodName)
                    );
                return(true);

            case MethodMissingBinding.Error:
                // method_missing is defined in Kernel, error has been reported:
                return(true);

            case MethodMissingBinding.Fallback:
                // method_missing is defined in Kernel:
                if (defaultFallback)
                {
                    metaBuilder.SetError(Methods.MakeMissingMemberError.OpCall(Ast.Constant(methodName)));
                    return(true);
                }
                return(false);
            }
            throw Assert.Unreachable;
        }
        protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) {
            if (TryImplicitConversion(metaBuilder, args)) {
                metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression);
                return true;
            }

            // TODO: this is our meta object, should we add IRubyMetaConvertible interface instead of using interop-binder?
            if (args.Target is IDynamicMetaObjectProvider) {
                metaBuilder.SetMetaResult(args.MetaTarget.BindConvert(new InteropBinder.Convert(args.RubyContext, _type, true)), false);
                return true;
            }

            if (defaultFallback) {
                metaBuilder.AddObjectTypeRestriction(args.Target, args.TargetExpression);

                metaBuilder.SetError(Methods.MakeTypeConversionError.OpCall(
                    args.MetaContext.Expression,
                    AstUtils.Convert(args.TargetExpression, typeof(object)),
                    Ast.Constant(_type)
                ));
                return true;
            }

            return false;
        }
Beispiel #4
0
        protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            object target = args.Target;

            if (args.Target == null)
            {
                metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(Ast.Constant("nil"), Ast.Constant(TargetTypeName)));
                return(true);
            }

            // TODO: other .NET primitive integer types
            if (target is int)
            {
                metaBuilder.Result = AstUtils.Convert(args.TargetExpression, typeof(int));
                return(true);
            }

            var bignum = target as BigInteger;

            if ((object)bignum != null)
            {
                metaBuilder.Result = Methods.ConvertBignumToFixnum.OpCall(AstUtils.Convert(args.TargetExpression, typeof(BigInteger)));
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Resolves an library method overload and builds call expression.
        /// The resulting expression on meta-builder doesn't handle block control flow yet.
        /// </summary>
        internal static void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name,
                                             IList <MethodBase> /*!*/ overloads, bool includeSelf, bool selfIsInstance)
        {
            var bindingTarget = ResolveOverload(name, overloads, args, includeSelf, selfIsInstance);

            if (bindingTarget.Success)
            {
                bool calleeHasBlockParam = HasBlockParameter(bindingTarget.Method);

                // Allocates a variable holding BlockParam. At runtime the BlockParam is created with a new RFC instance that
                // identifies the library method frame as a proc-converter target of a method unwinder triggered by break from a block.
                //
                // NOTE: We check for null block here -> test fore that fact is added in MakeActualArgs
                if (metaBuilder.BfcVariable == null && args.Signature.HasBlock && args.GetBlock() != null && calleeHasBlockParam)
                {
                    metaBuilder.BfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc");
                }

                var actualArgs       = MakeActualArgs(metaBuilder, args, includeSelf, selfIsInstance, calleeHasBlockParam, true);
                var parameterBinder  = new RubyParameterBinder(args.RubyContext.Binder, args.MetaContext.Expression, args.Signature.HasScope);
                var targetExpression = bindingTarget.MakeExpression(parameterBinder, actualArgs);

                metaBuilder.Result = targetExpression;
            }
            else
            {
                metaBuilder.SetError(
                    Methods.MakeInvalidArgumentTypesError.OpCall(Ast.Constant(name))
                    );
            }
        }
Beispiel #6
0
 internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
 {
     // TODO: splat, rhs, ...
     if (args.Signature.ArgumentCount == 0)
     {
         if (args.Signature.HasBlock)
         {
             metaBuilder.Result = Methods.HookupEvent.OpCall(
                 AstUtils.Constant(this),
                 args.TargetExpression,
                 Ast.Convert(args.GetBlockExpression(), typeof(Proc))
                 );
         }
         else
         {
             metaBuilder.Result = Methods.CreateEvent.OpCall(
                 AstUtils.Constant(this),
                 args.TargetExpression,
                 AstUtils.Constant(name)
                 );
         }
     }
     else
     {
         metaBuilder.SetError(Methods.MakeWrongNumberOfArgumentsError.OpCall(Ast.Constant(args.Signature.ArgumentCount), Ast.Constant(0)));
     }
 }
Beispiel #7
0
 private void SetError(MetaObjectBuilder /*!*/ metaBuilder, Expression /*!*/ targetClassNameConstant, CallArguments /*!*/ args)
 {
     if (ConversionResultValidator != null)
     {
         metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(targetClassNameConstant, Ast.Constant(TargetTypeName)));
     }
     else
     {
         metaBuilder.Result = args.TargetExpression;
     }
 }
Beispiel #8
0
        internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
        {
            Expression expr     = null;
            Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType);

            if (_isSetter)
            {
                // parameters should be: instance/type, value
                if (args.SimpleArgumentCount == 0 && args.Signature.HasRhsArgument)
                {
                    expr = Ast.Assign(
                        Ast.Field(instance, _fieldInfo),
                        // TODO: remove
                        args.RubyContext.Binder.ConvertExpression(
                            args.GetRhsArgumentExpression(),
                            _fieldInfo.FieldType,
                            ConversionResultKind.ExplicitCast,
                            args.ScopeExpression
                            )
                        );
                }
            }
            else
            {
                // parameter should be: instance/type
                if (args.SimpleArgumentCount == 0)
                {
                    if (_fieldInfo.IsLiteral)
                    {
                        // TODO: seems like Compiler should correctly handle the literal field case
                        // (if you emit a read to a literal field, you get a NotSupportedExpception from
                        // FieldHandle when we try to emit)
                        expr = Ast.Constant(_fieldInfo.GetValue(null));
                    }
                    else
                    {
                        expr = Ast.Field(instance, _fieldInfo);
                    }
                }
            }

            if (expr != null)
            {
                metaBuilder.Result = expr;
            }
            else
            {
                metaBuilder.SetError(
                    Methods.MakeInvalidArgumentTypesError.OpCall(Ast.Constant(_isSetter ? name + "=" : name))
                    );
            }
        }
        internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name)
        {
            var visibleOverloads = GetVisibleOverloads(args, MethodBases, false);

            if (visibleOverloads.Count == 0)
            {
                metaBuilder.SetError(Methods.MakeClrProtectedMethodCalledError.OpCall(
                                         args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name)
                                         ));
            }
            else
            {
                BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions);
            }
        }
Beispiel #10
0
        internal override void BuildSuperCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name, RubyModule /*!*/ declaringModule)
        {
            Assert.NotNull(declaringModule, metaBuilder, args);
            var visibleOverloads = GetVisibleOverloads(args, MethodBases, true);

            if (visibleOverloads.Count == 0)
            {
                metaBuilder.SetError(Methods.MakeClrVirtualMethodCalledError.OpCall(
                                         args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name)
                                         ));
            }
            else
            {
                BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions);
            }
        }
Beispiel #11
0
        internal void SetRule(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            RubyModule currentDeclaringModule;
            string     currentMethodName;

            var scope = args.Scope;

            object target;

            scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target);

            var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self");

            metaBuilder.AddCondition(
                Methods.IsSuperCallTarget.OpCall(
                    AstUtils.Convert(args.ScopeExpression, typeof(RubyScope)),
                    Ast.Constant(currentDeclaringModule),
                    AstUtils.Constant(currentMethodName),
                    targetExpression
                    )
                );

            args.SetTarget(targetExpression, target);

            Debug.Assert(currentDeclaringModule != null);

            // target is stored in a local, therefore it cannot be part of the restrictions:
            metaBuilder.TreatRestrictionsAsConditions = true;
            metaBuilder.AddTargetTypeTest(target, targetExpression, scope.RubyContext, args.ContextExpression);
            metaBuilder.TreatRestrictionsAsConditions = false;

            RubyMemberInfo method = scope.RubyContext.ResolveSuperMethod(target, currentMethodName, currentDeclaringModule);

            // super calls don't go to method_missing
            if (method == null)
            {
                metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(Ast.Constant(currentMethodName)));
            }
            else
            {
                method.InvalidateSitesOnOverride = true;
                method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule);
            }
        }
Beispiel #12
0
        /// <summary>
        /// Resolves an library method overload and builds call expression.
        /// The resulting expression on meta-builder doesn't handle block control flow yet.
        /// </summary>
        internal static void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name,
                                             IList <OverloadInfo> /*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions)
        {
            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, implicitProtocolConversions, out resolver);

            if (bindingTarget.Success)
            {
                // TODO: create a custom overload info:
                if (ReferenceEquals(bindingTarget.Overload.ReflectionInfo, Methods.CreateDefaultInstance))
                {
                    Debug.Assert(args.TargetClass.TypeTracker.Type.IsValueType);
                    metaBuilder.Result = Ast.New(args.TargetClass.TypeTracker.Type);
                }
                else if (args.Signature.IsVirtualCall && bindingTarget.Overload.IsVirtual)
                {
                    // Virtual methods that have been detached from the CLR type and
                    // defined on the corresponding Ruby class or its subclass are not
                    // directly invoked from a dynamic virtual call to prevent recursion.
                    // Instead the base call is performed.
                    //
                    // Example:
                    // class C < ArrayList
                    //   define_method(:Add, instance_method(:Add))
                    // end
                    //
                    // C.new.Add(1)
                    //
                    // C.new.Add dispatches to the virtual ArrayList::Add, which in turn dispatches to the auto-generated override C$1::Add.
                    // That gets here since the defined method is a Ruby method (a detached CLR method group). If we called it directly
                    // it would invoke the C$1::Add override again leading to a stack overflow. So we need to use a base call instead.
                    metaBuilder.Result = Ast.Field(null, Fields.ForwardToBase);
                }
                else
                {
                    metaBuilder.Result = bindingTarget.MakeExpression();
                }
            }
            else
            {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
Beispiel #13
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     // TODO: splat, rhs, ...
     if (args.Signature.ArgumentCount == 0) {
         if (args.Signature.HasBlock) {
             metaBuilder.Result = Methods.HookupEvent.OpCall(
                 AstUtils.Constant(this),
                 args.TargetExpression,
                 Ast.Convert(args.GetBlockExpression(), typeof(Proc))
             );
         } else {
             metaBuilder.Result = Methods.CreateEvent.OpCall(
                 AstUtils.Constant(this),
                 args.TargetExpression,
                 AstUtils.Constant(name)
             );
         }
     } else {
         metaBuilder.SetError(Methods.MakeWrongNumberOfArgumentsError.OpCall(Ast.Constant(args.Signature.ArgumentCount), Ast.Constant(0)));
     }
 }
Beispiel #14
0
        protected override bool TryImplicitConversion(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args)
        {
            object target           = args.Target;
            var    targetExpression = args.TargetExpression;

            if (args.Target == null)
            {
                metaBuilder.SetError(Methods.CreateTypeConversionError.OpCall(Ast.Constant("nil"), Ast.Constant(TargetTypeName)));
                return(true);
            }

            var str = target as MutableString;

            if (str != null)
            {
                metaBuilder.Result = Methods.ConvertMutableStringToSymbol.OpCall(AstUtils.Convert(targetExpression, typeof(MutableString)));
                return(true);
            }

            var sym = target as string;

            if (sym != null)
            {
                metaBuilder.Result = AstUtils.Convert(targetExpression, typeof(string));
                return(true);
            }

            if (target is SymbolId)
            {
                metaBuilder.Result = Methods.ConvertSymbolIdToSymbol.OpCall(AstUtils.Convert(targetExpression, typeof(SymbolId)));
                return(true);
            }

            if (target is int)
            {
                metaBuilder.Result = Methods.ConvertFixnumToSymbol.OpCall(args.ContextExpression, AstUtils.Convert(targetExpression, typeof(int)));
                return(true);
            }

            return(false);
        }
Beispiel #15
0
        internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
            Expression expr = null;
            Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType);

            if (_isSetter) {
                // parameters should be: instance/type, value
                if (args.SimpleArgumentCount == 0 && args.Signature.HasRhsArgument) {
                    expr = Ast.Assign(
                        Ast.Field(instance, _fieldInfo),
                        // TODO: remove
                        args.RubyContext.Binder.ConvertExpression(
                            args.GetRhsArgumentExpression(), 
                            _fieldInfo.FieldType, 
                            ConversionResultKind.ExplicitCast, 
                            args.ScopeExpression
                        )
                    );
                }
            } else {
                // parameter should be: instance/type
                if (args.SimpleArgumentCount == 0) {
                    if (_fieldInfo.IsLiteral) {
                        // TODO: seems like Compiler should correctly handle the literal field case
                        // (if you emit a read to a literal field, you get a NotSupportedExpception from
                        // FieldHandle when we try to emit)
                        expr = Ast.Constant(_fieldInfo.GetValue(null));
                    } else {
                        expr = Ast.Field(instance, _fieldInfo);
                    }
                }
            }

            if (expr != null) {
                metaBuilder.Result = expr;
            } else {
                metaBuilder.SetError(
                    Methods.MakeInvalidArgumentTypesError.OpCall(Ast.Constant(_isSetter ? name + "=" : name))
                );
            }
        }
Beispiel #16
0
        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;
        }
Beispiel #17
0
        internal static bool BindToMethodMissing(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName,
            RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall, bool defaultFallback) {
            // Assumption: args already contain method name.
            
            // TODO: better check for builtin method
            if (methodMissing == null ||
                methodMissing.DeclaringModule == methodMissing.Context.KernelModule && methodMissing is RubyLibraryMethodInfo) {

                if (isSuperCall) {
                    metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName)));
                } else if (incompatibleVisibility == RubyMethodVisibility.Private) {
                    metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall(
                        AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                    );
                } else if (incompatibleVisibility == RubyMethodVisibility.Protected) {
                    metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall(
                        AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                    );
                } else if (defaultFallback) {
                    args.InsertMethodName(methodName);
                    methodMissing.BuildCall(metaBuilder, args, methodName);
                } else {
                    return false;
                }
            } else {
                args.InsertMethodName(methodName);
                methodMissing.BuildCall(metaBuilder, args, methodName);
            }

            return true;
        }
Beispiel #18
0
        private void BuildCall(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
            var actualArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue);
            if (metaBuilder.Error) {
                return;
            }
            
            metaBuilder.AddRestriction(
                Ast.Equal(
                    Ast.Property(Ast.Convert(args.TargetExpression, typeof(Win32API)), VersionProperty),
                    Ast.Constant(_version)
                )
            );
            
            if (_function == IntPtr.Zero) {
                metaBuilder.SetError(Ast.Throw(new Func<Exception>(UninitializedFunctionError).Method.OpCall(), typeof(object)));
                return;
            }

            if (_signature.Length != actualArgs.Count) {
                metaBuilder.SetError(Ast.Throw(new Func<int, int, Exception>(InvalidParameterCountError).Method.OpCall(
                    Ast.Constant(_signature.Length), Ast.Constant(actualArgs.Count)), typeof(object)
                ));
                return;
            }

            var calliArgs = new AstExpressions();
            calliArgs.Add(Ast.Property(Ast.Convert(args.TargetExpression, typeof(Win32API)), FunctionProperty));
            for (int i = 0; i < actualArgs.Count; i++) {
                calliArgs.Add(MarshalArgument(metaBuilder, actualArgs[i], _signature[i]));
            }

            metaBuilder.Result = Ast.Call(EmitCalliStub(), calliArgs);

            // MRI returns 0 if void return type is given:
            if (_returnType == ArgType.None) {
                metaBuilder.Result = Ast.Block(metaBuilder.Result, AstUtils.Constant(0));
            }
        }
        /// <summary>
        /// Resolves an library method overload and builds call expression.
        /// The resulting expression on meta-builder doesn't handle block control flow yet.
        /// </summary>
        internal static void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name,
            IList<OverloadInfo>/*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions) {

            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, implicitProtocolConversions, out resolver);
            if (bindingTarget.Success) {
                // TODO: create a custom overload info:
                if (ReferenceEquals(bindingTarget.Overload.ReflectionInfo, Methods.CreateDefaultInstance)) {
                    Debug.Assert(args.TargetClass.TypeTracker.Type.IsValueType);
                    metaBuilder.Result = Ast.New(args.TargetClass.TypeTracker.Type);
                } else if (args.Signature.IsVirtualCall && bindingTarget.Overload.IsVirtual) {
                    // Virtual methods that have been detached from the CLR type and 
                    // defined on the corresponding Ruby class or its subclass are not
                    // directly invoked from a dynamic virtual call to prevent recursion.
                    // Instead the base call is performed. 
                    //
                    // Example:
                    // class C < ArrayList           
                    //   define_method(:Add, instance_method(:Add))          
                    // end
                    // 
                    // C.new.Add(1)
                    // 
                    // C.new.Add dispatches to the virtual ArrayList::Add, which in turn dispatches to the auto-generated override C$1::Add.
                    // That gets here since the defined method is a Ruby method (a detached CLR method group). If we called it directly
                    // it would invoke the C$1::Add override again leading to a stack overflow. So we need to use a base call instead.
                    metaBuilder.Result = Ast.Field(null, Fields.ForwardToBase);
                } else {
                    metaBuilder.Result = bindingTarget.MakeExpression();
                }
            } else {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
 internal override void BuildSuperCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, RubyModule/*!*/ declaringModule) {
     Assert.NotNull(declaringModule, metaBuilder, args);
     var visibleOverloads = GetVisibleOverloads(args, MethodBases, true);
     if (visibleOverloads.Count == 0) {
         metaBuilder.SetError(Methods.MakeClrVirtualMethodCalledError.OpCall(
             args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name)
         ));
     } else {
         BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions);
     }
 }
Beispiel #21
0
        public void BuildObjectConstructionNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName) {
            Debug.Assert(!IsSingletonClass, "Cannot instantiate singletons");

            Type type = GetUnderlyingSystemType();

            RubyMemberInfo initializer;
            using (Context.ClassHierarchyLocker()) {
                // check version of the class so that we invalidate the rule whenever the initializer changes:
                metaBuilder.AddVersionTest(this);

                initializer = ResolveMethodForSiteNoLock(Symbols.Initialize, IgnoreVisibility).Info;

                // Initializer resolves to Object#initializer unless overridden in a derived class.
                // We ensure that this method cannot be removed.
                Debug.Assert(initializer != null);
            }

            bool hasRubyInitializer = initializer is RubyMethodInfo;
            bool hasLibraryInitializer = !hasRubyInitializer && initializer.DeclaringModule != Context.ObjectClass;

            if (hasRubyInitializer || hasLibraryInitializer && _isRubyClass) {
                // allocate and initialize:
                bool allocatorFound = BuildAllocatorCall(metaBuilder, args, () => AstUtils.Constant(Name));
                if (metaBuilder.Error) {
                    return;
                }

                if (!allocatorFound) {
                    metaBuilder.SetError(Methods.MakeMissingDefaultConstructorError.OpCall(
                        Ast.Convert(args.TargetExpression, typeof(RubyClass)),
                        Ast.Constant(initializer.DeclaringModule.Name)
                    ));
                    return;
                }

                if (!initializer.IsEmpty) {
                    BuildOverriddenInitializerCall(metaBuilder, args, initializer);
                }
            } else {
                // construct:
                MethodBase[] constructionOverloads;
                SelfCallConvention callConvention = SelfCallConvention.SelfIsParameter;
                bool implicitProtocolConversions = false;

                if (typeof(Delegate).IsAssignableFrom(type)) {
                    BuildDelegateConstructorCall(metaBuilder, args, type);
                    return;
                } else if (type.IsArray && type.GetArrayRank() == 1) {
                    constructionOverloads = ClrVectorFactories;
                } else if (_structInfo != null) {
                    constructionOverloads = new MethodBase[] { Methods.CreateStructInstance };
                } else if (_factories.Length != 0) {
                    constructionOverloads = (MethodBase[])ReflectionUtils.GetMethodInfos(_factories);
                } else {
                    // TODO: handle protected constructors
                    constructionOverloads = (type == typeof(object) ? typeof(RubyObject) : type).GetConstructors();

                    if (type.IsValueType) {
                        if (constructionOverloads.Length == 0 || type.GetConstructor(Type.EmptyTypes) == null) {
                            constructionOverloads = ArrayUtils.Append(constructionOverloads, Methods.CreateDefaultInstance);
                        }
                    } else if (constructionOverloads.Length == 0) {
                        metaBuilder.SetError(Methods.MakeAllocatorUndefinedError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass))));
                        return;
                    }

                    callConvention = SelfCallConvention.NoSelf;
                    implicitProtocolConversions = true;
                }

                RubyMethodGroupInfo.BuildCallNoFlow(metaBuilder, args, methodName, constructionOverloads, callConvention, implicitProtocolConversions);

                // we need to handle break, which unwinds to a proc-converter that could be this method's frame:
                if (!metaBuilder.Error) {
                    metaBuilder.ControlFlowBuilder = RubyMethodGroupInfo.RuleControlFlowBuilder;
                }
            }
        }
Beispiel #22
0
 protected override DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) {
     metaBuilder.SetError(Ast.New(
         typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }),
         Ast.Constant("Super call not supported on foreign meta-objects")
     ));
     return metaBuilder.CreateMetaObject(this);
 }
Beispiel #23
0
        // Returns true if the call was bound (with success or failure), false if fallback should be performed.
        internal static bool BuildMethodMissingAccess(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName,
            RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall, bool defaultFallback) {

            switch (BindToKernelMethodMissing(metaBuilder, args, methodName, methodMissing, incompatibleVisibility, isSuperCall)) {
                case MethodMissingBinding.Custom:
                    // we pretend we found the member and return a method that calls method_missing:
                    Debug.Assert(!metaBuilder.Error);
                    metaBuilder.Result = Methods.CreateBoundMissingMember.OpCall(
                        AstUtils.Convert(args.TargetExpression, typeof(object)),
                        Ast.Constant(methodMissing, typeof(RubyMemberInfo)),
                        Ast.Constant(methodName)
                    );
                    return true;

                case MethodMissingBinding.Error:
                    // method_missing is defined in Kernel, error has been reported:
                    return true;

                case MethodMissingBinding.Fallback:
                    // method_missing is defined in Kernel:
                    if (defaultFallback) {
                        metaBuilder.SetError(Methods.MakeMissingMemberError.OpCall(Ast.Constant(methodName)));
                        return true;
                    }
                    return false;
            }
            throw Assert.Unreachable;
        }
Beispiel #24
0
 internal override void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name) {
     var visibleOverloads = GetVisibleOverloads(args, MethodBases, false);
     if (visibleOverloads.Count == 0) {
         metaBuilder.SetError(Methods.MakeClrProtectedMethodCalledError.OpCall(
             args.MetaContext.Expression, args.MetaTarget.Expression, Ast.Constant(name)
         ));
     } else {
         BuildCallNoFlow(metaBuilder, args, name, visibleOverloads, CallConvention, ImplicitProtocolConversions);
     }
 }
Beispiel #25
0
        /// <summary>
        /// Resolves an library method overload and builds call expression.
        /// The resulting expression on meta-builder doesn't handle block control flow yet.
        /// </summary>
        internal static void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, 
            IList<MethodBase>/*!*/ overloads, SelfCallConvention callConvention) {

            var bindingTarget = ResolveOverload(name, overloads, args, callConvention);
            bool calleeHasBlockParam = bindingTarget.Success && HasBlockParameter(bindingTarget.Method);

            // Allocates a variable holding BlockParam. At runtime the BlockParam is created with a new RFC instance that
            // identifies the library method frame as a proc-converter target of a method unwinder triggered by break from a block.
            if (args.Signature.HasBlock) {
                var metaBlock = args.GetMetaBlock();
                if (metaBlock.Value != null && calleeHasBlockParam) {
                    if (metaBuilder.BfcVariable == null) {
                        metaBuilder.BfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc");
                    }
                    metaBuilder.ControlFlowBuilder = RuleControlFlowBuilder;
                }

                // Block test - we need to test for a block regardless of whether it is actually passed to the method or not
                // since the information that the block is not null is used for overload resolution.
                if (metaBlock.Value == null) {
                    metaBuilder.AddRestriction(Ast.Equal(metaBlock.Expression, AstUtils.Constant(null)));
                } else {
                    // don't need to test the exact type of the Proc since the code is subclass agnostic:
                    metaBuilder.AddRestriction(Ast.NotEqual(metaBlock.Expression, AstUtils.Constant(null)));
                }
            }

            var actualArgs = MakeActualArgs(metaBuilder, args, callConvention, calleeHasBlockParam, true);

            if (bindingTarget.Success) {
                var parameterBinder = new RubyParameterBinder(args.RubyContext.Binder, args.MetaContext.Expression, args.Signature.HasScope);
                metaBuilder.Result = bindingTarget.MakeExpression(parameterBinder, actualArgs);
            } else {
                metaBuilder.SetError(args.RubyContext.RubyBinder.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
Beispiel #26
0
        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);
        }
        internal static bool BuildConversion(MetaObjectBuilder/*!*/ metaBuilder, DynamicMetaObject/*!*/ target, Expression/*!*/ contextExpression, 
            Type/*!*/ toType, bool defaultFallback) {

            Expression expr = TryImplicitConversion(target, toType);
            if (expr != null) {
                metaBuilder.Result = expr;
                metaBuilder.AddObjectTypeRestriction(target.Value, target.Expression);
                return true;
            }

            if (defaultFallback) {
                metaBuilder.AddObjectTypeRestriction(target.Value, target.Expression);

                metaBuilder.SetError(Methods.MakeTypeConversionError.OpCall(
                    contextExpression,
                    AstUtils.Convert(target.Expression, typeof(object)),
                    Ast.Constant(toType)
                ));
                return true;
            }

            return false;
        }
        /// <summary>
        /// Resolves an library method overload and builds call expression.
        /// The resulting expression on meta-builder doesn't handle block control flow yet.
        /// </summary>
        internal static void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, 
            IList<MethodBase>/*!*/ overloads, bool includeSelf, bool selfIsInstance) {

            var bindingTarget = ResolveOverload(name, overloads, args, includeSelf, selfIsInstance);
            if (bindingTarget.Success) {
                bool calleeHasBlockParam = HasBlockParameter(bindingTarget.Method);

                // Allocates a variable holding BlockParam. At runtime the BlockParam is created with a new RFC instance that
                // identifies the library method frame as a proc-converter target of a method unwinder triggered by break from a block.
                //
                // NOTE: We check for null block here -> test fore that fact is added in MakeActualArgs
                if (metaBuilder.BfcVariable == null && args.Signature.HasBlock && args.GetBlock() != null && calleeHasBlockParam) {
                    metaBuilder.BfcVariable = metaBuilder.GetTemporary(typeof(BlockParam), "#bfc");
                }

                var actualArgs = MakeActualArgs(metaBuilder, args, includeSelf, selfIsInstance, calleeHasBlockParam, true);
                var parameterBinder = new RubyParameterBinder(args.RubyContext.Binder, args.MetaContext.Expression, args.Signature.HasScope);
                var targetExpression = bindingTarget.MakeExpression(parameterBinder, actualArgs);

                metaBuilder.Result = targetExpression;
            } else {
                metaBuilder.SetError(
                    Methods.MakeInvalidArgumentTypesError.OpCall(Ast.Constant(name))
                );
            }
        }
Beispiel #29
0
        private DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) {
            // TODO: argument count limit depends on the binder!

            // TODO: pass block as the last (before RHS arg?) parameter/ignore block if args not accepting block:
            var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue);
            if (!metaBuilder.Error) {
                MethodInfo postConverter;
                var interopBinder = GetInteropBinder(args.RubyContext, normalizedArgs, out postConverter);
                if (interopBinder != null) {
                    Type resultType;
                    var result = interopBinder.Bind(args.MetaTarget, ArrayUtils.MakeArray(normalizedArgs));

                    metaBuilder.SetMetaResult(result, args);
                    if (postConverter != null) {
                        // TODO: do better?
                        var paramType = postConverter.GetParameters()[0].ParameterType;

                        metaBuilder.Result = Ast.Call(null, postConverter, AstUtils.Convert(metaBuilder.Result, paramType));
                        resultType = postConverter.ReturnType;
                    } else {
                        resultType = ((IInteropBinder)interopBinder).ResultType;
                    }

                    return metaBuilder.CreateMetaObject(interopBinder, resultType);
                } else {
                    metaBuilder.SetError(Ast.New(
                       typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }),
                       Ast.Constant(String.Format("{0} not supported on foreign meta-objects", this))
                    ));
                }
            }
            return metaBuilder.CreateMetaObject(this);
        }
Beispiel #30
0
        private static MethodMissingBinding BindToKernelMethodMissing(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName,
            RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall) {

            // TODO: better specialization of method_missing methods
            if (methodMissing == null ||
                methodMissing.DeclaringModule == methodMissing.Context.KernelModule && methodMissing is RubyLibraryMethodInfo) {

                if (isSuperCall) {
                    metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName)));
                } else if (incompatibleVisibility == RubyMethodVisibility.Private) {
                    metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall(
                        AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                    );
                } else if (incompatibleVisibility == RubyMethodVisibility.Protected) {
                    metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall(
                        AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                    );
                } else {
                    return MethodMissingBinding.Fallback;
                }

                return MethodMissingBinding.Error;
            }

            return MethodMissingBinding.Custom;
        }
Beispiel #31
0
 /// <summary>
 /// Implements Class#clr_new feature.
 /// </summary>
 public void BuildClrObjectConstruction(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName) {
     OverloadInfo[] ctors;
     if (TypeTracker == null) {
         metaBuilder.SetError(Methods.MakeNotClrTypeError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass))));
     } else if ((ctors = GetConstructors(TypeTracker.Type).ToArray()).Length == 0) {
         metaBuilder.SetError(Methods.MakeConstructorUndefinedError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass))));
     } else {
         RubyMethodGroupInfo.BuildCallNoFlow(metaBuilder, args, methodName, ctors, SelfCallConvention.NoSelf, true);
     }
 }
Beispiel #32
0
        /// <summary>
        /// Implements Class#allocate feature.
        /// </summary>  
        public void BuildObjectAllocation(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName) {
            // check for empty arguments (handles splat correctly):
            var argsBuilder = new ArgsBuilder(0, 0, 0, 0, false);
            argsBuilder.AddCallArguments(metaBuilder, args);

            if (!metaBuilder.Error) {
                if (!BuildAllocatorCall(metaBuilder, args, () => AstUtils.Constant(Name))) {
                    metaBuilder.SetError(Methods.MakeAllocatorUndefinedError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass))));
                }
            }
        }
        /// <summary>
        /// Resolves an library method overload and builds call expression.
        /// The resulting expression on meta-builder doesn't handle block control flow yet.
        /// </summary>
        internal static void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name, 
            IList<MethodBase>/*!*/ overloads, SelfCallConvention callConvention) {

            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, out resolver);
            if (bindingTarget.Success) {
                metaBuilder.Result = bindingTarget.MakeExpression();
            } else {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }
Beispiel #34
0
        public void BuildObjectConstructionNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName) {
            if (IsSingletonClass) {
                metaBuilder.SetError(Methods.MakeVirtualClassInstantiatedError.OpCall());
                return;
            }

            Type type = GetUnderlyingSystemType();

            RubyMemberInfo initializer;
            using (Context.ClassHierarchyLocker()) {
                // check version of the class so that we invalidate the rule whenever the initializer changes:
                metaBuilder.AddVersionTest(this);

                initializer = ResolveMethodForSiteNoLock(Symbols.Initialize, VisibilityContext.AllVisible).Info;

                // Initializer resolves to BasicObject#initialize unless overridden in a derived class.
                // We ensure that initializer cannot be removed/undefined so that we don't ever fall back to method_missing (see RubyModule.RemoveMethodNoEvent).
                Debug.Assert(initializer != null);
            }

            bool isLibraryMethod = initializer is RubyLibraryMethodInfo;
            bool isRubyInitializer = initializer.IsRubyMember && !isLibraryMethod;
            bool isLibraryInitializer = isLibraryMethod && !initializer.DeclaringModule.IsObjectClass && !initializer.DeclaringModule.IsBasicObjectClass;

            if (isRubyInitializer || isLibraryInitializer && _isRubyClass) {
                // allocate and initialize:
                bool allocatorFound = BuildAllocatorCall(metaBuilder, args, () => AstUtils.Constant(Name));
                if (metaBuilder.Error) {
                    return;
                }

                if (!allocatorFound) {
                    metaBuilder.SetError(Methods.MakeMissingDefaultConstructorError.OpCall(
                        Ast.Convert(args.TargetExpression, typeof(RubyClass)),
                        Ast.Constant(initializer.DeclaringModule.Name)
                    ));
                    return;
                }

                if (!initializer.IsEmpty) {
                    BuildOverriddenInitializerCall(metaBuilder, args, initializer);
                }
            } else {
                // construct:
                OverloadInfo[] constructionOverloads;
                SelfCallConvention callConvention = SelfCallConvention.SelfIsParameter;
                bool implicitProtocolConversions = false;

                if (typeof(Delegate).IsAssignableFrom(type)) {
                    BuildDelegateConstructorCall(metaBuilder, args, type);
                    return;
                } else if (type.IsArray && type.GetArrayRank() == 1) {
                    constructionOverloads = GetClrVectorFactories();
                } else if (_structInfo != null) {
                    constructionOverloads = new OverloadInfo[] { new ReflectionOverloadInfo(Methods.CreateStructInstance) };
                } else if (_factories.Length != 0) {
                    constructionOverloads = ArrayUtils.ConvertAll(_factories, (d) => new ReflectionOverloadInfo(d.GetMethod()));
                } else {
                    // TODO: handle protected constructors
                    constructionOverloads = GetConstructors(type == typeof(object) ? typeof(RubyObject) : type).ToArray();

                    if (type.IsValueType()) {
                        if (constructionOverloads.Length == 0 || GetConstructor(type) == null) {
                            constructionOverloads = ArrayUtils.Append(constructionOverloads, new ReflectionOverloadInfo(Methods.CreateDefaultInstance));
                        }
                    } else if (constructionOverloads.Length == 0) {
                        metaBuilder.SetError(Methods.MakeAllocatorUndefinedError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass))));
                        return;
                    }

                    callConvention = SelfCallConvention.NoSelf;
                    implicitProtocolConversions = true;
                }

                RubyMethodGroupInfo.BuildCallNoFlow(metaBuilder, args, methodName, constructionOverloads, callConvention, implicitProtocolConversions);

                if (!metaBuilder.Error) {
                    metaBuilder.Result = MarkNewException(metaBuilder.Result);

                    // we need to handle break, which unwinds to a proc-converter that could be this method's frame:
                    if (args.Signature.HasBlock) {
                        metaBuilder.ControlFlowBuilder = RubyMethodGroupInfo.RuleControlFlowBuilder;
                    }
                }
            }
        }
Beispiel #35
0
        /// <summary>
        /// Resolves an library method overload and builds call expression.
        /// The resulting expression on meta-builder doesn't handle block control flow yet.
        /// </summary>
        internal static void BuildCallNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ name,
            IList<MethodBase>/*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions) {

            RubyOverloadResolver resolver;
            var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, implicitProtocolConversions, out resolver);
            if (bindingTarget.Success) {
                if (ReferenceEquals(bindingTarget.Method, Methods.CreateDefaultInstance)) {
                    Debug.Assert(args.TargetClass.TypeTracker.Type.IsValueType);
                    metaBuilder.Result = Ast.New(args.TargetClass.TypeTracker.Type);
                } else {
                    metaBuilder.Result = bindingTarget.MakeExpression();
                }
            } else {
                metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression);
            }
        }