From b12c86a4dff39ccac158c1ac50addeb96cf25749 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Tue, 9 Nov 2021 10:30:17 -0800 Subject: [PATCH] Overload resolution was ignoring HasTypeArgumentInferredFromFunctionType for calls in expanded form (#57633) --- .../MemberResolutionResult.cs | 11 ++-- .../OverloadResolution/OverloadResolution.cs | 45 +++++++--------- .../Semantic/Semantics/DelegateTypeTests.cs | 52 +++++++++++++++++++ 3 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionResult.cs index 17960c0c15134..b719b9604f3ef 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionResult.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MemberResolutionResult.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// internal readonly bool HasTypeArgumentInferredFromFunctionType; - internal MemberResolutionResult(TMember member, TMember leastOverriddenMember, MemberAnalysisResult result, bool hasTypeArgumentInferredFromFunctionType = false) + internal MemberResolutionResult(TMember member, TMember leastOverriddenMember, MemberAnalysisResult result, bool hasTypeArgumentInferredFromFunctionType) { _member = member; _leastOverriddenMember = leastOverriddenMember; @@ -30,6 +30,11 @@ internal MemberResolutionResult(TMember member, TMember leastOverriddenMember, M HasTypeArgumentInferredFromFunctionType = hasTypeArgumentInferredFromFunctionType; } + internal MemberResolutionResult WithResult(MemberAnalysisResult result) + { + return new MemberResolutionResult(Member, LeastOverriddenMember, result, HasTypeArgumentInferredFromFunctionType); + } + internal bool IsNull { get { return (object)_member == null; } @@ -92,12 +97,12 @@ public bool IsApplicable internal MemberResolutionResult Worse() { - return new MemberResolutionResult(Member, LeastOverriddenMember, MemberAnalysisResult.Worse()); + return WithResult(MemberAnalysisResult.Worse()); } internal MemberResolutionResult Worst() { - return new MemberResolutionResult(Member, LeastOverriddenMember, MemberAnalysisResult.Worst()); + return WithResult(MemberAnalysisResult.Worst()); } internal bool HasUseSiteDiagnosticToReport diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index fd6e17709465f..07965c314f1c3 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -385,7 +385,7 @@ private static void RemoveStaticInstanceMismatches(ArrayBuilder(member, result.LeastOverriddenMember, MemberAnalysisResult.StaticInstanceMismatch()); + results[f] = result.WithResult(MemberAnalysisResult.StaticInstanceMismatch()); } } } @@ -401,7 +401,7 @@ private static void RemoveMethodsNotDeclaredStatic(ArrayBuilder(member, result.LeastOverriddenMember, MemberAnalysisResult.StaticInstanceMismatch()); + results[f] = result.WithResult(MemberAnalysisResult.StaticInstanceMismatch()); } } } @@ -426,8 +426,7 @@ private void RemoveConstraintViolations(ArrayBuilder constraintFailureDiagnosticsOpt, template)) { - results[f] = new MemberResolutionResult( - result.Member, result.LeastOverriddenMember, + results[f] = result.WithResult( MemberAnalysisResult.ConstraintFailure(constraintFailureDiagnosticsOpt.ToImmutableAndFree())); } } @@ -559,7 +558,7 @@ private void RemoveCallingConventionMismatches(ArrayBuilder makeWrongCallingConvention(MemberResolutionResult result) - => new MemberResolutionResult(result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongCallingConvention()); + => result.WithResult(MemberAnalysisResult.WrongCallingConvention()); } #nullable disable @@ -649,13 +648,11 @@ private void RemoveDelegateConversionsWithWrongReturnType( if (!returnsMatch) { - results[f] = new MemberResolutionResult( - result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongReturnType()); + results[f] = result.WithResult(MemberAnalysisResult.WrongReturnType()); } else if (method.RefKind != returnRefKind) { - results[f] = new MemberResolutionResult( - result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongRefKind()); + results[f] = result.WithResult(MemberAnalysisResult.WrongRefKind()); } } } @@ -699,7 +696,7 @@ private void AddConstructorToCandidateSet(MethodSymbol constructor, ArrayBuilder Debug.Assert(!MemberAnalysisResult.UnsupportedMetadata().HasUseSiteDiagnosticToReportFor(constructor)); if (completeResults) { - results.Add(new MemberResolutionResult(constructor, constructor, MemberAnalysisResult.UnsupportedMetadata())); + results.Add(new MemberResolutionResult(constructor, constructor, MemberAnalysisResult.UnsupportedMetadata(), hasTypeArgumentInferredFromFunctionType: false)); } return; } @@ -721,7 +718,7 @@ private void AddConstructorToCandidateSet(MethodSymbol constructor, ArrayBuilder // If the constructor has a use site diagnostic, we don't want to discard it because we'll have to report the diagnostic later. if (result.IsValid || completeResults || result.HasUseSiteDiagnosticToReportFor(constructor)) { - results.Add(new MemberResolutionResult(constructor, constructor, result)); + results.Add(new MemberResolutionResult(constructor, constructor, result, hasTypeArgumentInferredFromFunctionType: false)); } } @@ -905,7 +902,7 @@ private void AddMemberToCandidateSet( Debug.Assert(!MemberAnalysisResult.UnsupportedMetadata().HasUseSiteDiagnosticToReportFor(member)); if (completeResults) { - results.Add(new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.UnsupportedMetadata())); + results.Add(new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.UnsupportedMetadata(), hasTypeArgumentInferredFromFunctionType: false)); } return; } @@ -1141,7 +1138,7 @@ private void RemoveInaccessibleTypeArguments(ArrayBuilder(result.Member, result.LeastOverriddenMember, MemberAnalysisResult.InaccessibleTypeArgument()); + results[f] = result.WithResult(MemberAnalysisResult.InaccessibleTypeArgument()); } } } @@ -1272,7 +1269,7 @@ private static void RemoveLessDerivedMembers(ArrayBuilder(result.Member, result.LeastOverriddenMember, MemberAnalysisResult.LessDerived()); + results[f] = result.WithResult(MemberAnalysisResult.LessDerived()); } } } @@ -1383,7 +1380,7 @@ private static void RemoveAllInterfaceMembers(ArrayBuilder(member, result.LeastOverriddenMember, MemberAnalysisResult.LessDerived()); + results[f] = result.WithResult(MemberAnalysisResult.LessDerived()); } } } @@ -3284,7 +3281,7 @@ private MemberResolutionResult IsMemberApplicableInNormalForm( // thus improving the API and intellisense experience. break; default: - return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis)); + return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis), hasTypeArgumentInferredFromFunctionType: false); } } @@ -3292,7 +3289,7 @@ private MemberResolutionResult IsMemberApplicableInNormalForm( // NOTE: The diagnostic may not be reported (e.g. if the member is later removed as less-derived). if (member.HasUseSiteError) { - return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError()); + return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError(), hasTypeArgumentInferredFromFunctionType: false); } bool hasAnyRefOmittedArgument; @@ -3334,7 +3331,7 @@ private MemberResolutionResult IsMemberApplicableInNormalForm( // type inference and lambda binding. In that case we still need to return the argument mismatch failure here. if (completeResults && !argumentAnalysis.IsValid) { - return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis)); + return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis), hasTypeArgumentInferredFromFunctionType: false); } return applicableResult; @@ -3355,14 +3352,14 @@ private MemberResolutionResult IsMemberApplicableInExpandedForm(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis)); + return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis), hasTypeArgumentInferredFromFunctionType: false); } // Check after argument analysis, but before more complicated type inference and argument type validation. // NOTE: The diagnostic may not be reported (e.g. if the member is later removed as less-derived). if (member.HasUseSiteError) { - return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError()); + return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError(), hasTypeArgumentInferredFromFunctionType: false); } bool hasAnyRefOmittedArgument; @@ -3401,9 +3398,7 @@ private MemberResolutionResult IsMemberApplicableInExpandedForm( - result.Member, - result.LeastOverriddenMember, + result.WithResult( MemberAnalysisResult.ExpandedForm(result.Result.ArgsToParamsOpt, result.Result.ConversionsOpt, hasAnyRefOmittedArgument)) : result; } @@ -3465,7 +3460,7 @@ private MemberResolutionResult IsApplicable( ref useSiteInfo); if (typeArguments.IsDefault) { - return new MemberResolutionResult(member, leastOverriddenMember, inferenceError); + return new MemberResolutionResult(member, leastOverriddenMember, inferenceError, hasTypeArgumentInferredFromFunctionType: false); } } @@ -3505,7 +3500,7 @@ private MemberResolutionResult IsApplicable( { if (!parameterTypes[i].Type.CheckAllConstraints(Compilation, Conversions)) { - return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.ConstructedParameterFailedConstraintsCheck(i)); + return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.ConstructedParameterFailedConstraintsCheck(i), hasTypeArgumentsInferredFromFunctionType); } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index d8fc48de45a43..520309633c00d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -4306,6 +4306,58 @@ static void Main() CompileAndVerify(source, expectedOutput: expectedOutput); } + [WorkItem(57627, "https://github.com/dotnet/roslyn/issues/57627")] + [Fact] + public void OverloadResolution_48() + { + var source = +@"using System; +using System.Threading.Tasks; + +delegate void MyAction(); +delegate T MyFunc(); + +class A +{ + public static void F(object o) { Console.WriteLine(""F(object o)""); } + public static void F(object o, string format, params object[] args) { Console.WriteLine(""F(object o, string format, params object[] args)""); } + + public static void F(T t) { Console.WriteLine(""F(T t)""); } + public static void F(T t, string format, params object[] args) { Console.WriteLine(""F(T t, string format, params object[] args)""); } + + public static void F(MyAction a) { Console.WriteLine(""F(MyAction a)""); } + public static void F(MyAction a, string format, params object[] args) { Console.WriteLine(""F(MyAction a, string format, params object[] args)""); } + + public static void F(MyFunc f) { Console.WriteLine(""F(MyFunc f)""); } + public static void F(MyFunc f, string format, params object[] args) { Console.WriteLine(""F(MyFunc f, string format, params object[] args)""); } +} + +class B +{ + static async Task Main() + { + A.F(() => { }); + A.F(() => { }, """"); + A.F(() => { }, ""{0}"", 1); + A.F(async () => await Task.FromResult(null)); + A.F(async () => await Task.FromResult(null), """"); + A.F(async () => await Task.FromResult(null), ""{0}"", 1); + } +}"; + + string expectedOutput = +@"F(MyAction a) +F(MyAction a, string format, params object[] args) +F(MyAction a, string format, params object[] args) +F(MyFunc f) +F(MyFunc f, string format, params object[] args) +F(MyFunc f, string format, params object[] args) +"; + CompileAndVerify(source, parseOptions: TestOptions.Regular9, expectedOutput: expectedOutput); + CompileAndVerify(source, parseOptions: TestOptions.Regular10, expectedOutput: expectedOutput); + CompileAndVerify(source, expectedOutput: expectedOutput); + } + [Fact] public void BestCommonType_01() {