Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overload resolution was ignoring HasTypeArgumentInferredFromFunctionType for calls in expanded form #57633

Merged
merged 1 commit into from
Nov 9, 2021
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
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(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result.WithResult

The fix is this change to retain result.HasTypeInferredFromFunctionType.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasTypeArgumentInferredFromFunctionType: false

Why not simply pass hasTypeArgumentsInferredFromFunctionType?

Copy link
Member Author

@cston cston Nov 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could although typeArguments.IsDefault is returned for error conditions, and hasTypeArgumentsInferredFromFunctionType == 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
Original file line number Diff line number Diff line change
Expand Up @@ -4371,6 +4371,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