private static ArgumentAnalysisResult AnalyzeArgumentsForNormalFormNoNamedArguments(
            ImmutableArray <ParameterSymbol> parameters,
            AnalyzedArguments arguments,
            bool isMethodGroupConversion,
            bool isVararg
            )
        {
            Debug.Assert(!parameters.IsDefault);
            Debug.Assert(arguments != null);
            Debug.Assert(arguments.Names.Count == 0);

            // We simulate an additional non-optional parameter for a vararg method.
            int parameterCount = parameters.Length + (isVararg ? 1 : 0);
            int argumentCount  = arguments.Arguments.Count;

            // If there are no named arguments then analyzing the argument and parameter
            // matching in normal form is simple: each argument corresponds exactly to
            // the matching parameter, and if there are not enough arguments then the
            // unmatched parameters had better all be optional. If there are too
            // few parameters then one of the arguments has no matching parameter.
            // Otherwise, everything is just right.

            if (argumentCount < parameterCount)
            {
                for (
                    int parameterPosition = argumentCount;
                    parameterPosition < parameterCount;
                    ++parameterPosition
                    )
                {
                    if (
                        parameters.Length == parameterPosition ||
                        !CanBeOptional(parameters[parameterPosition], isMethodGroupConversion)
                        )
                    {
                        return(ArgumentAnalysisResult.RequiredParameterMissing(parameterPosition));
                    }
                }
            }
            else if (parameterCount < argumentCount)
            {
                return(ArgumentAnalysisResult.NoCorrespondingParameter(parameterCount));
            }

            // A null map means that every argument in the argument list corresponds exactly to
            // the same position in the formal parameter list.
            return(ArgumentAnalysisResult.NormalForm(default(ImmutableArray <int>)));
        }
Пример #2
0
        private static ArgumentAnalysisResult AnalyzeArguments(
            Symbol symbol,
            AnalyzedArguments arguments,
            bool isMethodGroupConversion,
            bool expanded)
        {
            Debug.Assert((object)symbol != null);
            Debug.Assert(arguments != null);

            ImmutableArray <ParameterSymbol> parameters = symbol.GetParameters();
            bool isVararg = symbol.GetIsVararg();

            // The easy out is that we have no named arguments and are in normal form.
            if (!expanded && arguments.Names.Count == 0)
            {
                return(AnalyzeArgumentsForNormalFormNoNamedArguments(parameters, arguments, isMethodGroupConversion, isVararg));
            }

            // We simulate an additional non-optional parameter for a vararg method.

            int argumentCount = arguments.Arguments.Count;

            int[] parametersPositions      = null;
            int?  unmatchedArgumentIndex   = null;
            bool? unmatchedArgumentIsNamed = null;

            // Try to map every argument position to a formal parameter position:

            bool seenNamedParams = false;
            bool seenOutOfPositionNamedArgument = false;
            bool isValidParams = IsValidParams(symbol);

            for (int argumentPosition = 0; argumentPosition < argumentCount; ++argumentPosition)
            {
                // We use -1 as a sentinel to mean that no parameter was found that corresponded to this argument.
                bool isNamedArgument;
                int  parameterPosition = CorrespondsToAnyParameter(parameters, expanded, arguments, argumentPosition,
                                                                   isValidParams, isVararg, out isNamedArgument, ref seenNamedParams, ref seenOutOfPositionNamedArgument) ?? -1;

                if (parameterPosition == -1 && unmatchedArgumentIndex == null)
                {
                    unmatchedArgumentIndex   = argumentPosition;
                    unmatchedArgumentIsNamed = isNamedArgument;
                }

                if (parameterPosition != argumentPosition && parametersPositions == null)
                {
                    parametersPositions = new int[argumentCount];
                    for (int i = 0; i < argumentPosition; ++i)
                    {
                        parametersPositions[i] = i;
                    }
                }

                if (parametersPositions != null)
                {
                    parametersPositions[argumentPosition] = parameterPosition;
                }
            }

            ParameterMap argsToParameters = new ParameterMap(parametersPositions, argumentCount);

            // We have analyzed every argument and tried to make it correspond to a particular parameter.
            // We must now answer the following questions:
            //
            // (1) Is there any named argument used out-of-position and followed by unnamed arguments?
            // (2) Is there any argument without a corresponding parameter?
            // (3) Was there any named argument that specified a parameter that was already
            //     supplied with a positional parameter?
            // (4) Is there any non-optional parameter without a corresponding argument?
            // (5) Is there any named argument that were specified twice?
            //
            // If the answer to any of these questions is "yes" then the method is not applicable.
            // It is possible that the answer to any number of these questions is "yes", and so
            // we must decide which error condition to prioritize when reporting the error,
            // should we need to report why a given method is not applicable. We prioritize
            // them in the given order.

            // (1) Is there any named argument used out-of-position and followed by unnamed arguments?

            int?badNonTrailingNamedArgument = CheckForBadNonTrailingNamedArgument(arguments, argsToParameters, parameters);

            if (badNonTrailingNamedArgument != null)
            {
                return(ArgumentAnalysisResult.BadNonTrailingNamedArgument(badNonTrailingNamedArgument.Value));
            }

            // (2) Is there any argument without a corresponding parameter?

            if (unmatchedArgumentIndex != null)
            {
                if (unmatchedArgumentIsNamed.Value)
                {
                    return(ArgumentAnalysisResult.NoCorrespondingNamedParameter(unmatchedArgumentIndex.Value));
                }
                else
                {
                    return(ArgumentAnalysisResult.NoCorrespondingParameter(unmatchedArgumentIndex.Value));
                }
            }

            // (3) was there any named argument that specified a parameter that was already
            //     supplied with a positional parameter?

            int?nameUsedForPositional = NameUsedForPositional(arguments, argsToParameters);

            if (nameUsedForPositional != null)
            {
                return(ArgumentAnalysisResult.NameUsedForPositional(nameUsedForPositional.Value));
            }

            // (4) Is there any non-optional parameter without a corresponding argument?

            int?requiredParameterMissing = CheckForMissingRequiredParameter(argsToParameters, parameters, isMethodGroupConversion, expanded);

            if (requiredParameterMissing != null)
            {
                return(ArgumentAnalysisResult.RequiredParameterMissing(requiredParameterMissing.Value));
            }

            // __arglist cannot be used with named arguments (as it doesn't have a name)
            if (arguments.Names.Any() && arguments.Names.Last() != null && isVararg)
            {
                return(ArgumentAnalysisResult.RequiredParameterMissing(parameters.Length));
            }

            // (5) Is there any named argument that were specified twice?

            int?duplicateNamedArgument = CheckForDuplicateNamedArgument(arguments);

            if (duplicateNamedArgument != null)
            {
                return(ArgumentAnalysisResult.DuplicateNamedArgument(duplicateNamedArgument.Value));
            }

            // We're good; this one might be applicable in the given form.

            return(expanded ?
                   ArgumentAnalysisResult.ExpandedForm(argsToParameters.ToImmutableArray()) :
                   ArgumentAnalysisResult.NormalForm(argsToParameters.ToImmutableArray()));
        }