Skip to content

Commit

Permalink
Overload resolution was ignoring HasTypeArgumentInferredFromFunctionT…
Browse files Browse the repository at this point in the history
…ype for calls in expanded form (#57633) (#57737)
  • Loading branch information
cston authored Nov 18, 2021
1 parent add472b commit 33aa1d2
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ namespace Microsoft.CodeAnalysis.CSharp
/// </summary>
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;
_result = result;
HasTypeArgumentInferredFromFunctionType = hasTypeArgumentInferredFromFunctionType;
}

internal MemberResolutionResult<TMember> WithResult(MemberAnalysisResult result)
{
return new MemberResolutionResult<TMember>(Member, LeastOverriddenMember, result, HasTypeArgumentInferredFromFunctionType);
}

internal bool IsNull
{
get { return (object)_member == null; }
Expand Down Expand Up @@ -92,12 +97,12 @@ public bool IsApplicable

internal MemberResolutionResult<TMember> Worse()
{
return new MemberResolutionResult<TMember>(Member, LeastOverriddenMember, MemberAnalysisResult.Worse());
return WithResult(MemberAnalysisResult.Worse());
}

internal MemberResolutionResult<TMember> Worst()
{
return new MemberResolutionResult<TMember>(Member, LeastOverriddenMember, MemberAnalysisResult.Worst());
return WithResult(MemberAnalysisResult.Worst());
}

internal bool HasUseSiteDiagnosticToReport
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ private static void RemoveStaticInstanceMismatches<TMember>(ArrayBuilder<MemberR
TMember member = result.Member;
if (result.Result.IsValid && member.RequiresInstanceReceiver() == requireStatic)
{
results[f] = new MemberResolutionResult<TMember>(member, result.LeastOverriddenMember, MemberAnalysisResult.StaticInstanceMismatch());
results[f] = result.WithResult(MemberAnalysisResult.StaticInstanceMismatch());
}
}
}
Expand All @@ -401,7 +401,7 @@ private static void RemoveMethodsNotDeclaredStatic<TMember>(ArrayBuilder<MemberR
TMember member = result.Member;
if (result.Result.IsValid && !member.IsStatic)
{
results[f] = new MemberResolutionResult<TMember>(member, result.LeastOverriddenMember, MemberAnalysisResult.StaticInstanceMismatch());
results[f] = result.WithResult(MemberAnalysisResult.StaticInstanceMismatch());
}
}
}
Expand All @@ -426,8 +426,7 @@ private void RemoveConstraintViolations<TMember>(ArrayBuilder<MemberResolutionRe
if ((result.Result.IsValid || result.Result.Kind == MemberResolutionKind.ConstructedParameterFailedConstraintCheck) &&
FailsConstraintChecks(member, out ArrayBuilder<TypeParameterDiagnosticInfo> constraintFailureDiagnosticsOpt, template))
{
results[f] = new MemberResolutionResult<TMember>(
result.Member, result.LeastOverriddenMember,
results[f] = result.WithResult(
MemberAnalysisResult.ConstraintFailure(constraintFailureDiagnosticsOpt.ToImmutableAndFree()));
}
}
Expand Down Expand Up @@ -559,7 +558,7 @@ private void RemoveCallingConventionMismatches<TMember>(ArrayBuilder<MemberResol
}

static MemberResolutionResult<TMember> makeWrongCallingConvention(MemberResolutionResult<TMember> result)
=> new MemberResolutionResult<TMember>(result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongCallingConvention());
=> result.WithResult(MemberAnalysisResult.WrongCallingConvention());
}
#nullable disable

Expand Down Expand Up @@ -649,13 +648,11 @@ private void RemoveDelegateConversionsWithWrongReturnType<TMember>(

if (!returnsMatch)
{
results[f] = new MemberResolutionResult<TMember>(
result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongReturnType());
results[f] = result.WithResult(MemberAnalysisResult.WrongReturnType());
}
else if (method.RefKind != returnRefKind)
{
results[f] = new MemberResolutionResult<TMember>(
result.Member, result.LeastOverriddenMember, MemberAnalysisResult.WrongRefKind());
results[f] = result.WithResult(MemberAnalysisResult.WrongRefKind());
}
}
}
Expand Down Expand Up @@ -699,7 +696,7 @@ private void AddConstructorToCandidateSet(MethodSymbol constructor, ArrayBuilder
Debug.Assert(!MemberAnalysisResult.UnsupportedMetadata().HasUseSiteDiagnosticToReportFor(constructor));
if (completeResults)
{
results.Add(new MemberResolutionResult<MethodSymbol>(constructor, constructor, MemberAnalysisResult.UnsupportedMetadata()));
results.Add(new MemberResolutionResult<MethodSymbol>(constructor, constructor, MemberAnalysisResult.UnsupportedMetadata(), hasTypeArgumentInferredFromFunctionType: false));
}
return;
}
Expand All @@ -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<MethodSymbol>(constructor, constructor, result));
results.Add(new MemberResolutionResult<MethodSymbol>(constructor, constructor, result, hasTypeArgumentInferredFromFunctionType: false));
}
}

