From 1914c0441e7acc78c26a6d7ab3c5ad892e89f16e Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Wed, 14 Sep 2016 15:28:33 -0700 Subject: [PATCH] Fix a bug in lambda type inference for `delegate {...}`. (#13804) The bug is that, as an optimization, we use 'null' as the delegate type for a parameterless `delegate` lambda, but code elsewhere in the compiler assumes that a null delegate type occurs only in error recovery situations. Fixes #13797 --- .../OverloadResolution/MethodTypeInference.cs | 48 ++++++++----------- .../Test/Semantic/Semantics/LambdaTests.cs | 19 ++++++++ 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs index 843b7a2ca26..515c0788764 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs @@ -2615,36 +2615,26 @@ private TypeSymbol InferReturnType(BoundExpression source, NamedTypeSymbol targe } var anonymousFunction = (UnboundLambda)source; + if (anonymousFunction.HasSignature) + { + // Optimization: + // We know that the anonymous function has a parameter list. If it does not + // have the same arity as the delegate, then it cannot possibly be applicable. + // Rather than have type inference fail, we will simply not make a return + // type inference and have type inference continue on. Either inference + // will fail, or we will infer a nonapplicable method. Either way, there + // is no change to the semantics of overload resolution. + + var originalDelegateParameters = target.DelegateParameters(); + if (originalDelegateParameters.IsDefault) + { + return null; + } - // If the anonymous function is an anonymous method with no formal parameter - // list then infer the return type; there are no parameters to be typed, so - // we should be able to work out the return type regardless of the delegate type. - - // Future optimization: we could return null if - // the delegate has any out parameters, since this will then not be applicable. - - if (!anonymousFunction.HasSignature) - { - return anonymousFunction.InferReturnType(null, ref useSiteDiagnostics); - } - - // Optimization: - // We know that the anonymous function has a parameter list. If it does not - // have the same arity as the delegate, then it cannot possibly be applicable. - // Rather than have type inference fail, we will simply not make a return - // type inference and have type inference continue on. Either inference - // will fail, or we will infer a nonapplicable method. Either way, there - // is no change to the semantics of overload resolution. - - var originalDelegateParameters = target.DelegateParameters(); - if (originalDelegateParameters.IsDefault) - { - return null; - } - - if (originalDelegateParameters.Length != anonymousFunction.ParameterCount) - { - return null; + if (originalDelegateParameters.Length != anonymousFunction.ParameterCount) + { + return null; + } } var fixedDelegate = GetFixedDelegate(target); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 42ae4b004c1..5395126e78e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -2271,5 +2271,24 @@ static void Main(string[] args) Assert.NotEmpty(typeInfo.Type.GetMembers("Replace")); } } + + [Fact] + [WorkItem(13797, "https://github.com/dotnet/roslyn/issues/13797")] + public void DelegateAsAction() + { + var source = @" +using System; + +public static class C +{ + public static void M() => Dispatch(delegate { }); + + public static T Dispatch(Func func) => default(T); + + public static void Dispatch(Action func) { } +}"; + var comp = CreateCompilationWithMscorlib(source); + CompileAndVerify(comp); + } } } -- GitLab