Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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