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); }
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); } }
/// <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); }
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); }
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()); }