Example #1
0
        protected BoundExpression MakeConstruction(CSharpSyntaxNode node, NamedTypeSymbol toCreate, ImmutableArray <BoundExpression> args, DiagnosticBag diagnostics)
        {
            AnalyzedArguments analyzedArguments = AnalyzedArguments.GetInstance();

            analyzedArguments.Arguments.AddRange(args);
            var result = BindClassCreationExpression(node, toCreate.Name, node, toCreate, analyzedArguments, diagnostics);

            result.WasCompilerGenerated = true;
            analyzedArguments.Free();
            return(result);
        }
Example #2
0
 public static void GetDelegateArguments(SyntaxNode syntax, AnalyzedArguments analyzedArguments, ImmutableArray <ParameterSymbol> delegateParameters, CSharpCompilation compilation)
 {
     foreach (var p in delegateParameters)
     {
         ParameterSymbol parameter = p;
         analyzedArguments.Arguments.Add(new BoundParameter(syntax, parameter)
         {
             WasCompilerGenerated = true
         });
         analyzedArguments.RefKinds.Add(parameter.RefKind);
     }
 }
Example #3
0
 /// <summary>
 /// Resolve method group based on the optional delegate invoke method.
 /// If the invoke method is null, ignore arguments in resolution.
 /// </summary>
 private static MethodGroupResolution ResolveDelegateMethodGroup(Binder binder, BoundMethodGroup source, MethodSymbol delegateInvokeMethodOpt, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
 {
     if ((object)delegateInvokeMethodOpt != null)
     {
         var analyzedArguments = AnalyzedArguments.GetInstance();
         GetDelegateArguments(source.Syntax, analyzedArguments, delegateInvokeMethodOpt.Parameters, binder.Compilation);
         var resolution = binder.ResolveMethodGroup(source, analyzedArguments, useSiteDiagnostics: ref useSiteDiagnostics, inferWithDynamic: true,
                                                    isMethodGroupConversion: true, returnRefKind: delegateInvokeMethodOpt.RefKind, returnType: delegateInvokeMethodOpt.ReturnType.TypeSymbol);
         analyzedArguments.Free();
         return(resolution);
     }
     else
     {
         return(binder.ResolveMethodGroup(source, analyzedArguments: null, isMethodGroupConversion: true, ref useSiteDiagnostics));
     }
 }
        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>)));
        }
        public MethodGroupResolution(
            MethodGroup methodGroup,
            Symbol otherSymbol,
            OverloadResolutionResult <MethodSymbol> overloadResolutionResult,
            AnalyzedArguments analyzedArguments,
            LookupResultKind resultKind,
            ImmutableArray <Diagnostic> diagnostics)
        {
            Debug.Assert((methodGroup == null) || (methodGroup.Methods.Count > 0));
            Debug.Assert((methodGroup == null) || ((object)otherSymbol == null));
            // Methods should be represented in the method group.
            Debug.Assert(((object)otherSymbol == null) || (otherSymbol.Kind != SymbolKind.Method));
            Debug.Assert(resultKind != LookupResultKind.Ambiguous); // HasAnyApplicableMethod is expecting Viable methods.
            Debug.Assert(!diagnostics.IsDefault);

            this.MethodGroup = methodGroup;
            this.OtherSymbol = otherSymbol;
            this.OverloadResolutionResult = overloadResolutionResult;
            this.AnalyzedArguments        = analyzedArguments;
            this.ResultKind  = resultKind;
            this.Diagnostics = diagnostics;
        }
        private static int?CheckForBadNonTrailingNamedArgument(AnalyzedArguments arguments, ParameterMap argsToParameters, ImmutableArray <ParameterSymbol> parameters)
        {
            // Is there any named argument used out-of-position and followed by unnamed arguments?

            // If the map is trivial then clearly not.
            if (argsToParameters.IsTrivial)
            {
                return(null);
            }

            // Find the first named argument which is used out-of-position
            int foundPosition = -1;
            int length        = arguments.Arguments.Count;

            for (int i = 0; i < length; i++)
            {
                int parameter = argsToParameters[i];
                if (parameter != -1 && parameter != i && arguments.Name(i) != null)
                {
                    foundPosition = i;
                    break;
                }
            }

            if (foundPosition != -1)
            {
                // Verify that all the following arguments are named
                for (int i = foundPosition + 1; i < length; i++)
                {
                    if (arguments.Name(i) == null)
                    {
                        return(foundPosition);
                    }
                }
            }

            return(null);
        }
        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()));
        }
        private static int?CorrespondsToAnyParameter(
            ImmutableArray <ParameterSymbol> memberParameters,
            bool expanded,
            AnalyzedArguments arguments,
            int argumentPosition,
            bool isValidParams,
            bool isVararg,
            out bool isNamedArgument,
            ref bool seenNamedParams,
            ref bool seenOutOfPositionNamedArgument)
        {
            // Spec 7.5.1.1: Corresponding parameters:
            // For each argument in an argument list there has to be a corresponding parameter in
            // the function member or delegate being invoked. The parameter list used in the
            // following is determined as follows:
            // - For virtual methods and indexers defined in classes, the parameter list is picked from the most specific
            //   declaration or override of the function member, starting with the static type of the receiver, and searching through its base classes.
            // - For interface methods and indexers, the parameter list is picked form the most specific definition of the member,
            //   starting with the interface type and searching through the base interfaces. If no unique parameter list is found,
            //   a parameter list with inaccessible names and no optional parameters is constructed, so that invocations cannot use
            //   named parameters or omit optional arguments.
            // - For partial methods, the parameter list of the defining partial method declaration is used.
            // - For all other function members and delegates there is only a single parameter list, which is the one used.
            //
            // The position of an argument or parameter is defined as the number of arguments or
            // parameters preceding it in the argument list or parameter list.
            //
            // The corresponding parameters for function member arguments are established as follows:
            //
            // Arguments in the argument-list of instance constructors, methods, indexers and delegates:

            isNamedArgument = arguments.Names.Count > argumentPosition && arguments.Names[argumentPosition] != null;

            if (!isNamedArgument)
            {
                // Spec:
                // - A positional argument where a fixed parameter occurs at the same position in the
                //   parameter list corresponds to that parameter.
                // - A positional argument of a function member with a parameter array invoked in its
                //   normal form corresponds to the parameter array, which must occur at the same
                //   position in the parameter list.
                // - A positional argument of a function member with a parameter array invoked in its
                //   expanded form, where no fixed parameter occurs at the same position in the
                //   parameter list, corresponds to an element in the parameter array.

                if (seenNamedParams)
                {
                    // Unnamed arguments after a named argument corresponding to a params parameter cannot correspond to any parameters
                    return(null);
                }

                if (seenOutOfPositionNamedArgument)
                {
                    // Unnamed arguments after an out-of-position named argument cannot correspond to any parameters
                    return(null);
                }

                int parameterCount = memberParameters.Length + (isVararg ? 1 : 0);
                if (argumentPosition >= parameterCount)
                {
                    return(expanded ? parameterCount - 1 : (int?)null);
                }

                return(argumentPosition);
            }
            else
            {
                // SPEC: A named argument corresponds to the parameter of the same name in the parameter list.

                // SPEC VIOLATION: The intention of this line of the specification, when contrasted with
                // SPEC VIOLATION: the lines on positional arguments quoted above, was to disallow a named
                // SPEC VIOLATION: argument from corresponding to an element of a parameter array when
                // SPEC VIOLATION: the method was invoked in its expanded form. That is to say that in
                // SPEC VIOLATION: this case:  M(params int[] x) ... M(x : 1234); the named argument
                // SPEC VIOLATION: corresponds to x in the normal form (and is then inapplicable), but
                // SPEC VIOLATION: the named argument does *not* correspond to a member of params array
                // SPEC VIOLATION: x in the expanded form.
                // SPEC VIOLATION: Sadly that is not what we implemented in C# 4, and not what we are
                // SPEC VIOLATION: implementing here. If you do that, we make x correspond to the
                // SPEC VIOLATION: parameter array and allow the candidate to be applicable in its
                // SPEC VIOLATION: expanded form.

                var name = arguments.Names[argumentPosition];
                for (int p = 0; p < memberParameters.Length; ++p)
                {
                    // p is initialized to zero; it is ok for a named argument to "correspond" to
                    // _any_ parameter (not just the parameters past the point of positional arguments)
                    if (memberParameters[p].Name == name.Identifier.ValueText)
                    {
                        if (isValidParams && p == memberParameters.Length - 1)
                        {
                            seenNamedParams = true;
                        }

                        if (p != argumentPosition)
                        {
                            seenOutOfPositionNamedArgument = true;
                        }

                        return(p);
                    }
                }
            }

            return(null);
        }
