示例#1
0
        protected void AdjustCallArgumentsForParams(CType callingObjectType, CType type, MethodOrPropertySymbol mp, TypeArray pTypeArgs, EXPR argsPtr, out EXPR newArgs)
        {
            Debug.Assert(mp != null);
            Debug.Assert(mp.Params != null);
            newArgs = null;
            EXPR newArgsTail = null;

            MethodOrPropertySymbol mostDerivedMethod = GroupToArgsBinder.FindMostDerivedMethod(GetSymbolLoader(), mp, callingObjectType);

            int paramCount = mp.Params.size;
            TypeArray @params = mp.Params;
            int iDst = 0;
            bool markTypeFromExternCall = mp.IsFMETHSYM() && mp.AsFMETHSYM().isExternal;
            int argCount = ExpressionIterator.Count(argsPtr);

            if (mp.IsFMETHSYM() && mp.AsFMETHSYM().isVarargs)
            {
                paramCount--; // we don't care about the vararg sentinel
            }

            bool bDontFixParamArray = false;

            ExpressionIterator it = new ExpressionIterator(argsPtr);

            if (argsPtr == null)
            {
                if (mp.isParamArray)
                    goto FIXUPPARAMLIST;
                return;
            }
            for (; !it.AtEnd(); it.MoveNext())
            {
                EXPR indir = it.Current();
                // this will splice the optional arguments into the list

                if (indir.type.IsParameterModifierType())
                {
                    if (paramCount != 0)
                        paramCount--;
                    if (markTypeFromExternCall)
                        SetExternalRef(indir.type);
                    GetExprFactory().AppendItemToList(indir, ref newArgs, ref newArgsTail);
                }
                else if (paramCount != 0)
                {
                    if (paramCount == 1 && mp.isParamArray && argCount > mp.Params.size)
                    {
                        // we arrived at the last formal, and we have more than one actual, so
                        // we need to put the rest in an array...
                        goto FIXUPPARAMLIST;
                    }

                    EXPR argument = indir;
                    EXPR rval;
                    if (argument.isNamedArgumentSpecification())
                    {
                        int index = 0;
                        // If we're named, look for the type of the matching name.
                        foreach (Name i in mostDerivedMethod.ParameterNames)
                        {
                            if (i == argument.asNamedArgumentSpecification().Name)
                            {
                                break;
                            }
                            index++;
                        }
                        Debug.Assert(index != mp.Params.size);
                        CType substDestType = GetTypes().SubstType(@params.Item(index), type, pTypeArgs);

                        // If we cant convert the argument and we're the param array argument, then deal with it.
                        if (!canConvert(argument.asNamedArgumentSpecification().Value, substDestType) &&
                            mp.isParamArray && index == mp.Params.size - 1)
                        {
                            // We have a param array, but we're not at the end yet. This will happen
                            // with named arguments when the user specifies a name for the param array,
                            // and its not an actual array.
                            // 
                            // For example:
                            // void Foo(int y, params int[] x);
                            // ...
                            // Foo(x:1, y:1);
                            CType arrayType = GetTypes().SubstType(mp.Params.Item(mp.Params.size - 1), type, pTypeArgs);
                            CType elemType = arrayType.AsArrayType().GetElementType();

                            // Use an EK_ARRINIT even in the empty case so empty param arrays in attributes work.
                            EXPRARRINIT arrayInit = GetExprFactory().CreateArrayInit(0, arrayType, null, null, null);
                            arrayInit.GeneratedForParamArray = true;
                            arrayInit.dimSizes = new int[] { arrayInit.dimSize };
                            arrayInit.dimSize = 1;
                            arrayInit.SetOptionalArguments(argument.asNamedArgumentSpecification().Value);

                            argument.asNamedArgumentSpecification().Value = arrayInit;
                            bDontFixParamArray = true;
                        }
                        else
                        {
                            // Otherwise, force the conversion and get errors if needed.
                            argument.asNamedArgumentSpecification().Value = tryConvert(
                                argument.asNamedArgumentSpecification().Value,
                                substDestType);
                        }
                        rval = argument;
                    }
                    else
                    {
                        CType substDestType = GetTypes().SubstType(@params.Item(iDst), type, pTypeArgs);
                        rval = tryConvert(indir, substDestType);
                    }

                    if (rval == null)
                    {
                        // the last arg failed to fix up, so it must fixup into the array element
                        // if we have a param array (we will be passing a 1 element array...)
                        if (mp.isParamArray && paramCount == 1 && argCount >= mp.Params.size)
                        {
                            goto FIXUPPARAMLIST;
                        }
                        else
                        {
                            // This is either the error case that the args are of the wrong type, 
                            // or that we have some optional arguments being used. Either way,
                            // we wont need to expand the param array.
                            return;
                        }
                    }
                    Debug.Assert(rval != null);
                    indir = rval;
                    GetExprFactory().AppendItemToList(rval, ref newArgs, ref newArgsTail);
                    paramCount--;
                }
                // note that destype might not be valid if we are in varargs, but then we won't ever use it...
                iDst++;

                if (paramCount != 0 && mp.isParamArray && iDst == argCount)
                {
                    // we run out of actuals, but we still have formals, so this is an empty array being passed
                    // into the last param...
                    indir = null;
                    it.MoveNext();
                    goto FIXUPPARAMLIST;
                }
            }

            return;

        FIXUPPARAMLIST:
            if (bDontFixParamArray)
            {
                // We've already fixed the param array for named arguments.
                return;
            }

            // we need to create an array and put it as the last arg...
            CType substitutedArrayType = GetTypes().SubstType(mp.Params.Item(mp.Params.size - 1), type, pTypeArgs);
            if (!substitutedArrayType.IsArrayType() || substitutedArrayType.AsArrayType().rank != 1)
            {
                // Invalid type for params array parameter. Happens in LAF scenarios, e.g.
                //
                // void Foo(int i, params int ar = null) { }
                // ...
                // Foo(1);
                return;
            }

            CType elementType = substitutedArrayType.AsArrayType().GetElementType();

            // Use an EK_ARRINIT even in the empty case so empty param arrays in attributes work.
            EXPRARRINIT exprArrayInit = GetExprFactory().CreateArrayInit(0, substitutedArrayType, null, null, null);
            exprArrayInit.GeneratedForParamArray = true;
            exprArrayInit.dimSizes = new int[] { exprArrayInit.dimSize };

            if (it.AtEnd())
            {
                exprArrayInit.dimSize = 0;
                exprArrayInit.dimSizes[0] = 0;
                exprArrayInit.SetOptionalArguments(null);
                if (argsPtr == null)
                {
                    argsPtr = exprArrayInit;
                }
                else
                {
                    argsPtr = GetExprFactory().CreateList(argsPtr, exprArrayInit);
                }
                GetExprFactory().AppendItemToList(exprArrayInit, ref newArgs, ref newArgsTail);
            }
            else
            {
                // Go through the list - for each argument, do the conversion and append it to the new list.
                EXPR newList = null;
                EXPR newListTail = null;
                int count = 0;

                for (; !it.AtEnd(); it.MoveNext())
                {
                    EXPR expr = it.Current();
                    count++;

                    if (expr.isNamedArgumentSpecification())
                    {
                        expr.asNamedArgumentSpecification().Value = tryConvert(
                            expr.asNamedArgumentSpecification().Value, elementType);
                    }
                    else
                    {
                        expr = tryConvert(expr, elementType);
                    }
                    GetExprFactory().AppendItemToList(expr, ref newList, ref newListTail);
                }

                exprArrayInit.dimSize = count;
                exprArrayInit.dimSizes[0] = count;
                exprArrayInit.SetOptionalArguments(newList);
                GetExprFactory().AppendItemToList(exprArrayInit, ref newArgs, ref newArgsTail);
            }
        }