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 5 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
#region In Parameter #region In Parameter
static void CallWithInParam() static void CallWithInParam()
{ {
Console.WriteLine("OverloadSetWithInParam:");
#if CS72 #if CS72
Console.WriteLine("OverloadSetWithInParam:");
OverloadSetWithInParam(1); OverloadSetWithInParam(1);
OverloadSetWithInParam(2L); OverloadSetWithInParam(2L);
int i = 3; int i = 3;
OverloadSetWithInParam(in i); 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 #endif
} }
@ -293,6 +308,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{ {
Console.WriteLine("long " + l); 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 #endif
#endregion #endregion
} }

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

@ -1283,7 +1283,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
args[i] = new ResolveResult(parameterType); 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) if (or.FoundApplicableCandidate)
{ {
IMethod method = (IMethod)or.GetBestCandidateWithSubstitutedTypeArguments(); IMethod method = (IMethod)or.GetBestCandidateWithSubstitutedTypeArguments();

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

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

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

@ -183,6 +183,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary> /// </summary>
public bool AllowOptionalParameters { get; set; } 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> /// <summary>
/// Gets/Sets whether ConversionResolveResults created by this OverloadResolution /// Gets/Sets whether ConversionResolveResults created by this OverloadResolution
/// instance apply overflow checking. /// instance apply overflow checking.
@ -649,22 +654,32 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
continue; continue;
} }
ReferenceKind paramRefKind = candidate.Parameters[parameterIndex].ReferenceKind;
if (arguments[i] is ByReferenceResolveResult brrr) if (arguments[i] is ByReferenceResolveResult brrr)
{ {
if (brrr.ReferenceKind != candidate.Parameters[parameterIndex].ReferenceKind) if (brrr.ReferenceKind != paramRefKind)
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch); candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
} }
else if (arguments[i] is OutVarResolveResult) else if (arguments[i] is OutVarResolveResult)
{ {
if (candidate.Parameters[parameterIndex].ReferenceKind != ReferenceKind.Out) if (paramRefKind != ReferenceKind.Out)
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch); candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
// 'out var decl' arguments are compatible with any out parameter // 'out var decl' arguments are compatible with any out parameter
continue; continue;
} }
else 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); candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
}
} }
IType parameterType = candidate.ParameterTypes[parameterIndex]; IType parameterType = candidate.ParameterTypes[parameterIndex];
Conversion c = conversions.ImplicitConversion(arguments[i], parameterType); Conversion c = conversions.ImplicitConversion(arguments[i], parameterType);

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

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

Loading…
Cancel
Save