diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs index 1290b31e0..69f703a42 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs @@ -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(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 { 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 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 } diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs index 1fa11555c..86be39f38 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs @@ -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(); diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs b/ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs index 8951cb596..30529bbeb 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs @@ -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 or.AllowExpandingParams = allowExpandingParams; or.AllowOptionalParameters = allowOptionalParameters; or.CheckForOverflow = checkForOverflow; + or.AllowImplicitIn = allowImplicitIn; or.AddMethodLists(methodLists); diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs index b86c2854d..e2727948c 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs @@ -183,6 +183,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver /// public bool AllowOptionalParameters { get; set; } + /// + /// Gets/Sets whether a value argument can be passed to an `in` reference parameter. + /// + public bool AllowImplicitIn { get; set; } = true; + /// /// Gets/Sets whether ConversionResolveResults created by this OverloadResolution /// instance apply overflow checking. @@ -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); diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs index 5af195db5..1c02d9da6 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs @@ -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;