diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs index ccd262709..1290b31e0 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs @@ -35,6 +35,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness Issue1281(); Issue1747(); CallAmbiguousOutParam(); + CallWithInParam(); } #region ConstructorTest @@ -270,6 +271,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness AmbiguousOutParam(out b); } #endregion + + #region In Parameter + static void CallWithInParam() + { + Console.WriteLine("OverloadSetWithInParam:"); +#if CS72 + OverloadSetWithInParam(1); + OverloadSetWithInParam(2L); + int i = 3; + OverloadSetWithInParam(in i); +#endif + } + +#if CS72 + static void OverloadSetWithInParam(in int i) + { + Console.WriteLine("in int " + i); + } + static void OverloadSetWithInParam(long l) + { + Console.WriteLine("long " + l); + } +#endif + #endregion } class IndexerTests diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs index a91ca7a82..c34a6a183 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs @@ -131,4 +131,51 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { } } + +#if CS72 + internal class T03ConversionWithInArgument + { + private struct T + { + private byte dummy; + + public static implicit operator T(in int val) + { + return default(T); + } + + public static explicit operator T(in long val) + { + return default(T); + } + } + + private struct U + { + private byte dummy; + + public static implicit operator T(in U u) + { + return default(T); + } + + public static explicit operator int(in U u) + { + return 0; + } + } + + private void UseT(T t) + { + } + + private int Test(int i, long l, U u) + { + UseT(i); + UseT((T)l); + UseT(u); + return (int)u; + } + } +#endif } diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index f27fabec1..ff5122676 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -1154,6 +1154,12 @@ namespace ICSharpCode.Decompiler.CSharp argument = argument.ConvertTo(method.Parameters[0].Type, expressionBuilder); conv = conversions.ImplicitConversion(argument.Type, targetType); } + if (argument.Expression is DirectionExpression { FieldDirection: FieldDirection.In, Expression: var lvalueExpr }) + { + // `(TargetType)(in arg)` is invalid syntax. + // Also, `f(in arg)` is invalid when there's an implicit conversion involved. + argument = argument.UnwrapChild(lvalueExpr); + } return new CastExpression(expressionBuilder.ConvertType(targetType), argument.Expression) .WithRR(new ConversionResolveResult(targetType, argument.ResolveResult, conv)); } diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs index b88829c78..1fa11555c 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs @@ -1103,6 +1103,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver } } + static IType UnderlyingTypeForConversion(IType type) + { + if (type.Kind == TypeKind.ByReference) + { + type = ((ByReferenceType)type).ElementType; + } + return NullableType.GetUnderlyingType(type); + } + List GetApplicableConversionOperators(ResolveResult fromResult, IType fromType, IType toType, bool isExplicit) { // Find the candidate operators: @@ -1112,13 +1121,17 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver else opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1; - var operators = NullableType.GetUnderlyingType(fromType).GetMethods(opFilter) - .Concat(NullableType.GetUnderlyingType(toType).GetMethods(opFilter)).Distinct(); + var operators = UnderlyingTypeForConversion(fromType).GetMethods(opFilter) + .Concat(UnderlyingTypeForConversion(toType).GetMethods(opFilter)).Distinct(); // Determine whether one of them is applicable: List result = new List(); foreach (IMethod op in operators) { IType sourceType = op.Parameters[0].Type; + if (sourceType.Kind == TypeKind.ByReference && op.Parameters[0].IsIn && fromType.Kind != TypeKind.ByReference) + { + sourceType = ((ByReferenceType)sourceType).ElementType; + } IType targetType = op.ReturnType; // Try if the operator is applicable: bool isApplicable;