From 0ba07a16d6e5ef21bab10750573c4c75b278b72d Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 13 Jun 2024 22:19:52 +0000 Subject: [PATCH 1/5] Validate generic constraints in ILLink tests And add test for byref-like types --- .../Attributes.OnlyKeepUsedTests.g.cs | 8 ++- .../GenericsTests.g.cs | 6 ++ .../KeptAttributeOnConstraintAttribute.cs | 15 +++++ .../KeptGenericParamAttributesAttribute.cs | 16 +++++ .../MethodWithUnmanagedConstraint.cs | 7 +- .../OnlyKeepUsed/NullableOnConstraintsKept.cs | 59 ++++++++++++++++ ...nts.cs => NullableOnConstraintsRemoved.cs} | 28 +++++--- .../DataFlow/NullableAnnotations.cs | 31 +++++++-- .../Generics/ByRefLike.cs | 42 ++++++++++++ .../Generics/NewConstraintOnClass.cs | 19 ++++-- .../Generics/VariantCasting.cs | 9 ++- ...ctWithNestedStructImplementingInterface.cs | 7 +- .../StaticAbstractInterfaceMethodsLibrary.cs | 12 +++- .../StaticInterfaceMethods/VarianceBasic.cs | 12 +++- .../Reflection/ActivatorCreateInstance.cs | 5 +- .../Reflection/ObjectGetType.cs | 7 +- .../TestCasesRunner/AssemblyChecker.cs | 67 ++++++++++++++++++- 17 files changed, 317 insertions(+), 33 deletions(-) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeOnConstraintAttribute.cs create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptGenericParamAttributesAttribute.cs create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsKept.cs rename src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/{NullableOnConstraints.cs => NullableOnConstraintsRemoved.cs} (62%) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs 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 d2be67138b5d48..893331bcc141b9 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 90356bd4df1ee3..b61127a3e55423 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 00000000000000..ee2eca3bc60993 --- /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 00000000000000..bb3992586b686a --- /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 713ed17db49d54..2deaa8e0204dc8 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,5 @@ +using System.Reflection; + using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; @@ -19,7 +21,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 00000000000000..2d7f9d0df6b55c --- /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 62% 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 0151df2caa1ace..f87d6018d426cc 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,8 @@ #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 +12,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 +31,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 e1764eb986fa51..8f11a98281eee7 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 00000000000000..7a4e5c4a69d5fe --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs @@ -0,0 +1,42 @@ +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 +{ + 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 0acdf9191b65c5..eda9e3e09dabe3 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 bc82aa51c4bfbb..cc8bd7c6375653 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 0bdc4a2a4dbb2d..4d043ac43e782d 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,6 @@ using System; +using System.Reflection; + using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnValueType @@ -33,7 +35,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 7fcc3bf3c6e08b..83ac88620e808b 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,8 @@ // 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 +412,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 +423,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 75ae157dc1848b..b73e61f135bc9e 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,6 @@ using System; +using System.Reflection; + using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.StaticInterfaceMethods @@ -11,13 +13,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 4aca2d51861850..70289934fe5367 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 3dcd1b7fd11759..451cf28afbde40 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 6e45fbadcdb529..7d984ef2e48637 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 (src, nameof (KeptGenericParamAttributesAttribute)).FirstOrDefault () ?? System.Reflection.GenericParameterAttributes.None); + var linkedAttributes = (System.Reflection.GenericParameterAttributes) linked.Attributes; + if (expectedAttributes != linkedAttributes) + yield return $"Mismatch in generic parameter attributes on {src} of {src.Owner}. Expected: {expectedAttributes}, Output: {linkedAttributes}"; + } + IEnumerable VerifyParameters (IMethodSignature src, IMethodSignature linked, bool compilerGenerated) { if (src.HasParameters != linked.HasParameters) From 555b9be5bd4254357c374bfa2edf3ba76fdde0ae Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 13 Jun 2024 16:33:40 -0700 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> --- .../Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs | 1 - .../OnValueType/StructWithNestedStructImplementingInterface.cs | 1 - .../StaticAbstractInterfaceMethodsLibrary.cs | 1 - .../StaticInterfaceMethods/VarianceBasic.cs | 1 - 4 files changed, 4 deletions(-) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs index f87d6018d426cc..dca7d00cc0ef4e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraintsRemoved.cs @@ -2,7 +2,6 @@ using System.Reflection; using System.Runtime.CompilerServices; - using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; 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 4d043ac43e782d..f4c06c40e1b11c 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,6 +1,5 @@ using System; using System.Reflection; - using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnValueType 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 83ac88620e808b..370a5c7dd538d5 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 @@ -3,7 +3,6 @@ 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; 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 b73e61f135bc9e..727780e2434d42 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,6 +1,5 @@ using System; using System.Reflection; - using Mono.Linker.Tests.Cases.Expectations.Assertions; namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.StaticInterfaceMethods From e19c5932373d7572922b8bccc8f368a88230b362 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 13 Jun 2024 16:34:17 -0700 Subject: [PATCH 3/5] Update src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs --- .../Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs | 1 - 1 file changed, 1 deletion(-) 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 2deaa8e0204dc8..6b58c1dbf0de9c 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,5 +1,4 @@ using System.Reflection; - using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; From 25bd9caf00ff47f8f3e129fc191e26e46a06a67b Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 14 Jun 2024 18:40:18 +0000 Subject: [PATCH 4/5] Ignore test for NativeAOT --- .../illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs | 1 + 1 file changed, 1 insertion(+) 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 index 7a4e5c4a69d5fe..649cc7ff88b16e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs @@ -7,6 +7,7 @@ namespace Mono.Linker.Tests.Cases.Generics { + [IgnoreTestCase ("Ignore in NativeAOT, see https://github.com/dotnet/runtime/issues/82447", IgnoredBy = Tool.NativeAot)] class ByRefLike { static void Main () From 03c0890cf59a35cf852bfbac95b3ff94467bb954 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 14 Jun 2024 19:42:42 +0000 Subject: [PATCH 5/5] Expect IgnoreTestCaseAttribute --- .../illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs | 1 + 1 file changed, 1 insertion(+) 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 index 649cc7ff88b16e..af6de6f7fdb4cd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/ByRefLike.cs @@ -8,6 +8,7 @@ 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 ()