diff --git a/build/Rulesets/Roslyn_BuildRules.ruleset b/build/Rulesets/Roslyn_BuildRules.ruleset
index cdd2d050c7ccd..b3b1231c550d2 100644
--- a/build/Rulesets/Roslyn_BuildRules.ruleset
+++ b/build/Rulesets/Roslyn_BuildRules.ruleset
@@ -89,7 +89,7 @@
-
+
diff --git a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
index b41e6fa9d4fce..53c2964ee6228 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -46,26 +48,9 @@ internal partial class BoundCall : IInvocationExpression
(object)this.Method.ReplacedBy == null &&
!this.ReceiverOpt.SuppressVirtualCalls;
- ImmutableArray IInvocationExpression.ArgumentsInSourceOrder
- {
- get
- {
- ArrayBuilder sourceOrderArguments = ArrayBuilder.GetInstance(this.Arguments.Length);
- for (int argumentIndex = 0; argumentIndex < this.Arguments.Length; argumentIndex++)
- {
- IArgument argument = DeriveArgument(this.ArgsToParamsOpt.IsDefault ? argumentIndex : this.ArgsToParamsOpt[argumentIndex], argumentIndex, this.Arguments, this.ArgumentNamesOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax);
- sourceOrderArguments.Add(argument);
- if (argument.ArgumentKind == ArgumentKind.ParamArray)
- {
- break;
- }
- }
-
- return sourceOrderArguments.ToImmutableAndFree();
- }
- }
+ ImmutableArray IHasArgumentsExpression.ArgumentsInEvaluationOrder => DeriveArgumentsInEvaluationOrder(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax, this.Method);
- ImmutableArray IHasArgumentsExpression.ArgumentsInParameterOrder => DeriveArguments(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax);
+ ImmutableArray IHasArgumentsExpression.ArgumentsInParameterOrder => DeriveArgumentsInParameterOrder(this.Arguments, this.ArgumentNamesOpt, this.ArgsToParamsOpt, this.ArgumentRefKindsOpt, this.Method.Parameters, this.Syntax, this.Method);
IArgument IHasArgumentsExpression.GetArgumentMatchingParameter(IParameterSymbol parameter)
{
@@ -84,67 +69,109 @@ public override TResult Accept(OperationVisitor DeriveArguments(ImmutableArray boundArguments, ImmutableArray argumentNames, ImmutableArray argumentsToParameters, ImmutableArray argumentRefKinds, ImmutableArray parameters, SyntaxNode invocationSyntax)
+ internal static ImmutableArray DeriveArgumentsInParameterOrder(ImmutableArray boundArguments, ImmutableArray argumentNames, ImmutableArray argumentsToParameters, ImmutableArray argumentRefKinds, ImmutableArray parameters, CSharpSyntaxNode invocationSyntax, Symbols.MethodSymbol targetMethod)
{
- ArrayBuilder arguments = ArrayBuilder.GetInstance(boundArguments.Length);
- for (int parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++)
+ ImmutableArray argumentsInEvaluationOrder = DeriveArgumentsInEvaluationOrder(boundArguments, argumentNames, argumentsToParameters, argumentRefKinds, parameters, invocationSyntax, targetMethod);
+
+ // If all of the arguments were specified positionally the evaluation order is the same as the parameter order.
+ if (ArgumentsAreInParameterOrder(argumentsInEvaluationOrder))
{
- int argumentIndex = -1;
- if (argumentsToParameters.IsDefault)
+ return argumentsInEvaluationOrder;
+ }
+
+ return argumentsInEvaluationOrder.Sort(
+ (x, y) =>
{
- argumentIndex = parameterIndex;
- }
- else
+ int x1 = x.Parameter.Ordinal;
+ int y1 = y.Parameter.Ordinal;
+
+ return x1 == y1 ? 0 : (x1 < y1 ? -1 : 1);
+ });
+ }
+
+ private static bool ArgumentsAreInParameterOrder(ImmutableArray arguments)
+ {
+ for (int argumentIndex = 0; argumentIndex < arguments.Length; argumentIndex++)
+ {
+ if (arguments[argumentIndex].Parameter.Ordinal != argumentIndex)
{
- argumentIndex = argumentsToParameters.IndexOf(parameterIndex);
+ return false;
}
+ }
- if ((uint)argumentIndex >= (uint)boundArguments.Length)
- {
- // No argument has been supplied for the parameter at `parameterIndex`:
- // 1. `argumentIndex == -1' when the arguments are specified out of parameter order, and no argument is provided for parameter corresponding to `parameters[parameterIndex]`.
- // 2. `argumentIndex >= boundArguments.Length` when the arguments are specified in parameter order, and no argument is provided at `parameterIndex`.
+ return true;
+ }
- Symbols.ParameterSymbol parameter = parameters[parameterIndex];
- if (parameter.HasExplicitDefaultValue)
- {
- // The parameter is optional with a default value.
- arguments.Add(new Argument(ArgumentKind.DefaultValue, parameter, new Literal(parameter.ExplicitDefaultConstantValue, parameter.Type, invocationSyntax)));
- }
- else
- {
- // If the invocation is semantically valid, the parameter will be a params array and an empty array will be provided.
- // If the argument is otherwise omitted for a parameter with no default value, the invocation is not valid and a null argument will be provided.
- arguments.Add(DeriveArgument(parameterIndex, boundArguments.Length, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax));
- }
+ internal static ImmutableArray DeriveArgumentsInEvaluationOrder(ImmutableArray boundArguments, ImmutableArray argumentNames, ImmutableArray argumentsToParameters, ImmutableArray argumentRefKinds, ImmutableArray parameters, CSharpSyntaxNode invocationSyntax, Symbols.MethodSymbol targetMethod)
+ {
+ DiagnosticBag diagnostics = new DiagnosticBag();
+ SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(invocationSyntax, diagnostics);
+ LocalRewriter rewriter = new LocalRewriter(null, null, 0, null, factory, null, false, diagnostics, inIOperationContext: true);
+ ImmutableArray temporaries;
+ var args = rewriter.MakeArguments(invocationSyntax, boundArguments, targetMethod, targetMethod, paramsArrayExpanded, argumentsToParameters, ref argumentRefKinds, out temporaries);
+
+
+
+
+ HashSet matchedParameters = new HashSet();
+ ArrayBuilder evaluationOrderArguments = ArrayBuilder.GetInstance(parameters.Length);
+ for (int argumentIndex = 0; argumentIndex < boundArguments.Length; argumentIndex++)
+ {
+ int parameterIndex = argumentsToParameters.IsDefault ? argumentIndex : argumentsToParameters[argumentIndex];
+ IArgument argument = DeriveArgument(parameterIndex, argumentIndex, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax);
+ evaluationOrderArguments.Add(argument);
+ matchedParameters.Add(parameterIndex);
+ // If the current argument matches a params parameter and is unnamed, following explicit arguments are treated as part of the params arrray.
+ if ((uint)parameterIndex < parameters.Length && parameters[parameterIndex].IsParams && (argumentNames.IsDefaultOrEmpty || argumentNames[argumentIndex] == null))
+ {
+ break;
}
- else
+ }
+
+ // Include implicit arguments after the explicit arguments.
+ foreach (Symbols.ParameterSymbol parameter in parameters)
+ {
+ if (!matchedParameters.Contains(parameter.Ordinal))
{
- arguments.Add(DeriveArgument(parameterIndex, argumentIndex, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax));
+ evaluationOrderArguments.Add(DeriveArgument(parameter.Ordinal, -1, boundArguments, argumentNames, argumentRefKinds, parameters, invocationSyntax));
}
}
- return arguments.ToImmutableAndFree();
+ return evaluationOrderArguments.ToImmutableAndFree();
}
private static readonly ConditionalWeakTable s_argumentMappings = new ConditionalWeakTable();
+ private static readonly ConditionalWeakTable> s_omittedArgumentMappings = new ConditionalWeakTable>();
private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, ImmutableArray boundArguments, ImmutableArray argumentNames, ImmutableArray argumentRefKinds, ImmutableArray parameters, SyntaxNode invocationSyntax)
{
if ((uint)argumentIndex >= (uint)boundArguments.Length)
{
- // Check for an omitted argument that becomes an empty params array.
- if (parameters.Length > 0)
+ ConcurrentDictionary omittedArguments = s_omittedArgumentMappings.GetValue(invocationSyntax, syntax => new ConcurrentDictionary());
+
+ return omittedArguments.GetOrAdd(
+ parameters[parameterIndex],
+ (parameter) =>
{
- Symbols.ParameterSymbol lastParameter = parameters[parameters.Length - 1];
- if (lastParameter.IsParams)
+ // No argument has been supplied for the parameter at `parameterIndex`:
+ // 1. `argumentIndex == -1' when the arguments are specified out of parameter order, and no argument is provided for the parameter corresponding to `parameters[parameterIndex]`.
+ // 2. `argumentIndex >= boundArguments.Length` when the arguments are specified in parameter order, and no argument is provided at `parameterIndex`.
+
+ // Check for a parameter with a default value.
+ if (parameter.HasExplicitDefaultValue)
{
- return new Argument(ArgumentKind.ParamArray, lastParameter, CreateParamArray(lastParameter, boundArguments, argumentIndex, invocationSyntax));
+ return new Argument(parameter, new Literal(parameter.ExplicitDefaultConstantValue, parameter.Type, invocationSyntax));
}
- }
- // There is no supplied argument and there is no params parameter. Any action is suspect at this point.
- return new SimpleArgument(null, new InvalidExpression(invocationSyntax));
+ // Check for an omitted argument that becomes an empty params array.
+ if (parameter.IsParams)
+ {
+ return new Argument(parameter, CreateParamArray(parameter, boundArguments, argumentIndex, invocationSyntax));
+ }
+
+ // There is no supplied argument and there is no params parameter. Any action is suspect at this point.
+ return new Argument(parameter, new InvalidExpression(invocationSyntax));
+ });
}
return s_argumentMappings.GetValue(
@@ -160,7 +187,7 @@ private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, I
if (refMode != RefKind.None)
{
- return new Argument(ArgumentKind.Positional, parameter, argument);
+ return new Argument(parameter, argument);
}
if (argumentIndex >= parameters.Length - 1 &&
@@ -171,30 +198,39 @@ private static IArgument DeriveArgument(int parameterIndex, int argumentIndex, I
argument.Type.TypeKind != TypeKind.Array ||
!argument.Type.Equals(parameters[parameters.Length - 1].Type, ignoreCustomModifiersAndArraySizesAndLowerBounds: true)))
{
- return new Argument(ArgumentKind.ParamArray, parameters[parameters.Length - 1], CreateParamArray(parameters[parameters.Length - 1], boundArguments, argumentIndex, invocationSyntax));
+ return new Argument(parameters[parameters.Length - 1], CreateParamArray(parameters[parameters.Length - 1], boundArguments, argumentIndex, invocationSyntax));
}
else
{
- return new SimpleArgument(parameter, argument);
+ return new Argument(parameter, argument);
}
}
- return new Argument(ArgumentKind.Named, parameter, argument);
+ return new Argument(parameter, argument);
});
}
-
+
private static IOperation CreateParamArray(IParameterSymbol parameter, ImmutableArray boundArguments, int firstArgumentElementIndex, SyntaxNode invocationSyntax)
{
if (parameter.Type.TypeKind == TypeKind.Array)
{
IArrayTypeSymbol arrayType = (IArrayTypeSymbol)parameter.Type;
- ArrayBuilder builder = ArrayBuilder.GetInstance(boundArguments.Length - firstArgumentElementIndex);
+ ImmutableArray paramArrayArguments;
- for (int index = firstArgumentElementIndex; index < boundArguments.Length; index++)
+ // If there are no matching arguments, then the argument index is negative.
+ if (firstArgumentElementIndex >= 0)
+ {
+ ArrayBuilder builder = ArrayBuilder.GetInstance(boundArguments.Length - firstArgumentElementIndex);
+ for (int index = firstArgumentElementIndex; index < boundArguments.Length; index++)
+ {
+ builder.Add(boundArguments[index]);
+ }
+ paramArrayArguments = builder.ToImmutableAndFree();
+ }
+ else
{
- builder.Add(boundArguments[index]);
+ paramArrayArguments = ImmutableArray.Empty;
}
- var paramArrayArguments = builder.ToImmutableAndFree();
// Use the invocation syntax node if there is no actual syntax available for the argument (because the paramarray is empty.)
return new ArrayCreation(arrayType, paramArrayArguments, paramArrayArguments.Length > 0 ? paramArrayArguments[0].Syntax : invocationSyntax);
@@ -206,12 +242,7 @@ private static IOperation CreateParamArray(IParameterSymbol parameter, Immutable
internal static IArgument ArgumentMatchingParameter(ImmutableArray arguments, ImmutableArray argumentsToParameters, ImmutableArray argumentNames, ImmutableArray argumentRefKinds, ISymbol targetMethod, ImmutableArray parameters, IParameterSymbol parameter, SyntaxNode invocationSyntax)
{
int argumentIndex = ArgumentIndexMatchingParameter(arguments, argumentsToParameters, targetMethod, parameter);
- if (argumentIndex >= 0)
- {
- return DeriveArgument(parameter.Ordinal, argumentIndex, arguments, argumentNames, argumentRefKinds, parameters, invocationSyntax);
- }
-
- return null;
+ return DeriveArgument(parameter.Ordinal, argumentIndex, arguments, argumentNames, argumentRefKinds, parameters, invocationSyntax);
}
private static int ArgumentIndexMatchingParameter(ImmutableArray arguments, ImmutableArray argumentsToParameters, ISymbol targetMethod, IParameterSymbol parameter)
@@ -219,10 +250,9 @@ private static int ArgumentIndexMatchingParameter(ImmutableArray parameterIndices = argumentsToParameters;
- if (!parameterIndices.IsDefaultOrEmpty)
+ if (!argumentsToParameters.IsDefaultOrEmpty)
{
- return parameterIndices.IndexOf(parameterIndex);
+ return argumentsToParameters.IndexOf(parameterIndex);
}
return parameterIndex;
@@ -231,9 +261,9 @@ private static int ArgumentIndexMatchingParameter(ImmutableArray ConstantValue => default(Optional