diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Attributes.OnlyKeepUsedTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Attributes.OnlyKeepUsedTests.g.cs
index d2be67138b5d4..893331bcc141b 100644
--- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Attributes.OnlyKeepUsedTests.g.cs
+++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Attributes.OnlyKeepUsedTests.g.cs
@@ -64,7 +64,13 @@ public Task MethodWithUnmanagedConstraint ()
}
[Fact]
- public Task NullableOnConstraints ()
+ public Task NullableOnConstraintsKept ()
+ {
+ return RunTest (allowMissingWarnings: true);
+ }
+
+ [Fact]
+ public Task NullableOnConstraintsRemoved ()
{
return RunTest (allowMissingWarnings: true);
}
diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/GenericsTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/GenericsTests.g.cs
index 90356bd4df1ee..b61127a3e5542 100644
--- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/GenericsTests.g.cs
+++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/GenericsTests.g.cs
@@ -15,6 +15,12 @@ public Task ArrayVariantCasting ()
return RunTest (allowMissingWarnings: true);
}
+ [Fact]
+ public Task ByRefLike ()
+ {
+ return RunTest (allowMissingWarnings: true);
+ }
+
[Fact]
public Task CorrectOverloadedMethodGetsStrippedInGenericClass ()
{
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnConstraintAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnConstraintAttribute.cs
new file mode 100644
index 0000000000000..ee2eca3bc6099
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnConstraintAttribute.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ [AttributeUsage (AttributeTargets.GenericParameter, Inherited = false)]
+ public class KeptAttributeOnConstraintAttribute : KeptAttribute
+ {
+ public KeptAttributeOnConstraintAttribute (Type constraintType, Type attributeType)
+ {
+ }
+ }
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptGenericParamAttributesAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptGenericParamAttributesAttribute.cs
new file mode 100644
index 0000000000000..bb3992586b686
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptGenericParamAttributesAttribute.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Reflection;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ [AttributeUsage (AttributeTargets.All, Inherited = false)]
+ public class KeptGenericParamAttributesAttribute : KeptAttribute
+ {
+ public KeptGenericParamAttributesAttribute (GenericParameterAttributes attributes)
+ {
+ }
+ }
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs
index 713ed17db49d5..6b58c1dbf0de9 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs
@@ -1,3 +1,4 @@
+using System.Reflection;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Metadata;
@@ -19,7 +20,10 @@ public static void Main ()
///
///
[Kept]
- static void Method () where T : unmanaged
+ static void Method<
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > () where T : unmanaged
{
}
}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsKept.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsKept.cs
new file mode 100644
index 0000000000000..2d7f9d0df6b55
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsKept.cs
@@ -0,0 +1,59 @@
+#nullable enable
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed
+{
+ [SetupCSharpCompilerToUse ("csc")]
+ [SetupLinkerTrimMode ("link")]
+ public class NullableOnConstraintsKept
+ {
+ public static void Main ()
+ {
+ Test.Run ();
+ }
+
+ [Kept]
+ [KeptInterface (typeof (I))]
+ class Test : I
+ {
+ [Kept]
+ public static void Run ()
+ {
+ new C ();
+ Method ();
+ }
+
+ [Kept]
+ [KeptAttributeAttribute (typeof (NullableContextAttribute))]
+ static T? Method<
+ [KeptGenericParamAttributes (GenericParameterAttributes.ReferenceTypeConstraint)]
+ [KeptAttributeAttribute (typeof (NullableAttribute))]
+ T
+ > ()
+ where T : class, I?
+ {
+ return default;
+ }
+ }
+
+ [Kept]
+ interface I
+ {
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ class C<
+ [KeptAttributeOnConstraint (typeof (I), typeof (NullableAttribute))]
+ T
+ >
+ where T : I?
+ {
+ }
+ }
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraints.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs
similarity index 63%
rename from src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraints.cs
rename to src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs
index 0151df2caa1ac..dca7d00cc0ef4 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraints.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs
@@ -1,5 +1,7 @@
#nullable enable
+using System.Reflection;
+using System.Runtime.CompilerServices;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Metadata;
@@ -9,7 +11,7 @@ namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed
[SetupLinkerArgument ("--used-attrs-only", "true")]
[SetupLinkerTrimMode ("link")]
[IgnoreDescriptors (false)]
- public class NullableOnConstraints
+ public class NullableOnConstraintsRemoved
{
public static void Main ()
{
@@ -28,21 +30,24 @@ public static void Run ()
}
[Kept]
- static T? Method () where T : class, I?
+ static T? Method<
+ [KeptGenericParamAttributes (GenericParameterAttributes.ReferenceTypeConstraint)]
+ T
+ > () where T : class, I?
{
return default;
}
}
- }
- [Kept]
- interface I
- {
- }
+ [Kept]
+ interface I
+ {
+ }
- [Kept]
- [KeptMember (".ctor()")]
- class C where T : I?
- {
+ [Kept]
+ [KeptMember (".ctor()")]
+ class C where T : I?
+ {
+ }
}
}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs
index e1764eb986fa5..8f11a98281eee 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/NullableAnnotations.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Helpers;
using DAM = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute;
@@ -131,14 +132,22 @@ static void UnderlyingTypeOfUnannotatedGenericParameterRequiresProperties () where T : struct
+ static void NullableOfAnnotatedGenericParameterRequiresPublicProperties<
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ [KeptAttributeAttribute (typeof (DAM))]
+ [DAM (DAMT.PublicProperties)]
+ T
+ > () where T : struct
{
Nullable.GetUnderlyingType (typeof (Nullable)).RequiresPublicProperties ();
}
[Kept]
[ExpectedWarning ("IL2087")]
- static void NullableOfUnannotatedGenericParameterRequiresPublicProperties () where T : struct
+ static void NullableOfUnannotatedGenericParameterRequiresPublicProperties<
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > () where T : struct
{
Nullable.GetUnderlyingType (typeof (Nullable)).RequiresPublicProperties ();
}
@@ -240,7 +249,12 @@ static void DamOnNullableKeepsUnderlyingMembers ()
}
[Kept]
- static void UnderlyingTypeOfCreatedNullableOfAnnotatedTRequiresPublicProperties<[KeptAttributeAttribute (typeof (DAM))][DAM (DAMT.PublicProperties)] T> () where T : struct
+ static void UnderlyingTypeOfCreatedNullableOfAnnotatedTRequiresPublicProperties<
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ [KeptAttributeAttribute (typeof (DAM))]
+ [DAM (DAMT.PublicProperties)]
+ T
+ > () where T : struct
{
Type t = typeof (Nullable);
t = Nullable.GetUnderlyingType (t);
@@ -262,13 +276,20 @@ struct StructWithFieldsReferencedThroughDamOnNullable
[Kept]
[ExpectedWarning ("IL2091")]
- static void NullableOfUnannotatedGenericParamPassedAsGenericParamRequiresPublicFields () where T : struct
+ static void NullableOfUnannotatedGenericParamPassedAsGenericParamRequiresPublicFields<
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > () where T : struct
{
RequirePublicFieldsOnGenericParam> ();
}
[Kept]
- static void NullableOfAnnotatedGenericParamPassedAsGenericParamRequiresPublicFields<[KeptAttributeAttribute (typeof (DAM))][DAM (DAMT.PublicFields)] T> () where T : struct
+ static void NullableOfAnnotatedGenericParamPassedAsGenericParamRequiresPublicFields<
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ [KeptAttributeAttribute (typeof (DAM))]
+ [DAM (DAMT.PublicFields)] T
+ > () where T : struct
{
RequirePublicFieldsOnGenericParam> ();
}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs
new file mode 100644
index 0000000000000..af6de6f7fdb4c
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Generics
+{
+ [IgnoreTestCase ("Ignore in NativeAOT, see https://github.com/dotnet/runtime/issues/82447", IgnoredBy = Tool.NativeAot)]
+ [KeptAttributeAttribute (typeof (IgnoreTestCaseAttribute), By = Tool.Trimmer)]
+ class ByRefLike
+ {
+ static void Main ()
+ {
+ Test ();
+ }
+
+ [Kept]
+ static void Test ()
+ {
+ G g = new ();
+ }
+
+ [Kept]
+ [KeptAttributeAttribute (typeof (IsByRefLikeAttribute))]
+ [KeptAttributeAttribute (typeof (ObsoleteAttribute))] // Signals this is unsupported to older compilers
+ [KeptAttributeAttribute (typeof (CompilerFeatureRequiredAttribute))]
+ ref struct RefStruct {
+ }
+
+ [Kept]
+ [KeptAttributeAttribute (typeof (IsByRefLikeAttribute))]
+ [KeptAttributeAttribute (typeof (ObsoleteAttribute))] // Signals this is unsupported to older compilers
+ [KeptAttributeAttribute (typeof (CompilerFeatureRequiredAttribute))]
+ ref struct G<
+ [KeptGenericParamAttributes (GenericParameterAttributes.AllowByRefLike)]
+ T
+ > where T : allows ref struct {
+ [Kept]
+ public T t;
+ }
+ }
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/NewConstraintOnClass.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/NewConstraintOnClass.cs
index 0acdf9191b65c..eda9e3e09dabe 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/NewConstraintOnClass.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/NewConstraintOnClass.cs
@@ -1,4 +1,5 @@
-using System.Runtime.CompilerServices;
+using System.Reflection;
+using System.Runtime.CompilerServices;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
namespace Mono.Linker.Tests.Cases.Generics
@@ -36,7 +37,10 @@ public void Foo ()
[Kept]
[KeptMember (".ctor()")]
- class WithConstraint where T : new()
+ class WithConstraint<
+ [KeptGenericParamAttributes (GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > where T : new()
{
}
@@ -70,7 +74,10 @@ public void Foo ()
[Kept]
[KeptMember (".ctor()")]
- class WithConstraint where T : struct
+ class WithConstraint<
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > where T : struct
{
}
@@ -104,7 +111,11 @@ public void Foo ()
[Kept]
[KeptMember (".ctor()")]
- class WithConstraint<[KeptAttributeAttribute (typeof (IsUnmanagedAttribute))] T> where T : unmanaged
+ class WithConstraint<
+ [KeptAttributeAttribute (typeof (IsUnmanagedAttribute))]
+ [KeptGenericParamAttributes (GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > where T : unmanaged
{
}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/VariantCasting.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/VariantCasting.cs
index bc82aa51c4bfb..cc8bd7c637565 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/VariantCasting.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/VariantCasting.cs
@@ -1,11 +1,16 @@
-using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using System.Reflection;
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
namespace Mono.Linker.Tests.Cases.Generics
{
public class VariantCasting
{
[Kept]
- interface IVariant { }
+ interface IVariant<
+ [KeptGenericParamAttributes (GenericParameterAttributes.Covariant)]
+ out T
+ > { }
[Kept]
interface IFoo { }
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnValueType/StructWithNestedStructImplementingInterface.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnValueType/StructWithNestedStructImplementingInterface.cs
index 0bdc4a2a4dbb2..f4c06c40e1b11 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnValueType/StructWithNestedStructImplementingInterface.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnValueType/StructWithNestedStructImplementingInterface.cs
@@ -1,4 +1,5 @@
using System;
+using System.Reflection;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnValueType
@@ -33,7 +34,10 @@ public interface IBuilder
}
[Kept]
- public interface IBuildable : IBuildable where T : IBuilder, new()
+ public interface IBuildable<
+ [KeptGenericParamAttributes (GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > : IBuildable where T : IBuilder, new()
{
}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/StaticAbstractInterfaceMethodsLibrary.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/StaticAbstractInterfaceMethodsLibrary.cs
index 7fcc3bf3c6e08..370a5c7dd538d 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/StaticAbstractInterfaceMethodsLibrary.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/StaticAbstractInterfaceMethodsLibrary.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using System.Reflection;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Helpers;
using Mono.Linker.Tests.Cases.Expectations.Metadata;
@@ -410,7 +411,10 @@ internal interface IStaticAndInstanceMethodsInternalUsed
}
[Kept]
- internal static void CallExplicitImplMethod () where T : IStaticAndInstanceMethods, new()
+ internal static void CallExplicitImplMethod<
+ [KeptGenericParamAttributes (GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > () where T : IStaticAndInstanceMethods, new()
{
T.StaticMethodExplicitImpl ();
IStaticAndInstanceMethods x = new T ();
@@ -418,7 +422,10 @@ internal interface IStaticAndInstanceMethodsInternalUsed
}
[Kept]
- internal static void CallExplicitImplMethodInternalUsed () where T : IStaticAndInstanceMethodsInternalUsed, new()
+ internal static void CallExplicitImplMethodInternalUsed<
+ [KeptGenericParamAttributes (GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > () where T : IStaticAndInstanceMethodsInternalUsed, new()
{
T.StaticMethodExplicitImpl ();
IStaticAndInstanceMethodsInternalUsed x = new T ();
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/VarianceBasic.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/VarianceBasic.cs
index 75ae157dc1848..727780e2434d4 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/VarianceBasic.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/StaticInterfaceMethods/VarianceBasic.cs
@@ -1,4 +1,5 @@
using System;
+using System.Reflection;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.StaticInterfaceMethods
@@ -11,13 +12,19 @@ static void Main ()
TestEntrypoint.Test ();
}
[Kept]
- public interface InterfaceScenario1
+ public interface InterfaceScenario1<
+ [KeptGenericParamAttributes (GenericParameterAttributes.Contravariant)]
+ in T
+ >
{
[Kept]
static abstract int Method ();
}
[Kept]
- public interface InterfaceScenario2
+ public interface InterfaceScenario2<
+ [KeptGenericParamAttributes (GenericParameterAttributes.Contravariant)]
+ in T
+ >
{
[Kept]
static abstract int Method ();
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
index 4aca2d5186185..70289934fe536 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ActivatorCreateInstance.cs
@@ -541,7 +541,10 @@ public TestCreateInstanceOfTWithNewConstraintType (int i)
}
[Kept]
- private static void TestCreateInstanceOfTWithNewConstraint () where T : new()
+ private static void TestCreateInstanceOfTWithNewConstraint<
+ [KeptGenericParamAttributes (GenericParameterAttributes.DefaultConstructorConstraint)]
+ T
+ > () where T : new()
{
Activator.CreateInstance ();
}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs
index 3dcd1b7fd1175..451cf28afbde4 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using System.Reflection;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
@@ -195,9 +196,11 @@ class TestType
[Kept]
[KeptMember (".cctor()")]
class Generic<
+ [KeptGenericParamAttributes (GenericParameterAttributes.DefaultConstructorConstraint)]
[KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
- [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
- TWithMethods> where TWithMethods : new()
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
+ TWithMethods
+ > where TWithMethods : new()
{
[Kept]
static TWithMethods ReturnAnnotated () { return new TWithMethods (); }
diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
index 6e45fbadcdb52..7d984ef2e4863 100644
--- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
@@ -1151,10 +1151,14 @@ IEnumerable VerifyGenericParameters (IGenericParameterProvider src, IGen
Assert.AreEqual (src.HasGenericParameters, linked.HasGenericParameters);
if (src.HasGenericParameters) {
for (int i = 0; i < src.GenericParameters.Count; ++i) {
- // TODO: Verify constraints
var srcp = src.GenericParameters[i];
var lnkp = linked.GenericParameters[i];
+ foreach (var err in VerifyGenericParameterConstraints (srcp, lnkp))
+ yield return err;
+ foreach (var err in VerifyGenericParameterAttributes (srcp, lnkp))
+ yield return err;
+
if (!compilerGenerated) {
foreach (var err in VerifyCustomAttributes (srcp, lnkp))
yield return err;
@@ -1176,6 +1180,67 @@ IEnumerable VerifyGenericParameters (IGenericParameterProvider src, IGen
}
}
+ IEnumerable VerifyGenericParameterConstraints (GenericParameter src, GenericParameter linked)
+ {
+ if (src.HasConstraints != linked.HasConstraints) {
+ yield return $"Mismatch in generic parameter constraints on {src} of {src.Owner}. Input has constraints?: {src.HasConstraints}, Output has constraints?: {linked.HasConstraints}";
+ yield break;
+ }
+
+ if (!src.HasConstraints)
+ yield break;
+
+ if (src.Constraints.Count != linked.Constraints.Count) {
+ yield return $"Mismatch in generic parameter constraint count on {src} of {src.Owner}. Input has {src.Constraints.Count} constraints, Output has {linked.Constraints.Count} constraints";
+ yield break;
+ }
+
+ // ILLink doesn't rewrite generic parameter constraint types, so just check they are identical to inputs.
+ for (int i = 0; i < src.Constraints.Count; i++) {
+ var srcConstraint = src.Constraints[i];
+ var linkedConstraint = linked.Constraints[i];
+ if (srcConstraint.ConstraintType.FullName != linkedConstraint.ConstraintType.FullName) {
+ yield return $"Mismatch in generic parameter constraint type. {src} constraint {i} is {srcConstraint.ConstraintType.FullName}, {linked} constraint {i} is {linkedConstraint.ConstraintType.FullName}";
+ }
+ }
+
+ // C# doesn't have syntax for annotating generic parameter constraints with arbitrary attributes,
+ // so expected attributes on generic parameter constraints are specified on the generic parameter itself.
+ HashSet<(string ConstraintType, string AttributeType)> expectedConstraintAttributes = src.CustomAttributes
+ .Where (a => IsKeptAttributeOnConstraint (a))
+ .Select (a => (a.ConstructorArguments[0].Value.ToString (), a.ConstructorArguments[1].Value.ToString ()))
+ .ToHashSet ();
+
+ HashSet<(string ConstraintType, string AttributeType)> linkedConstraintAttributes = linked.Constraints
+ .Where (c => c.HasCustomAttributes)
+ .SelectMany (c => c.CustomAttributes.Select (a => (c.ConstraintType.FullName, a.AttributeType.FullName)))
+ .ToHashSet ();
+
+ if (!expectedConstraintAttributes.SetEquals (linkedConstraintAttributes)) {
+ var missing = $"Missing: {string.Join (", ", expectedConstraintAttributes.Except (linkedConstraintAttributes).Select (c => $"{c.AttributeType} on {c.ConstraintType}"))}";
+ var extra = $"Extra: {string.Join (", ", linkedConstraintAttributes.Except (expectedConstraintAttributes).Select (c => $"{c.AttributeType} on {c.ConstraintType}"))}";
+ yield return string.Join (Environment.NewLine, $"Custom attributes on `{src}' generic parameter constraints are not matching:", missing, extra);
+ }
+
+ static bool IsKeptAttributeOnConstraint (CustomAttribute attr) {
+ if (attr.AttributeType.Name != nameof (KeptAttributeOnConstraintAttribute))
+ return false;
+
+ if (attr.ConstructorArguments.Count != 2)
+ throw new NotImplementedException ("Unexpected KeptCustomAttributeOnConstraintAttribute ctor variant");
+
+ return true;
+ }
+ }
+
+ IEnumerable VerifyGenericParameterAttributes (GenericParameter src, GenericParameter linked)
+ {
+ var expectedAttributes = (System.Reflection.GenericParameterAttributes) (GetCustomAttributeCtorValues