Skip to content

Commit

Permalink
Type argument inference with unambiguous method group
Browse files Browse the repository at this point in the history
  • Loading branch information
alrz committed Dec 13, 2018
1 parent af98474 commit c96534d
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -1327,7 +1327,7 @@ private static TypeSymbol MethodGroupReturnType(
//
// Explicit parameter type inferences
//
private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbolWithAnnotations target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
private void ExplicitParameterTypeInference(Binder binder, BoundExpression source, TypeSymbolWithAnnotations target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert(source != null);
Debug.Assert(!target.IsNull);
Expand All @@ -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;
}
Expand All @@ -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();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(Func<T, bool> predicate)
{
Console.Write(predicate(default(T)));
}
}";

var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics();
CompileAndVerify(compilation, expectedOutput: "True");
}
}
}

0 comments on commit c96534d

Please sign in to comment.