Skip to content

Commit

Permalink
Revert "Add support for calling local functions with dynamic args (#1…
Browse files Browse the repository at this point in the history
…0710)"

This reverts commit 1548892.
  • Loading branch information
agocke committed Apr 22, 2016
1 parent 1548892 commit 5777c60
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 337 deletions.
92 changes: 9 additions & 83 deletions src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ private BoundExpression BindDynamicInvocation(
BoundMethodGroup methodGroup = (BoundMethodGroup)expression;
BoundExpression receiver = methodGroup.ReceiverOpt;

if ((methodGroup.LookupSymbolOpt as MethodSymbol)?.MethodKind == MethodKind.LocalFunction)
{
diagnostics.Add(ErrorCode.ERR_DynamicLocalFunctionParameter, node.Location, methodGroup.Syntax);
}

// receiver is null if we are calling a static method declared on an outer class via its simple name:
if (receiver != null)
{
Expand Down Expand Up @@ -324,8 +329,8 @@ private BoundExpression BindDynamicInvocation(
arguments.GetNames(),
arguments.RefKinds.ToImmutableOrNull(),
applicableMethods,
type: Compilation.DynamicType,
hasErrors: hasErrors);
Compilation.DynamicType,
hasErrors);
}

private ImmutableArray<BoundExpression> BuildArgumentsForDynamicInvocation(AnalyzedArguments arguments, DiagnosticBag diagnostics)
Expand Down Expand Up @@ -511,16 +516,9 @@ private BoundExpression BindMethodGroupInvocation(
{
// If overload resolution found one or more applicable methods and at least one argument
// was dynamic then treat this as a dynamic call.
if (resolution.AnalyzedArguments.HasDynamicArgument &&
resolution.OverloadResolutionResult.HasAnyApplicableMember)
if (resolution.AnalyzedArguments.HasDynamicArgument && resolution.OverloadResolutionResult.HasAnyApplicableMember)
{
if (resolution.IsLocalFunctionInvocation)
{
result = BindLocalFunctionInvocationWithDynamicArgument(
syntax, expression, methodName, methodGroup,
diagnostics, queryClause, resolution);
}
else if (resolution.IsExtensionMethodGroup)
if (resolution.IsExtensionMethodGroup)
{
// error CS1973: 'T' has no applicable method named 'M' but appears to have an
// extension method by that name. Extension methods cannot be dynamically dispatched. Consider
Expand Down Expand Up @@ -574,78 +572,6 @@ private BoundExpression BindMethodGroupInvocation(
return result;
}

private BoundExpression BindLocalFunctionInvocationWithDynamicArgument(
CSharpSyntaxNode syntax,
CSharpSyntaxNode expression,
string methodName,
BoundMethodGroup methodGroup,
DiagnosticBag diagnostics,
CSharpSyntaxNode queryClause,
MethodGroupResolution resolution)
{
// Invocations of local functions with dynamic arguments
// don't need to be dispatched as dynamic invocations
// since they cannot be overloaded. Instead, we'll just
// emit a standard call with dynamic implicit conversions
// for any dynamic arguments. The one exception is params
// arguments which cannot be targeted by dynamic arguments
// because there is an ambiguity between an array target
// and the params element target. See
// https://github.com/dotnet/roslyn/issues/10708

Debug.Assert(resolution.OverloadResolutionResult.Succeeded);
Debug.Assert(queryClause == null);

var validResult = resolution.OverloadResolutionResult.ValidResult;

var args = resolution.AnalyzedArguments.Arguments;
var localFunction = validResult.Member;
var parameters = localFunction.Parameters;
var methodResult = validResult.Result;

// We're only in trouble if a dynamic argument is passed to the
// params parameter and is ambiguous at compile time between
// normal and expanded form i.e., there is exactly one dynamic
// argument to a params parameter
if (OverloadResolution.IsValidParams(localFunction) &&
methodResult.Kind == MemberResolutionKind.ApplicableInNormalForm)
{
Debug.Assert(parameters.Last().IsParams);
var lastParamIndex = parameters.Length - 1;

for (int i = 0; i < args.Count; ++i)
{
var arg = args[i];
if (arg.HasDynamicType() &&
methodResult.ParameterFromArgument(i) == lastParamIndex)
{
Error(diagnostics,
ErrorCode.ERR_DynamicLocalFunctionParamsParameter,
syntax, parameters.Last().Name, localFunction.Name);
return BindDynamicInvocation(
syntax,
methodGroup,
resolution.AnalyzedArguments,
resolution.OverloadResolutionResult.GetAllApplicableMembers(),
diagnostics,
queryClause);
}
}
}

return BindInvocationExpressionContinued(
node: syntax,
expression: expression,
methodName: methodName,
result: resolution.OverloadResolutionResult,
analyzedArguments: resolution.AnalyzedArguments,
methodGroup: resolution.MethodGroup,
delegateTypeOpt: null,
diagnostics: diagnostics,
extensionMethodsOfSameViabilityAreAvailable: resolution.ExtensionMethodsOfSameViabilityAreAvailable,
queryClause: queryClause);
}

private ImmutableArray<MethodSymbol> GetCandidatesPassingFinalValidation(CSharpSyntaxNode syntax, OverloadResolutionResult<MethodSymbol> overloadResolutionResult, BoundMethodGroup methodGroup, DiagnosticBag diagnostics)
{
Debug.Assert(overloadResolutionResult.HasAnyApplicableMember);
Expand Down
4 changes: 0 additions & 4 deletions src/Compilers/CSharp/Portable/Binder/MethodGroupResolution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@ public bool IsExtensionMethodGroup
get { return (this.MethodGroup != null) && this.MethodGroup.IsExtensionMethodGroup; }
}

public bool IsLocalFunctionInvocation =>
MethodGroup.Methods.Count == 1 && // Local functions cannot be overloaded
MethodGroup.Methods[0].MethodKind == MethodKind.LocalFunction;

public void Free()
{
if (this.MethodGroup != null)
Expand Down
6 changes: 3 additions & 3 deletions src/Compilers/CSharp/Portable/CSharpResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4821,8 +4821,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_ReturnTypesDontMatch" xml:space="preserve">
<value>Cannot infer the return type of '{0}' due to differing return types.</value>
</data>
<data name="ERR_DynamicLocalFunctionParamsParameter" xml:space="preserve">
<value>Cannot pass argument with dynamic type to params parameter '{0}' of local function '{1}'.</value>
<data name="ERR_DynamicLocalFunctionParameter" xml:space="preserve">
<value>Cannot invoke the local function '{0}' with dynamic parameters.</value>
</data>
<data name="ERR_CantInferVoid" xml:space="preserve">
<value>Cannot infer the type of '{0}' as it does not return a value.</value>
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,7 @@ internal enum ErrorCode
ERR_TooManyUserStrings = 8103,
ERR_PeWritingFailure = 8104,
ERR_ReturnTypesDontMatch = 8105,
ERR_DynamicLocalFunctionParamsParameter = 8106,
ERR_DynamicLocalFunctionParameter = 8106,
ERR_CantInferVoid = 8107,
ERR_PatternNullableType = 8108,
ERR_BadIsPatternExpression = 8109,
Expand Down
123 changes: 3 additions & 120 deletions src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,13 @@ private CompilationVerifier CompileAndVerifyIL(
MetadataReference[] references = null,
bool allowUnsafe = false,
[CallerFilePath]string callerPath = null,
[CallerLineNumber]int callerLine = 0,
CSharpParseOptions parseOptions = null)
[CallerLineNumber]int callerLine = 0)
{
references = references ?? new[] { SystemCoreRef, CSharpRef };

// verify that we emit correct optimized and unoptimized IL:
var unoptimizedCompilation = CreateCompilationWithMscorlib45(source, references, parseOptions: parseOptions, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe));
var optimizedCompilation = CreateCompilationWithMscorlib45(source, references, parseOptions: parseOptions, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe));
var unoptimizedCompilation = CreateCompilationWithMscorlib45(source, references, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe));
var optimizedCompilation = CreateCompilationWithMscorlib45(source, references, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe));

var unoptimizedVerifier = CompileAndVerify(unoptimizedCompilation);
var optimizedVerifier = CompileAndVerify(optimizedCompilation);
Expand All @@ -54,8 +53,6 @@ private CompilationVerifier CompileAndVerifyIL(
return (expectedUnoptimizedIL != null) ^ (expectedOptimizedIL != null) ? (unoptimizedVerifier ?? optimizedVerifier) : null;
}

private readonly CSharpParseOptions _localFunctionParseOptions = TestOptions.Regular.WithLocalFunctionsFeature();

#endregion


Expand Down Expand Up @@ -1491,120 +1488,6 @@ .locals init (C.<>c__DisplayClass11_0 V_0, //CS$<>8__locals0

#region Conversions

[Fact]
public void LocalFunctionArgumentConversion()
{
string src = @"
using System;
public class C
{
static void Main()
{
int capture1 = 0;
void L1(int x) => Console.Write(x);
Action<int> L2(int x)
{
Console.Write(capture1);
Console.Write(x);
void L3(int y)
{
Console.Write(y + x);
}
return L3;
}
dynamic d = 2;
L1(d);
dynamic l3 = L2(d);
l3(d);
}
}";
CompileAndVerify(src,
expectedOutput: "2024",
parseOptions: _localFunctionParseOptions,
additionalRefs: new[] { SystemCoreRef, CSharpRef }).VerifyDiagnostics();
CompileAndVerifyIL(src, "C.Main",
parseOptions: _localFunctionParseOptions,
expectedOptimizedIL: @"
{
// Code size 250 (0xfa)
.maxstack 7
.locals init (C.<>c__DisplayClass0_0 V_0, //CS$<>8__locals0
object V_1, //d
object V_2) //l3
IL_0000: ldloca.s V_0
IL_0002: initobj ""C.<>c__DisplayClass0_0""
IL_0008: ldloca.s V_0
IL_000a: ldc.i4.0
IL_000b: stfld ""int C.<>c__DisplayClass0_0.capture1""
IL_0010: ldc.i4.2
IL_0011: box ""int""
IL_0016: stloc.1
IL_0017: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__0""
IL_001c: brtrue.s IL_0042
IL_001e: ldc.i4.0
IL_001f: ldtoken ""int""
IL_0024: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0029: ldtoken ""C""
IL_002e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0033: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.Convert(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, System.Type, System.Type)""
IL_0038: call ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_003d: stsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__0""
IL_0042: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__0""
IL_0047: ldfld ""System.Func<System.Runtime.CompilerServices.CallSite, object, int> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>>.Target""
IL_004c: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__0""
IL_0051: ldloc.1
IL_0052: callvirt ""int System.Func<System.Runtime.CompilerServices.CallSite, object, int>.Invoke(System.Runtime.CompilerServices.CallSite, object)""
IL_0057: call ""void C.<Main>g__L10_0(int)""
IL_005c: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__1""
IL_0061: brtrue.s IL_0087
IL_0063: ldc.i4.0
IL_0064: ldtoken ""int""
IL_0069: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_006e: ldtoken ""C""
IL_0073: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0078: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.Convert(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, System.Type, System.Type)""
IL_007d: call ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_0082: stsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__1""
IL_0087: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__1""
IL_008c: ldfld ""System.Func<System.Runtime.CompilerServices.CallSite, object, int> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>>.Target""
IL_0091: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, int>> C.<>o__0.<>p__1""
IL_0096: ldloc.1
IL_0097: callvirt ""int System.Func<System.Runtime.CompilerServices.CallSite, object, int>.Invoke(System.Runtime.CompilerServices.CallSite, object)""
IL_009c: ldloca.s V_0
IL_009e: call ""System.Action<int> C.<Main>g__L20_1(int, ref C.<>c__DisplayClass0_0)""
IL_00a3: stloc.2
IL_00a4: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, object, object>> C.<>o__0.<>p__2""
IL_00a9: brtrue.s IL_00e3
IL_00ab: ldc.i4 0x100
IL_00b0: ldtoken ""C""
IL_00b5: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_00ba: ldc.i4.2
IL_00bb: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo""
IL_00c0: dup
IL_00c1: ldc.i4.0
IL_00c2: ldc.i4.0
IL_00c3: ldnull
IL_00c4: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_00c9: stelem.ref
IL_00ca: dup
IL_00cb: ldc.i4.1
IL_00cc: ldc.i4.0
IL_00cd: ldnull
IL_00ce: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_00d3: stelem.ref
IL_00d4: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.Invoke(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)""
IL_00d9: call ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, object, object>> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, object, object>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_00de: stsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, object, object>> C.<>o__0.<>p__2""
IL_00e3: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, object, object>> C.<>o__0.<>p__2""
IL_00e8: ldfld ""System.Action<System.Runtime.CompilerServices.CallSite, object, object> System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, object, object>>.Target""
IL_00ed: ldsfld ""System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, object, object>> C.<>o__0.<>p__2""
IL_00f2: ldloc.2
IL_00f3: ldloc.1
IL_00f4: callvirt ""void System.Action<System.Runtime.CompilerServices.CallSite, object, object>.Invoke(System.Runtime.CompilerServices.CallSite, object, object)""
IL_00f9: ret
}");
}

[Fact]
public void Conversion_Assignment()
{
Expand Down
Loading

0 comments on commit 5777c60

Please sign in to comment.