From c96534d4dd002c632854ac0f2d96a0a53c97697e Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Thu, 13 Dec 2018 14:31:51 +0330 Subject: [PATCH] Type argument inference with unambiguous method group --- .../Semantics/Conversions/ConversionsBase.cs | 8 ++ .../OverloadResolution/MethodTypeInference.cs | 82 +++++++++++++------ .../Semantics/EnhancedTypeInferenceTests.cs | 28 +++++++ 3 files changed, 95 insertions(+), 23 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 856e1b8ee1861..3232d23543c27 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -896,6 +896,14 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi case BoundKind.ThrowExpression: return Conversion.ImplicitThrow; + + case BoundKind.Parameter: + if (sourceExpression.WasCompilerGenerated && + sourceExpression.Type.TypeKind == TypeKind.TypeParameter) + { + return Conversion.Identity; + } + break; } return Conversion.NoConversion; diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs index 027beea0b0eec..b018b898b93cc 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs @@ -543,9 +543,9 @@ private void MakeExplicitParameterTypeInferences(Binder binder, BoundExpression var source = argument.Type; - if (argument.Kind == BoundKind.UnboundLambda) + if (argument.Kind == BoundKind.UnboundLambda || argument.Kind == BoundKind.MethodGroup) { - ExplicitParameterTypeInference(argument, target, ref useSiteDiagnostics); + ExplicitParameterTypeInference(binder, argument, target, ref useSiteDiagnostics); } else if (argument.Kind != BoundKind.TupleLiteral || !MakeExplicitParameterTypeInferences(binder, (BoundTupleLiteral)argument, target, kind, ref useSiteDiagnostics)) @@ -1327,7 +1327,7 @@ private static TypeSymbol MethodGroupReturnType( // // Explicit parameter type inferences // - private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics) + private void ExplicitParameterTypeInference(Binder binder, BoundExpression source, TypeSymbolWithAnnotations target, ref HashSet useSiteDiagnostics) { Debug.Assert(source != null); Debug.Assert(!target.IsNull); @@ -1339,14 +1339,7 @@ private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbolWi // SPEC: parameter types V1...Vk then for each Ui an exact inference is made // SPEC: from Ui to the corresponding Vi. - if (source.Kind != BoundKind.UnboundLambda) - { - return; - } - - UnboundLambda anonymousFunction = (UnboundLambda)source; - - if (!anonymousFunction.HasExplicitlyTypedParameterList) + if (source.Kind != BoundKind.UnboundLambda && source.Kind != BoundKind.MethodGroup) { return; } @@ -1363,22 +1356,65 @@ private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbolWi return; } - int size = delegateParameters.Length; - if (anonymousFunction.ParameterCount < size) + if (source is UnboundLambda anonymousFunction) { - size = anonymousFunction.ParameterCount; - } + if (!anonymousFunction.HasExplicitlyTypedParameterList) + { + return; + } - // SPEC ISSUE: What should we do if there is an out/ref mismatch between an - // SPEC ISSUE: anonymous function parameter and a delegate parameter? - // SPEC ISSUE: The result will not be applicable no matter what, but should - // SPEC ISSUE: we make any inferences? This is going to be an error - // SPEC ISSUE: ultimately, but it might make a difference for intellisense or - // SPEC ISSUE: other analysis. + // SPEC ISSUE: What should we do if there is an out/ref mismatch between an + // SPEC ISSUE: anonymous function parameter and a delegate parameter? + // SPEC ISSUE: The result will not be applicable no matter what, but should + // SPEC ISSUE: we make any inferences? This is going to be an error + // SPEC ISSUE: ultimately, but it might make a difference for intellisense or + // SPEC ISSUE: other analysis. - for (int i = 0; i < size; ++i) + int size = Math.Min(delegateParameters.Length, anonymousFunction.ParameterCount); + for (int i = 0; i < size; ++i) + { + ExactInference(anonymousFunction.ParameterType(i), delegateParameters[i].Type, ref useSiteDiagnostics); + } + } + else if (source is BoundMethodGroup methodGroup) { - ExactInference(anonymousFunction.ParameterType(i), delegateParameters[i].Type, ref useSiteDiagnostics); + if (delegateParameters.Length == 0) + { + return; + } + + var analyzedArguments = AnalyzedArguments.GetInstance(); + Conversions.GetDelegateArguments(source.Syntax, analyzedArguments, delegateParameters, binder.Compilation); + + var delegateInvokeMethod = delegateType.DelegateInvokeMethod; + var resolution = binder.ResolveMethodGroup(methodGroup, analyzedArguments, useSiteDiagnostics: ref useSiteDiagnostics, + isMethodGroupConversion: true, returnRefKind: delegateInvokeMethod.RefKind, + returnType: null); + + if (!resolution.IsEmpty) + { + var result = resolution.OverloadResolutionResult; + if (result.Succeeded) + { + MethodSymbol member = result.BestResult.Member; + var memberParameterTypes = member.ParameterTypes; + int size = Math.Min(delegateParameters.Length, member.ParameterCount); + for (int i = 0; i < size; ++i) + { + var memberParameterType = memberParameterTypes[i]; + var delegateParameterType = delegateParameters[i].Type; + if (memberParameterType.IsSameAs(delegateParameterType)) + { + continue; + } + + ExactInference(memberParameterType, delegateParameterType, ref useSiteDiagnostics); + } + } + } + + analyzedArguments.Free(); + resolution.Free(); } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/EnhancedTypeInferenceTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/EnhancedTypeInferenceTests.cs index 763a9557007c7..300cfeb203d2d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/EnhancedTypeInferenceTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/EnhancedTypeInferenceTests.cs @@ -124,5 +124,33 @@ void M() var compilation = CreateCompilation(source); compilation.VerifyDiagnostics(); } + + [Fact] + public void MethodGroup_01() + { + var source = @" +using System; +class Program +{ + public static void Main() + { + Program.Test(Program.IsEven); + } + + public static bool IsEven(int x) + { + return true; + } + + public static void Test(Func predicate) + { + Console.Write(predicate(default(T))); + } +}"; + + var compilation = CreateCompilation(source, options: TestOptions.DebugExe); + compilation.VerifyDiagnostics(); + CompileAndVerify(compilation, expectedOutput: "True"); + } } }