Example #9
0
        private static bool ReportQueryInferenceFailedSelectMany(FromClauseSyntax fromClause, string methodName, BoundExpression receiver, AnalyzedArguments arguments, ImmutableArray <Symbol> symbols, DiagnosticBag diagnostics)
        {
            Debug.Assert(methodName == "SelectMany");

            // Estimate the return type of Select's lambda argument
            BoundExpression arg  = arguments.Argument(arguments.IsExtensionMethodInvocation ? 1 : 0);
            TypeSymbol      type = null;

            if (arg.Kind == BoundKind.UnboundLambda)
            {
                var unbound = (UnboundLambda)arg;
                foreach (var t in unbound.Data.InferredReturnTypes())
                {
                    if (!t.IsErrorType())
                    {
                        type = t;
                        break;
                    }
                }
            }

            if ((object)type == null || type.IsErrorType())
            {
                return(false);
            }

            TypeSymbol receiverType = receiver?.Type;

            diagnostics.Add(new DiagnosticInfoWithSymbols(
                                ErrorCode.ERR_QueryTypeInferenceFailedSelectMany,
                                new object[] { type, receiverType, methodName },
                                symbols), fromClause.Expression.Location);
            return(true);
        }
Example #10
0
        internal static void ReportQueryInferenceFailed(CSharpSyntaxNode queryClause, string methodName, BoundExpression receiver, AnalyzedArguments arguments, ImmutableArray <Symbol> symbols, DiagnosticBag diagnostics)
        {
            string clauseKind = null;
            bool   multiple   = false;

            switch (queryClause.Kind())
            {
            case SyntaxKind.JoinClause:
                clauseKind = SyntaxFacts.GetText(SyntaxKind.JoinKeyword);
                multiple   = true;
                break;

            case SyntaxKind.LetClause:
                clauseKind = SyntaxFacts.GetText(SyntaxKind.LetKeyword);
                break;

            case SyntaxKind.SelectClause:
                clauseKind = SyntaxFacts.GetText(SyntaxKind.SelectKeyword);
                break;

            case SyntaxKind.WhereClause:
                clauseKind = SyntaxFacts.GetText(SyntaxKind.WhereKeyword);
                break;

            case SyntaxKind.OrderByClause:
            case SyntaxKind.AscendingOrdering:
            case SyntaxKind.DescendingOrdering:
                clauseKind = SyntaxFacts.GetText(SyntaxKind.OrderByKeyword);
                multiple   = true;
                break;

            case SyntaxKind.QueryContinuation:
                clauseKind = SyntaxFacts.GetText(SyntaxKind.IntoKeyword);
                break;

            case SyntaxKind.GroupClause:
                clauseKind = SyntaxFacts.GetText(SyntaxKind.GroupKeyword) + " " + SyntaxFacts.GetText(SyntaxKind.ByKeyword);
                multiple   = true;
                break;

            case SyntaxKind.FromClause:
                if (ReportQueryInferenceFailedSelectMany((FromClauseSyntax)queryClause, methodName, receiver, arguments, symbols, diagnostics))
                {
                    return;
                }
                clauseKind = SyntaxFacts.GetText(SyntaxKind.FromKeyword);
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(queryClause.Kind());
            }

            diagnostics.Add(new DiagnosticInfoWithSymbols(
                                multiple ? ErrorCode.ERR_QueryTypeInferenceFailedMulti : ErrorCode.ERR_QueryTypeInferenceFailed,
                                new object[] { clauseKind, methodName },
                                symbols), queryClause.GetFirstToken().GetLocation());
        }