Skip to content

Commit 2ca6e22

Browse files
authored
Merge pull request #3527 from jjonescz/allows-ref-struct
Support `allows ref struct` constraint
2 parents 0d8a85c + 2357d00 commit 2ca6e22

File tree

15 files changed

+84
-2
lines changed

15 files changed

+84
-2
lines changed

ICSharpCode.Decompiler.Tests/DisassemblerPrettyTestRunner.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ public void AllFilesHaveTests()
5252
}
5353
}
5454

55+
[Test]
56+
public async Task GenericConstraints()
57+
{
58+
await Run();
59+
}
60+
5561
[Test]
5662
public async Task SecurityDeclarations()
5763
{

ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<None Include="TestCases\Correctness\StackTests.il" />
9292
<None Include="TestCases\Correctness\StackTypes.il" />
9393
<None Include="TestCases\Correctness\Uninit.vb" />
94+
<None Include="TestCases\Disassembler\Pretty\GenericConstraints.il" />
9495
<None Include="TestCases\Disassembler\Pretty\InterfaceImplAttributes.il" />
9596
<None Include="TestCases\Disassembler\Pretty\SortMembers.expected.il" />
9697
<None Include="TestCases\Disassembler\Pretty\SortMembers.il" />

ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ async Task Run([CallerMemberName] string testName = null, AssemblerOptions asmOp
792792
configureDecompiler?.Invoke(settings);
793793
var decompiled = await Tester.DecompileCSharp(exeFile, settings).ConfigureAwait(false);
794794

795-
// 3. Compile
795+
// 3. Compare
796796
CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).Append("EXPECTED_OUTPUT").ToArray());
797797
Tester.RepeatOnIOError(() => File.Delete(decompiled));
798798
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
.assembly extern mscorlib
2+
{
3+
.publickeytoken = (
4+
b7 7a 5c 56 19 34 e0 89
5+
)
6+
.ver 4:0:0:0
7+
}
8+
.assembly GenericConstraints
9+
{
10+
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = (
11+
01 00 07 31 2e 30 2e 30 2e 30 00 00
12+
)
13+
.hash algorithm 0x00008004 // SHA1
14+
.ver 1:0:0:0
15+
}
16+
17+
.module GenericConstraints.dll
18+
.imagebase 0x10000000
19+
.file alignment 0x00000200
20+
.stackreserve 0x00100000
21+
.subsystem 0x0003 // WindowsCui
22+
.corflags 0x00000001 // ILOnly
23+
24+
.class private auto ansi '<Module>'
25+
{
26+
} // end of class <Module>
27+
28+
.class public auto ansi beforefieldinit TestType`1<byreflike T>
29+
extends [mscorlib]System.Object
30+
{
31+
// Methods
32+
.method public hidebysig specialname rtspecialname
33+
instance void .ctor () cil managed
34+
{
35+
// Method begins at RVA 0x2050
36+
// Header size: 1
37+
// Code size: 7 (0x7)
38+
.maxstack 8
39+
40+
IL_0000: ldarg.0
41+
IL_0001: call instance void [mscorlib]System.Object::.ctor()
42+
IL_0006: ret
43+
} // end of method TestType::.ctor
44+
45+
} // end of class TestType

ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,12 @@ public unsafe static int UnmanagedConstraint<T>() where T : unmanaged
293293
}
294294
#endif
295295

296+
#if NET90
297+
public static void AllowsRefStruct<T>() where T : allows ref struct
298+
{
299+
}
300+
#endif
301+
296302
public static void Issue1959(int a, int b, int? c)
297303
{
298304
// This line requires parentheses around `a < b` to avoid a grammar ambiguity.

ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2465,7 +2465,7 @@ internal TypeParameterDeclaration ConvertTypeParameter(ITypeParameter tp)
24652465

24662466
internal Constraint ConvertTypeParameterConstraint(ITypeParameter tp)
24672467
{
2468-
if (!tp.HasDefaultConstructorConstraint && !tp.HasReferenceTypeConstraint && !tp.HasValueTypeConstraint && tp.NullabilityConstraint != Nullability.NotNullable && tp.DirectBaseTypes.All(IsObjectOrValueType))
2468+
if (!tp.HasDefaultConstructorConstraint && !tp.HasReferenceTypeConstraint && !tp.HasValueTypeConstraint && !tp.AllowsRefLikeType && tp.NullabilityConstraint != Nullability.NotNullable && tp.DirectBaseTypes.All(IsObjectOrValueType))
24692469
{
24702470
return null;
24712471
}
@@ -2518,6 +2518,10 @@ internal Constraint ConvertTypeParameterConstraint(ITypeParameter tp)
25182518
{
25192519
c.BaseTypes.Add(new PrimitiveType("new"));
25202520
}
2521+
if (tp.AllowsRefLikeType)
2522+
{
2523+
c.BaseTypes.Add(new PrimitiveType("allows ref struct"));
2524+
}
25212525
return c;
25222526
}
25232527

ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using ICSharpCode.Decompiler.DebugInfo;
2929
using ICSharpCode.Decompiler.IL;
3030
using ICSharpCode.Decompiler.Metadata;
31+
using ICSharpCode.Decompiler.TypeSystem;
3132

3233
namespace ICSharpCode.Decompiler.Disassembler
3334
{
@@ -1733,6 +1734,10 @@ void WriteTypeParameters(ITextOutput output, MetadataFile module, MetadataGeneri
17331734
{
17341735
output.Write("valuetype ");
17351736
}
1737+
if ((gp.Attributes & TypeUtils.AllowByRefLike) == TypeUtils.AllowByRefLike)
1738+
{
1739+
output.Write("byreflike ");
1740+
}
17361741
if ((gp.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) == GenericParameterAttributes.DefaultConstructorConstraint)
17371742
{
17381743
output.Write(".ctor ");

ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ public interface ITypeParameter : IType, ISymbol
9797
/// </summary>
9898
bool HasUnmanagedConstraint { get; }
9999

100+
/// <summary>
101+
/// <see langword="true"/> if the <c>allows ref struct</c> constraint is specified for the type parameter.
102+
/// </summary>
103+
bool AllowsRefLikeType { get; }
104+
100105
/// <summary>
101106
/// Nullability of the reference type constraint. (e.g. "where T : class?").
102107
///

ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ IReadOnlyCollection<IType> CalculateEffectiveInterfaceSet()
175175
public abstract bool HasReferenceTypeConstraint { get; }
176176
public abstract bool HasValueTypeConstraint { get; }
177177
public abstract bool HasUnmanagedConstraint { get; }
178+
public abstract bool AllowsRefLikeType { get; }
178179
public abstract Nullability NullabilityConstraint { get; }
179180

180181
public TypeKind Kind {

ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultTypeParameter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public DefaultTypeParameter(
7171
public override bool HasReferenceTypeConstraint => hasReferenceTypeConstraint;
7272
public override bool HasDefaultConstructorConstraint => hasDefaultConstructorConstraint;
7373
public override bool HasUnmanagedConstraint => false;
74+
public override bool AllowsRefLikeType => false;
7475
public override Nullability NullabilityConstraint => nullabilityConstraint;
7576

7677
public override IReadOnlyList<TypeConstraint> TypeConstraints { get; }

0 commit comments

Comments
 (0)