Browse Source

Fix overload resolution: overloads with `in` parameters are applicable even if the argument is passed without explicit `in`

pull/2301/head
Daniel Grunwald 4 years ago
parent
commit
3c554b5e6c
  1. 41
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
  2. 8
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  3. 2
      ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs
  4. 21
      ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
  5. 9
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

41
ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs

@ -275,12 +275,27 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -275,12 +275,27 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
#region In Parameter
static void CallWithInParam()
{
Console.WriteLine("OverloadSetWithInParam:");
#if CS72
Console.WriteLine("OverloadSetWithInParam:");
OverloadSetWithInParam(1);
OverloadSetWithInParam(2L);
int i = 3;
OverloadSetWithInParam(in i);
OverloadSetWithInParam((long)4);
Console.WriteLine("OverloadSetWithInParam2:");
OverloadSetWithInParam2(1);
OverloadSetWithInParam2((object)1);
Console.WriteLine("OverloadSetWithInParam3:");
OverloadSetWithInParam3(1);
OverloadSetWithInParam3<int>(2);
OverloadSetWithInParam3((object)3);
Console.WriteLine("InVsRegularParam:");
InVsRegularParam(1);
i = 2;
InVsRegularParam(in i);
#endif
}
@ -293,6 +308,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -293,6 +308,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
Console.WriteLine("long " + l);
}
static void OverloadSetWithInParam2(in long i)
{
Console.WriteLine("in long " + i);
}
static void OverloadSetWithInParam2(object o)
{
Console.WriteLine("object " + o);
}
static void OverloadSetWithInParam3(in int i)
{
Console.WriteLine("in int " + i);
}
static void OverloadSetWithInParam3<T>(T a)
{
Console.WriteLine("T " + a);
}
static void InVsRegularParam(in int i)
{
Console.WriteLine("in int " + i);
}
static void InVsRegularParam(int i)
{
Console.WriteLine("int " + i);
}
#endif
#endregion
}

8
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -1283,7 +1283,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1283,7 +1283,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
args[i] = new ResolveResult(parameterType);
}
}
var or = rr.PerformOverloadResolution(compilation, args, allowExpandingParams: false, allowOptionalParameters: false, conversions: this);
var or = rr.PerformOverloadResolution(
compilation, args,
allowExpandingParams: false,
allowOptionalParameters: false,
allowImplicitIn: false,
conversions: this
);
if (or.FoundApplicableCandidate)
{
IMethod method = (IMethod)or.GetBestCandidateWithSubstitutedTypeArguments();

2
ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs

@ -233,6 +233,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -233,6 +233,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool allowExtensionMethods = true,
bool allowExpandingParams = true,
bool allowOptionalParameters = true,
bool allowImplicitIn = true,
bool checkForOverflow = false, CSharpConversions conversions = null)
{
Log.WriteLine("Performing overload resolution for " + this);
@ -243,6 +244,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -243,6 +244,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
or.AllowExpandingParams = allowExpandingParams;
or.AllowOptionalParameters = allowOptionalParameters;
or.CheckForOverflow = checkForOverflow;
or.AllowImplicitIn = allowImplicitIn;
or.AddMethodLists(methodLists);

21
ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs

@ -183,6 +183,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -183,6 +183,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
public bool AllowOptionalParameters { get; set; }
/// <summary>
/// Gets/Sets whether a value argument can be passed to an `in` reference parameter.
/// </summary>
public bool AllowImplicitIn { get; set; } = true;
/// <summary>
/// Gets/Sets whether ConversionResolveResults created by this OverloadResolution
/// instance apply overflow checking.
@ -649,22 +654,32 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -649,22 +654,32 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
continue;
}
ReferenceKind paramRefKind = candidate.Parameters[parameterIndex].ReferenceKind;
if (arguments[i] is ByReferenceResolveResult brrr)
{
if (brrr.ReferenceKind != candidate.Parameters[parameterIndex].ReferenceKind)
if (brrr.ReferenceKind != paramRefKind)
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
}
else if (arguments[i] is OutVarResolveResult)
{
if (candidate.Parameters[parameterIndex].ReferenceKind != ReferenceKind.Out)
if (paramRefKind != ReferenceKind.Out)
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
// 'out var decl' arguments are compatible with any out parameter
continue;
}
else
{
if (candidate.Parameters[parameterIndex].ReferenceKind != ReferenceKind.None)
if (paramRefKind == ReferenceKind.In && AllowImplicitIn
&& candidate.ParameterTypes[parameterIndex].SkipModifiers() is ByReferenceType brt)
{
// Treat the parameter as if it was not declared "in" for the following steps
// (applicability + better function member)
candidate.ParameterTypes[parameterIndex] = brt.ElementType;
}
else if (paramRefKind != ReferenceKind.None)
{
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
}
}
IType parameterType = candidate.ParameterTypes[parameterIndex];
Conversion c = conversions.ImplicitConversion(arguments[i], parameterType);

9
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -578,9 +578,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -578,9 +578,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
args[i] = new ResolveResult(parameterType);
}
}
var or = mgrr.PerformOverloadResolution(compilation,
args,
allowExpandingParams: false, allowOptionalParameters: false);
var or = mgrr.PerformOverloadResolution(
compilation, args,
allowExpandingParams: false,
allowOptionalParameters: false,
allowImplicitIn: false
);
if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null)
{
IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;

Loading…
Cancel
Save