diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs index 686233381..dfc3eb8ac 100644 --- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs @@ -792,7 +792,7 @@ namespace ICSharpCode.Decompiler.Tests configureDecompiler?.Invoke(settings); var decompiled = await Tester.DecompileCSharp(exeFile, settings).ConfigureAwait(false); - // 3. Compile + // 3. Compare CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).Append("EXPECTED_OUTPUT").ToArray()); Tester.RepeatOnIOError(() => File.Delete(decompiled)); } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs index c02845c9c..e9875da6d 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs @@ -293,6 +293,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } #endif +#if NET90 + public static void AllowsRefStruct() where T : allows ref struct + { + } +#endif + public static void Issue1959(int a, int b, int? c) { // This line requires parentheses around `a < b` to avoid a grammar ambiguity. diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index 119185bc5..05a62d68d 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -2465,7 +2465,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax internal Constraint ConvertTypeParameterConstraint(ITypeParameter tp) { - if (!tp.HasDefaultConstructorConstraint && !tp.HasReferenceTypeConstraint && !tp.HasValueTypeConstraint && tp.NullabilityConstraint != Nullability.NotNullable && tp.DirectBaseTypes.All(IsObjectOrValueType)) + if (!tp.HasDefaultConstructorConstraint && !tp.HasReferenceTypeConstraint && !tp.HasValueTypeConstraint && !tp.AllowsRefLikeType && tp.NullabilityConstraint != Nullability.NotNullable && tp.DirectBaseTypes.All(IsObjectOrValueType)) { return null; } @@ -2518,6 +2518,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { c.BaseTypes.Add(new PrimitiveType("new")); } + if (tp.AllowsRefLikeType) + { + c.BaseTypes.Add(new PrimitiveType("allows ref struct")); + } return c; } diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 76affb1ca..81365516d 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -28,6 +28,7 @@ using System.Threading; using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.Disassembler { @@ -1733,8 +1734,7 @@ namespace ICSharpCode.Decompiler.Disassembler { output.Write("valuetype "); } - const GenericParameterAttributes allowByRefLike = (GenericParameterAttributes)0x0020; - if ((gp.Attributes & allowByRefLike) == allowByRefLike) + if ((gp.Attributes & TypeUtils.AllowByRefLike) == TypeUtils.AllowByRefLike) { output.Write("byreflike "); } diff --git a/ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs index 09bed7da3..8748d227b 100644 --- a/ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs @@ -97,6 +97,11 @@ namespace ICSharpCode.Decompiler.TypeSystem /// bool HasUnmanagedConstraint { get; } + /// + /// if the allows ref struct constraint is specified for the type parameter. + /// + bool AllowsRefLikeType { get; } + /// /// Nullability of the reference type constraint. (e.g. "where T : class?"). /// diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs index 289fc35e7..87f6ad524 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs @@ -175,6 +175,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public abstract bool HasReferenceTypeConstraint { get; } public abstract bool HasValueTypeConstraint { get; } public abstract bool HasUnmanagedConstraint { get; } + public abstract bool AllowsRefLikeType { get; } public abstract Nullability NullabilityConstraint { get; } public TypeKind Kind { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultTypeParameter.cs index 3e4398ec3..a2c225a53 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultTypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultTypeParameter.cs @@ -71,6 +71,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public override bool HasReferenceTypeConstraint => hasReferenceTypeConstraint; public override bool HasDefaultConstructorConstraint => hasDefaultConstructorConstraint; public override bool HasUnmanagedConstraint => false; + public override bool AllowsRefLikeType => false; public override Nullability NullabilityConstraint => nullabilityConstraint; public override IReadOnlyList TypeConstraints { get; } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs index 16f96c6e5..dc0e73814 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs @@ -179,6 +179,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation bool ITypeParameter.HasReferenceTypeConstraint => false; bool ITypeParameter.HasValueTypeConstraint => false; bool ITypeParameter.HasUnmanagedConstraint => false; + bool ITypeParameter.AllowsRefLikeType => false; Nullability ITypeParameter.NullabilityConstraint => Nullability.Oblivious; IReadOnlyList ITypeParameter.TypeConstraints => EmptyList.Instance; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs index 282e5c2bf..8fab173a9 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs @@ -119,6 +119,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public override bool HasDefaultConstructorConstraint => (attr & GenericParameterAttributes.DefaultConstructorConstraint) != 0; public override bool HasReferenceTypeConstraint => (attr & GenericParameterAttributes.ReferenceTypeConstraint) != 0; public override bool HasValueTypeConstraint => (attr & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0; + public override bool AllowsRefLikeType => (attr & TypeUtils.AllowByRefLike) != 0; public override bool HasUnmanagedConstraint { get { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/NullabilityAnnotatedType.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/NullabilityAnnotatedType.cs index abfd5b184..141e5fe9f 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/NullabilityAnnotatedType.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/NullabilityAnnotatedType.cs @@ -115,6 +115,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation bool ITypeParameter.HasReferenceTypeConstraint => baseType.HasReferenceTypeConstraint; bool ITypeParameter.HasValueTypeConstraint => baseType.HasValueTypeConstraint; bool ITypeParameter.HasUnmanagedConstraint => baseType.HasUnmanagedConstraint; + bool ITypeParameter.AllowsRefLikeType => baseType.AllowsRefLikeType; Nullability ITypeParameter.NullabilityConstraint => baseType.NullabilityConstraint; IReadOnlyList ITypeParameter.TypeConstraints => baseType.TypeConstraints; SymbolKind ISymbol.SymbolKind => SymbolKind.TypeParameter; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs index e72d6eeb7..0bcf4a49c 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs @@ -278,6 +278,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public override bool HasReferenceTypeConstraint => baseTp.HasReferenceTypeConstraint; public override bool HasDefaultConstructorConstraint => baseTp.HasDefaultConstructorConstraint; public override bool HasUnmanagedConstraint => baseTp.HasUnmanagedConstraint; + public override bool AllowsRefLikeType => baseTp.AllowsRefLikeType; public override Nullability NullabilityConstraint => baseTp.NullabilityConstraint; diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs b/ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs index d2176704a..687dcf27d 100644 --- a/ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs +++ b/ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs @@ -16,6 +16,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System.Reflection; + using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -25,6 +27,8 @@ namespace ICSharpCode.Decompiler.TypeSystem { public const int NativeIntSize = 6; // between 4 (Int32) and 8 (Int64) + public const GenericParameterAttributes AllowByRefLike = (GenericParameterAttributes)0x0020; + /// /// Gets the size (in bytes) of the input type. /// Returns NativeIntSize for pointer-sized types.