diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Conversions.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Conversions.cs index 01b76929d..59e94ed4b 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Conversions.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Conversions.cs @@ -19,6 +19,7 @@ // #include "../../../ICSharpCode.Decompiler/Util/CSharpPrimitiveCast.cs" using System; +using System.Runtime.CompilerServices; using ICSharpCode.Decompiler.Util; @@ -111,6 +112,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness Console.WriteLine(ReadZeroTerminatedString("Hello World!".Length)); C1.Test(); +#if ROSLYN2 && !NET40 + C3.Run(); +#endif } static void RunTest(bool checkForOverflow) @@ -199,4 +203,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness return new C1(); } } + +#if ROSLYN2 && !NET40 + class C3 + { + [InlineArray(4)] struct MyArray { private int elem; } + + static void Foo(object o) + { + Console.WriteLine("Foo(object) called"); + } + + static void Foo(ReadOnlySpan o) + { + Console.WriteLine("Foo(ReadOnlySpan) called"); + } + + static void Test(MyArray arr) + { + Foo((object)arr); + } + + public static void Run() + { + Console.WriteLine("C3.Run() called"); + Test(default); + } + } +#endif } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineArrayTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineArrayTests.cs index 79b800c39..886947d31 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineArrayTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineArrayTests.cs @@ -91,9 +91,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty Byte16 buffer2 = GetByte16(); Receiver((ReadOnlySpan)buffer2); Byte16 buffer3 = GetByte16(); - ReceiverSpan((Span)buffer3); + ReceiverSpan(buffer3); Byte16 buffer4 = GetByte16(); - ReceiverReadOnlySpan((ReadOnlySpan)buffer4); + ReceiverReadOnlySpan(buffer4); } public Byte16 GetByte16() diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs index f190a554f..0d1789ea7 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs @@ -230,12 +230,20 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver if (c != Conversion.None) return c; } + if ((toType.IsKnownType(KnownTypeCode.SpanOfT) || toType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT)) + && fromType.IsInlineArrayType()) + { + var @field = fromType.GetFields(f => !f.IsStatic, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); + var spanElementType = toType.TypeArguments[0]; + if (field != null && IdentityConversion(field.ReturnType, spanElementType)) + return Conversion.InlineArrayConversion; + } return Conversion.None; } /// /// Gets whether the type 'fromType' is convertible to 'toType' - /// using one of the conversions allowed when satisying constraints (§4.4.4) + /// using one of the conversions allowed when satisfying constraints (§4.4.4) /// public bool IsConstraintConvertible(IType fromType, IType toType) { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs index 59d2c19eb..a9e59e0d9 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs @@ -112,11 +112,14 @@ namespace ICSharpCode.Decompiler.TypeSystem // C# 11 attributes: RequiredAttribute, + + // C# 12 attributes: + InlineArray, } public static class KnownAttributes { - internal const int Count = (int)KnownAttribute.RequiredAttribute + 1; + internal const int Count = (int)KnownAttribute.InlineArray + 1; static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{ default, @@ -186,6 +189,8 @@ namespace ICSharpCode.Decompiler.TypeSystem new TopLevelTypeName("System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute"), // C# 11 attributes: new TopLevelTypeName("System.Runtime.CompilerServices", "RequiredMemberAttribute"), + // C# 12 attributes: + new TopLevelTypeName("System.Runtime.CompilerServices", "InlineArrayAttribute"), }; public static ref readonly TopLevelTypeName GetTypeName(this KnownAttribute attr) diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs index d4009bb31..54cfaf9a4 100644 --- a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs +++ b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs @@ -306,6 +306,16 @@ namespace ICSharpCode.Decompiler.TypeSystem } } + public static bool IsInlineArrayType(this IType type) + { + if (type.Kind != TypeKind.Struct) + return false; + var td = type.GetDefinition(); + if (td == null) + return false; + return td.HasAttribute(KnownAttribute.InlineArray); + } + /// /// Gets whether the type is the specified known type. /// For generic known types, this returns true for any parameterization of the type (and also for the definition itself).