Expand Down Expand Up @@ -905,7 +902,7 @@ private void AddMemberToCandidateSet<TMember>(
Debug.Assert(!MemberAnalysisResult.UnsupportedMetadata().HasUseSiteDiagnosticToReportFor(member));
if (completeResults)
{
results.Add(new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.UnsupportedMetadata()));
results.Add(new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.UnsupportedMetadata(), hasTypeArgumentInferredFromFunctionType: false));
}
return;
}
Expand Down Expand Up @@ -1141,7 +1138,7 @@ private void RemoveInaccessibleTypeArguments<TMember>(ArrayBuilder<MemberResolut
var result = results[f];
if (result.Result.IsValid && !TypeArgumentsAccessible(result.Member.GetMemberTypeArgumentsNoUseSiteDiagnostics(), ref useSiteInfo))
{
results[f] = new MemberResolutionResult<TMember>(result.Member, result.LeastOverriddenMember, MemberAnalysisResult.InaccessibleTypeArgument());
results[f] = result.WithResult(MemberAnalysisResult.InaccessibleTypeArgument());
}
}
}
Expand Down Expand Up @@ -1272,7 +1269,7 @@ private static void RemoveLessDerivedMembers<TMember>(ArrayBuilder<MemberResolut

if (IsLessDerivedThanAny(result.LeastOverriddenMember.ContainingType, results, ref useSiteInfo))
{
results[f] = new MemberResolutionResult<TMember>(result.Member, result.LeastOverriddenMember, MemberAnalysisResult.LessDerived());
results[f] = result.WithResult(MemberAnalysisResult.LessDerived());
}
}
}
Expand Down Expand Up @@ -1383,7 +1380,7 @@ private static void RemoveAllInterfaceMembers<TMember>(ArrayBuilder<MemberResolu
var member = result.Member;
if (member.ContainingType.IsInterfaceType())
{
results[f] = new MemberResolutionResult<TMember>(member, result.LeastOverriddenMember, MemberAnalysisResult.LessDerived());
results[f] = result.WithResult(MemberAnalysisResult.LessDerived());
}
}
}
Expand Down Expand Up @@ -3284,15 +3281,15 @@ private MemberResolutionResult<TMember> IsMemberApplicableInNormalForm<TMember>(
// thus improving the API and intellisense experience.
break;
default:
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
return new MemberResolutionResult<TMember>(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<TMember>(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError());
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError(), hasTypeArgumentInferredFromFunctionType: false);
}

bool hasAnyRefOmittedArgument;
Expand Down Expand Up @@ -3334,7 +3331,7 @@ private MemberResolutionResult<TMember> IsMemberApplicableInNormalForm<TMember>(
// 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<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis), hasTypeArgumentInferredFromFunctionType: false);
}

return applicableResult;
Expand All @@ -3355,14 +3352,14 @@ private MemberResolutionResult<TMember> IsMemberApplicableInExpandedForm<TMember
var argumentAnalysis = AnalyzeArguments(member, arguments, isMethodGroupConversion: false, expanded: true);
if (!argumentAnalysis.IsValid)
{
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
return new MemberResolutionResult<TMember>(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<TMember>(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError());
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError(), hasTypeArgumentInferredFromFunctionType: false);
}

bool hasAnyRefOmittedArgument;
Expand Down Expand Up @@ -3401,9 +3398,7 @@ private MemberResolutionResult<TMember> IsMemberApplicableInExpandedForm<TMember
useSiteInfo: ref useSiteInfo);

return result.Result.IsValid ?
new MemberResolutionResult<TMember>(
result.Member,
result.LeastOverriddenMember,
result.WithResult(
MemberAnalysisResult.ExpandedForm(result.Result.ArgsToParamsOpt, result.Result.ConversionsOpt, hasAnyRefOmittedArgument)) :
result;
}
Expand Down Expand Up @@ -3465,7 +3460,7 @@ private MemberResolutionResult<TMember> IsApplicable<TMember>(
ref useSiteInfo);
if (typeArguments.IsDefault)
{
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, inferenceError);
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, inferenceError, hasTypeArgumentInferredFromFunctionType: false);
}
}

Expand Down Expand Up @@ -3505,7 +3500,7 @@ private MemberResolutionResult<TMember> IsApplicable<TMember>(
{
if (!parameterTypes[i].Type.CheckAllConstraints(Compilation, Conversions))
{
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ConstructedParameterFailedConstraintsCheck(i));
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ConstructedParameterFailedConstraintsCheck(i), hasTypeArgumentsInferredFromFunctionType);
}
}

Expand Down
52 changes: 52 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>();
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 t) { Console.WriteLine(""F<T>(T t)""); }
public static void F<T>(T t, string format, params object[] args) { Console.WriteLine(""F<T>(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<T>(MyFunc<T> f) { Console.WriteLine(""F<T>(MyFunc<T> f)""); }
public static void F<T>(MyFunc<T> f, string format, params object[] args) { Console.WriteLine(""F<T>(MyFunc<T> 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<object>(null));
A.F(async () => await Task.FromResult<object>(null), """");
A.F(async () => await Task.FromResult<object>(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<T>(MyFunc<T> f)
F<T>(MyFunc<T> f, string format, params object[] args)
F<T>(MyFunc<T> 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()
{
Expand Down

0 comments on commit 33aa1d2

Please sign in to comment.