diff --git a/eng/Subsets.props b/eng/Subsets.props
index a058a944b993ad..b27d1e55a8bdd9 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -150,6 +150,7 @@
$(CoreClrProjectRoot)src\tools\dotnet-pgo\dotnet-pgo.csproj;
$(CoreClrProjectRoot)src\tools\r2rtest\R2RTest.csproj" Category="clr" BuildInParallel="true" />
+
diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs
new file mode 100644
index 00000000000000..6d611fd7db0f0f
--- /dev/null
+++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ArrayOfTRuntimeInterfacesAlgorithm.cs
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+ ///
+ /// RuntimeInterfaces algorithm for for array types which are similar to a generic type
+ ///
+ public sealed class ArrayOfTRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm
+ {
+ ///
+ /// Open type to instantiate to get the interfaces associated with an array.
+ ///
+ private MetadataType _arrayOfTType;
+
+ ///
+ /// RuntimeInterfaces algorithm for for array types which are similar to a generic type
+ ///
+ /// Open type to instantiate to get the interfaces associated with an array.
+ public ArrayOfTRuntimeInterfacesAlgorithm(MetadataType arrayOfTType)
+ {
+ _arrayOfTType = arrayOfTType;
+ Debug.Assert(!(arrayOfTType is InstantiatedType));
+ }
+
+ public override DefType[] ComputeRuntimeInterfaces(TypeDesc _type)
+ {
+ ArrayType arrayType = (ArrayType)_type;
+ Debug.Assert(arrayType.IsSzArray);
+ TypeDesc arrayOfTInstantiation = _arrayOfTType.MakeInstantiatedType(arrayType.ElementType);
+
+ return arrayOfTInstantiation.RuntimeInterfaces;
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs
new file mode 100644
index 00000000000000..ee7bcd978dc4e2
--- /dev/null
+++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ConstructedTypeRewritingHelpers.cs
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Internal.TypeSystem
+{
+ public static class ConstructedTypeRewritingHelpers
+ {
+ ///
+ /// Determine if the construction of a type contains one of a given set of types. This is a deep
+ /// scan. For instance, given type MyType<SomeGeneric<int[]>>, and a set of typesToFind
+ /// that includes int, this function will return true. Does not detect the open generics that may be
+ /// instantiated over in this type. IsConstructedOverType would return false if only passed MyType,
+ /// or SomeGeneric for the above examplt.
+ ///
+ /// type to examine
+ /// types to search for in the construction of type
+ /// true if a type in typesToFind is found
+ public static bool IsConstructedOverType(this TypeDesc type, TypeDesc[] typesToFind)
+ {
+ int directDiscoveryIndex = Array.IndexOf(typesToFind, type);
+
+ if (directDiscoveryIndex != -1)
+ return true;
+
+ if (type.HasInstantiation)
+ {
+ for (int instantiationIndex = 0; instantiationIndex < type.Instantiation.Length; instantiationIndex++)
+ {
+ if (type.Instantiation[instantiationIndex].IsConstructedOverType(typesToFind))
+ {
+ return true;
+ }
+ }
+ }
+ else if (type.IsParameterizedType)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType)type;
+ return parameterizedType.ParameterType.IsConstructedOverType(typesToFind);
+ }
+ else if (type.IsFunctionPointer)
+ {
+ MethodSignature functionPointerSignature = ((FunctionPointerType)type).Signature;
+ if (functionPointerSignature.ReturnType.IsConstructedOverType(typesToFind))
+ return true;
+
+ for (int paramIndex = 0; paramIndex < functionPointerSignature.Length; paramIndex++)
+ {
+ if (functionPointerSignature[paramIndex].IsConstructedOverType(typesToFind))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Replace some of the types in a type's construction with a new set of types. This function does not
+ /// support any situation where there is an instantiated generic that is not represented by an
+ /// InstantiatedType. Does not replace the open generics that may be instantiated over in this type.
+ ///
+ /// For instance, Given MyType<object, int[]>,
+ /// an array of types to replace such as {int,object}, and
+ /// an array of replacement types such as {string,__Canon}.
+ /// The result shall be MyType<__Canon, string[]>
+ ///
+ /// This function cannot be used to replace MyType in the above example.
+ ///
+ public static TypeDesc ReplaceTypesInConstructionOfType(this TypeDesc type, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes)
+ {
+ int directReplacementIndex = Array.IndexOf(typesToReplace, type);
+
+ if (directReplacementIndex != -1)
+ return replacementTypes[directReplacementIndex];
+
+ if (type.HasInstantiation)
+ {
+ TypeDesc[] newInstantiation = null;
+ Debug.Assert(type is InstantiatedType);
+ int instantiationIndex = 0;
+ for (; instantiationIndex < type.Instantiation.Length; instantiationIndex++)
+ {
+ TypeDesc oldType = type.Instantiation[instantiationIndex];
+ TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+ if ((oldType != newType) || (newInstantiation != null))
+ {
+ if (newInstantiation == null)
+ {
+ newInstantiation = new TypeDesc[type.Instantiation.Length];
+ for (int i = 0; i < instantiationIndex; i++)
+ newInstantiation[i] = type.Instantiation[i];
+ }
+ newInstantiation[instantiationIndex] = newType;
+ }
+ }
+ if (newInstantiation != null)
+ return type.Context.GetInstantiatedType((MetadataType)type.GetTypeDefinition(), new Instantiation(newInstantiation));
+ }
+ else if (type.IsParameterizedType)
+ {
+ ParameterizedType parameterizedType = (ParameterizedType)type;
+ TypeDesc oldParameter = parameterizedType.ParameterType;
+ TypeDesc newParameter = oldParameter.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+ if (oldParameter != newParameter)
+ {
+ if (type.IsArray)
+ {
+ ArrayType arrayType = (ArrayType)type;
+ if (arrayType.IsSzArray)
+ return type.Context.GetArrayType(newParameter);
+ else
+ return type.Context.GetArrayType(newParameter, arrayType.Rank);
+ }
+ else if (type.IsPointer)
+ {
+ return type.Context.GetPointerType(newParameter);
+ }
+ else if (type.IsByRef)
+ {
+ return type.Context.GetByRefType(newParameter);
+ }
+ Debug.Fail("Unknown form of type");
+ }
+ }
+ else if (type.IsFunctionPointer)
+ {
+ MethodSignature oldSig = ((FunctionPointerType)type).Signature;
+ MethodSignatureBuilder sigBuilder = new MethodSignatureBuilder(oldSig);
+ sigBuilder.ReturnType = oldSig.ReturnType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+ for (int paramIndex = 0; paramIndex < oldSig.Length; paramIndex++)
+ sigBuilder[paramIndex] = oldSig[paramIndex].ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+
+ MethodSignature newSig = sigBuilder.ToSignature();
+ if (newSig != oldSig)
+ return type.Context.GetFunctionPointerType(newSig);
+ }
+
+ return type;
+ }
+
+ ///
+ /// Replace some of the types in a method's construction with a new set of types.
+ /// Does not replace the open generics that may be instantiated over in this type.
+ ///
+ /// For instance, Given MyType<object, int[]>.Function<short>(),
+ /// an array of types to replace such as {int,short}, and
+ /// an array of replacement types such as {string,char}.
+ /// The result shall be MyType<object, string[]>.Function<char>
+ ///
+ /// This function cannot be used to replace MyType in the above example.
+ ///
+ public static MethodDesc ReplaceTypesInConstructionOfMethod(this MethodDesc method, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes)
+ {
+ TypeDesc newOwningType = method.OwningType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+ MethodDesc methodOnOwningType = null;
+ bool owningTypeChanged = false;
+ if (newOwningType == method.OwningType)
+ {
+ methodOnOwningType = method.GetMethodDefinition();
+ }
+ else
+ {
+ methodOnOwningType = TypeSystemHelpers.FindMethodOnExactTypeWithMatchingTypicalMethod(newOwningType, method);
+ owningTypeChanged = true;
+ }
+
+ MethodDesc result;
+ if (!method.HasInstantiation)
+ {
+ result = methodOnOwningType;
+ }
+ else
+ {
+ Debug.Assert(method is InstantiatedMethod);
+
+ TypeDesc[] newInstantiation = null;
+ int instantiationIndex = 0;
+ for (; instantiationIndex < method.Instantiation.Length; instantiationIndex++)
+ {
+ TypeDesc oldType = method.Instantiation[instantiationIndex];
+ TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
+ if ((oldType != newType) || (newInstantiation != null))
+ {
+ if (newInstantiation == null)
+ {
+ newInstantiation = new TypeDesc[method.Instantiation.Length];
+ for (int i = 0; i < instantiationIndex; i++)
+ newInstantiation[i] = method.Instantiation[i];
+ }
+ newInstantiation[instantiationIndex] = newType;
+ }
+ }
+
+ if (newInstantiation != null)
+ result = method.Context.GetInstantiatedMethod(methodOnOwningType, new Instantiation(newInstantiation));
+ else if (owningTypeChanged)
+ result = method.Context.GetInstantiatedMethod(methodOnOwningType, method.Instantiation);
+ else
+ result = method;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs
new file mode 100644
index 00000000000000..2e66f33b8f72a5
--- /dev/null
+++ b/src/coreclr/src/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+using Internal.NativeFormat;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+ public class UniversalCanonLayoutAlgorithm : FieldLayoutAlgorithm
+ {
+ public static UniversalCanonLayoutAlgorithm Instance = new UniversalCanonLayoutAlgorithm();
+
+ private UniversalCanonLayoutAlgorithm() { }
+
+ public override bool ComputeContainsGCPointers(DefType type)
+ {
+ // This should never be called
+ throw new NotSupportedException();
+ }
+
+ public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind)
+ {
+ return new ComputedInstanceFieldLayout()
+ {
+ FieldSize = LayoutInt.Indeterminate,
+ FieldAlignment = LayoutInt.Indeterminate,
+ ByteCountUnaligned = LayoutInt.Indeterminate,
+ ByteCountAlignment = LayoutInt.Indeterminate,
+ Offsets = Array.Empty()
+ };
+ }
+
+ public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind)
+ {
+ return new ComputedStaticFieldLayout()
+ {
+ NonGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+ GcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+ ThreadNonGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+ ThreadGcStatics = new StaticsBlock() { Size = LayoutInt.Zero, LargestAlignment = LayoutInt.Zero },
+ Offsets = Array.Empty()
+ };
+ }
+
+ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
+ {
+ return ValueTypeShapeCharacteristics.None;
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs
new file mode 100644
index 00000000000000..1ac22562f67e1e
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Internal.TypeSystem.Ecma;
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+ public class ArchitectureSpecificFieldLayoutTests
+ {
+ TestTypeSystemContext _contextX86;
+ ModuleDesc _testModuleX86;
+ TestTypeSystemContext _contextX64;
+ ModuleDesc _testModuleX64;
+ TestTypeSystemContext _contextARM;
+ ModuleDesc _testModuleARM;
+
+ public ArchitectureSpecificFieldLayoutTests()
+ {
+ _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64);
+ var systemModuleX64 = _contextX64.CreateModuleForSimpleName("CoreTestAssembly");
+ _contextX64.SetSystemModule(systemModuleX64);
+
+ _testModuleX64 = systemModuleX64;
+
+ _contextARM = new TestTypeSystemContext(TargetArchitecture.ARM);
+ var systemModuleARM = _contextARM.CreateModuleForSimpleName("CoreTestAssembly");
+ _contextARM.SetSystemModule(systemModuleARM);
+
+ _testModuleARM = systemModuleARM;
+
+ _contextX86 = new TestTypeSystemContext(TargetArchitecture.X86);
+ var systemModuleX86 = _contextX86.CreateModuleForSimpleName("CoreTestAssembly");
+ _contextX86.SetSystemModule(systemModuleX86);
+
+ _testModuleX86 = systemModuleX86;
+ }
+
+ [Fact]
+ public void TestInstanceLayoutDoubleBool()
+ {
+ MetadataType tX64 = _testModuleX64.GetType("Sequential", "ClassDoubleBool");
+ MetadataType tX86 = _testModuleX86.GetType("Sequential", "ClassDoubleBool");
+ MetadataType tARM = _testModuleARM.GetType("Sequential", "ClassDoubleBool");
+
+ Assert.Equal(0x8, tX64.InstanceByteAlignment.AsInt);
+ Assert.Equal(0x8, tARM.InstanceByteAlignment.AsInt);
+ Assert.Equal(0x4, tX86.InstanceByteAlignment.AsInt);
+
+ Assert.Equal(0x11, tX64.InstanceByteCountUnaligned.AsInt);
+ Assert.Equal(0x11, tARM.InstanceByteCountUnaligned.AsInt);
+ Assert.Equal(0x11, tX86.InstanceByteCountUnaligned.AsInt);
+
+ Assert.Equal(0x18, tX64.InstanceByteCount.AsInt);
+ Assert.Equal(0x18, tARM.InstanceByteCount.AsInt);
+ Assert.Equal(0x14, tX86.InstanceByteCount.AsInt);
+ }
+
+ [Fact]
+ public void TestInstanceLayoutBoolDoubleBool()
+ {
+ MetadataType tX64 = _testModuleX64.GetType("Sequential", "ClassBoolDoubleBool");
+ MetadataType tX86 = _testModuleX86.GetType("Sequential", "ClassBoolDoubleBool");
+ MetadataType tARM = _testModuleARM.GetType("Sequential", "ClassBoolDoubleBool");
+
+ Assert.Equal(0x8, tX64.InstanceByteAlignment.AsInt);
+ Assert.Equal(0x8, tARM.InstanceByteAlignment.AsInt);
+ Assert.Equal(0x4, tX86.InstanceByteAlignment.AsInt);
+
+ Assert.Equal(0x19, tX64.InstanceByteCountUnaligned.AsInt);
+ Assert.Equal(0x11, tARM.InstanceByteCountUnaligned.AsInt);
+ Assert.Equal(0x11, tX86.InstanceByteCountUnaligned.AsInt);
+
+ Assert.Equal(0x20, tX64.InstanceByteCount.AsInt);
+ Assert.Equal(0x18, tARM.InstanceByteCount.AsInt);
+ Assert.Equal(0x14, tX86.InstanceByteCount.AsInt);
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs
new file mode 100644
index 00000000000000..c04941848398a0
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs
@@ -0,0 +1,327 @@
+// Licensed to the.NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+ public class CanonicalizationTests
+ {
+ private TestTypeSystemContext _context;
+ private ModuleDesc _testModule;
+
+ private MetadataType _referenceType;
+ private MetadataType _otherReferenceType;
+ private MetadataType _structType;
+ private MetadataType _otherStructType;
+ private MetadataType _genericReferenceType;
+ private MetadataType _genericStructType;
+ private MetadataType _genericReferenceTypeWithThreeParams;
+ private MetadataType _genericStructTypeWithThreeParams;
+
+ public CanonicalizationTests()
+ {
+ _context = new TestTypeSystemContext(TargetArchitecture.Unknown);
+ var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+ _context.SetSystemModule(systemModule);
+
+ _testModule = systemModule;
+
+ _referenceType = _testModule.GetType("Canonicalization", "ReferenceType");
+ _otherReferenceType = _testModule.GetType("Canonicalization", "OtherReferenceType");
+ _structType = _testModule.GetType("Canonicalization", "StructType");
+ _otherStructType = _testModule.GetType("Canonicalization", "OtherStructType");
+ _genericReferenceType = _testModule.GetType("Canonicalization", "GenericReferenceType`1");
+ _genericStructType = _testModule.GetType("Canonicalization", "GenericStructType`1");
+ _genericReferenceTypeWithThreeParams = _testModule.GetType("Canonicalization", "GenericReferenceTypeWithThreeParams`3");
+ _genericStructTypeWithThreeParams = _testModule.GetType("Canonicalization", "GenericStructTypeWithThreeParams`3");
+ }
+
+ [Theory]
+ [InlineData(CanonicalizationMode.Standard)]
+ [InlineData(CanonicalizationMode.RuntimeDetermined)]
+ public void TestGenericTypes(CanonicalizationMode algorithmType)
+ {
+ _context.CanonMode = algorithmType;
+
+ // Canonical forms of reference type over two different reference types are equivalent
+ var referenceOverReference = _genericReferenceType.MakeInstantiatedType(_referenceType);
+ var referenceOverOtherReference = _genericReferenceType.MakeInstantiatedType(_otherReferenceType);
+ Assert.Same(
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+ referenceOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+ referenceOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ var referenceOverReferenceOverReference = _genericReferenceType.MakeInstantiatedType(referenceOverReference);
+ Assert.Same(
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+ referenceOverReferenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+ referenceOverReferenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ var threeParamReferenceOverS1R1S1 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+ _structType, _referenceType, _structType);
+ var threeParamReferenceOverS1R2S1 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+ _structType, _otherReferenceType, _structType);
+ var threeParamReferenceOverS1R2S2 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+ _structType, _otherReferenceType, _otherStructType);
+ Assert.Same(
+ threeParamReferenceOverS1R1S1.ConvertToCanonForm(CanonicalFormKind.Specific),
+ threeParamReferenceOverS1R2S1.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.Same(
+ threeParamReferenceOverS1R1S1.ConvertToCanonForm(CanonicalFormKind.Universal),
+ threeParamReferenceOverS1R2S1.ConvertToCanonForm(CanonicalFormKind.Universal));
+ Assert.Same(
+ threeParamReferenceOverS1R1S1.ConvertToCanonForm(CanonicalFormKind.Universal),
+ threeParamReferenceOverS1R2S2.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ // Universal canonical forms of reference type over reference and value types are equivalent
+ var referenceOverStruct = _genericReferenceType.MakeInstantiatedType(_structType);
+ var referenceOverOtherStruct = _genericReferenceType.MakeInstantiatedType(_otherStructType);
+ Assert.Same(
+ referenceOverStruct.ConvertToCanonForm(CanonicalFormKind.Universal),
+ referenceOverOtherStruct.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ // Canon forms of reference type instantiated over a generic valuetype over any reference type
+ var genericStructOverReference = _genericStructType.MakeInstantiatedType(_referenceType);
+ var genericStructOverOtherReference = _genericStructType.MakeInstantiatedType(_otherReferenceType);
+ var referenceOverGenericStructOverReference = _genericReferenceType.MakeInstantiatedType(genericStructOverReference);
+ var referenceOverGenericStructOverOtherReference = _genericReferenceType.MakeInstantiatedType(genericStructOverOtherReference);
+ Assert.Same(
+ referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+ referenceOverGenericStructOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.NotSame(
+ referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+ referenceOverGenericStructOverOtherReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+ Assert.Same(
+ referenceOverGenericStructOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ // Canon of a type instantiated over a signature variable is the same type when just canonicalizing as specific,
+ // but the universal canon form when performing universal canonicalization.
+ var genericStructOverSignatureVariable = _genericStructType.MakeInstantiatedType(_context.GetSignatureVariable(0, false));
+ Assert.Same(
+ genericStructOverSignatureVariable,
+ genericStructOverSignatureVariable.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.NotSame(
+ genericStructOverSignatureVariable,
+ genericStructOverSignatureVariable.ConvertToCanonForm(CanonicalFormKind.Universal));
+ }
+
+ [Theory]
+ [InlineData(CanonicalizationMode.Standard)]
+ [InlineData(CanonicalizationMode.RuntimeDetermined)]
+ public void TestGenericTypesNegative(CanonicalizationMode algorithmType)
+ {
+ _context.CanonMode = algorithmType;
+
+ // Two different types instantiated over the same type are not canonically equivalent
+ var referenceOverReference = _genericReferenceType.MakeInstantiatedType(_referenceType);
+ var structOverReference = _genericStructType.MakeInstantiatedType(_referenceType);
+ Assert.NotSame(
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Specific),
+ structOverReference.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.NotSame(
+ referenceOverReference.ConvertToCanonForm(CanonicalFormKind.Universal),
+ structOverReference.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ // Specific canonical forms of reference type over reference and value types are not equivalent
+ var referenceOverStruct = _genericReferenceType.MakeInstantiatedType(_structType);
+ var referenceOverOtherStruct = _genericReferenceType.MakeInstantiatedType(_otherStructType);
+ Assert.NotSame(
+ referenceOverStruct.ConvertToCanonForm(CanonicalFormKind.Specific),
+ referenceOverOtherStruct.ConvertToCanonForm(CanonicalFormKind.Specific));
+
+ var threeParamReferenceOverS1R2S1 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+ _structType, _otherReferenceType, _structType);
+ var threeParamReferenceOverS1R2S2 = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+ _structType, _otherReferenceType, _otherStructType);
+ Assert.NotSame(
+ threeParamReferenceOverS1R2S1.ConvertToCanonForm(CanonicalFormKind.Specific),
+ threeParamReferenceOverS1R2S2.ConvertToCanonForm(CanonicalFormKind.Specific));
+ }
+
+ [Theory]
+ [InlineData(CanonicalizationMode.Standard)]
+ [InlineData(CanonicalizationMode.RuntimeDetermined)]
+ public void TestArrayTypes(CanonicalizationMode algorithmType)
+ {
+ _context.CanonMode = algorithmType;
+
+ // Generic type instantiated over an array has the same canonical form as generic type over any other reference type
+ var genericStructOverArrayOfInt = _genericStructType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32).MakeArrayType());
+ var genericStructOverReferenceType = _genericStructType.MakeInstantiatedType(_referenceType);
+ Assert.Same(
+ genericStructOverArrayOfInt.ConvertToCanonForm(CanonicalFormKind.Specific),
+ genericStructOverReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.Same(
+ genericStructOverArrayOfInt.ConvertToCanonForm(CanonicalFormKind.Universal),
+ genericStructOverReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ // Canonical form of SzArray and Multidim array are not the same
+ var arrayOfReferenceType = _referenceType.MakeArrayType();
+ var mdArrayOfReferenceType = _referenceType.MakeArrayType(1);
+ Assert.NotSame(
+ arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific),
+ mdArrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.NotSame(
+ arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal),
+ mdArrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ // Canonical forms of arrays over different reference types are same
+ var arrayOfOtherReferenceType = _otherReferenceType.MakeArrayType();
+ Assert.Same(
+ arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific),
+ arrayOfOtherReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.Same(
+ arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal),
+ arrayOfOtherReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal));
+
+ // Canonical forms of arrays of value types are only same for universal canon form
+ var arrayOfStruct = _structType.MakeArrayType();
+ Assert.NotSame(
+ arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Specific),
+ arrayOfStruct.ConvertToCanonForm(CanonicalFormKind.Specific));
+ Assert.Same(
+ arrayOfReferenceType.ConvertToCanonForm(CanonicalFormKind.Universal),
+ arrayOfStruct.ConvertToCanonForm(CanonicalFormKind.Universal));
+ }
+
+ [Theory]
+ [InlineData(CanonicalizationMode.Standard)]
+ [InlineData(CanonicalizationMode.RuntimeDetermined)]
+ public void TestMethodsOnGenericTypes(CanonicalizationMode algorithmType)
+ {
+ _context.CanonMode = algorithmType;
+
+ var referenceOverReference = _genericReferenceType.MakeInstantiatedType(_referenceType);
+ var referenceOverOtherReference = _genericReferenceType.MakeInstantiatedType(_otherReferenceType);
+ Assert.NotSame(
+ referenceOverReference.GetMethod("Method", null),
+ referenceOverOtherReference.GetMethod("Method", null));
+ Assert.Same(
+ referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+ referenceOverOtherReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+ referenceOverOtherReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+ var referenceOverStruct = _genericReferenceType.MakeInstantiatedType(_structType);
+ Assert.NotSame(
+ referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+ referenceOverStruct.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverReference.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+ referenceOverStruct.GetMethod("Method", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+ Assert.Same(
+ referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Specific),
+ referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_otherReferenceType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Universal),
+ referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_otherReferenceType).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+ Assert.NotSame(
+ referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Specific),
+ referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Universal),
+ referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+ Assert.NotSame(
+ referenceOverStruct.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Specific),
+ referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ Assert.Same(
+ referenceOverStruct.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_referenceType).GetCanonMethodTarget(CanonicalFormKind.Universal),
+ referenceOverOtherReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+ Assert.NotSame(
+ referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType),
+ referenceOverReference.GetMethod("GenericMethod", null).MakeInstantiatedMethod(_structType).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ }
+
+ [Theory]
+ [InlineData(CanonicalizationMode.Standard)]
+ [InlineData(CanonicalizationMode.RuntimeDetermined)]
+ public void TestArrayMethods(CanonicalizationMode algorithmType)
+ {
+ _context.CanonMode = algorithmType;
+
+ var arrayOfReferenceType = _referenceType.MakeArrayType(1);
+ var arrayOfOtherReferenceType = _otherReferenceType.MakeArrayType(1);
+
+ Assert.Same(
+ arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+ arrayOfOtherReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ Assert.Same(
+ arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+ arrayOfOtherReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+
+ var arrayOfStruct = _structType.MakeArrayType(1);
+
+ Assert.NotSame(
+ arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific),
+ arrayOfStruct.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Specific));
+ Assert.Same(
+ arrayOfReferenceType.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal),
+ arrayOfStruct.GetMethod("Set", null).GetCanonMethodTarget(CanonicalFormKind.Universal));
+ }
+
+ [Theory]
+ [InlineData(CanonicalizationMode.Standard)]
+ [InlineData(CanonicalizationMode.RuntimeDetermined)]
+ public void TestUpgradeToUniversalCanon(CanonicalizationMode algorithmType)
+ {
+ _context.CanonMode = algorithmType;
+
+ var gstOverUniversalCanon = _genericStructType.MakeInstantiatedType(_context.UniversalCanonType);
+ var grtOverRtRtStOverUniversal = _genericReferenceTypeWithThreeParams.MakeInstantiatedType(
+ _referenceType, _referenceType, gstOverUniversalCanon);
+ var grtOverRtRtStOverUniversalCanon = grtOverRtRtStOverUniversal.ConvertToCanonForm(CanonicalFormKind.Specific);
+
+ // Specific form gets upgraded to universal in the presence of universal canon.
+ // GenericReferenceTypeWithThreeParams> is
+ // GenericReferenceTypeWithThreeParams
+ Assert.Same(_context.UniversalCanonType, grtOverRtRtStOverUniversalCanon.Instantiation[0]);
+ Assert.Same(_context.UniversalCanonType, grtOverRtRtStOverUniversalCanon.Instantiation[2]);
+ }
+
+ [Theory]
+ [InlineData(CanonicalizationMode.Standard)]
+ [InlineData(CanonicalizationMode.RuntimeDetermined)]
+ public void TestDowngradeFromUniversalCanon(CanonicalizationMode algorithmType)
+ {
+ _context.CanonMode = algorithmType;
+ var grtOverUniversalCanon = _genericReferenceType.MakeInstantiatedType(_context.UniversalCanonType);
+ var gstOverGrtOverUniversalCanon = _genericStructType.MakeInstantiatedType(grtOverUniversalCanon);
+ var gstOverCanon = _genericStructType.MakeInstantiatedType(_context.CanonType);
+ Assert.Same(gstOverCanon, gstOverGrtOverUniversalCanon.ConvertToCanonForm(CanonicalFormKind.Specific));
+
+ var gstOverGstOverGrtOverUniversalCanon = _genericStructType.MakeInstantiatedType(gstOverGrtOverUniversalCanon);
+ var gstOverGstOverCanon = _genericStructType.MakeInstantiatedType(gstOverCanon);
+ Assert.Same(gstOverGstOverCanon, gstOverGstOverGrtOverUniversalCanon.ConvertToCanonForm(CanonicalFormKind.Specific));
+ }
+
+ [Fact]
+ public void TestCanonicalizationOfRuntimeDeterminedUniversalGeneric()
+ {
+ var gstOverUniversalCanon = _genericStructType.MakeInstantiatedType(_context.UniversalCanonType);
+ var rdtUniversalCanon = (RuntimeDeterminedType)gstOverUniversalCanon.ConvertToSharedRuntimeDeterminedForm().Instantiation[0];
+ Assert.Same(_context.UniversalCanonType, rdtUniversalCanon.CanonicalType);
+
+ var gstOverRdtUniversalCanon = _genericStructType.MakeInstantiatedType(rdtUniversalCanon);
+ Assert.Same(gstOverUniversalCanon, gstOverRdtUniversalCanon.ConvertToCanonForm(CanonicalFormKind.Specific));
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs
new file mode 100644
index 00000000000000..1d81c8196441b0
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CastingTests.cs
@@ -0,0 +1,219 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+ public class CastingTests
+ {
+ private TestTypeSystemContext _context;
+ private ModuleDesc _testModule;
+
+ public CastingTests()
+ {
+ _context = new TestTypeSystemContext(TargetArchitecture.X64);
+ var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+ _context.SetSystemModule(systemModule);
+
+ _testModule = systemModule;
+ }
+
+ [Fact]
+ public void TestCastingInHierarchy()
+ {
+ TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+ TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+ TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+ TypeDesc uintType = _context.GetWellKnownType(WellKnownType.UInt32);
+
+ Assert.True(stringType.CanCastTo(objectType));
+ Assert.True(objectType.CanCastTo(objectType));
+ Assert.True(intType.CanCastTo(objectType));
+
+ Assert.False(objectType.CanCastTo(stringType));
+ Assert.False(intType.CanCastTo(uintType));
+ Assert.False(uintType.CanCastTo(intType));
+ }
+
+ [Fact]
+ public void TestInterfaceCasting()
+ {
+ TypeDesc iFooType = _testModule.GetType("Casting", "IFoo");
+ TypeDesc classImplementingIFooType =
+ _testModule.GetType("Casting", "ClassImplementingIFoo");
+ TypeDesc classImplementingIFooIndirectlyType =
+ _testModule.GetType("Casting", "ClassImplementingIFooIndirectly");
+ TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+
+ Assert.True(classImplementingIFooType.CanCastTo(iFooType));
+ Assert.True(classImplementingIFooIndirectlyType.CanCastTo(iFooType));
+ Assert.True(iFooType.CanCastTo(objectType));
+
+ Assert.False(objectType.CanCastTo(iFooType));
+ }
+
+ [Fact]
+ public void TestSameSizeArrayTypeCasting()
+ {
+ TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+ TypeDesc uintType = _context.GetWellKnownType(WellKnownType.UInt32);
+ TypeDesc byteType = _context.GetWellKnownType(WellKnownType.Byte);
+ TypeDesc sbyteType = _context.GetWellKnownType(WellKnownType.SByte);
+ TypeDesc intPtrType = _context.GetWellKnownType(WellKnownType.IntPtr);
+ TypeDesc ulongType = _context.GetWellKnownType(WellKnownType.UInt64);
+
+ TypeDesc doubleType = _context.GetWellKnownType(WellKnownType.Double);
+ TypeDesc boolType = _context.GetWellKnownType(WellKnownType.Boolean);
+
+ TypeDesc intBasedEnumType = _testModule.GetType("Casting", "IntBasedEnum");
+ TypeDesc uintBasedEnumType = _testModule.GetType("Casting", "UIntBasedEnum");
+ TypeDesc shortBasedEnumType = _testModule.GetType("Casting", "ShortBasedEnum");
+
+ Assert.True(intType.MakeArrayType().CanCastTo(uintType.MakeArrayType()));
+ Assert.True(intType.MakeArrayType().CanCastTo(uintType.MakeArrayType(1)));
+ Assert.False(intType.CanCastTo(uintType));
+
+ Assert.True(byteType.MakeArrayType().CanCastTo(sbyteType.MakeArrayType()));
+ Assert.False(byteType.CanCastTo(sbyteType));
+
+ Assert.True(intPtrType.MakeArrayType().CanCastTo(ulongType.MakeArrayType()));
+ Assert.False(intPtrType.CanCastTo(ulongType));
+
+ // These are same size, but not allowed to cast
+ Assert.False(doubleType.MakeArrayType().CanCastTo(ulongType.MakeArrayType()));
+ Assert.False(boolType.MakeArrayType().CanCastTo(byteType.MakeArrayType()));
+
+ Assert.True(intBasedEnumType.MakeArrayType().CanCastTo(uintType.MakeArrayType()));
+ Assert.True(intBasedEnumType.MakeArrayType().CanCastTo(uintBasedEnumType.MakeArrayType()));
+ Assert.False(shortBasedEnumType.MakeArrayType().CanCastTo(intType.MakeArrayType()));
+ }
+
+ [Fact]
+ public void TestArrayInterfaceCasting()
+ {
+ TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+ MetadataType iListType = _context.SystemModule.GetType("System.Collections", "IList");
+ MetadataType iListOfTType = _context.SystemModule.GetType("System.Collections.Generic", "IList`1");
+
+ InstantiatedType iListOfIntType = iListOfTType.MakeInstantiatedType(intType);
+ TypeDesc intSzArrayType = intType.MakeArrayType();
+ TypeDesc intArrayType = intType.MakeArrayType(1);
+
+ Assert.True(intSzArrayType.CanCastTo(iListOfIntType));
+ Assert.True(intSzArrayType.CanCastTo(iListType));
+
+ Assert.False(intArrayType.CanCastTo(iListOfIntType));
+ Assert.True(intArrayType.CanCastTo(iListType));
+ }
+
+ [Fact]
+ public void TestArrayCasting()
+ {
+ TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+ TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+ TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+ TypeDesc arrayType = _context.GetWellKnownType(WellKnownType.Array);
+ TypeDesc intSzArrayType = intType.MakeArrayType();
+ TypeDesc intArray1Type = intType.MakeArrayType(1);
+ TypeDesc intArray2Type = intType.MakeArrayType(2);
+ TypeDesc stringSzArrayType = stringType.MakeArrayType();
+ TypeDesc objectSzArrayType = objectType.MakeArrayType();
+
+ Assert.True(intSzArrayType.CanCastTo(intArray1Type));
+ Assert.False(intArray1Type.CanCastTo(intSzArrayType));
+
+ Assert.False(intArray1Type.CanCastTo(intArray2Type));
+
+ Assert.True(intSzArrayType.CanCastTo(arrayType));
+ Assert.True(intArray1Type.CanCastTo(arrayType));
+
+ Assert.True(stringSzArrayType.CanCastTo(objectSzArrayType));
+ Assert.False(intSzArrayType.CanCastTo(objectSzArrayType));
+ }
+
+ [Fact]
+ public void TestGenericParameterCasting()
+ {
+ TypeDesc paramWithNoConstraint =
+ _testModule.GetType("Casting", "ClassWithNoConstraint`1").Instantiation[0];
+ TypeDesc paramWithValueTypeConstraint =
+ _testModule.GetType("Casting", "ClassWithValueTypeConstraint`1").Instantiation[0];
+ TypeDesc paramWithInterfaceConstraint =
+ _testModule.GetType("Casting", "ClassWithInterfaceConstraint`1").Instantiation[0];
+
+ TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+ TypeDesc valueTypeType = _context.GetWellKnownType(WellKnownType.ValueType);
+ TypeDesc iFooType = _testModule.GetType("Casting", "IFoo");
+ TypeDesc classImplementingIFooType = _testModule.GetType("Casting", "ClassImplementingIFoo");
+ TypeDesc classImplementingIFooIndirectlyType =
+ _testModule.GetType("Casting", "ClassImplementingIFooIndirectly");
+
+ Assert.True(paramWithNoConstraint.CanCastTo(objectType));
+ Assert.False(paramWithNoConstraint.CanCastTo(valueTypeType));
+ Assert.False(paramWithNoConstraint.CanCastTo(iFooType));
+ Assert.False(paramWithNoConstraint.CanCastTo(classImplementingIFooType));
+
+ Assert.True(paramWithValueTypeConstraint.CanCastTo(objectType));
+ Assert.True(paramWithValueTypeConstraint.CanCastTo(valueTypeType));
+ Assert.False(paramWithValueTypeConstraint.CanCastTo(iFooType));
+ Assert.False(paramWithValueTypeConstraint.CanCastTo(classImplementingIFooType));
+
+ Assert.True(paramWithInterfaceConstraint.CanCastTo(objectType));
+ Assert.False(paramWithInterfaceConstraint.CanCastTo(valueTypeType));
+ Assert.True(paramWithInterfaceConstraint.CanCastTo(iFooType));
+ Assert.False(paramWithInterfaceConstraint.CanCastTo(classImplementingIFooType));
+ }
+
+ [Fact]
+ public void TestVariantCasting()
+ {
+ TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
+ TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);
+ TypeDesc exceptionType = _context.GetWellKnownType(WellKnownType.Exception);
+
+ TypeDesc stringSzArrayType = stringType.MakeArrayType();
+
+ MetadataType iEnumerableOfTType =
+ _context.SystemModule.GetType("System.Collections.Generic", "IEnumerable`1");
+ InstantiatedType iEnumerableOfObjectType = iEnumerableOfTType.MakeInstantiatedType(objectType);
+ InstantiatedType iEnumerableOfExceptionType = iEnumerableOfTType.MakeInstantiatedType(exceptionType);
+
+ Assert.True(stringSzArrayType.CanCastTo(iEnumerableOfObjectType));
+ Assert.False(stringSzArrayType.CanCastTo(iEnumerableOfExceptionType));
+
+ MetadataType iContravariantOfTType = _testModule.GetType("Casting", "IContravariant`1");
+ InstantiatedType iContravariantOfObjectType = iContravariantOfTType.MakeInstantiatedType(objectType);
+ InstantiatedType iEnumerableOfStringType = iEnumerableOfTType.MakeInstantiatedType(stringType);
+
+ Assert.True(iContravariantOfObjectType.CanCastTo(objectType));
+ Assert.True(iEnumerableOfStringType.CanCastTo(objectType));
+ }
+
+ [Fact]
+ public void TestNullableCasting()
+ {
+ TypeDesc intType = _context.GetWellKnownType(WellKnownType.Int32);
+ MetadataType nullableType = (MetadataType)_context.GetWellKnownType(WellKnownType.Nullable);
+ TypeDesc nullableOfIntType = nullableType.MakeInstantiatedType(intType);
+
+ Assert.True(intType.CanCastTo(nullableOfIntType));
+ }
+
+ [Fact]
+ public void TestRecursiveCanCast()
+ {
+ // Tests the stack overflow protection in CanCastTo
+
+ TypeDesc classWithRecursiveImplementation = _testModule.GetType("Casting", "ClassWithRecursiveImplementation");
+ MetadataType iContravariantOfTType = (MetadataType)_testModule.GetType("Casting", "IContravariant`1");
+
+ TypeDesc testType = iContravariantOfTType.MakeInstantiatedType(classWithRecursiveImplementation);
+
+ Assert.False(classWithRecursiveImplementation.CanCastTo(testType));
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs
new file mode 100644
index 00000000000000..bcb985634b0e92
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ConstraintsValidationTest.cs
@@ -0,0 +1,359 @@
+// Licensed to the.NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.TypeSystem;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+ public class ConstraintsValidationTest
+ {
+ private TestTypeSystemContext _context;
+ private ModuleDesc _testModule;
+
+ private MetadataType _iNonGenType;
+ private MetadataType _iGenType;
+ private MetadataType _arg1Type;
+ private MetadataType _arg2Type;
+ private MetadataType _arg3Type;
+ private MetadataType _structArgWithDefaultCtorType;
+ private MetadataType _structArgWithoutDefaultCtorType;
+ private MetadataType _classArgWithDefaultCtorType;
+ private MetadataType _classArgWithPrivateDefaultCtorType;
+ private MetadataType _abstractClassArgWithDefaultCtorType;
+ private MetadataType _classArgWithoutDefaultCtorType;
+ private MetadataType _referenceTypeConstraintType;
+ private MetadataType _defaultConstructorConstraintType;
+ private MetadataType _notNullableValueTypeConstraintType;
+ private MetadataType _simpleTypeConstraintType;
+ private MetadataType _doubleSimpleTypeConstraintType;
+ private MetadataType _simpleGenericConstraintType;
+ private MetadataType _complexGenericConstraint1Type;
+ private MetadataType _complexGenericConstraint2Type;
+ private MetadataType _complexGenericConstraint3Type;
+ private MetadataType _complexGenericConstraint4Type;
+ private MetadataType _multipleConstraintsType;
+
+ private MetadataType _genericMethodsType;
+ private MethodDesc _simpleGenericConstraintMethod;
+ private MethodDesc _complexGenericConstraintMethod;
+
+ public ConstraintsValidationTest()
+ {
+ _context = new TestTypeSystemContext(TargetArchitecture.Unknown);
+ var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+ _context.SetSystemModule(systemModule);
+
+ _testModule = systemModule;
+
+ _iNonGenType = _testModule.GetType("GenericConstraints", "INonGen");
+ _iGenType = _testModule.GetType("GenericConstraints", "IGen`1");
+ _arg1Type = _testModule.GetType("GenericConstraints", "Arg1");
+ _arg2Type = _testModule.GetType("GenericConstraints", "Arg2`1");
+ _arg3Type = _testModule.GetType("GenericConstraints", "Arg3`1");
+ _structArgWithDefaultCtorType = _testModule.GetType("GenericConstraints", "StructArgWithDefaultCtor");
+ _structArgWithoutDefaultCtorType = _testModule.GetType("GenericConstraints", "StructArgWithoutDefaultCtor");
+ _classArgWithDefaultCtorType = _testModule.GetType("GenericConstraints", "ClassArgWithDefaultCtor");
+ _classArgWithPrivateDefaultCtorType = _testModule.GetType("GenericConstraints", "ClassArgWithPrivateDefaultCtor");
+ _abstractClassArgWithDefaultCtorType = _testModule.GetType("GenericConstraints", "AbstractClassArgWithDefaultCtor");
+ _classArgWithoutDefaultCtorType = _testModule.GetType("GenericConstraints", "ClassArgWithoutDefaultCtor");
+
+ _referenceTypeConstraintType = _testModule.GetType("GenericConstraints", "ReferenceTypeConstraint`1");
+ _defaultConstructorConstraintType = _testModule.GetType("GenericConstraints", "DefaultConstructorConstraint`1");
+ _notNullableValueTypeConstraintType = _testModule.GetType("GenericConstraints", "NotNullableValueTypeConstraint`1");
+ _simpleTypeConstraintType = _testModule.GetType("GenericConstraints", "SimpleTypeConstraint`1");
+ _doubleSimpleTypeConstraintType = _testModule.GetType("GenericConstraints", "DoubleSimpleTypeConstraint`1");
+ _simpleGenericConstraintType = _testModule.GetType("GenericConstraints", "SimpleGenericConstraint`2");
+ _complexGenericConstraint1Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint1`2");
+ _complexGenericConstraint2Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint2`2");
+ _complexGenericConstraint3Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint3`2");
+ _complexGenericConstraint4Type = _testModule.GetType("GenericConstraints", "ComplexGenericConstraint4`2");
+ _multipleConstraintsType = _testModule.GetType("GenericConstraints", "MultipleConstraints`2");
+
+ _genericMethodsType = _testModule.GetType("GenericConstraints", "GenericMethods");
+ _simpleGenericConstraintMethod = _genericMethodsType.GetMethod("SimpleGenericConstraintMethod", null);
+ _complexGenericConstraintMethod = _genericMethodsType.GetMethod("ComplexGenericConstraintMethod", null);
+ }
+
+ [Fact]
+ public void TestTypeConstraints()
+ {
+ TypeDesc instantiatedType;
+ MethodDesc instantiatedMethod;
+
+ MetadataType arg2OfInt = _arg2Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+ MetadataType arg2OfBool = _arg2Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Boolean));
+ MetadataType arg2OfObject = _arg2Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+
+ // ReferenceTypeConstraint
+ {
+ instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_arg1Type);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_iNonGenType);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+ Assert.False(instantiatedType.CheckConstraints());
+ }
+
+ // DefaultConstructorConstraint
+ {
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_arg1Type);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_classArgWithDefaultCtorType);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_classArgWithPrivateDefaultCtorType);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_abstractClassArgWithDefaultCtorType);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_classArgWithoutDefaultCtorType);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ // Structs always have implicit default constructors
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_structArgWithoutDefaultCtorType);
+ Assert.True(instantiatedType.CheckConstraints());
+ }
+
+ // NotNullableValueTypeConstraint
+ {
+ instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_arg1Type);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ MetadataType nullable = (MetadataType)_context.GetWellKnownType(WellKnownType.Nullable);
+ MetadataType nullableOfInt = nullable.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Int32));
+
+ instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(nullableOfInt);
+ Assert.False(instantiatedType.CheckConstraints());
+ }
+
+ // Special constraints instantiated with generic parameter
+ {
+ instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_referenceTypeConstraintType.Instantiation[0]);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_defaultConstructorConstraintType.Instantiation[0]);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_notNullableValueTypeConstraintType.Instantiation[0]);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_notNullableValueTypeConstraintType.Instantiation[0]);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_arg2Type.Instantiation[0]);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_arg2Type.Instantiation[0]);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_arg2Type.Instantiation[0]);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _referenceTypeConstraintType.MakeInstantiatedType(_simpleTypeConstraintType.Instantiation[0]);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _defaultConstructorConstraintType.MakeInstantiatedType(_simpleTypeConstraintType.Instantiation[0]);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _notNullableValueTypeConstraintType.MakeInstantiatedType(_simpleTypeConstraintType.Instantiation[0]);
+ Assert.False(instantiatedType.CheckConstraints());
+ }
+
+ // SimpleTypeConstraint and DoubleSimpleTypeConstraint
+ foreach(var genType in new MetadataType[] { _simpleTypeConstraintType , _doubleSimpleTypeConstraintType })
+ {
+ instantiatedType = genType.MakeInstantiatedType(_arg1Type);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = genType.MakeInstantiatedType(_iNonGenType);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = genType.MakeInstantiatedType(_classArgWithDefaultCtorType);
+ Assert.False(instantiatedType.CheckConstraints());
+ }
+
+ // SimpleGenericConstraint
+ {
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _arg1Type);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _iNonGenType);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_classArgWithDefaultCtorType, _classArgWithoutDefaultCtorType);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_structArgWithDefaultCtorType, _context.GetWellKnownType(WellKnownType.ValueType));
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.ValueType));
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.UInt16), _context.GetWellKnownType(WellKnownType.UInt32));
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.UInt16), _context.GetWellKnownType(WellKnownType.ValueType));
+ Assert.True(instantiatedType.CheckConstraints());
+ }
+
+ // ComplexGenericConstraint1
+ {
+ instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(_arg1Type, _arg1Type /* uninteresting */);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(arg2OfInt, _arg1Type /* uninteresting */);
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(arg2OfBool, _arg1Type /* uninteresting */);
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _complexGenericConstraint1Type.MakeInstantiatedType(arg2OfObject, _arg1Type /* uninteresting */);
+ Assert.False(instantiatedType.CheckConstraints());
+ }
+
+ // ComplexGenericConstraint2
+ {
+ MetadataType arg2OfArg2OfInt = _arg2Type.MakeInstantiatedType(arg2OfInt);
+ MetadataType arg2OfArg2OfBool = _arg2Type.MakeInstantiatedType(arg2OfBool);
+ MetadataType arg2OfArg2OfObject = _arg2Type.MakeInstantiatedType(arg2OfObject);
+
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.Int32));
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfInt, _context.GetWellKnownType(WellKnownType.Int32));
+ Assert.True(instantiatedType.CheckConstraints());
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfBool, _context.GetWellKnownType(WellKnownType.Int32));
+ Assert.False(instantiatedType.CheckConstraints());
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfObject, _context.GetWellKnownType(WellKnownType.Int32));
+ Assert.False(instantiatedType.CheckConstraints());
+
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfInt, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.False(instantiatedType.CheckConstraints());
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfBool, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.False(instantiatedType.CheckConstraints());
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfObject, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.True(instantiatedType.CheckConstraints());
+
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfInt, _context.GetWellKnownType(WellKnownType.Boolean));
+ Assert.False(instantiatedType.CheckConstraints());
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfBool, _context.GetWellKnownType(WellKnownType.Boolean));
+ Assert.True(instantiatedType.CheckConstraints());
+ instantiatedType = _complexGenericConstraint2Type.MakeInstantiatedType(arg2OfArg2OfObject, _context.GetWellKnownType(WellKnownType.Boolean));
+ Assert.False(instantiatedType.CheckConstraints());
+ }
+
+ // ComplexGenericConstraint3
+ {
+ MetadataType igenOfObject = _iGenType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+
+ instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(igenOfObject, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.True(instantiatedType.CheckConstraints());
+
+ // Variance-compatible instantiation argument
+ instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(igenOfObject, _context.GetWellKnownType(WellKnownType.String));
+ Assert.True(instantiatedType.CheckConstraints());
+
+ // Type that implements the interface
+ var arg3OfObject = _arg3Type.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Object));
+ instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(arg3OfObject, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.True(instantiatedType.CheckConstraints());
+
+ // Type that implements a variant compatible interface
+ instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(arg3OfObject, _context.GetWellKnownType(WellKnownType.String));
+ Assert.True(instantiatedType.CheckConstraints());
+ }
+
+ // Constraints requiring InstantiationContext
+ {
+ // Instantiate type / method with own generic parameters
+ instantiatedType = _complexGenericConstraint3Type.MakeInstantiatedType(_complexGenericConstraint3Type.Instantiation[0], _complexGenericConstraint3Type.Instantiation[1]);
+ Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(instantiatedType.Instantiation, default(Instantiation))));
+
+ instantiatedType = _complexGenericConstraint4Type.MakeInstantiatedType(_complexGenericConstraint4Type.Instantiation[0], _complexGenericConstraint4Type.Instantiation[1]);
+ Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(instantiatedType.Instantiation, default(Instantiation))));
+
+ instantiatedMethod = _simpleGenericConstraintMethod.MakeInstantiatedMethod(_simpleGenericConstraintMethod.Instantiation);
+ Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(default(Instantiation), instantiatedMethod.Instantiation)));
+
+ instantiatedMethod = _complexGenericConstraintMethod.MakeInstantiatedMethod(_complexGenericConstraintMethod.Instantiation);
+ Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(default(Instantiation), instantiatedMethod.Instantiation)));
+
+ // Instantiate type with generic parameters of method
+ instantiatedType = _simpleGenericConstraintType.MakeInstantiatedType(_simpleGenericConstraintMethod.Instantiation);
+ Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(default(Instantiation), _simpleGenericConstraintMethod.Instantiation)));
+
+ instantiatedType = _complexGenericConstraint4Type.MakeInstantiatedType(_complexGenericConstraintMethod.Instantiation);
+ Assert.True(instantiatedType.CheckConstraints(new InstantiationContext(default(Instantiation), _complexGenericConstraintMethod.Instantiation)));
+
+ // Instantiate method with generic parameters of type
+ instantiatedMethod = _simpleGenericConstraintMethod.MakeInstantiatedMethod(_simpleGenericConstraintType.Instantiation);
+ Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(_simpleGenericConstraintType.Instantiation, default(Instantiation))));
+
+ instantiatedMethod = _complexGenericConstraintMethod.MakeInstantiatedMethod(_complexGenericConstraint4Type.Instantiation);
+ Assert.True(instantiatedMethod.CheckConstraints(new InstantiationContext(_complexGenericConstraint4Type.Instantiation, default(Instantiation))));
+ }
+
+ // MultipleConstraints
+ {
+ // Violate the class constraint
+ instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_structArgWithDefaultCtorType, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.False(instantiatedType.CheckConstraints());
+
+ // Violate the new() constraint
+ instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_classArgWithoutDefaultCtorType, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.False(instantiatedType.CheckConstraints());
+
+ // Violate the IGen constraint
+ instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_arg1Type, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.False(instantiatedType.CheckConstraints());
+
+ // Satisfy all constraints
+ instantiatedType = _multipleConstraintsType.MakeInstantiatedType(_classArgWithDefaultCtorType, _context.GetWellKnownType(WellKnownType.Object));
+ Assert.True(instantiatedType.CheckConstraints());
+ }
+
+ // InvalidInstantiationArgs
+ {
+ var pointer = _context.GetWellKnownType(WellKnownType.Int16).MakePointerType();
+ var byref = _context.GetWellKnownType(WellKnownType.Int16).MakeByRefType();
+
+ Assert.False(_iGenType.Instantiation.CheckValidInstantiationArguments());
+
+ instantiatedType = _iGenType.MakeInstantiatedType(_context.GetWellKnownType(WellKnownType.Void));
+ Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+
+ instantiatedType = _iGenType.MakeInstantiatedType(pointer);
+ Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+
+ instantiatedType = _iGenType.MakeInstantiatedType(byref);
+ Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+
+ instantiatedType = _iGenType.MakeInstantiatedType(byref);
+ instantiatedType = _iGenType.MakeInstantiatedType(instantiatedType);
+ Assert.False(instantiatedType.Instantiation.CheckValidInstantiationArguments());
+ }
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs
new file mode 100644
index 00000000000000..58c5b14596f134
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Canonicalization.cs
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Canonicalization
+{
+ class ReferenceType
+ {
+ void Method()
+ {
+ }
+
+ void GenericMethod()
+ {
+ }
+ }
+
+ class OtherReferenceType
+ {
+ }
+
+ struct StructType
+ {
+ void Method()
+ {
+ }
+
+ void GenericMethod()
+ {
+ }
+ }
+
+ struct OtherStructType
+ {
+ }
+
+ class GenericReferenceType
+ {
+ void Method()
+ {
+ }
+
+ void GenericMethod()
+ {
+ }
+ }
+
+ struct GenericStructType
+ {
+ void Method()
+ {
+ }
+
+ void GenericMethod()
+ {
+ }
+ }
+
+ class GenericReferenceTypeWithThreeParams
+ {
+ }
+
+ class GenericStructTypeWithThreeParams
+ {
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs
new file mode 100644
index 00000000000000..2ae42bd4b9a413
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Casting.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Casting
+{
+ interface IFoo { }
+
+ interface IContravariant { }
+
+ class ClassImplementingIFoo : IFoo { }
+
+ class ClassImplementingIFooIndirectly : ClassImplementingIFoo { }
+
+ enum IntBasedEnum : int { }
+
+ enum UIntBasedEnum : uint { }
+
+ enum ShortBasedEnum : short { }
+
+ class ClassWithNoConstraint { }
+
+ class ClassWithValueTypeConstraint where T : struct { }
+
+ class ClassWithInterfaceConstraint where T : IFoo { }
+
+ class ClassWithRecursiveImplementation : IContravariant> { }
+}
\ No newline at end of file
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj
new file mode 100644
index 00000000000000..4c028c607aca10
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/CoreTestAssembly.csproj
@@ -0,0 +1,15 @@
+
+
+ Library
+ CoreTestAssembly
+ false
+ true
+ true
+ netstandard2.0
+
+ true
+
+ v4.0.30319
+ false
+
+
\ No newline at end of file
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs
new file mode 100644
index 00000000000000..7b884ea7bdd301
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GCPointerMap.cs
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 169 // Field 'blah' is never used
+
+namespace GCPointerMap
+{
+ [StructLayout(LayoutKind.Sequential)]
+ class ClassWithArrayFields
+ {
+ int[] a1;
+ string[] a2;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ class ClassWithStringField
+ {
+ static string dummy;
+ int i;
+ string s;
+ bool z;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct MixedStruct
+ {
+ public int X;
+ public object Y;
+ public int Z;
+ public byte U;
+ public object V;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct Struct4GcPointers
+ {
+ public object o1;
+ public object o2;
+ public object o3;
+ public object o4;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct Struct32GcPointers
+ {
+ public Struct4GcPointers x1;
+ public Struct4GcPointers x2;
+ public Struct4GcPointers x3;
+ public Struct4GcPointers x4;
+ public Struct4GcPointers x5;
+ public Struct4GcPointers x6;
+ public Struct4GcPointers x7;
+ public Struct4GcPointers x8;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct StructWithSameGCLayoutAsMixedStruct
+ {
+ MixedStruct s;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct DoubleMixedStructLayout
+ {
+ StructWithSameGCLayoutAsMixedStruct X;
+ MixedStruct Y;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ struct ExplicitlyFarPointer
+ {
+ [FieldOffset(0)]
+ object X;
+
+ [FieldOffset(32 * 8)]
+ object Y;
+
+ [FieldOffset(40 * 8)]
+ object Z;
+
+ [FieldOffset(56 * 8)]
+ MixedStruct W;
+ }
+
+ class MixedStaticClass
+ {
+ object dummy1;
+ static object o;
+ static int dummy2;
+ const string dummy3 = "Hello";
+ static StructWithSameGCLayoutAsMixedStruct m1;
+ static MixedStruct m2;
+ }
+
+ class MixedThreadStaticClass
+ {
+ object dummy1;
+ static object dummy2;
+
+ [ThreadStatic]
+ static int i;
+
+ [ThreadStatic]
+ static StructWithSameGCLayoutAsMixedStruct m1;
+
+ [ThreadStatic]
+ static MixedStruct m2;
+
+ [ThreadStatic]
+ static object o;
+
+ [ThreadStatic]
+ static short s;
+ }
+}
diff --git a/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs
new file mode 100644
index 00000000000000..8af32283939143
--- /dev/null
+++ b/src/coreclr/src/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/GenericConstraints.cs
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace GenericConstraints
+{
+ public interface INonGen { }
+
+ public interface IGen { }
+
+ public class Arg1 : INonGen { }
+
+ public class Arg2 { }
+
+ public class Arg3 : IGen { }
+
+ public struct StructArgWithDefaultCtor { }
+
+ public struct StructArgWithoutDefaultCtor
+ {
+ public StructArgWithoutDefaultCtor(int argument) { }
+ }
+
+ public class ClassArgWithDefaultCtor : IGen