Type equivalence support in Crossgen2 (#87899)
authorDavid Wrighton <davidwr@microsoft.com>
Thu, 6 Jul 2023 00:55:38 +0000 (17:55 -0700)
committerGitHub <noreply@github.com>
Thu, 6 Jul 2023 00:55:38 +0000 (17:55 -0700)
We currently have a small behavior hole on Windows where if a binary uses TypeEquivalence, it is technically possible to get crossgen2 to generate invalid code.

This fixes that by adding support for type equivalence to the managed type system, and adjusting crossgen2 to use it. This is complicated by the detail that this may generate some type references which cannot be referenced from an R2R file, so additional error checking was needed (this additional error checking is what fixes #67855).

However, while basic support for type equivalence has been added to the type system, support for actually performing type equivalent interface resolution has not been, so devirtualization of type equivalent interface calls is disabled. At this time, I do not expect to see a customer need for implementing that fairly complicated feature

Fixes #67855

52 files changed:
src/coreclr/inc/corinfo.h
src/coreclr/inc/jiteeversionguid.h
src/coreclr/jit/compiler.cpp
src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.Validation.cs
src/coreclr/tools/Common/Compiler/TypeExtensions.cs
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.TypeEquivalence.cs [new file with mode: 0644]
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.cs
src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.TypeEquivalence.cs [new file with mode: 0644]
src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.cs
src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs
src/coreclr/tools/Common/TypeSystem/Common/MethodDesc.cs
src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.TypeEquivalence.cs [new file with mode: 0644]
src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs
src/coreclr/tools/Common/TypeSystem/Ecma/EcmaModule.cs
src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.TypeEquivalence.cs [new file with mode: 0644]
src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.cs
src/coreclr/tools/Common/TypeSystem/Ecma/EffectiveVisibility.cs [moved from src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/EffectiveVisibility.cs with 55% similarity]
src/coreclr/tools/Common/TypeSystem/Interop/MarshalAsDescriptor.cs
src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedType.cs
src/coreclr/tools/ILVerification/ILVerification.csproj
src/coreclr/tools/ILVerification/ILVerification.projitems
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeValidationChecker.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Canonicalization.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Platform.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILCompiler.TypeSystem.Tests.csproj
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TestTypeSystemContext.cs
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypeEquivalenceAssembly1.csproj [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypeEquivalenceAssembly2.csproj [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotLoad.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotMatch.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichMatch.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceTests.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
src/coreclr/vm/methodtable.cpp
src/tests/baseservices/typeequivalence/istypeequivalent/istypeequivalent.cs [new file with mode: 0644]
src/tests/baseservices/typeequivalence/istypeequivalent/istypeequivalent.csproj [new file with mode: 0644]
src/tests/baseservices/typeequivalence/istypeequivalent/typeequivalenttypes_1.csproj [new file with mode: 0644]
src/tests/baseservices/typeequivalence/istypeequivalent/typeequivalenttypes_2.csproj [new file with mode: 0644]
src/tests/baseservices/typeequivalence/signatures/basetestclassesil.il [new file with mode: 0644]
src/tests/baseservices/typeequivalence/signatures/basetestclassesil.ilproj [new file with mode: 0644]
src/tests/baseservices/typeequivalence/signatures/nopiatestil.il [new file with mode: 0644]
src/tests/baseservices/typeequivalence/signatures/nopiatestil.ilproj [new file with mode: 0644]
src/tests/baseservices/typeequivalence/signatures/testclassesil.il [new file with mode: 0644]
src/tests/baseservices/typeequivalence/signatures/testclassesil.ilproj [new file with mode: 0644]
src/tests/issues.targets

index 867962d..bb07aab 100644 (file)
@@ -1634,6 +1634,7 @@ enum CORINFO_DEVIRTUALIZATION_DETAIL
     CORINFO_DEVIRTUALIZATION_FAILED_BUBBLE_IMPL_NOT_REFERENCEABLE, // object class cannot be referenced from R2R code due to missing tokens
     CORINFO_DEVIRTUALIZATION_FAILED_DUPLICATE_INTERFACE,           // crossgen2 virtual method algorithm and runtime algorithm differ in the presence of duplicate interface implementations
     CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE,        // Decl method cannot be represented in R2R image
+    CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE,              // Support for type equivalence in devirtualization is not yet implemented in crossgen2
     CORINFO_DEVIRTUALIZATION_COUNT,                                // sentinel for maximum value
 };
 
index 1585cfd..fda1fde 100644 (file)
@@ -43,13 +43,13 @@ typedef const GUID *LPCGUID;
 #define GUID_DEFINED
 #endif // !GUID_DEFINED
 
-constexpr GUID JITEEVersionIdentifier = { /* 2335da47-1d6c-4844-96b6-025558a525ba */
-    0x2335da47,
-    0x1d6c,
-    0x4844,
-    {0x96, 0xb6, 0x02, 0x55, 0x58, 0xa5, 0x25, 0xba}
+constexpr GUID JITEEVersionIdentifier = { /* ba2c087c-9b8b-49c1-a52f-3514eb489308 */
+    0xba2c087c,
+    0x9b8b,
+    0x49c1,
+    {0xa5, 0x2f, 0x35, 0x14, 0xeb, 0x48, 0x93, 0x08}
   };
-
+  
 //////////////////////////////////////////////////////////////////////////////////////////////////////////
 //
 // END JITEEVersionIdentifier
index 827f7c0..5804e73 100644 (file)
@@ -10353,6 +10353,8 @@ const char* Compiler::devirtualizationDetailToString(CORINFO_DEVIRTUALIZATION_DE
                    "interface implementations";
         case CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE:
             return "Decl method cannot be represented in R2R image";
+        case CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE:
+            return "Support for type equivalence in devirtualization is not yet implemented in crossgen2";
         default:
             return "undefined";
     }
index fa77552..018f576 100644 (file)
@@ -45,6 +45,14 @@ namespace ILCompiler
 
         private static TypeDesc EnsureLoadableTypeUncached(TypeDesc type)
         {
+            if (type.TypeIdentifierData != null)
+            {
+                if (!type.TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType)
+                {
+                    ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
+                }
+            }
+
             if (type.IsParameterizedType)
             {
                 // Validate parameterized types
index 989bc65..5d73412 100644 (file)
@@ -322,7 +322,7 @@ namespace ILCompiler
                 bDepth--;
             }
 
-            while (ta != tb)
+            while (!ta.IsEquivalentTo(tb))
             {
                 ta = ta.BaseType;
                 tb = tb.BaseType;
@@ -350,7 +350,11 @@ namespace ILCompiler
             Debug.Assert(taElem != tbElem);
 
             TypeDesc mergeElem;
-            if (taElem.IsArray && tbElem.IsArray)
+            if (taElem.IsEquivalentTo(tbElem))
+            {
+                mergeElem = taElem;
+            }
+            else if (taElem.IsArray && tbElem.IsArray)
             {
                 mergeElem = MergeArrayTypesToCommonParent((ArrayType)taElem, (ArrayType)tbElem);
             }
index 13fd08e..453e80c 100644 (file)
@@ -857,6 +857,10 @@ namespace Internal.JitInterface
             sig->_retType = (byte)corInfoRetType;
             sig->retTypeSigClass = ObjectToHandle(signature.ReturnType);
 
+#if READYTORUN
+            ValidateSafetyOfUsingTypeEquivalenceOfType(signature.ReturnType);
+#endif
+
             sig->flags = 0;    // used by IL stubs code
 
             sig->numArgs = (ushort)signature.Length;
@@ -1755,6 +1759,7 @@ namespace Internal.JitInterface
                     ModuleToken methodModuleToken = HandleToModuleToken(ref pResolvedToken);
                     var resolver = _compilation.NodeFactory.Resolver;
                     resolver.AddModuleTokenForMethod(method, methodModuleToken);
+                    ValidateSafetyOfUsingTypeEquivalenceInSignature(method.Signature);
                 }
 #else
                 _compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _additionalDependencies, _compilation.NodeFactory, (MethodIL)methodIL, method);
@@ -1781,6 +1786,8 @@ namespace Internal.JitInterface
 
 #if !READYTORUN
                 _compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _additionalDependencies, _compilation.NodeFactory, (MethodIL)methodIL, field);
+#else
+                ValidateSafetyOfUsingTypeEquivalenceOfType(field.FieldType);
 #endif
             }
             else
index e3c6fc1..fcc4a2e 100644 (file)
@@ -1058,6 +1058,7 @@ namespace Internal.JitInterface
         CORINFO_DEVIRTUALIZATION_FAILED_BUBBLE_IMPL_NOT_REFERENCEABLE, // object class cannot be referenced from R2R code due to missing tokens
         CORINFO_DEVIRTUALIZATION_FAILED_DUPLICATE_INTERFACE,           // crossgen2 virtual method algorithm and runtime algorithm differ in the presence of duplicate interface implementations
         CORINFO_DEVIRTUALIZATION_FAILED_DECL_NOT_REPRESENTABLE,        // Decl method cannot be represented in R2R image
+        CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE,              // Support for type equivalence in devirtualization is not yet implemented in crossgen2
         CORINFO_DEVIRTUALIZATION_COUNT,                                // sentinel for maximum value
     }
 
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.TypeEquivalence.cs b/src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.TypeEquivalence.cs
new file mode 100644 (file)
index 0000000..8797efd
--- /dev/null
@@ -0,0 +1,336 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Debug = System.Diagnostics.Debug;
+using System.Collections.Generic;
+using Internal.TypeSystem.Ecma;
+
+namespace Internal.TypeSystem
+{
+    public static partial class CastingHelper
+    {
+        static partial void IsEquivalentTo(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect visited, ref bool isEquivalentTo)
+        {
+            isEquivalentTo = IsEquivalentToHelper(thisType, otherType, visited);
+            return;
+        }
+
+        private static bool IsEquivalentToHelper(TypeDesc thisType, TypeDesc otherType, StackOverflowProtect visited)
+        {
+            if (thisType == otherType)
+                return true;
+
+            if (thisType.Category != otherType.Category)
+                return false;
+
+            switch (thisType.Category)
+            {
+                case TypeFlags.SignatureTypeVariable:
+                case TypeFlags.SignatureMethodVariable:
+                case TypeFlags.GenericParameter:
+                    return false;
+
+                case TypeFlags.Array:
+                    var arrayType = (ArrayType)thisType;
+                    var otherArrayType = (ArrayType)otherType;
+                    if (arrayType.Rank != otherArrayType.Rank)
+                        return false;
+                    return arrayType.ParameterType.IsEquivalentTo(otherArrayType.ParameterType, visited);
+
+                case TypeFlags.SzArray:
+                case TypeFlags.ByRef:
+                case TypeFlags.Pointer:
+                    return ((ParameterizedType)thisType).ParameterType.IsEquivalentTo(((ParameterizedType)otherType).ParameterType, visited);
+
+                case TypeFlags.FunctionPointer:
+                    return false;
+
+                default:
+                    Debug.Assert(thisType.IsDefType);
+                    if (!thisType.IsTypeDefEquivalent || !otherType.IsTypeDefEquivalent)
+                    {
+                        if (thisType.HasInstantiation && otherType.HasInstantiation)
+                        {
+                            // We might be in the generic interface case
+                        }
+                        else
+                        {
+                            return false;
+                        }
+                    }
+                    return ((DefType)thisType).IsEquivalentToDefType((DefType)otherType, visited);
+            }
+        }
+
+        private static bool IsEquivalentToDefType(this DefType thisType, DefType otherType, StackOverflowProtect visited)
+        {
+            if (thisType.HasInstantiation)
+            {
+                // Limit equivalence on generics only to interfaces
+                if (!thisType.IsInterface || !otherType.IsInterface)
+                {
+                    return false;
+                }
+
+                if (thisType.Instantiation.Length != otherType.Instantiation.Length)
+                {
+                    return false;
+                }
+
+                // Generic equivalence only allows the instantiation to be non-equal
+                if (!thisType.HasSameTypeDefinition(otherType))
+                    return false;
+
+                for (int i = 0; i < thisType.Instantiation.Length; i++)
+                {
+                    if (!thisType.Instantiation[i].IsEquivalentTo(otherType.Instantiation[i], visited))
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+
+            return IsEquivalentTo_TypeDefinition((MetadataType)thisType.GetTypeDefinition(), (MetadataType)otherType.GetTypeDefinition(), visited);
+
+            static bool IsEquivalentTo_TypeDefinition(MetadataType type1, MetadataType type2, StackOverflowProtect visited)
+            {
+                Debug.Assert(type1.GetTypeDefinition() == type1);
+                Debug.Assert(type2.GetTypeDefinition() == type2);
+
+                var stackOverflowProtectKey = new CastingPair(type1, type2);
+                if (visited != null)
+                {
+                    if (visited.Contains(stackOverflowProtectKey))
+                    {
+                        // we are in the process of comparing these tokens already. Assume success
+                        return true;
+                    }
+                }
+
+                StackOverflowProtect protect = new StackOverflowProtect(stackOverflowProtectKey, visited);
+
+                TypeIdentifierData data1 = type1.TypeIdentifierData;
+                TypeIdentifierData data2 = type2.TypeIdentifierData;
+                if (data1 == null || data2 == null)
+                {
+                    return false;
+                }
+
+                // Check to ensure that the types are actually opted into equivalence
+                if (!type1.IsTypeDefEquivalent || !type2.IsTypeDefEquivalent)
+                    return false;
+
+                if (!data1.Equals(data2))
+                    return false;
+
+                if (type1.Name != type2.Name)
+                    return false;
+
+                if (type1.Namespace != type2.Namespace)
+                    return false;
+
+                var containingType1 = (MetadataType)type1.ContainingType;
+                var containingType2 = (MetadataType)type2.ContainingType;
+
+                // Types must be either not nested, or nested in equivalent types
+                if ((containingType1 == null) != (containingType2 == null))
+                {
+                    return false;
+                }
+
+                if ((containingType1 != null) && !IsEquivalentTo_TypeDefinition(containingType1, containingType2, visited))
+                {
+                    return false;
+                }
+
+                if (type1.IsInterface != type2.IsInterface)
+                {
+                    return false;
+                }
+                if (type1.IsInterface)
+                {
+                    return true;
+                }
+                if ((type1.IsEnum != type2.IsEnum) || (type1.IsValueType != type2.IsValueType))
+                {
+                    return false;
+                }
+
+                if (type1.IsEnum)
+                {
+                    return CompareStructuresForEquivalence(type1, type2, visited, enumMode: true);
+                }
+                else if (type1.IsValueType)
+                {
+                    return CompareStructuresForEquivalence(type1, type2, visited, enumMode: false);
+                }
+                else if ((type1.IsDelegate == type2.IsDelegate) && type1.IsDelegate)
+                {
+                    return CompareDelegatesForEquivalence(type1, type2, visited);
+                }
+
+                return false;
+            }
+
+            static bool CompareDelegatesForEquivalence(MetadataType type1, MetadataType type2, StackOverflowProtect visited)
+            {
+                var invoke1 = type1.GetMethod("Invoke", null);
+                var invoke2 = type2.GetMethod("Invoke", null);
+
+                if (invoke1 == null)
+                    return false;
+
+                if (invoke2 == null)
+                    return false;
+
+                return invoke1.Signature.EquivalentTo(invoke2.Signature, visited);
+            }
+
+            static bool CompareStructuresForEquivalence(MetadataType type1, MetadataType type2, StackOverflowProtect visited, bool enumMode)
+            {
+                foreach (var method in type1.GetMethods())
+                {
+                    // If there are any methods, then it isn't actually a type-equivalent type
+                    return false;
+                }
+
+                foreach (var method in type2.GetMethods())
+                {
+                    // If there are any methods, then it isn't actually a type-equivalent type
+                    return false;
+                }
+
+                // Compare field types for equivalence
+                var fields1 = type1.GetFields().GetEnumerator();
+                var fields2 = type2.GetFields().GetEnumerator();
+
+                while (true)
+                {
+                    bool nonTypeEquivalentValidFieldFound;
+
+                    FieldDesc field1 = GetNextTypeEquivalentField(fields1, enumMode, out nonTypeEquivalentValidFieldFound);
+                    if (nonTypeEquivalentValidFieldFound)
+                        return false;
+                    FieldDesc field2 = GetNextTypeEquivalentField(fields2, enumMode, out nonTypeEquivalentValidFieldFound);
+                    if (nonTypeEquivalentValidFieldFound)
+                        return false;
+
+                    if ((field1 == null) && (field2 == null))
+                    {
+                        // We ran out of fields on both types before finding a failure
+                        break;
+                    }
+
+                    if ((field1 == null) || (field2 == null))
+                    {
+                        // we ran out of fields on 1 type.
+                        return false;
+                    }
+
+                    // Compare the field signatures for equivalence
+                    // TODO: Technically this comparison should include custom modifiers on the field signatures
+                    if (!field1.FieldType.IsEquivalentTo(field2.FieldType, visited))
+                    {
+                        return false;
+                    }
+
+                    // Compare the field marshal details
+                    var marshalAsDescriptor1 = field1.GetMarshalAsDescriptor();
+                    var marshalAsDescriptor2 = field2.GetMarshalAsDescriptor();
+
+                    if (marshalAsDescriptor1 == null || marshalAsDescriptor2 == null)
+                    {
+                        if (marshalAsDescriptor1 != marshalAsDescriptor2)
+                            return false;
+                    }
+                    else if (!marshalAsDescriptor1.Equals(marshalAsDescriptor2))
+                    {
+                        return false;
+                    }
+                }
+
+                // At this point we know that the set of fields is the same, and have the same types
+                if (!enumMode)
+                {
+                    if (!CompareTypeLayout(type1, type2))
+                    {
+                        return false;
+                    }
+                }
+                return true;
+
+                static bool CompareTypeLayout(MetadataType type1, MetadataType type2)
+                {
+                    // Types must either be Sequential or Explicit layout
+                    if (type1.IsSequentialLayout != type2.IsSequentialLayout)
+                    {
+                        return false;
+                    }
+
+                    if (type1.IsExplicitLayout != type2.IsExplicitLayout)
+                    {
+                        return false;
+                    }
+
+                    if (!(type1.IsSequentialLayout || type1.IsExplicitLayout))
+                    {
+                        return false;
+                    }
+
+                    bool explicitLayout = type1.IsExplicitLayout;
+
+                    // they must have the same charset
+                    if (type1.PInvokeStringFormat != type2.PInvokeStringFormat)
+                    {
+                        return false;
+                    }
+
+                    var layoutMetadata1 = type1.GetClassLayout();
+                    var layoutMetadata2 = type2.GetClassLayout();
+                    if ((layoutMetadata1.PackingSize != layoutMetadata2.PackingSize) ||
+                        (layoutMetadata1.Size != layoutMetadata2.Size))
+                        return false;
+
+                    if ((explicitLayout) && !(layoutMetadata1.Offsets == null && layoutMetadata2.Offsets == null))
+                    {
+                        if (layoutMetadata1.Offsets == null)
+                            return false;
+
+                        if (layoutMetadata2.Offsets == null)
+                            return false;
+
+                        for (int index = 0; index < layoutMetadata1.Offsets.Length; index++)
+                        {
+                            if (layoutMetadata1.Offsets[index].Offset != layoutMetadata2.Offsets[index].Offset)
+                                return false;
+                        }
+                    }
+
+                    return true;
+                }
+
+                static FieldDesc GetNextTypeEquivalentField(IEnumerator<FieldDesc> fieldEnum, bool enumMode, out bool fieldNotValidInEquivalentTypeFound)
+                {
+                    fieldNotValidInEquivalentTypeFound = false;
+                    while (fieldEnum.MoveNext())
+                    {
+                        var field = fieldEnum.Current;
+
+                        if (field.GetAttributeEffectiveVisibility() == EffectiveVisibility.Public && !field.IsStatic)
+                            return field;
+
+                        // Only public instance fields, and literal fields on enums are permitted in type equivalent structures
+                        if (!enumMode || !field.IsLiteral)
+                        {
+                            fieldNotValidInEquivalentTypeFound = true;
+                            return null;
+                        }
+                    }
+                    return null;
+                }
+            }
+        }
+    }
+}
index 67d8337..3036ce1 100644 (file)
@@ -98,6 +98,11 @@ namespace Internal.TypeSystem
         /// </summary>
         public static bool IsCompatibleWith(this TypeDesc thisType, TypeDesc otherType)
         {
+            return thisType.IsCompatibleWith(otherType, null);
+        }
+
+        internal  static bool IsCompatibleWith(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect visited)
+        {
             // Structs can be cast to the interfaces they implement, but they are not compatible according to ECMA I.8.7.1
             bool isCastFromValueTypeToReferenceType = otherType.IsValueType && !thisType.IsValueType;
             if (isCastFromValueTypeToReferenceType)
@@ -133,7 +138,7 @@ namespace Internal.TypeSystem
             }
 
             // Nullable<T> can be cast to T, but this is not compatible according to ECMA I.8.7.1
-            bool isCastFromNullableOfTtoT = thisType.IsNullable && otherType.IsEquivalentTo(thisType.Instantiation[0]);
+            bool isCastFromNullableOfTtoT = thisType.IsNullable && otherType.IsEquivalentTo(thisType.Instantiation[0], visited);
             if (isCastFromNullableOfTtoT)
             {
                 return false;
@@ -142,12 +147,25 @@ namespace Internal.TypeSystem
             return otherType.CanCastTo(thisType);
         }
 
-        private static bool IsEquivalentTo(this TypeDesc thisType, TypeDesc otherType)
+        public static bool IsEquivalentTo(this TypeDesc thisType, TypeDesc otherType)
         {
-            // TODO: Once type equivalence is implemented, this implementation needs to be enhanced to honor it.
-            return thisType == otherType;
+            bool isEquivalentTo = thisType == otherType;
+            if (!isEquivalentTo)
+                thisType.IsEquivalentTo(otherType, (StackOverflowProtect)null, ref isEquivalentTo);
+
+            return isEquivalentTo;
         }
 
+        internal static bool IsEquivalentTo(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect visited)
+        {
+            bool isEquivalentTo = thisType == otherType;
+            if (!isEquivalentTo)
+                thisType.IsEquivalentTo(otherType, visited, ref isEquivalentTo);
+
+            return isEquivalentTo;
+        }
+
+        static partial void IsEquivalentTo(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect visited, ref bool isEquivalentTo);
         private static bool CanCastToInternal(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect)
         {
             if (thisType == otherType)
@@ -257,7 +275,7 @@ namespace Internal.TypeSystem
             // unboxed versions do not.  Parameterized types have the
             // unboxed version, thus, if the from type parameter is value
             // class then only an exact match/equivalence works.
-            if (thisType.ParameterType == paramType)
+            if (thisType.ParameterType.IsEquivalentTo(paramType))
             {
                 return true;
             }
@@ -398,14 +416,14 @@ namespace Internal.TypeSystem
 
         private static bool CanCastToNonVariantInterface(this TypeDesc thisType, TypeDesc otherType)
         {
-            if (otherType == thisType)
+            if (otherType.IsEquivalentTo(thisType))
             {
                 return true;
             }
 
             foreach (var interfaceType in thisType.RuntimeInterfaces)
             {
-                if (interfaceType == otherType)
+                if (interfaceType.IsEquivalentTo(otherType))
                 {
                     return true;
                 }
@@ -416,6 +434,11 @@ namespace Internal.TypeSystem
 
         private static bool CanCastByVarianceToInterfaceOrDelegate(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protectInput)
         {
+            if (thisType == otherType)
+            {
+                return true;
+            }
+
             if (!thisType.HasSameTypeDefinition(otherType))
             {
                 return false;
@@ -442,7 +465,7 @@ namespace Internal.TypeSystem
                 TypeDesc arg = instantiationThis[i];
                 TypeDesc targetArg = instantiationTarget[i];
 
-                if (arg != targetArg)
+                if (!arg.IsEquivalentTo(targetArg))
                 {
                     GenericParameterDesc openArgType = (GenericParameterDesc)instantiationOpen[i];
 
@@ -484,7 +507,7 @@ namespace Internal.TypeSystem
                 // First chase inheritance hierarchy until we hit a class that only differs in its instantiation
                 do
                 {
-                    if (curType == otherType)
+                    if (curType.IsEquivalentTo(otherType))
                     {
                         return true;
                     }
@@ -515,7 +538,7 @@ namespace Internal.TypeSystem
 
                 do
                 {
-                    if (curType == otherType)
+                    if (curType.IsEquivalentTo(otherType))
                         return true;
 
                     curType = curType.BaseType;
@@ -544,39 +567,47 @@ namespace Internal.TypeSystem
 
             return false;
         }
+    }
 
-        private sealed class StackOverflowProtect
-        {
-            private CastingPair _value;
-            private StackOverflowProtect _previous;
-
-            public StackOverflowProtect(CastingPair value, StackOverflowProtect previous)
-            {
-                _value = value;
-                _previous = previous;
-            }
+    internal sealed class StackOverflowProtect
+    {
+        private CastingPair _value;
+        private StackOverflowProtect _previous;
 
-            public bool Contains(CastingPair value)
-            {
-                for (var current = this; current != null; current = current._previous)
-                    if (current._value.Equals(value))
-                        return true;
-                return false;
-            }
+        public StackOverflowProtect(CastingPair value, StackOverflowProtect previous)
+        {
+            _value = value;
+            _previous = previous;
         }
 
-        private struct CastingPair
+        public static StackOverflowProtect GetTypeEquivalentForbiddenScope(StackOverflowProtect previous)
         {
-            public readonly TypeDesc FromType;
-            public readonly TypeDesc ToType;
+            var protect = new StackOverflowProtect(default(CastingPair), previous);
+            return protect;
+        }
 
-            public CastingPair(TypeDesc fromType, TypeDesc toType)
+        public bool Contains(CastingPair value)
+        {
+            for (var current = this; current != null; current = current._previous)
             {
-                FromType = fromType;
-                ToType = toType;
+                if (current._value.Equals(value))
+                    return true;
             }
+            return false;
+        }
+    }
 
-            public bool Equals(CastingPair other) => FromType == other.FromType && ToType == other.ToType;
+    internal struct CastingPair
+    {
+        public readonly TypeDesc FromType;
+        public readonly TypeDesc ToType;
+
+        public CastingPair(TypeDesc fromType, TypeDesc toType)
+        {
+            FromType = fromType;
+            ToType = toType;
         }
+
+        public bool Equals(CastingPair other) => FromType == other.FromType && ToType == other.ToType;
     }
 }
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.TypeEquivalence.cs b/src/coreclr/tools/Common/TypeSystem/Common/InstantiatedType.TypeEquivalence.cs
new file mode 100644 (file)
index 0000000..018d172
--- /dev/null
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Internal.TypeSystem
+{
+    public partial class InstantiatedType
+    {
+        public override TypeIdentifierData TypeIdentifierData => _typeDef.TypeIdentifierData;
+        public override bool IsWindowsRuntime => _typeDef.IsWindowsRuntime;
+
+    }
+}
index d6fb23d..25ed6d2 100644 (file)
@@ -159,6 +159,14 @@ namespace Internal.TypeSystem
             return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this);
         }
 
+        public override MethodDesc GetMethodWithEquivalentSignature(string name, MethodSignature signature, Instantiation substitution)
+        {
+            MethodDesc typicalMethodDef = _typeDef.GetMethodWithEquivalentSignature(name, signature, substitution);
+            if (typicalMethodDef == null)
+                return null;
+            return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this);
+        }
+
         public override MethodDesc GetStaticConstructor()
         {
             MethodDesc typicalCctor = _typeDef.GetStaticConstructor();
index ae2c4cb..8d2b8a4 100644 (file)
@@ -315,6 +315,7 @@ namespace Internal.TypeSystem
 
         /// <summary>
         /// Find matching a matching method by name and sig on a type. (Restricted to virtual methods only)
+        /// This will find both exact and equivalent matches, but will prefer exact matches.
         /// </summary>
         /// <param name="targetMethod"></param>
         /// <param name="currentType"></param>
@@ -330,25 +331,32 @@ namespace Internal.TypeSystem
             MethodSignature sig = targetMethod.Signature;
 
             MethodDesc implMethod = null;
+            MethodDesc implMethodEquivalent = null;
             foreach (MethodDesc candidate in currentType.GetAllVirtualMethods())
             {
                 if (candidate.Name == name)
                 {
-                    if (candidate.Signature.Equals(sig))
+                    if (candidate.Signature.EquivalentTo(sig))
                     {
                         if (nameSigMatchMethodIsValidCandidate == null || nameSigMatchMethodIsValidCandidate(targetMethod, candidate))
                         {
-                            implMethod = candidate;
+                            implMethodEquivalent = candidate;
+
+                            if (candidate.Signature.Equals(sig))
+                                implMethod = candidate;
 
                             // If reverseMethodSearch is enabled, we want to find the last match on this type, not the first
                             // (reverseMethodSearch is used for most matches except for searches for name/sig method matches for interface methods on the most derived type)
-                            if (!reverseMethodSearch)
+                            if (!reverseMethodSearch && implMethod != null)
                                 return implMethod;
                         }
                     }
                 }
             }
 
+            if (implMethod == null)
+                return implMethodEquivalent;
+
             return implMethod;
         }
 
@@ -503,7 +511,7 @@ namespace Internal.TypeSystem
 
                     if (unificationGroup.RequiresSlotUnification(declSlot) || implSlot.RequiresSlotUnification())
                     {
-                        if (implSlot.Signature.EqualsWithCovariantReturnType(unificationGroup.DefiningMethod.Signature))
+                        if (implSlot.Signature.EquivalentWithCovariantReturnType(unificationGroup.DefiningMethod.Signature))
                         {
                             unificationGroup.AddMethodRequiringSlotUnification(declSlot);
                             unificationGroup.AddMethodRequiringSlotUnification(implSlot);
@@ -524,7 +532,7 @@ namespace Internal.TypeSystem
                         FindBaseUnificationGroup(baseType, addDeclGroup);
                         Debug.Assert(
                             addDeclGroup.IsInGroupOrIsDefiningSlot(declSlot) ||
-                            (addDeclGroup.RequiresSlotUnification(declSlot) && addDeclGroup.DefiningMethod.Signature.EqualsWithCovariantReturnType(declSlot.Signature)));
+                            (addDeclGroup.RequiresSlotUnification(declSlot) && addDeclGroup.DefiningMethod.Signature.EquivalentWithCovariantReturnType(declSlot.Signature)));
 
                         foreach (MethodDesc methodImplRequiredToRemainInEffect in addDeclGroup.MethodsRequiringSlotUnification)
                         {
@@ -558,7 +566,7 @@ namespace Internal.TypeSystem
                     }
                     else if (unificationGroup.RequiresSlotUnification(declSlot))
                     {
-                        if (implSlot.Signature.EqualsWithCovariantReturnType(unificationGroup.DefiningMethod.Signature))
+                        if (implSlot.Signature.EquivalentWithCovariantReturnType(unificationGroup.DefiningMethod.Signature))
                         {
                             unificationGroup.AddMethodRequiringSlotUnification(implSlot);
                             unificationGroup.SetDefiningMethod(implSlot);
index 6e12253..4361789 100644 (file)
@@ -214,15 +214,25 @@ namespace Internal.TypeSystem
 
         public bool Equals(MethodSignature otherSignature)
         {
-            return Equals(otherSignature, allowCovariantReturn: false);
+            return Equals(otherSignature, allowCovariantReturn: false, allowEquivalence: false);
         }
 
-        public bool EqualsWithCovariantReturnType(MethodSignature otherSignature)
+        public bool EquivalentWithCovariantReturnType(MethodSignature otherSignature)
         {
-            return Equals(otherSignature, allowCovariantReturn: true);
+            return Equals(otherSignature, allowCovariantReturn: true, allowEquivalence: true);
         }
 
-        private bool Equals(MethodSignature otherSignature, bool allowCovariantReturn)
+        public bool EquivalentTo(MethodSignature otherSignature)
+        {
+            return Equals(otherSignature, allowCovariantReturn: false, allowEquivalence: true, visited: null);
+        }
+
+        internal bool EquivalentTo(MethodSignature otherSignature, StackOverflowProtect visited)
+        {
+            return Equals(otherSignature, allowCovariantReturn: false, allowEquivalence: true, visited: visited);
+        }
+
+        private bool Equals(MethodSignature otherSignature, bool allowCovariantReturn, bool allowEquivalence, StackOverflowProtect visited = null)
         {
             if (this._flags != otherSignature._flags)
                 return false;
@@ -230,12 +240,12 @@ namespace Internal.TypeSystem
             if (this._genericParameterCount != otherSignature._genericParameterCount)
                 return false;
 
-            if (this._returnType != otherSignature._returnType)
+            if (!IsTypeEqualHelper(this._returnType, otherSignature._returnType, allowEquivalence, visited))
             {
                 if (!allowCovariantReturn)
                     return false;
 
-                if (!otherSignature._returnType.IsCompatibleWith(this._returnType))
+                if (!otherSignature._returnType.IsCompatibleWith(this._returnType, visited))
                     return false;
             }
 
@@ -244,7 +254,7 @@ namespace Internal.TypeSystem
 
             for (int i = 0; i < this._parameters.Length; i++)
             {
-                if (this._parameters[i] != otherSignature._parameters[i])
+                if (!IsTypeEqualHelper(this._parameters[i], otherSignature._parameters[i], allowEquivalence, visited))
                     return false;
             }
 
@@ -274,7 +284,7 @@ namespace Internal.TypeSystem
 
                     if (thisData.index != otherData.index ||
                         thisData.kind != otherData.kind ||
-                        thisData.type != otherData.type)
+                        !IsTypeEqualHelper(thisData.type, otherData.type, allowEquivalence, visited))
                     {
                         return false;
                     }
@@ -284,6 +294,21 @@ namespace Internal.TypeSystem
             }
 
             return false;
+
+            static bool IsTypeEqualHelper(TypeDesc type1, TypeDesc type2, bool allowEquivalence, StackOverflowProtect visited)
+            {
+                if (type1 == type2)
+                    return true;
+
+                if (allowEquivalence)
+                {
+                    if (type1.IsEquivalentTo(type2, visited))
+                    {
+                        return true;
+                    }
+                }
+                return false;
+            }
         }
 
         public override bool Equals(object obj)
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.TypeEquivalence.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.TypeEquivalence.cs
new file mode 100644 (file)
index 0000000..3ae8c0f
--- /dev/null
@@ -0,0 +1,163 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Debug = System.Diagnostics.Debug;
+using System;
+
+namespace Internal.TypeSystem
+{
+    public class TypeIdentifierData : IEquatable<TypeIdentifierData>
+    {
+        public TypeIdentifierData(string scope, string name)
+        {
+            Debug.Assert(scope != null);
+            Debug.Assert(name != null);
+            Scope = scope;
+            Name = name;
+        }
+
+        public static readonly TypeIdentifierData Empty = new TypeIdentifierData("", "");
+
+        public string Scope { get; }
+        public string Name { get; }
+
+        public bool Equals(TypeIdentifierData other)
+        {
+            if (Scope != other.Scope)
+                return false;
+            return Name == other.Name;
+        }
+
+        public override int GetHashCode()
+        {
+            return Scope.GetHashCode() ^ Name.GetHashCode();
+        }
+
+        public override bool Equals(object o)
+        {
+            if (o is TypeIdentifierData other)
+                return Equals(other);
+            return false;
+        }
+    }
+
+    public partial class TypeDesc
+    {
+        public virtual TypeIdentifierData TypeIdentifierData => null;
+
+        public bool IsTypeDefEquivalent => TypeIdentifierData != null;
+
+        public bool HasTypeEquivalence
+        {
+            get
+            {
+                if (!Context.SupportsTypeEquivalence)
+                    return false;
+                if (IsTypeDefEquivalent)
+                    return true;
+                if (HasInstantiation)
+                {
+                    foreach (var type in Instantiation)
+                    {
+                        if (type.HasTypeEquivalence)
+                            return true;
+                    }
+                }
+
+                return false;
+            }
+        }
+
+        public virtual bool IsWindowsRuntime => false;
+
+        public virtual bool IsComImport => false;
+
+        public virtual bool IsComEventInterface => false;
+
+        public bool TypeHasCharacteristicsRequiredToBeTypeEquivalent
+        {
+            get
+            {
+                if (this is not DefType)
+                    return false;
+
+                var defType = (DefType)this;
+
+                // 1. Type is a COMImport/COMEvent interface, enum, struct, or delegate
+                if (!(IsInterface && (IsComImport || IsComEventInterface)) && !IsValueType && !IsDelegate)
+                    return false;
+
+                // 2. Type is not generic
+                if (HasInstantiation)
+                    return false;
+
+                // 3. Type is externally visible (i.e public)
+                if (!((TypeDesc)defType).GetEffectiveVisibility().IsExposedOutsideOfThisAssembly(false))
+                    return false;
+
+                // 4. Type is not tdWindowsRuntime
+                if (IsWindowsRuntime)
+                    return false;
+
+                var containingType = defType.ContainingType;
+                if (defType.ContainingType != null)
+                {
+                    if (containingType.TypeIdentifierData == null)
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+        }
+
+        // A type may be type equivalent for the purposes of signature comparison, but not permitted
+        // to actually be loaded. This predicate checks for the loadability with regards
+        // to type equivalence rules for types that have a TypeIdentifierData
+        public bool TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType
+        {
+            get
+            {
+                // There is a set of checks that must be passed to be eligible implicitly for
+                // type equivalence. We need to pass these checks for explicitly type equivalent
+                // types as well.
+                if (!TypeHasCharacteristicsRequiredToBeTypeEquivalent)
+                    return false;
+
+                // A type equivalent structure type MUST not have any non-static methods
+                if (IsValueType)
+                {
+                    foreach (var method in GetMethods())
+                    {
+                        // Note that while a type equivalent structure MAY have static methods, if it does so it will never compare as
+                        // equivalent to another type. This is an odd quirk, but seems to be consistent in the runtime since the feature was built.
+                        if (!method.Signature.IsStatic)
+                            return false;
+                    }
+
+                    foreach (var field in GetFields())
+                    {
+                        if (field.IsLiteral)
+                        {
+                            // Literal fields are ok
+                            continue;
+                        }
+
+                        if (field.IsStatic)
+                        {
+                            return false;
+                        }
+
+                        if (field.GetEffectiveVisibility() != EffectiveVisibility.Public)
+                        {
+                            return false;
+                        }
+                    }
+                }
+
+                return true;
+            }
+        }
+    }
+}
index ae83551..58aa349 100644 (file)
@@ -545,6 +545,19 @@ namespace Internal.TypeSystem
             return null;
         }
 
+        public virtual MethodDesc GetMethodWithEquivalentSignature(string name, MethodSignature signature, Instantiation substitution)
+        {
+            foreach (var method in GetMethods())
+            {
+                if (method.Name == name)
+                {
+                    if (signature == null || signature.EquivalentTo(method.Signature.ApplySubstitution(substitution)))
+                        return method;
+                }
+            }
+            return null;
+        }
+
         /// <summary>
         /// Retrieves the class constructor method of this type.
         /// </summary>
index 233fedd..d423574 100644 (file)
@@ -779,5 +779,8 @@ namespace Internal.TypeSystem
         /// Determine if the type implements <code>IDynamicInterfaceCastable</code>
         /// </summary>
         protected internal abstract bool IsIDynamicInterfaceCastableInterface(DefType type);
+
+        public virtual bool SupportsTypeEquivalence => false;
+        public virtual bool SupportsCOMInterop => false;
     }
 }
index 738077d..e39d8be 100644 (file)
@@ -526,6 +526,8 @@ namespace Internal.TypeSystem.Ecma
                     do
                     {
                         MethodDesc method = typeDescToInspect.GetMethod(name, sig, substitution);
+                        if (method == null && Context.SupportsTypeEquivalence)
+                            method = typeDescToInspect.GetMethodWithEquivalentSignature(name, sig, substitution);
                         if (method != null)
                         {
                             // If this resolved to one of the base types, make sure it's not a constructor.
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.TypeEquivalence.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaType.TypeEquivalence.cs
new file mode 100644 (file)
index 0000000..94d7722
--- /dev/null
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Threading;
+
+namespace Internal.TypeSystem.Ecma
+{
+    public partial class EcmaType
+    {
+        private  TypeIdentifierData _data;
+
+        private TypeIdentifierData ComputeTypeIdentifierFromGuids()
+        {
+            CustomAttributeValue<TypeDesc>? guidAttribute;
+            if (IsInterface && _typeDefinition.Attributes.HasFlag(TypeAttributes.Import))
+            {
+                // ComImport interfaces get scope from their GUID
+                guidAttribute = this.GetDecodedCustomAttribute("System.Runtime.InteropServices", "GuidAttribute");
+            }
+            else
+            {
+                // other equivalent types get it from the declaring assembly
+                var attributeHandle = this.MetadataReader.GetCustomAttributeHandle(MetadataReader.GetAssemblyDefinition().GetCustomAttributes(), "System.Runtime.InteropServices", "GuidAttribute");
+                if (attributeHandle.IsNil)
+                    return null;
+
+                guidAttribute = this.MetadataReader.GetCustomAttribute(attributeHandle).DecodeValue(new CustomAttributeTypeProvider(this.EcmaModule));
+            }
+
+            if (!guidAttribute.HasValue)
+                return null;
+
+            if (guidAttribute.Value.FixedArguments.Length < 1)
+                return null;
+
+            if (guidAttribute.Value.FixedArguments[0].Type != Context.GetWellKnownType(WellKnownType.String))
+                return null;
+
+            string scope = (string)guidAttribute.Value.FixedArguments[0].Value;
+            string name = this.Name;
+            if (this.Namespace != null)
+                name = this.Namespace + "." + name;
+
+            return new TypeIdentifierData(scope, name);
+        }
+
+        private TypeIdentifierData ComputeTypeIdentifierData()
+        {
+            if (!Context.SupportsTypeEquivalence)
+                return null;
+
+            // Check for type identifier attribute
+            var typeIdentifierAttribute = this.GetDecodedCustomAttribute("System.Runtime.InteropServices", "TypeIdentifierAttribute");
+            if (typeIdentifierAttribute.HasValue)
+            {
+                // If the type has a type identifier attribute it is always considered to be type equivalent
+                if (typeIdentifierAttribute.Value.FixedArguments.Length == 0)
+                    return ComputeTypeIdentifierFromGuids();
+
+                if (typeIdentifierAttribute.Value.FixedArguments.Length != 2)
+                    return null;
+
+                if (typeIdentifierAttribute.Value.FixedArguments[0].Type != Context.GetWellKnownType(WellKnownType.String))
+                    return null;
+
+                if (typeIdentifierAttribute.Value.FixedArguments[1].Type != Context.GetWellKnownType(WellKnownType.String))
+                    return null;
+
+                _data = new TypeIdentifierData((string)typeIdentifierAttribute.Value.FixedArguments[0].Value, (string)typeIdentifierAttribute.Value.FixedArguments[1].Value);
+                return _data;
+            }
+            else
+            {
+                // In addition to the TypeIdentifierAttribute certain other types may also be opted in to type equivalence
+                if (Context.SupportsCOMInterop)
+                {
+                    // 1. Type is within assembly marked with ImportedFromTypeLibAttribute or PrimaryInteropAssemblyAttribute
+                    if (this.HasCustomAttribute("System.Runtime.InteropServices", "ImportedFromTypeLibAttribute") || this.HasCustomAttribute("System.Runtime.InteropServices", "PrimaryInteropAssemblyAttribute"))
+                    {
+                        // This type has a TypeIdentifier attribute if it has an appropriate shape to be considered type equivalent
+                    }
+
+                    if (!TypeHasCharacteristicsRequiredToBeTypeEquivalent)
+                        return null;
+
+                    _data = ComputeTypeIdentifierFromGuids();
+                }
+
+                return null;
+            }
+        }
+
+        public override TypeIdentifierData TypeIdentifierData
+        {
+            get
+            {
+                if (_data != null)
+                {
+                    if (object.ReferenceEquals(_data, TypeIdentifierData.Empty))
+                        return null;
+                    return _data;
+                }
+                var data = ComputeTypeIdentifierData() ?? TypeIdentifierData.Empty;
+
+                Interlocked.CompareExchange(ref _data, data, null);
+
+                // Recurse to read from _data and return a consistent result
+                return this.TypeIdentifierData;
+            }
+        }
+
+        public override bool IsWindowsRuntime
+        {
+            get
+            {
+                return _typeDefinition.Attributes.HasFlag(TypeAttributes.WindowsRuntime);
+            }
+        }
+
+        public override bool IsComImport
+        {
+            get
+            {
+                return _typeDefinition.Attributes.HasFlag(TypeAttributes.Import);
+            }
+        }
+
+        public override bool IsComEventInterface
+        {
+            get
+            {
+                return HasCustomAttribute("System.Runtime.InteropServices", "ComEventInterfaceAttribute");
+            }
+        }
+    }
+}
index 36944af..239537b 100644 (file)
@@ -346,6 +346,24 @@ namespace Internal.TypeSystem.Ecma
             return null;
         }
 
+        public override MethodDesc GetMethodWithEquivalentSignature(string name, MethodSignature signature, Instantiation substitution)
+        {
+            var metadataReader = this.MetadataReader;
+            var stringComparer = metadataReader.StringComparer;
+
+            foreach (var handle in _typeDefinition.GetMethods())
+            {
+                if (stringComparer.Equals(metadataReader.GetMethodDefinition(handle).Name, name))
+                {
+                    var method = _module.GetMethod(handle, this);
+                    if (signature == null || signature.EquivalentTo(method.Signature.ApplySubstitution(substitution)))
+                        return method;
+                }
+            }
+
+            return null;
+        }
+
         public override MethodDesc GetStaticConstructor()
         {
             var metadataReader = this.MetadataReader;
@@ -4,10 +4,9 @@
 using System;
 using System.Diagnostics;
 using System.Reflection;
-using Internal.TypeSystem;
 using Internal.TypeSystem.Ecma;
 
-namespace ILCompiler
+namespace Internal.TypeSystem
 {
     public enum EffectiveVisibility
     {
@@ -32,7 +31,11 @@ namespace ILCompiler
                 TypeAttributes.NestedFamily => EffectiveVisibility.Family,
                 TypeAttributes.NestedFamANDAssem => EffectiveVisibility.FamilyAndAssembly,
                 TypeAttributes.NestedFamORAssem => EffectiveVisibility.FamilyOrAssembly,
+#if NETSTANDARD2_0
+                _ => throw new Exception(),
+#else
                 _ => throw new UnreachableException()
+#endif
             };
         }
         private static EffectiveVisibility ToEffectiveVisibility(this MethodAttributes typeAttributes)
@@ -50,7 +53,34 @@ namespace ILCompiler
                 MethodAttributes.Family => EffectiveVisibility.Family,
                 MethodAttributes.FamANDAssem => EffectiveVisibility.FamilyAndAssembly,
                 MethodAttributes.FamORAssem => EffectiveVisibility.FamilyOrAssembly,
+#if NETSTANDARD2_0
+                _ => throw new Exception(),
+#else
                 _ => throw new UnreachableException()
+#endif
+            };
+        }
+
+        private static EffectiveVisibility ToEffectiveVisibility(this FieldAttributes typeAttributes)
+        {
+            return (typeAttributes & FieldAttributes.FieldAccessMask) switch
+            {
+                // PrivateScope == Compiler-Controlled in the ECMA spec. A member with this accessibility
+                // is only accessible through a MemberDef, not a MemberRef.
+                // As a result, it's only accessible within the current assembly, which is effectively the same rules as
+                // Family for our case.
+                FieldAttributes.PrivateScope => EffectiveVisibility.Assembly,
+                FieldAttributes.Public => EffectiveVisibility.Public,
+                FieldAttributes.Private => EffectiveVisibility.Private,
+                FieldAttributes.Assembly => EffectiveVisibility.Assembly,
+                FieldAttributes.Family => EffectiveVisibility.Family,
+                FieldAttributes.FamANDAssem => EffectiveVisibility.FamilyAndAssembly,
+                FieldAttributes.FamORAssem => EffectiveVisibility.FamilyOrAssembly,
+#if NETSTANDARD2_0
+                _ => throw new Exception(),
+#else
+                _ => throw new UnreachableException()
+#endif
             };
         }
 
@@ -71,7 +101,11 @@ namespace ILCompiler
                 (EffectiveVisibility.Assembly, EffectiveVisibility.FamilyAndAssembly) => EffectiveVisibility.FamilyAndAssembly,
                 (EffectiveVisibility.FamilyAndAssembly, EffectiveVisibility.Family) => EffectiveVisibility.FamilyAndAssembly,
                 (EffectiveVisibility.FamilyAndAssembly, EffectiveVisibility.Assembly) => EffectiveVisibility.FamilyAndAssembly,
+#if NETSTANDARD2_0
+                _ => throw new Exception(),
+#else
                 _ => throw new UnreachableException(),
+#endif
             };
         }
 
@@ -84,12 +118,78 @@ namespace ILCompiler
         public static EffectiveVisibility GetEffectiveVisibility(this EcmaMethod method)
         {
             EffectiveVisibility visibility = method.Attributes.ToEffectiveVisibility();
-            
+
             for (EcmaType type = (EcmaType)method.OwningType; type is not null; type = (EcmaType)type.ContainingType)
             {
                 visibility = visibility.ConstrainToVisibility(type.Attributes.ToEffectiveVisibility());
             }
             return visibility;
         }
+
+        public static EffectiveVisibility GetEffectiveVisibility(this EcmaType type)
+        {
+            EffectiveVisibility visibility = type.Attributes.ToEffectiveVisibility();
+            type = (EcmaType)type.ContainingType;
+            for (; type is not null; type = (EcmaType)type.ContainingType)
+            {
+                visibility = visibility.ConstrainToVisibility(type.Attributes.ToEffectiveVisibility());
+            }
+            return visibility;
+        }
+
+        public static EffectiveVisibility GetEffectiveVisibility(this TypeDesc type)
+        {
+            var definitionType = type.GetTypeDefinition();
+            if (definitionType is MetadataType)
+            {
+                if (definitionType is EcmaType ecmaType)
+                {
+                    return ecmaType.GetEffectiveVisibility();
+                }
+                return EffectiveVisibility.Public;
+            }
+            else
+            {
+                return EffectiveVisibility.Public;
+            }
+        }
+
+        public static EffectiveVisibility GetEffectiveVisibility(this EcmaField field)
+        {
+            // Treat all non-Ecma fields as always having public visibility
+            EffectiveVisibility visibility = field.Attributes.ToEffectiveVisibility();
+
+            for (EcmaType type = (EcmaType)field.OwningType; type is not null; type = (EcmaType)type.ContainingType)
+            {
+                visibility = visibility.ConstrainToVisibility(type.Attributes.ToEffectiveVisibility());
+            }
+            return visibility;
+        }
+
+        // Get the visibility declared on the field itself
+        // Treat all non-Ecma fields as always having public visibility
+        public static EffectiveVisibility GetAttributeEffectiveVisibility(this FieldDesc field)
+        {
+            if (field is EcmaField ecmaField)
+            {
+                return ecmaField.Attributes.ToEffectiveVisibility();
+            }
+            else
+            {
+                return EffectiveVisibility.Public;
+            }
+        }
+
+        public static EffectiveVisibility GetEffectiveVisibility(this FieldDesc field)
+        {
+            if (field is EcmaField ecmaField)
+            {
+                return GetEffectiveVisibility(ecmaField);
+            }
+            else
+            {
+                return EffectiveVisibility.Public;
+            }
+        }
     }
 }
index 39ecc97..4cc3c56 100644 (file)
@@ -1,6 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Diagnostics;
 
 namespace Internal.TypeSystem
@@ -45,7 +46,7 @@ namespace Internal.TypeSystem
         Variant = 0x51,
     }
 
-    public class MarshalAsDescriptor
+    public class MarshalAsDescriptor: IEquatable<MarshalAsDescriptor>
     {
         private TypeDesc _marshallerType;
         private string _cookie;
@@ -81,5 +82,30 @@ namespace Internal.TypeSystem
             _marshallerType = customMarshallerType;
             _cookie = cookie;
         }
+
+        public bool Equals(MarshalAsDescriptor other)
+        {
+            if ((Type != other.Type) ||
+                (ArraySubType != other.ArraySubType) ||
+                (SizeParamIndex != other.SizeParamIndex) ||
+                (SizeConst != other.SizeConst))
+                return false;
+
+            return true;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (obj is MarshalAsDescriptor other)
+            {
+                return Equals(other);
+            }
+            return false;
+        }
+
+        public override int GetHashCode()
+        {
+            return Type.GetHashCode() ^ (ArraySubType.GetHashCode() << 3);
+        }
     }
 }
index d9f2742..fffcc88 100644 (file)
@@ -129,6 +129,14 @@ namespace Internal.TypeSystem
             return Context.GetMethodForRuntimeDeterminedType(method.GetTypicalMethodDefinition(), this);
         }
 
+        public override MethodDesc GetMethodWithEquivalentSignature(string name, MethodSignature signature, Instantiation substitution)
+        {
+            MethodDesc method = _rawCanonType.GetMethodWithEquivalentSignature(name, signature, substitution);
+            if (method == null)
+                return null;
+            return Context.GetMethodForRuntimeDeterminedType(method.GetTypicalMethodDefinition(), this);
+        }
+
         protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
         {
             TypeFlags flags = 0;
index 0c6514f..4ac252c 100644 (file)
@@ -10,6 +10,7 @@
     <SignAssembly>true</SignAssembly>
     <StrongNameKeyId>Open</StrongNameKeyId>
     <RunAnalyzers>false</RunAnalyzers>
+    <DefineConstants>NETSTANDARD2_0</DefineConstants>
   </PropertyGroup>
 
   <Import Project="ILVerification.projitems" />
index 8c5e2e5..58c2204 100644 (file)
     <Compile Include="$(ToolsCommonPath)TypeSystem\Common\InstantiatedType.MethodImpls.cs">
       <Link>TypeSystem\Common\InstantiatedType.MethodImpls.cs</Link>
     </Compile>
+    <Compile Include="$(ToolsCommonPath)TypeSystem\Common\InstantiatedType.TypeEquivalence.cs">
+      <Link>TypeSystem\Common\InstantiatedType.TypeEquivalence.cs</Link>
+    </Compile>
     <Compile Include="$(ToolsCommonPath)TypeSystem\Common\LayoutInt.cs">
       <Link>TypeSystem\Common\LayoutInt.cs</Link>
     </Compile>
     <Compile Include="$(ToolsCommonPath)TypeSystem\Common\TypeDesc.ToString.cs">
       <Link>TypeSystem\Common\TypeDesc.ToString.cs</Link>
     </Compile>
+    <Compile Include="$(ToolsCommonPath)TypeSystem\Common\TypeDesc.TypeEquivalence.cs">
+      <Link>TypeSystem\Common\TypeDesc.TypeEquivalence.cs</Link>
+    </Compile>
     <Compile Include="$(ToolsCommonPath)TypeSystem\Common\DefType.cs">
       <Link>TypeSystem\Common\DefType.cs</Link>
     </Compile>
     <Compile Include="$(ToolsCommonPath)TypeSystem\Ecma\EcmaType.Interfaces.cs">
       <Link>Ecma\EcmaType.Interfaces.cs</Link>
     </Compile>
+    <Compile Include="$(ToolsCommonPath)TypeSystem\Ecma\EcmaType.TypeEquivalence.cs">
+      <Link>Ecma\EcmaType.TypeEquivalence.cs</Link>
+    </Compile>
+    <Compile Include="$(ToolsCommonPath)TypeSystem\Ecma\EffectiveVisibility.cs">
+      <Link>Ecma\EffectiveVisibility.cs</Link>
+    </Compile>
     <Compile Include="$(ToolsCommonPath)TypeSystem\Ecma\MetadataExtensions.cs">
       <Link>Ecma\MetadataExtensions.cs</Link>
     </Compile>
index 0b23b75..88882e1 100644 (file)
@@ -314,7 +314,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                     var methodDecl = type.EcmaModule.GetMethod(methodImpl.MethodDeclaration);
 
                     // Validate that all MethodImpls actually match signatures closely enough
-                    if (!methodBody.Signature.ApplySubstitution(type.Instantiation).EqualsWithCovariantReturnType(methodDecl.Signature.ApplySubstitution(type.Instantiation)))
+                    if (!methodBody.Signature.ApplySubstitution(type.Instantiation).EquivalentWithCovariantReturnType(methodDecl.Signature.ApplySubstitution(type.Instantiation)))
                     {
                         AddTypeValidationError(type, $"MethodImpl with Body '{methodBody}' and Decl '{methodDecl}' do not have matching signatures");
                         return false;
@@ -437,7 +437,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                         if ((virtualMethod.OwningType != type.BaseType) && (virtualMethod.OwningType != type) && (baseTypeVirtualMethodAlgorithm != null))
                         {
                             var implementationOnBaseType = baseTypeVirtualMethodAlgorithm.FindVirtualFunctionTargetMethodOnObjectType(virtualMethod, type.BaseType);
-                            if (!implementationMethod.Signature.ApplySubstitution(type.Instantiation).EqualsWithCovariantReturnType(implementationOnBaseType.Signature.ApplySubstitution(type.Instantiation)))
+                            if (!implementationMethod.Signature.ApplySubstitution(type.Instantiation).EquivalentWithCovariantReturnType(implementationOnBaseType.Signature.ApplySubstitution(type.Instantiation)))
                             {
                                 AddTypeValidationError(type, $"Virtual method '{virtualMethod}' overriden by method '{implementationMethod}' does not satisfy the covariant return type introduced with '{implementationOnBaseType}'");
                                 return false;
@@ -457,6 +457,14 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                     }
                 }
 
+                if (type.TypeIdentifierData != null)
+                {
+                    if (!type.TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType)
+                    {
+                        return false;
+                    }
+                }
+
                 return true;
             }
             catch (Exception ex)
index 234c48b..66c7767 100644 (file)
@@ -128,6 +128,46 @@ namespace ILCompiler
 
         public MethodDesc ResolveVirtualMethod(MethodDesc declMethod, TypeDesc implType, out CORINFO_DEVIRTUALIZATION_DETAIL devirtualizationDetail)
         {
+            if (declMethod.OwningType.IsInterface)
+            {
+                // The virtual method resolution algorithm in the managed type system is not implemented to work correctly
+                // in the presence of calling type equivalent interfaces.
+                // Notably:
+                // If the decl is to a interface equivalent to, but not equal to any interface implemented on the
+                // owning type, then the logic for matching up methods by method index is not present.
+                // AND
+                // If the owningType implements multiple different type equivalent interfaces that are all mutually
+                // equivalent, the implementation for finding the correct implementation method requires walking the
+                // type hierarchy and searching for exact and equivalent matches at each level (much like variance)
+                // This logic is also currently unimplemented.
+                // NOTE: We do not currently have tests in the runtime suite which cover these cases
+                if (declMethod.OwningType.HasTypeEquivalence)
+                {
+                    // To protect against this, require that the implType implement exactly the right interface, and
+                    // no additional interfaces that are equivalent
+                    bool foundExactMatch = false;
+                    bool foundEquivalentMatch = false;
+                    foreach (var @interface in implType.RuntimeInterfaces)
+                    {
+                        if (@interface == declMethod.OwningType)
+                        {
+                            foundExactMatch = true;
+                            continue;
+                        }
+                        if (@interface.IsEquivalentTo(declMethod.OwningType))
+                        {
+                            foundEquivalentMatch = true;
+                        }
+                    }
+
+                    if (!foundExactMatch || foundEquivalentMatch)
+                    {
+                        devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_TYPE_EQUIVALENCE;
+                        return null;
+                    }
+                }
+            }
+
             return _devirtualizationManager.ResolveVirtualMethod(declMethod, implType, out devirtualizationDetail);
         }
 
index 1395fa7..5e235da 100644 (file)
@@ -180,6 +180,9 @@ namespace ILCompiler
                 return _asyncStateMachineBox;
             }
         }
+
+        public override bool SupportsTypeEquivalence => Target.IsWindows;
+        public override bool SupportsCOMInterop => Target.IsWindows;
     }
 
     internal class VectorOfTFieldLayoutAlgorithm : FieldLayoutAlgorithm
index 1a2e182..21edfdd 100644 (file)
     <Compile Include="Compiler\DependencyAnalysis\ReadyToRunSymbolNodeFactory.cs" />
     <Compile Include="Compiler\DependencyAnalysis\SortableDependencyNodeCompilerSpecific.cs" />
     <Compile Include="Compiler\DependencyAnalysis\TypeAndMethod.cs" />
-    <Compile Include="Compiler\EffectiveVisibility.cs" />
     <Compile Include="Compiler\IRootingServiceProvider.cs" />
     <Compile Include="Compiler\ReadyToRunCompilationModuleGroupBase.cs" />
     <Compile Include="Compiler\PettisHansenSort\CallGraphNode.cs" />
index 944fa65..839b050 100644 (file)
@@ -2295,6 +2295,10 @@ namespace Internal.JitInterface
                 }
             }
 
+            // We validate the safety of the signature here, as it could have been adjusted
+            // by virtual resolution during getCallInfo (virtual resolution could find a result using type equivalence)
+            ValidateSafetyOfUsingTypeEquivalenceInSignature(targetMethod.GetTypicalMethodDefinition().Signature);
+
             // OK, if the EE said we're not doing a stub dispatch then just return the kind to
             // the caller.  No other kinds of virtual calls have extra information attached.
             switch (pResult->kind)
@@ -3204,5 +3208,27 @@ namespace Internal.JitInterface
             // Implemented for JIT and NativeAOT only for now.
             return false;
         }
+
+        private void ValidateSafetyOfUsingTypeEquivalenceInSignature(MethodSignature signature)
+        {
+            // Type equivalent valuetypes not in the current version bubble are problematic, and cannot be referred to in our current token
+            // scheme except through type references. So we need to detect them, and if they aren't referred to by type reference from a module
+            // in the current build, then we need to fallback to runtime jit.
+            ValidateSafetyOfUsingTypeEquivalenceOfType(signature.ReturnType);
+            foreach (var type in signature)
+            {
+                ValidateSafetyOfUsingTypeEquivalenceOfType(type);
+            }
+        }
+
+        void ValidateSafetyOfUsingTypeEquivalenceOfType(TypeDesc type)
+        {
+            if (type.IsValueType && type.IsTypeDefEquivalent && !_compilation.CompilationModuleGroup.VersionsWithTypeReference(type))
+            {
+                // Technically this is a bit pickier than needed, as cross module inlineable cases will be hit by this, but type equivalence is a
+                // rarely used feature, and we can fix that if we need to.
+                throw new RequiresRuntimeJitException($"Type equivalent valuetype '{type}' not directly referenced from member reference");
+            }
+        }
     }
 }
index c357cd1..fda0f02 100644 (file)
@@ -156,6 +156,79 @@ namespace System.Runtime.InteropServices
         }
         public int Value { get { return _val; } }
     }
+
+    public sealed class TypeIdentifierAttribute : Attribute
+    {
+        public TypeIdentifierAttribute() { }
+        public TypeIdentifierAttribute(string scope, string identifier)
+        {
+            Scope = scope;
+            Identifier = identifier;
+        }
+
+        public string Scope { get; }
+        public string Identifier { get; }
+    }
+
+    public enum UnmanagedType
+    {
+        Bool = 2,
+        I1 = 3,
+        U1 = 4,
+        I2 = 5,
+        U2 = 6,
+        I4 = 7,
+        U4 = 8,
+        I8 = 9,
+        U8 = 10,
+        R4 = 11,
+        R8 = 12,
+        Currency = 15,
+        BStr = 19,
+        LPStr = 20,
+        LPWStr = 21,
+        LPTStr = 22,
+        ByValTStr = 23,
+        IUnknown = 25,
+        IDispatch = 26,
+        Struct = 27,
+        Interface = 28,
+        SafeArray = 29,
+        ByValArray = 30,
+        SysInt = 31,
+        SysUInt = 32,
+        VBByRefStr = 34,
+        AnsiBStr = 35,
+        TBStr = 36,
+        VariantBool = 37,
+        FunctionPtr = 38,
+        AsAny = 40,
+        LPArray = 42,
+        LPStruct = 43,
+        CustomMarshaler = 44,
+        Error = 45,
+        IInspectable = 46,
+        HString = 47,
+        LPUTF8Str = 48
+    }
+    public sealed class MarshalAsAttribute : Attribute
+    {
+        public MarshalAsAttribute(UnmanagedType unmanagedType) { }
+    }
+
+    public sealed class ComImportAttribute : Attribute
+    {
+    }
+
+    public sealed class ComEventInterfaceAttribute : Attribute
+    {
+        public ComEventInterfaceAttribute(Type SourceInterface, Type EventProvider) { }
+    }
+
+    public sealed class GuidAttribute : Attribute
+    {
+        public GuidAttribute(string guid) { }
+    }
 }
 
 namespace System.Runtime.CompilerServices
index d62215c..61d16ee 100644 (file)
   </ItemGroup>
 
   <ItemGroup>
-    <ProjectReference Include="..\ILCompiler.TypeSystem\ILCompiler.TypeSystem.csproj" />
+    <ProjectReference Include="..\ILCompiler.TypeSystem\ILCompiler.TypeSystem.csproj">
+      <Private>True</Private>
+    </ProjectReference>
     <!-- Make sure the test data gets built -->
     <ProjectReference Include="CoreTestAssembly\CoreTestAssembly.csproj">
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
       <OutputItemType>Content</OutputItemType>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Private>True</Private>
     </ProjectReference>
     <ProjectReference Include="ILTestAssembly\ILTestAssembly.ilproj">
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
       <OutputItemType>Content</OutputItemType>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Private>True</Private>
+    </ProjectReference>
+    <ProjectReference Include="TypeEquivalenceAssembly\TypeEquivalenceAssembly1.csproj">
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <OutputItemType>Content</OutputItemType>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Private>True</Private>
+    </ProjectReference>
+    <ProjectReference Include="TypeEquivalenceAssembly\TypeEquivalenceAssembly2.csproj">
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <OutputItemType>Content</OutputItemType>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Private>True</Private>
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
@@ -62,6 +78,7 @@
     <Compile Include="SyntheticVirtualOverrideTests.cs" />
     <Compile Include="SyntheticVirtualOverrideTests.DiagnosticName.cs" />
     <Compile Include="TestMetadataFieldLayoutAlgorithm.cs" />
+    <Compile Include="TypeEquivalenceTests.cs" />
     <Compile Include="TypeNameParsingTests.cs" />
     <Compile Include="UniversalGenericFieldLayoutTests.cs" />
     <Compile Include="ValueTypeShapeCharacteristicsTests.cs" />
index 83cc977..cffbf2e 100644 (file)
@@ -139,5 +139,8 @@ namespace TypeSystemTests
 
         public override bool SupportsUniversalCanon => true;
         public override bool SupportsCanon => true;
+
+        public override bool SupportsCOMInterop => true;
+        public override bool SupportsTypeEquivalence => true;
     }
 }
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypeEquivalenceAssembly1.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypeEquivalenceAssembly1.csproj
new file mode 100644 (file)
index 0000000..36d58c2
--- /dev/null
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <SkipTestRun>true</SkipTestRun>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <!-- Don't add references to the netstandard platform since this is a core assembly -->
+    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
+    <!-- CSC needs explicit metadata version when it has no core library to reference -->
+    <RuntimeMetadataVersion>v4.0.30319</RuntimeMetadataVersion>
+    <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
+    <RunAnalyzers>false</RunAnalyzers>
+    <DefineConstants>TYPEEQUIVALENCEASSEMBLY_1</DefineConstants>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\CoreTestAssembly\CoreTestAssembly.csproj">
+      <Name>CoreTestAssembly</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypeEquivalenceAssembly2.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypeEquivalenceAssembly2.csproj
new file mode 100644 (file)
index 0000000..01f7f4a
--- /dev/null
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <SkipTestRun>true</SkipTestRun>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <!-- Don't add references to the netstandard platform since this is a core assembly -->
+    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
+    <!-- CSC needs explicit metadata version when it has no core library to reference -->
+    <RuntimeMetadataVersion>v4.0.30319</RuntimeMetadataVersion>
+    <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
+    <RunAnalyzers>false</RunAnalyzers>
+    <DefineConstants>TYPEEQUIVALENCEASSEMBLY_2</DefineConstants>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\CoreTestAssembly\CoreTestAssembly.csproj">
+      <Name>CoreTestAssembly</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotLoad.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotLoad.cs
new file mode 100644 (file)
index 0000000..38c7564
--- /dev/null
@@ -0,0 +1,68 @@
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 169
+
+namespace TypesWhichDoNotLoad
+{
+    // A case where a field is not public
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type1")]
+    public struct Type1
+    {
+        int field;
+    }
+
+    // A case where the type is not both public
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type2")]
+    enum Type2
+    {
+    }
+
+    // A case where the type is not both public
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type3")]
+    struct Type3
+    {
+    }
+
+    // A case where the type is not both public
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type4")]
+    delegate object Type4(object param);
+
+    // A case where the type is not nested public
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type4_IGNORE")]
+    public struct Type4_IGNORE
+    {
+        [TypeIdentifier("TypesWhichDoNotLoad", "Type5")]
+        struct Type5
+        { }
+    }
+
+    // A case with a static field
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type6")]
+    public struct Type6
+    {
+        public static int field;
+    }
+
+    // A case with an instance method
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type7")]
+    public struct Type7
+    {
+        public void Method() { }
+    }
+
+    // A case which is a normal interface (not ComImport of ComEventInterface)
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type8")]
+    public interface Type8 { }
+
+    // A generic type
+    [TypeIdentifier("TypesWhichDoNotLoad", "Type9")]
+    public struct Type9<T> { }
+
+    // A type nested in a non TypeEquivalent type
+    public struct NonTypeEquivalent
+    {
+        [TypeIdentifier("TypesWhichDoNotLoad", "Type10")]
+        public struct Type10 { }
+    }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotMatch.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotMatch.cs
new file mode 100644 (file)
index 0000000..67da855
--- /dev/null
@@ -0,0 +1,135 @@
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 169
+
+namespace TypesWhichDoNotMatch
+{
+    // A case where 1 type has a field, and another does not
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type1")]
+    public struct Type1
+    {
+#if TYPEEQUIVALENCEASSEMBLY_1
+        public int field;
+#endif
+    }
+
+    // A case where there is a static method on the type
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type2")]
+    public struct Type2
+    {
+        public static void Method() { }
+    }
+
+    // A case where a delegate varies in signature
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type3")]
+    public delegate
+#if TYPEEQUIVALENCEASSEMBLY_1
+        object
+#else
+        string
+#endif
+        Type3();
+
+    // A case where the type names are not the same
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type4")]
+    public struct
+#if TYPEEQUIVALENCEASSEMBLY_1
+        Type4
+#else
+        Type4NotQuite
+#endif
+    { }
+
+    // A case where MarshalAs behavior is different
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type5")]
+    public struct Type5
+    {
+#if TYPEEQUIVALENCEASSEMBLY_1
+        [MarshalAs(UnmanagedType.Bool)]
+#else
+        [MarshalAs(UnmanagedType.VariantBool)]
+#endif
+        public bool X;
+    }
+
+    // A different case where MarshalAs behavior is different
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type6")]
+    public struct Type6
+    {
+#if TYPEEQUIVALENCEASSEMBLY_1
+        [MarshalAs(UnmanagedType.Bool)]
+#endif
+        public bool X;
+    }
+
+    // A case where fixed layouts are not the same
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type7")]
+    [StructLayout(LayoutKind.Explicit)]
+    public struct Type7
+    {
+        [FieldOffset(0)]
+        public int Lol;
+#if TYPEEQUIVALENCEASSEMBLY_1
+        [FieldOffset(20)]
+#else
+        [FieldOffset(21)]
+#endif
+        public byte Omg;
+    }
+
+    // A case where the MDArray is different
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type8")]
+    public struct Type8
+    {
+        public
+#if TYPEEQUIVALENCEASSEMBLY_1
+            TypesWhichMatch.Type4[,,]
+#else
+            TypesWhichMatch.Type4[,,,]
+#endif
+            MDArray;
+    }
+
+    // A case where the underlying data of the enum does not match
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type9")]
+    public enum Type9 :
+#if TYPEEQUIVALENCEASSEMBLY_1
+        byte
+#else
+        sbyte
+#endif
+    {
+    }
+
+    // A case with a function pointer
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type10")]
+    public struct Type10
+    {
+        public unsafe delegate*<TypesWhichMatch.Type4, void> functionPointer;
+    }
+
+    // A case where the overall size is different
+#if TYPEEQUIVALENCEASSEMBLY_1
+    [StructLayout(LayoutKind.Explicit, Size = 40)]
+#else
+    [StructLayout(LayoutKind.Explicit, Size = 41)]
+#endif
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type11")]
+    public struct Type11
+    {
+        [FieldOffset(0)]
+        public int Lol;
+        [FieldOffset(20)]
+        public byte Omg;
+
+        // A test case where the type itself would match, but its containing type does not
+        [TypeIdentifier("TypesWhichDoNotMatch", "Type12")]
+        public struct Type12 { }
+    }
+
+    // No layoutkind auto struct will ever match (but it will load)
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type13")]
+    [StructLayout(LayoutKind.Auto)]
+    public struct Type13 { }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichMatch.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichMatch.cs
new file mode 100644 (file)
index 0000000..d25fd71
--- /dev/null
@@ -0,0 +1,124 @@
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 169
+
+#if TYPEEQUIVALENCEASSEMBLY_1
+public class TypeEquivalenceAssembly1
+{}
+#else
+public class TypeEquivalenceAssembly2
+{ }
+#endif
+
+namespace TypesWhichMatch
+{
+    [TypeIdentifier("TypesWhichMatch", "Type1")]
+    public enum Type1
+    {
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type2")]
+    public enum Type2
+    {
+// The actual values of the literal enums are not considered relevant for type equivalence
+#if TYPEEQUIVALENCEASSEMBLY_1
+        First = 1,
+        Second = 2,
+#else
+        First = 2,
+        Second = 1,
+#endif
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type3")]
+    public struct Type3
+    {
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type4")]
+    public struct Type4
+    {
+        public int X;
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type5")]
+    public struct Type5
+    {
+        public int X;
+        public Type4 type4;
+    }
+
+
+    [TypeIdentifier("TypesWhichMatch", "Type6")]
+    public delegate void Type6(int X);
+
+    [TypeIdentifier("TypesWhichMatch", "Type7")]
+    public delegate void Type7(int X);
+
+    [TypeIdentifier("TypesWhichMatch", "Type9")]
+    [ComImport]
+    [GuidAttribute("9ED54F84-A89D-4fcd-A854-44251E925F09")]
+    public interface Type9
+    {
+        // Mismatched methods don't impede equivalence for the purpose of IsEquivalent, but they will interfere with actual dispatch
+        void Method();
+#if TYPEEQUIVALENCEASSEMBLY_1
+        void Method2(int x);
+#else
+        void Method2(short x);
+        void Method3(int x, Type4 type4);
+#endif
+
+        // Test nested type
+        [TypeIdentifier("TypesWhichMatch", "Type10")]
+        public struct Type10
+        {
+            [MarshalAs(UnmanagedType.Bool)]
+            public bool X;
+        }
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type11")]
+    [StructLayout(LayoutKind.Explicit, Size = 40)]
+    public struct Type11
+    {
+        [FieldOffset(0)]
+        public int Lol;
+        [FieldOffset(20)]
+        public byte Omg;
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type12")]
+    [StructLayout(LayoutKind.Explicit)]
+    public struct Type12
+    {
+        [FieldOffset(0)]
+        public int Lol;
+        [FieldOffset(20)]
+        public byte Omg;
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type13")]
+    [ComEventInterface(null, null)]
+    public interface Type13
+    {
+    }
+
+    [TypeIdentifier("TypesWhichMatch", "Type14")]
+    public struct Type14
+    {
+        // Validate that arrays, pointers and mdarrays are handled appropriately
+        public Type4[] SzArray;
+        public unsafe Type4* Ptr;
+        public Type4[,,] MDArray;
+    }
+
+    // A case with a function pointer
+    [TypeIdentifier("TypesWhichDoNotMatch", "Type15")]
+    public struct Type15
+    {
+        public unsafe delegate*<int, void> functionPointer;
+    }
+
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceTests.cs
new file mode 100644 (file)
index 0000000..63b1c04
--- /dev/null
@@ -0,0 +1,242 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Reflection.Metadata;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace TypeSystemTests
+{
+    public class Entrypoint
+    {
+        class Logger : ITestOutputHelper
+        {
+            void ITestOutputHelper.WriteLine(string message) => Console.WriteLine(message);
+            void ITestOutputHelper.WriteLine(string format, params object[] args) => Console.WriteLine(format, args);
+        }
+
+        public static void NotQuiteMain()
+        {
+            TypeEquivalenceTests tests = new TypeEquivalenceTests(new Logger());
+            tests.TestTypesWhichShouldMatch();
+        }
+    }
+    public class TypeEquivalenceTests
+    {
+        private TestTypeSystemContext _context;
+        private EcmaModule _testModule1;
+        private EcmaModule _testModule2;
+
+        private MetadataType _referenceType;
+        private MetadataType _otherReferenceType;
+        private MetadataType _structType;
+        private MetadataType _otherStructType;
+        private MetadataType _genericReferenceType;
+        private MetadataType _genericStructType;
+        private MetadataType _genericReferenceTypeWithThreeParams;
+        private MetadataType _genericStructTypeWithThreeParams;
+        private MetadataType _interfaceGenericType;
+
+        private ITestOutputHelper _logger;
+
+        public TypeEquivalenceTests(ITestOutputHelper outputHelper)
+        {
+            _logger = outputHelper;
+            _context = new TestTypeSystemContext(TargetArchitecture.Unknown);
+            var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+            _context.SetSystemModule(systemModule);
+
+            _testModule1 = (EcmaModule)_context.CreateModuleForSimpleName("TypeEquivalenceAssembly1");
+            _testModule2 = (EcmaModule)_context.CreateModuleForSimpleName("TypeEquivalenceAssembly2");
+
+            _referenceType = systemModule.GetType("Canonicalization", "ReferenceType");
+            _otherReferenceType = systemModule.GetType("Canonicalization", "OtherReferenceType");
+            _structType = systemModule.GetType("Canonicalization", "StructType");
+            _otherStructType = systemModule.GetType("Canonicalization", "OtherStructType");
+            _genericReferenceType = systemModule.GetType("Canonicalization", "GenericReferenceType`1");
+            _genericStructType = systemModule.GetType("Canonicalization", "GenericStructType`1");
+            _genericReferenceTypeWithThreeParams = systemModule.GetType("Canonicalization", "GenericReferenceTypeWithThreeParams`3");
+            _genericStructTypeWithThreeParams = systemModule.GetType("Canonicalization", "GenericStructTypeWithThreeParams`3");
+            _interfaceGenericType = systemModule.GetType("Canonicalization", "InterfaceGenericType`1");
+        }
+
+        private IEnumerable<TypeDefinitionHandle> GetAllNestedTypes(MetadataReader metadataReader, TypeDefinition typeDef)
+        {
+            foreach (var nestedHandle in typeDef.GetNestedTypes())
+            {
+                yield return nestedHandle;
+                var nestedType = metadataReader.GetTypeDefinition(nestedHandle);
+                foreach (var moreNestedHandle in GetAllNestedTypes(metadataReader, nestedType))
+                {
+                    yield return moreNestedHandle;
+                }
+            }
+        }
+
+        private IEnumerable<TypeDefinitionHandle> GetAllTypesInNamespace(EcmaModule module, string @namespace)
+        {
+            var metadataReader = module.MetadataReader;
+            foreach (var typeDefHandle in metadataReader.TypeDefinitions)
+            {
+                var typeDef = metadataReader.GetTypeDefinition(typeDefHandle);
+                if (typeDef.IsNested)
+                {
+                    continue; // Ignore nested types for now
+                }
+
+                if (metadataReader.StringComparer.Equals(typeDef.Namespace, @namespace))
+                {
+                    yield return typeDefHandle;
+                    foreach (var nestedHandle in GetAllNestedTypes(metadataReader, typeDef))
+                    {
+                        yield return nestedHandle;
+                    }
+                }
+            }
+        }
+
+        private static bool IsEqualCustomAttributeName(CustomAttributeHandle attributeHandle, MetadataReader metadataReader,
+            string attributeNamespace, string attributeName)
+        {
+            StringHandle namespaceHandle, nameHandle;
+            if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceHandle, out nameHandle))
+                return false;
+
+            return metadataReader.StringComparer.Equals(namespaceHandle, attributeNamespace)
+                && metadataReader.StringComparer.Equals(nameHandle, attributeName);
+        }
+
+        private string GetTypeIdentiferFromTypeDef(EcmaModule module, TypeDefinitionHandle typeDefHandle)
+        {
+            CustomAttributeTypeProvider customAttributeTypeProvider = new CustomAttributeTypeProvider(module);
+            var typeDef = module.MetadataReader.GetTypeDefinition(typeDefHandle);
+            foreach (var attributeHandle in typeDef.GetCustomAttributes())
+            {
+                if (IsEqualCustomAttributeName(attributeHandle, module.MetadataReader, "System.Runtime.InteropServices", "TypeIdentifierAttribute"))
+                {
+                    var typeIdentifierAttribute = module.MetadataReader.GetCustomAttribute(attributeHandle).DecodeValue(customAttributeTypeProvider);
+
+                    if (typeIdentifierAttribute.FixedArguments.Length != 2)
+                        throw new Exception("Unexpected in this test suite");
+
+                    return $"{typeIdentifierAttribute.FixedArguments[0].Value}_{typeIdentifierAttribute.FixedArguments[1].Value}";
+                }
+            }
+
+            return null;
+        }
+
+        private Dictionary<string, TypeDefinitionHandle> GetTypeIdentifierAssociatedTypesInNamespace(EcmaModule module, string @namespace)
+        {
+            Dictionary<string, TypeDefinitionHandle> result = new Dictionary<string, TypeDefinitionHandle>();
+            foreach (var typeDef in GetAllTypesInNamespace(module, @namespace))
+            {
+                string typeId = GetTypeIdentiferFromTypeDef(module, typeDef);
+                if (typeId != null)
+                {
+                    result.Add(typeId, typeDef);
+                }
+            }
+            return result;
+        }
+
+        private IEnumerable<ValueTuple<TypeDesc, TypeDesc>> GetTypesWhichClaimMatchingTypeIdentifiersInNamespace(string @namespace)
+        {
+            var module1Types = GetTypeIdentifierAssociatedTypesInNamespace(_testModule1, @namespace);
+            var module2Types = GetTypeIdentifierAssociatedTypesInNamespace(_testModule2, @namespace);
+
+            foreach (var data in module1Types)
+            {
+                if (module2Types.TryGetValue(data.Key, out var typeDef2))
+                {
+                    yield return ((TypeDesc)_testModule1.GetObject(data.Value), (TypeDesc)_testModule2.GetObject(typeDef2));
+                }
+            }
+        }
+
+        [Fact]
+        public void TestTypesWhichShouldMatch()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichMatch"))
+            {
+                _logger.WriteLine($"Comparing {typePair.Item1} to {typePair.Item2}");
+                Assert.NotEqual(typePair.Item1, typePair.Item2);
+                Assert.True(typePair.Item1.IsEquivalentTo(typePair.Item2));
+                Assert.True(typePair.Item1.TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType);
+                Assert.True(typePair.Item2.TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType);
+            }
+        }
+
+        [Fact]
+        public void TestGenericInterfacesWithTypeEquivalence()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichMatch"))
+            {
+                var gen1 = _interfaceGenericType.MakeInstantiatedType(typePair.Item1);
+                var gen2 = _interfaceGenericType.MakeInstantiatedType(typePair.Item2);
+
+                _logger.WriteLine($"Comparing {gen1} to {gen2}");
+                Assert.NotEqual(gen1, gen2);
+                Assert.True(gen1.IsEquivalentTo(gen2));
+            }
+        }
+
+        [Fact]
+        public void TestGenericClassesWithTypeEquivalence()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichMatch"))
+            {
+                var gen1 = _genericReferenceType.MakeInstantiatedType(typePair.Item1);
+                var gen2 = _genericReferenceType.MakeInstantiatedType(typePair.Item2);
+
+                _logger.WriteLine($"Comparing{gen1} to {gen2}");
+                Assert.NotEqual(gen1, gen2);
+                Assert.False(gen1.IsEquivalentTo(gen2));
+            }
+        }
+
+        [Fact]
+        public void TestGenericStructsWithTypeEquivalence()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichMatch"))
+            {
+                var gen1 = _genericStructType.MakeInstantiatedType(typePair.Item1);
+                var gen2 = _genericStructType.MakeInstantiatedType(typePair.Item2);
+
+                _logger.WriteLine($"Comparing {gen1} to {gen2}");
+                Assert.NotEqual(gen1, gen2);
+                Assert.False(gen1.IsEquivalentTo(gen2));
+            }
+        }
+
+        [Fact]
+        public void TestTypesWhichShouldNotMatch()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichDoNotMatch"))
+            {
+                _logger.WriteLine($"Comparing {typePair.Item1} to {typePair.Item2}");
+                Assert.False(typePair.Item1.IsEquivalentTo(typePair.Item2));
+                Assert.True(typePair.Item1.TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType);
+                Assert.True(typePair.Item2.TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType);
+            }
+        }
+
+        [Fact]
+        public void TestTypesWhichShouldNotBeLoadable()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichDoNotLoad"))
+            {
+                if (((MetadataType)typePair.Item1).Name.EndsWith("IGNORE"))
+                    continue;
+
+                _logger.WriteLine($"Checking load behavior of {typePair.Item1}");
+                Assert.False(typePair.Item1.TypeHasCharacteristicsRequiredToBeLoadableTypeEquivalentType);
+            }
+        }
+    }
+}
index dc9f225..38077dc 100644 (file)
     <Compile Include="..\..\Common\TypeSystem\Common\CastingHelper.cs">
       <Link>TypeSystem\Common\CastingHelper.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Common\CastingHelper.TypeEquivalence.cs">
+      <Link>TypeSystem\Common\CastingHelper.TypeEquivalence.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\ConstructedTypeRewritingHelpers.cs">
       <Link>TypeSystem\Common\ConstructedTypeRewritingHelpers.cs</Link>
     </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\InstantiatedType.MethodImpls.cs">
       <Link>TypeSystem\Common\InstantiatedType.MethodImpls.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Common\InstantiatedType.TypeEquivalence.cs">
+      <Link>TypeSystem\Common\InstantiatedType.TypeEquivalence.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\LayoutInt.cs">
       <Link>TypeSystem\Common\LayoutInt.cs</Link>
     </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\TypeDesc.Interfaces.cs">
       <Link>TypeSystem\Common\TypeDesc.Interfaces.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Common\TypeDesc.TypeEquivalence.cs">
+      <Link>TypeSystem\Common\TypeDesc.TypeEquivalence.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Common\DefType.cs">
       <Link>TypeSystem\Common\DefType.cs</Link>
     </Compile>
     <Compile Include="..\..\Common\TypeSystem\Ecma\EcmaType.Sorting.cs">
       <Link>Ecma\EcmaType.Sorting.cs</Link>
     </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Ecma\EcmaType.TypeEquivalence.cs">
+      <Link>Ecma\EcmaType.TypeEquivalence.cs</Link>
+    </Compile>
+    <Compile Include="..\..\Common\TypeSystem\Ecma\EffectiveVisibility.cs">
+      <Link>Ecma\EffectiveVisibility.cs</Link>
+    </Compile>
     <Compile Include="..\..\Common\TypeSystem\Ecma\PrimitiveTypeProvider.cs">
       <Link>Ecma\PrimitiveTypeProvider.cs</Link>
     </Compile>
index b4364fa..0a137ed 100644 (file)
@@ -1350,7 +1350,7 @@ BOOL MethodTable::IsEquivalentTo_WorkerInner(MethodTable *pOtherMT COMMA_INDEBUG
     // Check if type is generic
     if (HasInstantiation())
     {
-        // Limit variance on generics only to interfaces
+        // Limit equivalence on generics only to interfaces
         if (!IsInterface() || !pOtherMT->IsInterface())
         {
             fEquivalent = FALSE;
diff --git a/src/tests/baseservices/typeequivalence/istypeequivalent/istypeequivalent.cs b/src/tests/baseservices/typeequivalence/istypeequivalent/istypeequivalent.cs
new file mode 100644 (file)
index 0000000..b1da461
--- /dev/null
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Xunit;
+
+// This test shares its logic with the managed type system test suite, and seeks to ensure the runtime agrees with it
+namespace istypeequivalent
+{
+    public class Test
+    {
+        private static IEnumerable<Type> GetAllTypesInNamespace(Module module, string @namespace)
+        {
+            foreach (var type in module.GetTypes())
+            {
+                if (type.Namespace == @namespace)
+                {
+                    Console.WriteLine($"Found {type}");
+                    yield return type;
+                }
+            }
+        }
+
+        private static string GetTypeIdentiferFromType(Type type)
+        {
+            foreach (var ca in type.GetCustomAttributes())
+            {
+                if (ca is TypeIdentifierAttribute typeId)
+                {
+                    return $"{typeId.Scope}_{typeId.Identifier}";
+                }
+            }
+
+            return null;
+        }
+
+        private static Dictionary<string, Type> GetTypeIdentifierAssociatedTypesInNamespace(Module module, string @namespace)
+        {
+            Dictionary<string, Type> result = new Dictionary<string, Type>();
+            foreach (var typeDef in GetAllTypesInNamespace(module, @namespace))
+            {
+                string typeId = GetTypeIdentiferFromType(typeDef);
+                if (typeId != null)
+                {
+                    result.Add(typeId, typeDef);
+                }
+            }
+            return result;
+        }
+
+        private static IEnumerable<ValueTuple<Type, Type>> GetTypesWhichClaimMatchingTypeIdentifiersInNamespace(string @namespace)
+        {
+            var module1Types = GetTypeIdentifierAssociatedTypesInNamespace(typeof(TypeEquivalenceAssembly1).Module, @namespace);
+            var module2Types = GetTypeIdentifierAssociatedTypesInNamespace(typeof(TypeEquivalenceAssembly2).Module, @namespace);
+
+            foreach (var data in module1Types)
+            {
+                if (module2Types.TryGetValue(data.Key, out var typeDef2))
+                {
+                    yield return (data.Value, typeDef2);
+                }
+            }
+        }
+
+        public static void TestTypesWhichShouldMatch()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichMatch"))
+            {
+                Console.WriteLine($"Comparing {typePair.Item1} to {typePair.Item2}");
+                Assert.NotEqual(typePair.Item1, typePair.Item2);
+                Assert.True(typePair.Item1.IsEquivalentTo(typePair.Item2));
+            }
+        }
+
+        public static void TestTypesWhichShouldNotMatch()
+        {
+            foreach (var typePair in GetTypesWhichClaimMatchingTypeIdentifiersInNamespace("TypesWhichDoNotMatch"))
+            {
+                Console.WriteLine($"Comparing {typePair.Item1} to {typePair.Item2}");
+                Assert.False(typePair.Item1.IsEquivalentTo(typePair.Item2));
+            }
+        }
+
+        public static int Main()
+        {
+            if (!OperatingSystem.IsWindows())
+            {
+                return 100;
+            }
+
+            TestTypesWhichShouldMatch();
+            TestTypesWhichShouldNotMatch();
+
+            return 100;
+        }
+    }
+}
diff --git a/src/tests/baseservices/typeequivalence/istypeequivalent/istypeequivalent.csproj b/src/tests/baseservices/typeequivalence/istypeequivalent/istypeequivalent.csproj
new file mode 100644 (file)
index 0000000..98d6ad8
--- /dev/null
@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+    <MonoAotIncompatible>true</MonoAotIncompatible>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="istypeequivalent.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="typeequivalenttypes_1.csproj" />
+    <ProjectReference Include="typeequivalenttypes_2.csproj" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetPathOfFileAbove(TypeEquivalence.targets))" />
+</Project>
diff --git a/src/tests/baseservices/typeequivalence/istypeequivalent/typeequivalenttypes_1.csproj b/src/tests/baseservices/typeequivalence/istypeequivalent/typeequivalenttypes_1.csproj
new file mode 100644 (file)
index 0000000..6bfdb95
--- /dev/null
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <CLRTestKind>SharedLibrary</CLRTestKind>
+    <DefineConstants>$(DefineConstants);TYPEEQUIVALENCEASSEMBLY_1</DefineConstants>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="../../../../coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotMatch.cs" />
+    <Compile Include="../../../../coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichMatch.cs" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/baseservices/typeequivalence/istypeequivalent/typeequivalenttypes_2.csproj b/src/tests/baseservices/typeequivalence/istypeequivalent/typeequivalenttypes_2.csproj
new file mode 100644 (file)
index 0000000..fc42393
--- /dev/null
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <CLRTestKind>SharedLibrary</CLRTestKind>
+    <DefineConstants>$(DefineConstants);TYPEEQUIVALENCEASSEMBLY_2</DefineConstants>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="../../../../coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichDoNotMatch.cs" />
+    <Compile Include="../../../../coreclr/tools/aot/ILCompiler.TypeSystem.Tests/TypeEquivalenceAssembly/TypesWhichMatch.cs" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/baseservices/typeequivalence/signatures/basetestclassesil.il b/src/tests/baseservices/typeequivalence/signatures/basetestclassesil.il
new file mode 100644 (file)
index 0000000..a8f15e2
--- /dev/null
@@ -0,0 +1,532 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.0.20326.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.AMD64chk
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly basetestclassesil
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module basetestclassesil.dll
+// MVID: {B2D2C9A1-63E8-4408-87AE-AD79B08CA2DE}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x00000000001D0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public sequential ansi sealed import beforefieldinit Struct0
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 30 00 00 )          // ...Struct.0..
+} // end of class Struct0
+
+.class public sequential ansi sealed import beforefieldinit Struct1
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 31 00 00 )          // ...Struct.1..
+} // end of class Struct1
+
+.class public sequential ansi sealed import beforefieldinit Struct2
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 32 00 00 )          // ...Struct.2..
+} // end of class Struct2
+
+.class public sequential ansi sealed import beforefieldinit Struct3
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 33 00 00 )          // ...Struct.3..
+} // end of class Struct3
+
+.class public sequential ansi sealed import beforefieldinit Struct4
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 34 00 00 )          // ...Struct.4..
+} // end of class Struct4
+
+.class public sequential ansi sealed import beforefieldinit Struct5
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 35 00 00 )          // ...Struct.5..
+} // end of class Struct5
+
+.class public sequential ansi sealed import beforefieldinit Struct6
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 36 00 00 )          // ...Struct.6..
+} // end of class Struct6
+
+.class public sequential ansi sealed import beforefieldinit Struct7
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 37 00 00 )          // ...Struct.7..
+} // end of class Struct7
+
+.class public sequential ansi sealed import beforefieldinit Struct8
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 38 00 00 )          // ...Struct.8..
+} // end of class Struct8
+
+.class public sequential ansi sealed import beforefieldinit Struct9
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 39 00 00 )          // ...Struct.9..
+} // end of class Struct9
+
+.class public sequential ansi sealed import beforefieldinit Struct10
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 30 00 00 )       // ...Struct.10..
+} // end of class Struct10
+
+.class public sequential ansi sealed import beforefieldinit Struct11
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 31 00 00 )       // ...Struct.11..
+} // end of class Struct11
+
+.class public sequential ansi sealed import beforefieldinit Struct12
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 32 00 00 )       // ...Struct.12..
+} // end of class Struct12
+
+.class public sequential ansi sealed import beforefieldinit Struct13
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 33 00 00 )       // ...Struct.13..
+} // end of class Struct13
+
+.class public sequential ansi sealed import beforefieldinit Struct14
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 34 00 00 )       // ...Struct.14..
+} // end of class Struct14
+
+.class public sequential ansi sealed import beforefieldinit Struct15
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 35 00 00 )       // ...Struct.15..
+} // end of class Struct15
+
+.class public sequential ansi sealed import beforefieldinit Struct16
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 36 00 00 )       // ...Struct.16..
+} // end of class Struct16
+
+.class public sequential ansi sealed import beforefieldinit Struct17
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 37 00 00 )       // ...Struct.17..
+} // end of class Struct17
+
+.class public sequential ansi sealed import beforefieldinit Struct18
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 38 00 00 )       // ...Struct.18..
+} // end of class Struct18
+
+.class public sequential ansi sealed import beforefieldinit Struct19
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 39 00 00 )       // ...Struct.19..
+} // end of class Struct19
+
+.class public sequential ansi sealed import beforefieldinit Struct20
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 30 00 00 )       // ...Struct.20..
+} // end of class Struct20
+
+.class public sequential ansi sealed import beforefieldinit Struct21
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 31 00 00 )       // ...Struct.21..
+} // end of class Struct21
+
+.class public sequential ansi sealed import beforefieldinit Struct22
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 32 00 00 )       // ...Struct.22..
+} // end of class Struct22
+
+.class public sequential ansi sealed import beforefieldinit Struct23
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 33 00 00 )       // ...Struct.23..
+} // end of class Struct23
+
+.class public sequential ansi sealed import beforefieldinit Struct24
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 34 00 00 )       // ...Struct.24..
+} // end of class Struct24
+
+.class public sequential ansi sealed import beforefieldinit Struct25
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 35 00 00 )       // ...Struct.25..
+} // end of class Struct25
+
+.class public sequential ansi sealed import beforefieldinit Struct26
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 36 00 00 )       // ...Struct.26..
+} // end of class Struct26
+
+.class public sequential ansi sealed import beforefieldinit Struct27
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 37 00 00 )       // ...Struct.27..
+} // end of class Struct27
+
+.class public sequential ansi sealed import beforefieldinit Struct28
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 38 00 00 )       // ...Struct.28..
+} // end of class Struct28
+
+.class public sequential ansi sealed import beforefieldinit Struct29
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 39 00 00 )       // ...Struct.29..
+} // end of class Struct29
+
+.class interface public abstract auto import ansi EquivalentInterface3
+{
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 09 49 6E 74 65 72 66 61 63 65 01 33 00 00 ) // ...Interface.3..
+  .method public hidebysig newslot abstract virtual 
+          instance valuetype Struct6  InterfaceFunction(valuetype Struct7 param) cil managed
+  {
+  } // end of method EquivalentInterface3::InterfaceFunction
+
+} // end of class EquivalentInterface3
+
+
+
+
+.class interface public abstract auto ansi TargetInterface8
+{
+  .method public hidebysig newslot abstract virtual 
+          instance valuetype Struct16  InterfaceFunction<T>(valuetype Struct17 param,
+                                                            !!T otherParam) cil managed
+  {
+  } // end of method TargetInterface8::InterfaceFunction
+
+} // end of class TargetInterface8
+
+.class public auto ansi beforefieldinit TargetClassTest2_Base
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct4  VirtualFunction(valuetype Struct5 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct4 V_0,
+             valuetype Struct4 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct4
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest2_Base::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest2_Base::.ctor
+
+} // end of class TargetClassTest2_Base
+
+.class public auto ansi beforefieldinit TargetClassTest6_Base
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct12  VirtualFunction<T>(valuetype Struct13 param,
+                                                          !!T paramOther) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct12 V_0,
+             valuetype Struct12 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct12
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest6_Base::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest6_Base::.ctor
+
+} // end of class TargetClassTest6_Base
+
+.class public auto ansi beforefieldinit TargetClassTest7_Base
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct14  VirtualFunction<T>(valuetype Struct15 param,
+                                                          !!T paramOther) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct14 V_0,
+             valuetype Struct14 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct14
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest7_Base::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest7_Base::.ctor
+
+} // end of class TargetClassTest7_Base
+
+.class public auto ansi beforefieldinit TargetClassTest10_Base
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig newslot virtual 
+          instance vararg valuetype Struct20 
+          VarargFunction(valuetype Struct21 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct20 V_0,
+             valuetype Struct20 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct20
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest10_Base::VarargFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest10_Base::.ctor
+
+} // end of class TargetClassTest10_Base
+
+
+.class public auto ansi beforefieldinit TargetClassTest11_Base
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct22  VirtualFunction(valuetype Struct23 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct22 V_0,
+             valuetype Struct22 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct22
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest11_Base::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest11_Base::.ctor
+
+} // end of class TargetClassTest11_Base
+
+.class public auto ansi beforefieldinit TargetClassTest12_Base
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct24  VirtualFunction(valuetype Struct25 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct24 V_0,
+             valuetype Struct24 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct24
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest12_Base::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest12_Base::.ctor
+
+} // end of class TargetClassTest12_Base
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file foo.res
diff --git a/src/tests/baseservices/typeequivalence/signatures/basetestclassesil.ilproj b/src/tests/baseservices/typeequivalence/signatures/basetestclassesil.ilproj
new file mode 100644 (file)
index 0000000..cfc7114
--- /dev/null
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk.IL">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <CLRTestKind>SharedLibrary</CLRTestKind>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="basetestclassesil.il" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/baseservices/typeequivalence/signatures/nopiatestil.il b/src/tests/baseservices/typeequivalence/signatures/nopiatestil.il
new file mode 100644 (file)
index 0000000..3ffaed8
--- /dev/null
@@ -0,0 +1,1085 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.0.20326.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.AMD64chk
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly extern testclassesil
+{
+  .ver 0:0:0:0
+}
+.assembly extern basetestclassesil
+{
+  .ver 0:0:0:0
+}
+.assembly nopiatestil
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module NoPiaTestIL.exe
+// MVID: {B2D2C9A1-63E8-4408-87AE-AD79B08CA2DE}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x00000000001D0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public sequential ansi sealed import beforefieldinit Struct0
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 30 00 00 )          // ...Struct.0..
+} // end of class Struct0
+
+.class public sequential ansi sealed import beforefieldinit Struct1
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 31 00 00 )          // ...Struct.1..
+} // end of class Struct1
+
+.class public sequential ansi sealed import beforefieldinit Struct2
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 32 00 00 )          // ...Struct.2..
+} // end of class Struct2
+
+.class public sequential ansi sealed import beforefieldinit Struct3
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 33 00 00 )          // ...Struct.3..
+} // end of class Struct3
+
+.class public sequential ansi sealed import beforefieldinit Struct4
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 34 00 00 )          // ...Struct.4..
+} // end of class Struct4
+
+.class public sequential ansi sealed import beforefieldinit Struct5
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 35 00 00 )          // ...Struct.5..
+} // end of class Struct5
+
+.class public sequential ansi sealed import beforefieldinit Struct6
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 36 00 00 )          // ...Struct.6..
+} // end of class Struct6
+
+.class public sequential ansi sealed import beforefieldinit Struct7
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 37 00 00 )          // ...Struct.7..
+} // end of class Struct7
+
+.class public sequential ansi sealed import beforefieldinit Struct8
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 38 00 00 )          // ...Struct.8..
+} // end of class Struct8
+
+.class public sequential ansi sealed import beforefieldinit Struct9
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 39 00 00 )          // ...Struct.9..
+} // end of class Struct9
+
+.class public sequential ansi sealed import beforefieldinit Struct10
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 30 00 00 )       // ...Struct.10..
+} // end of class Struct10
+
+.class public sequential ansi sealed import beforefieldinit Struct11
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 31 00 00 )       // ...Struct.11..
+} // end of class Struct11
+
+.class public sequential ansi sealed import beforefieldinit Struct12
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 32 00 00 )       // ...Struct.12..
+} // end of class Struct12
+
+.class public sequential ansi sealed import beforefieldinit Struct13
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 33 00 00 )       // ...Struct.13..
+} // end of class Struct13
+
+.class public sequential ansi sealed import beforefieldinit Struct14
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 34 00 00 )       // ...Struct.14..
+} // end of class Struct14
+
+.class public sequential ansi sealed import beforefieldinit Struct15
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 35 00 00 )       // ...Struct.15..
+} // end of class Struct15
+
+.class public sequential ansi sealed import beforefieldinit Struct16
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 36 00 00 )       // ...Struct.16..
+} // end of class Struct16
+
+.class public sequential ansi sealed import beforefieldinit Struct17
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 37 00 00 )       // ...Struct.17..
+} // end of class Struct17
+
+.class public sequential ansi sealed import beforefieldinit Struct18
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 38 00 00 )       // ...Struct.18..
+} // end of class Struct18
+
+.class public sequential ansi sealed import beforefieldinit Struct19
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 39 00 00 )       // ...Struct.19..
+} // end of class Struct19
+
+.class public sequential ansi sealed import beforefieldinit Struct20
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 30 00 00 )       // ...Struct.20..
+} // end of class Struct20
+
+.class public sequential ansi sealed import beforefieldinit Struct21
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 31 00 00 )       // ...Struct.21..
+} // end of class Struct21
+
+.class public sequential ansi sealed import beforefieldinit Struct22
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 32 00 00 )       // ...Struct.22..
+} // end of class Struct22
+
+.class public sequential ansi sealed import beforefieldinit Struct23
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 33 00 00 )       // ...Struct.23..
+} // end of class Struct23
+
+.class public sequential ansi sealed import beforefieldinit Struct24
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 34 00 00 )       // ...Struct.24..
+} // end of class Struct24
+
+.class public sequential ansi sealed import beforefieldinit Struct25
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 35 00 00 )       // ...Struct.25..
+} // end of class Struct25
+
+.class public sequential ansi sealed import beforefieldinit Struct26
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 36 00 00 )       // ...Struct.26..
+} // end of class Struct26
+
+.class public sequential ansi sealed import beforefieldinit Struct27
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 37 00 00 )       // ...Struct.27..
+} // end of class Struct27
+
+.class public sequential ansi sealed import beforefieldinit Struct28
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 38 00 00 )       // ...Struct.28..
+} // end of class Struct28
+
+.class public sequential ansi sealed import beforefieldinit Struct29
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 39 00 00 )       // ...Struct.29..
+} // end of class Struct29
+
+.class interface public abstract auto import ansi EquivalentInterface3
+{
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 09 49 6E 74 65 72 66 61 63 65 01 33 00 00 ) // ...Interface.3..
+  .method public hidebysig newslot abstract virtual 
+          instance valuetype Struct6  InterfaceFunction(valuetype Struct7 param) cil managed
+  {
+  } // end of method EquivalentInterface3::InterfaceFunction
+
+} // end of class EquivalentInterface3
+
+
+.class public auto ansi sealed Test13Delegate
+       extends [mscorlib]System.MulticastDelegate
+{
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor(object 'object',
+                               native int 'method') runtime managed
+  {
+  } // end of method Test13Delegate::.ctor
+
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct26  Invoke(valuetype Struct27 param) runtime managed
+  {
+  } // end of method Test13Delegate::Invoke
+
+  .method public hidebysig newslot virtual 
+          instance class [mscorlib]System.IAsyncResult 
+          BeginInvoke(valuetype Struct27 param,
+                      class [mscorlib]System.AsyncCallback callback,
+                      object 'object') runtime managed
+  {
+  } // end of method Test13Delegate::BeginInvoke
+
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct26  EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
+  {
+  } // end of method Test13Delegate::EndInvoke
+
+} // end of class Test13Delegate
+
+.class public auto ansi sealed Test14Delegate
+       extends [mscorlib]System.MulticastDelegate
+{
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor(object 'object',
+                               native int 'method') runtime managed
+  {
+  } // end of method Test14Delegate::.ctor
+
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct28  Invoke(valuetype Struct29 param) runtime managed
+  {
+  } // end of method Test14Delegate::Invoke
+
+  .method public hidebysig newslot virtual 
+          instance class [mscorlib]System.IAsyncResult 
+          BeginInvoke(valuetype Struct29 param,
+                      class [mscorlib]System.AsyncCallback callback,
+                      object 'object') runtime managed
+  {
+  } // end of method Test14Delegate::BeginInvoke
+
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct28  EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
+  {
+  } // end of method Test14Delegate::EndInvoke
+
+} // end of class Test14Delegate
+
+.class public auto ansi beforefieldinit NoPIATest.Program
+       extends [mscorlib]System.Object
+{
+  .method private hidebysig static void  Test1_0() cil managed noinlining
+  {
+    // Code size       28 (0x1c)
+    .maxstack  1
+    .locals init (valuetype Struct1 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... regular c"
+    + "all to static method"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldloca.s   V_0
+    IL_000e:  initobj    Struct1
+    IL_0014:  ldloc.0
+    IL_0015:  call       valuetype Struct0 [testclassesil]TargetClassTest1_0::NormalFunction1(valuetype Struct1)
+    IL_001a:  pop
+    IL_001b:  ret
+  } // end of method Program::Test1_0
+
+  .method private hidebysig static void  Test1_1() cil managed noinlining
+  {
+    // Code size       35 (0x23)
+    .maxstack  2
+    .locals init (class [testclassesil]TargetClassTest1_1 V_0,
+             valuetype Struct3 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... regular c"
+    + "all to instance method"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  newobj     instance void [testclassesil]TargetClassTest1_1::.ctor()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct3
+    IL_001b:  ldloc.1
+    IL_001c:  callvirt   instance valuetype Struct2 [testclassesil]TargetClassTest1_1::NormalFunction1(valuetype Struct3)
+    IL_0021:  pop
+    IL_0022:  ret
+  } // end of method Program::Test1_1
+
+  .method private hidebysig static class [testclassesil]TargetClassTest2 
+          GetTest2Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest2 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest2::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest2Object
+
+  .method private hidebysig static void  Test2() cil managed noinlining
+  {
+    // Code size       35 (0x23)
+    .maxstack  2
+    .locals init (class [testclassesil]TargetClassTest2 V_0,
+             valuetype Struct5 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... virtual c"
+    + "all"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest2 NoPIATest.Program::GetTest2Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct5
+    IL_001b:  ldloc.1
+    IL_001c:  callvirt   instance valuetype Struct4 [basetestclassesil]TargetClassTest2_Base::VirtualFunction(valuetype Struct5)
+    IL_0021:  pop
+    IL_0022:  ret
+  } // end of method Program::Test2
+
+  .method private hidebysig static class [testclassesil]TargetClassTest3 
+          GetTest3Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest3 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest3::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest3Object
+
+  .method private hidebysig static void  Test3() cil managed noinlining
+  {
+    // Code size       35 (0x23)
+    .maxstack  2
+    .locals init (class EquivalentInterface3 V_0,
+             valuetype Struct7 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... interface"
+    + " call"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest3 NoPIATest.Program::GetTest3Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct7
+    IL_001b:  ldloc.1
+    IL_001c:  callvirt   instance valuetype Struct6 EquivalentInterface3::InterfaceFunction(valuetype Struct7)
+    IL_0021:  pop
+    IL_0022:  ret
+  } // end of method Program::Test3
+
+  .method private hidebysig static void  Test4() cil managed noinlining
+  {
+    // Code size       33 (0x21)
+    .maxstack  2
+    .locals init (valuetype Struct9 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... generic c"
+    + "all instantiated over object"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldloca.s   V_0
+    IL_000e:  initobj    Struct9
+    IL_0014:  ldloc.0
+    IL_0015:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_001a:  call       valuetype Struct8 [testclassesil]TargetClassTest4::GenericFunction<object>(valuetype Struct9,
+                                                                                     !!0)
+    IL_001f:  pop
+    IL_0020:  ret
+  } // end of method Program::Test4
+
+  .method private hidebysig static class [testclassesil]TargetClassTest5 
+          GetTest5Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest5 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest5::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest5Object
+
+  .method private hidebysig static void  Test5() cil managed noinlining
+  {
+    // Code size       36 (0x24)
+    .maxstack  3
+    .locals init (class [testclassesil]TargetClassTest5 V_0,
+             valuetype Struct11 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... generic c"
+    + "all instantiated over int"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest5 NoPIATest.Program::GetTest5Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct11
+    IL_001b:  ldloc.1
+    IL_001c:  ldc.i4.1
+    IL_001d:  callvirt   instance valuetype Struct10 [testclassesil]TargetClassTest5::GenericFunction<int32>(valuetype Struct11,
+                                                                                              !!0)
+    IL_0022:  pop
+    IL_0023:  ret
+  } // end of method Program::Test5
+
+  .method private hidebysig static class [testclassesil]TargetClassTest6 
+          GetTest6Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest6 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest6::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest6Object
+
+  .method private hidebysig static void  Test6() cil managed noinlining
+  {
+    // Code size       40 (0x28)
+    .maxstack  3
+    .locals init (class [testclassesil]TargetClassTest6 V_0,
+             valuetype Struct13 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... generic v"
+    + "irtual call instantiated over object"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest6 NoPIATest.Program::GetTest6Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct13
+    IL_001b:  ldloc.1
+    IL_001c:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_0021:  callvirt   instance valuetype Struct12 [basetestclassesil]TargetClassTest6_Base::VirtualFunction<object>(valuetype Struct13,
+                                                                                                    !!0)
+    IL_0026:  pop
+    IL_0027:  ret
+  } // end of method Program::Test6
+
+  .method private hidebysig static class [testclassesil]TargetClassTest7 
+          GetTest7Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest7 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest7::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest7Object
+
+  .method private hidebysig static void  Test7() cil managed noinlining
+  {
+    // Code size       40 (0x28)
+    .maxstack  3
+    .locals init (class [testclassesil]TargetClassTest7 V_0,
+             valuetype Struct15 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... generic v"
+    + "irtual call instantiated over int"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest7 NoPIATest.Program::GetTest7Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct15
+    IL_001b:  ldloc.1
+    IL_001c:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_0021:  callvirt   instance valuetype Struct14 [basetestclassesil]TargetClassTest7_Base::VirtualFunction<object>(valuetype Struct15,
+                                                                                                    !!0)
+    IL_0026:  pop
+    IL_0027:  ret
+  } // end of method Program::Test7
+
+  .method private hidebysig static class [testclassesil]TargetClassTest8 
+          GetTest8Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest8 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest8::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest8Object
+
+  .method private hidebysig static void  Test8() cil managed noinlining
+  {
+    // Code size       40 (0x28)
+    .maxstack  3
+    .locals init (class [testclassesil]TargetInterface8 V_0,
+             valuetype Struct17 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... generic i"
+    + "nterface call instantiated over object"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest8 NoPIATest.Program::GetTest8Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct17
+    IL_001b:  ldloc.1
+    IL_001c:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_0021:  callvirt   instance valuetype Struct16 [testclassesil]TargetInterface8::InterfaceFunction<object>(valuetype Struct17,
+                                                                                                 !!0)
+    IL_0026:  pop
+    IL_0027:  ret
+  } // end of method Program::Test8
+
+  .method private hidebysig static class [testclassesil]TargetClassTest9 
+          GetTest9Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest9 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest9::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest9Object
+
+  .method private hidebysig static void  Test9() cil managed noinlining
+  {
+    // Code size       70 (0x46)
+    .maxstack  5
+    .locals init (class [testclassesil]TargetClassTest9 V_0,
+             valuetype Struct19 V_1,
+             valuetype [mscorlib]System.DateTime V_2)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... varargs c"
+    + "all"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest9 NoPIATest.Program::GetTest9Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct19
+    IL_001b:  ldloc.1
+    IL_001c:  callvirt   instance vararg valuetype Struct18 [testclassesil]TargetClassTest9::VarargFunction(valuetype Struct19)
+    IL_0021:  pop
+    IL_0022:  ldloc.0
+    IL_0023:  ldloca.s   V_1
+    IL_0025:  initobj    Struct19
+    IL_002b:  ldloc.1
+    IL_002c:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_0031:  ldloca.s   V_2
+    IL_0033:  initobj    [mscorlib]System.DateTime
+    IL_0039:  ldloc.2
+    IL_003a:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_003f:  callvirt   instance vararg valuetype Struct18 [testclassesil]TargetClassTest9::VarargFunction(valuetype Struct19,
+                                                                                             ...,
+                                                                                             object,
+                                                                                             valuetype [mscorlib]System.DateTime,
+                                                                                             object)
+    IL_0044:  pop
+    IL_0045:  ret
+  } // end of method Program::Test9
+
+  .method private hidebysig static class [testclassesil]TargetClassTest10 
+          GetTest10Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest10 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest10::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest10Object
+
+  .method private hidebysig static void  Test10() cil managed noinlining
+  {
+    // Code size       70 (0x46)
+    .maxstack  5
+    .locals init (class [testclassesil]TargetClassTest10 V_0,
+             valuetype Struct21 V_1,
+             valuetype [mscorlib]System.DateTime V_2)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... virtual v"
+    + "arargs call"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest10 NoPIATest.Program::GetTest10Object()
+    IL_0011:  stloc.0
+    IL_0012:  ldloc.0
+    IL_0013:  ldloca.s   V_1
+    IL_0015:  initobj    Struct21
+    IL_001b:  ldloc.1
+    IL_001c:  callvirt   instance vararg valuetype Struct20 [basetestclassesil]TargetClassTest10_Base::VarargFunction(valuetype Struct21)
+    IL_0021:  pop
+    IL_0022:  ldloc.0
+    IL_0023:  ldloca.s   V_1
+    IL_0025:  initobj    Struct21
+    IL_002b:  ldloc.1
+    IL_002c:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_0031:  ldloca.s   V_2
+    IL_0033:  initobj    [mscorlib]System.DateTime
+    IL_0039:  ldloc.2
+    IL_003a:  newobj     instance void [mscorlib]System.Object::.ctor()
+    IL_003f:  callvirt   instance vararg valuetype Struct20 [basetestclassesil]TargetClassTest10_Base::VarargFunction(valuetype Struct21,
+                                                                                                   ...,
+                                                                                                   object,
+                                                                                                   valuetype [mscorlib]System.DateTime,
+                                                                                                   object)
+    IL_0044:  pop
+    IL_0045:  ret
+  } // end of method Program::Test10
+
+  .method private hidebysig static class [testclassesil]TargetClassTest11`1<object> 
+          GetTest11Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest11`1<object> V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void class [testclassesil]TargetClassTest11`1<object>::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest11Object
+
+  .method private hidebysig static void  Test11() cil managed noinlining
+  {
+    // Code size       46 (0x2e)
+    .maxstack  2
+    .locals init (class [testclassesil]TargetClassTest11`1<object> V_0,
+             valuetype Struct23 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... virtual c"
+    + "all ... method defined on generic type instantiated over object"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldstr      "return and parameter value equivalent... virtual c"
+    + "all"
+    IL_0011:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0016:  nop
+    IL_0017:  call       class [testclassesil]TargetClassTest11`1<object> NoPIATest.Program::GetTest11Object()
+    IL_001c:  stloc.0
+    IL_001d:  ldloc.0
+    IL_001e:  ldloca.s   V_1
+    IL_0020:  initobj    Struct23
+    IL_0026:  ldloc.1
+    IL_0027:  callvirt   instance valuetype Struct22 [basetestclassesil]TargetClassTest11_Base::VirtualFunction(valuetype Struct23)
+    IL_002c:  pop
+    IL_002d:  ret
+  } // end of method Program::Test11
+
+  .method private hidebysig static class [testclassesil]TargetClassTest12`1<int32> 
+          GetTest12Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest12`1<int32> V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void class [testclassesil]TargetClassTest12`1<int32>::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest12Object
+
+  .method private hidebysig static void  Test12() cil managed noinlining
+  {
+    // Code size       46 (0x2e)
+    .maxstack  2
+    .locals init (class [testclassesil]TargetClassTest12`1<int32> V_0,
+             valuetype Struct25 V_1)
+    IL_0000:  nop
+    IL_0001:  ldstr      "return and parameter value equivalent... virtual c"
+    + "all ... method defined on generic type instantiated over int"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldstr      "return and parameter value equivalent... virtual c"
+    + "all"
+    IL_0011:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0016:  nop
+    IL_0017:  call       class [testclassesil]TargetClassTest12`1<int32> NoPIATest.Program::GetTest12Object()
+    IL_001c:  stloc.0
+    IL_001d:  ldloc.0
+    IL_001e:  ldloca.s   V_1
+    IL_0020:  initobj    Struct25
+    IL_0026:  ldloc.1
+    IL_0027:  callvirt   instance valuetype Struct24 [basetestclassesil]TargetClassTest12_Base::VirtualFunction(valuetype Struct25)
+    IL_002c:  pop
+    IL_002d:  ret
+  } // end of method Program::Test12
+
+  .method private hidebysig static void  Test13() cil managed noinlining
+  {
+    // Code size       68 (0x44)
+    .maxstack  3
+    .locals init (class Test13Delegate V_0,
+             class Test13Delegate V_1,
+             class Test13Delegate V_2,
+             valuetype Struct27 V_3)
+    IL_0000:  nop
+    IL_0001:  ldstr      "Calling a multicast delegate to a non-virtual meth"
+    + "od constructed with an equivalent method"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldnull
+    IL_000d:  ldftn      valuetype Struct26 [testclassesil]TargetClassTest13::NormalFunction(valuetype Struct27)
+    IL_0013:  newobj     instance void Test13Delegate::.ctor(object,
+                                                             native int)
+    IL_0018:  stloc.0
+    IL_0019:  ldnull
+    IL_001a:  ldftn      valuetype Struct26 [testclassesil]TargetClassTest13::NormalFunction(valuetype Struct27)
+    IL_0020:  newobj     instance void Test13Delegate::.ctor(object,
+                                                             native int)
+    IL_0025:  stloc.1
+    IL_0026:  ldloc.0
+    IL_0027:  ldloc.1
+    IL_0028:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
+                                                                                            class [mscorlib]System.Delegate)
+    IL_002d:  castclass  Test13Delegate
+    IL_0032:  stloc.2
+    IL_0033:  ldloc.2
+    IL_0034:  ldloca.s   V_3
+    IL_0036:  initobj    Struct27
+    IL_003c:  ldloc.3
+    IL_003d:  callvirt   instance valuetype Struct26 Test13Delegate::Invoke(valuetype Struct27)
+    IL_0042:  pop
+    IL_0043:  ret
+  } // end of method Program::Test13
+
+  .method private hidebysig static class [testclassesil]TargetClassTest14 
+          GetTest14Object() cil managed noinlining
+  {
+    // Code size       11 (0xb)
+    .maxstack  1
+    .locals init (class [testclassesil]TargetClassTest14 V_0)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void [testclassesil]TargetClassTest14::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  br.s       IL_0009
+
+    IL_0009:  ldloc.0
+    IL_000a:  ret
+  } // end of method Program::GetTest14Object
+
+  .method private hidebysig static void  Test14() cil managed noinlining
+  {
+    // Code size       78 (0x4e)
+    .maxstack  3
+    .locals init (class Test14Delegate V_0,
+             class Test14Delegate V_1,
+             class Test14Delegate V_2,
+             valuetype Struct29 V_3)
+    IL_0000:  nop
+    IL_0001:  ldstr      "Calling a multicast delegate to a virtual method c"
+    + "onstructed with an equivalent method"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  call       class [testclassesil]TargetClassTest14 NoPIATest.Program::GetTest14Object()
+    IL_0011:  dup
+    IL_0012:  ldvirtftn  instance valuetype Struct28 [testclassesil]TargetClassTest14::VirtualFunction(valuetype Struct29)
+    IL_0018:  newobj     instance void Test14Delegate::.ctor(object,
+                                                             native int)
+    IL_001d:  stloc.0
+    IL_001e:  call       class [testclassesil]TargetClassTest14 NoPIATest.Program::GetTest14Object()
+    IL_0023:  dup
+    IL_0024:  ldvirtftn  instance valuetype Struct28 [testclassesil]TargetClassTest14::VirtualFunction(valuetype Struct29)
+    IL_002a:  newobj     instance void Test14Delegate::.ctor(object,
+                                                             native int)
+    IL_002f:  stloc.1
+    IL_0030:  ldloc.0
+    IL_0031:  ldloc.1
+    IL_0032:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
+                                                                                            class [mscorlib]System.Delegate)
+    IL_0037:  castclass  Test14Delegate
+    IL_003c:  stloc.2
+    IL_003d:  ldloc.2
+    IL_003e:  ldloca.s   V_3
+    IL_0040:  initobj    Struct29
+    IL_0046:  ldloc.3
+    IL_0047:  callvirt   instance valuetype Struct28 Test14Delegate::Invoke(valuetype Struct29)
+    IL_004c:  pop
+    IL_004d:  ret
+  } // end of method Program::Test14
+
+  .method private hidebysig static int32 Main(string[] args) cil managed noinlining
+  {
+  .entrypoint
+  // Code size       249 (0xf9)
+  .maxstack  2
+  .locals init ([0] int32 start,
+           [1] int32 end,
+           [2] int32 iter,
+           [3] bool CS$4$0000,
+           [4] int32 CS$4$0001)
+  IL_0000:  nop
+  IL_0001:  ldc.i4.0
+  IL_0002:  stloc.0
+  IL_0003:  ldc.i4.s   14
+  IL_0005:  stloc.1
+  IL_0006:  ldarg.0
+  IL_0007:  ldlen
+  IL_0008:  conv.i4
+  IL_0009:  ldc.i4.0
+  IL_000a:  ceq
+  IL_000c:  stloc.3
+  IL_000d:  ldloc.3
+  IL_000e:  brtrue.s   IL_001d
+  IL_0010:  nop
+  IL_0011:  ldarg.0
+  IL_0012:  ldc.i4.0
+  IL_0013:  ldelem.ref
+  IL_0014:  call       int32 [mscorlib]System.Int32::Parse(string)
+  IL_0019:  dup
+  IL_001a:  stloc.1
+  IL_001b:  stloc.0
+  IL_001c:  nop
+  IL_001d:  ldloc.0
+  IL_001e:  stloc.2
+  IL_001f:  br         IL_00ea
+  IL_0024:  nop
+  IL_0025:  ldloc.2
+  IL_0026:  stloc.s    CS$4$0001
+  IL_0028:  ldloc.s    CS$4$0001
+  IL_002a:  switch     ( 
+                        IL_006d,
+                        IL_0075,
+                        IL_007d,
+                        IL_0085,
+                        IL_008d,
+                        IL_0095,
+                        IL_009d,
+                        IL_00a5,
+                        IL_00ad,
+                        IL_00b5,
+                        IL_00bd,
+                        IL_00c5,
+                        IL_00cd,
+                        IL_00d5,
+                        IL_00dd)
+  IL_006b:  br.s       IL_00e5
+  IL_006d:  call       void NoPIATest.Program::Test1_0()
+  IL_0072:  nop
+  IL_0073:  br.s       IL_00e5
+  IL_0075:  call       void NoPIATest.Program::Test1_1()
+  IL_007a:  nop
+  IL_007b:  br.s       IL_00e5
+  IL_007d:  call       void NoPIATest.Program::Test2()
+  IL_0082:  nop
+  IL_0083:  br.s       IL_00e5
+  IL_0085:  call       void NoPIATest.Program::Test3()
+  IL_008a:  nop
+  IL_008b:  br.s       IL_00e5
+  IL_008d:  call       void NoPIATest.Program::Test4()
+  IL_0092:  nop
+  IL_0093:  br.s       IL_00e5
+  IL_0095:  call       void NoPIATest.Program::Test5()
+  IL_009a:  nop
+  IL_009b:  br.s       IL_00e5
+  IL_009d:  call       void NoPIATest.Program::Test6()
+  IL_00a2:  nop
+  IL_00a3:  br.s       IL_00e5
+  IL_00a5:  call       void NoPIATest.Program::Test7()
+  IL_00aa:  nop
+  IL_00ab:  br.s       IL_00e5
+  IL_00ad:  call       void NoPIATest.Program::Test8()
+  IL_00b2:  nop
+  IL_00b3:  br.s       IL_00e5
+  IL_00b5:  call       void NoPIATest.Program::Test9()
+  IL_00ba:  nop
+  IL_00bb:  br.s       IL_00e5
+  IL_00bd:  call       void NoPIATest.Program::Test10()
+  IL_00c2:  nop
+  IL_00c3:  br.s       IL_00e5
+  IL_00c5:  call       void NoPIATest.Program::Test11()
+  IL_00ca:  nop
+  IL_00cb:  br.s       IL_00e5
+  IL_00cd:  call       void NoPIATest.Program::Test12()
+  IL_00d2:  nop
+  IL_00d3:  br.s       IL_00e5
+  IL_00d5:  call       void NoPIATest.Program::Test13()
+  IL_00da:  nop
+  IL_00db:  br.s       IL_00e5
+  IL_00dd:  call       void NoPIATest.Program::Test14()
+  IL_00e2:  nop
+  IL_00e3:  br.s       IL_00e5
+  IL_00e5:  nop
+  IL_00e6:  ldloc.2
+  IL_00e7:  ldc.i4.1
+  IL_00e8:  add
+  IL_00e9:  stloc.2
+  IL_00ea:  ldloc.2
+  IL_00eb:  ldloc.1
+  IL_00ec:  cgt
+  IL_00ee:  ldc.i4.0
+  IL_00ef:  ceq
+  IL_00f1:  stloc.3
+  IL_00f2:  ldloc.3
+  IL_00f3:  brtrue     IL_0024
+            ldc.i4 100
+  IL_00f8:  ret
+
+  } // end of method Program::Main
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method Program::.ctor
+
+} // end of class NoPIATest.Program
+
diff --git a/src/tests/baseservices/typeequivalence/signatures/nopiatestil.ilproj b/src/tests/baseservices/typeequivalence/signatures/nopiatestil.ilproj
new file mode 100644 (file)
index 0000000..c115663
--- /dev/null
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk.IL">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <MonoAotIncompatible>true</MonoAotIncompatible>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="nopiatestil.il" />
+    <ProjectReference Include="basetestclassesil.ilproj" />
+    <ProjectReference Include="testclassesil.ilproj" />
+  </ItemGroup>
+</Project>
diff --git a/src/tests/baseservices/typeequivalence/signatures/testclassesil.il b/src/tests/baseservices/typeequivalence/signatures/testclassesil.il
new file mode 100644 (file)
index 0000000..929de23
--- /dev/null
@@ -0,0 +1,839 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.0.20326.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.AMD64chk
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly extern basetestclassesil
+{
+  .ver 0:0:0:0
+}
+.assembly testclassesil
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module testclassesil.dll
+// MVID: {B2D2C9A1-63E8-4408-87AE-AD79B08CA2DE}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x00000000001D0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class public sequential ansi sealed import beforefieldinit Struct0
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 30 00 00 )          // ...Struct.0..
+} // end of class Struct0
+
+.class public sequential ansi sealed import beforefieldinit Struct1
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 31 00 00 )          // ...Struct.1..
+} // end of class Struct1
+
+.class public sequential ansi sealed import beforefieldinit Struct2
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 32 00 00 )          // ...Struct.2..
+} // end of class Struct2
+
+.class public sequential ansi sealed import beforefieldinit Struct3
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 33 00 00 )          // ...Struct.3..
+} // end of class Struct3
+
+.class public sequential ansi sealed import beforefieldinit Struct4
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 34 00 00 )          // ...Struct.4..
+} // end of class Struct4
+
+.class public sequential ansi sealed import beforefieldinit Struct5
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 35 00 00 )          // ...Struct.5..
+} // end of class Struct5
+
+.class public sequential ansi sealed import beforefieldinit Struct6
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 36 00 00 )          // ...Struct.6..
+} // end of class Struct6
+
+.class public sequential ansi sealed import beforefieldinit Struct7
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 37 00 00 )          // ...Struct.7..
+} // end of class Struct7
+
+.class public sequential ansi sealed import beforefieldinit Struct8
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 38 00 00 )          // ...Struct.8..
+} // end of class Struct8
+
+.class public sequential ansi sealed import beforefieldinit Struct9
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 01 39 00 00 )          // ...Struct.9..
+} // end of class Struct9
+
+.class public sequential ansi sealed import beforefieldinit Struct10
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 30 00 00 )       // ...Struct.10..
+} // end of class Struct10
+
+.class public sequential ansi sealed import beforefieldinit Struct11
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 31 00 00 )       // ...Struct.11..
+} // end of class Struct11
+
+.class public sequential ansi sealed import beforefieldinit Struct12
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 32 00 00 )       // ...Struct.12..
+} // end of class Struct12
+
+.class public sequential ansi sealed import beforefieldinit Struct13
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 33 00 00 )       // ...Struct.13..
+} // end of class Struct13
+
+.class public sequential ansi sealed import beforefieldinit Struct14
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 34 00 00 )       // ...Struct.14..
+} // end of class Struct14
+
+.class public sequential ansi sealed import beforefieldinit Struct15
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 35 00 00 )       // ...Struct.15..
+} // end of class Struct15
+
+.class public sequential ansi sealed import beforefieldinit Struct16
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 36 00 00 )       // ...Struct.16..
+} // end of class Struct16
+
+.class public sequential ansi sealed import beforefieldinit Struct17
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 37 00 00 )       // ...Struct.17..
+} // end of class Struct17
+
+.class public sequential ansi sealed import beforefieldinit Struct18
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 38 00 00 )       // ...Struct.18..
+} // end of class Struct18
+
+.class public sequential ansi sealed import beforefieldinit Struct19
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 31 39 00 00 )       // ...Struct.19..
+} // end of class Struct19
+
+.class public sequential ansi sealed import beforefieldinit Struct20
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 30 00 00 )       // ...Struct.20..
+} // end of class Struct20
+
+.class public sequential ansi sealed import beforefieldinit Struct21
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 31 00 00 )       // ...Struct.21..
+} // end of class Struct21
+
+.class public sequential ansi sealed import beforefieldinit Struct22
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 32 00 00 )       // ...Struct.22..
+} // end of class Struct22
+
+.class public sequential ansi sealed import beforefieldinit Struct23
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 33 00 00 )       // ...Struct.23..
+} // end of class Struct23
+
+.class public sequential ansi sealed import beforefieldinit Struct24
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 34 00 00 )       // ...Struct.24..
+} // end of class Struct24
+
+.class public sequential ansi sealed import beforefieldinit Struct25
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 35 00 00 )       // ...Struct.25..
+} // end of class Struct25
+
+.class public sequential ansi sealed import beforefieldinit Struct26
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 36 00 00 )       // ...Struct.26..
+} // end of class Struct26
+
+.class public sequential ansi sealed import beforefieldinit Struct27
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 37 00 00 )       // ...Struct.27..
+} // end of class Struct27
+
+.class public sequential ansi sealed import beforefieldinit Struct28
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 38 00 00 )       // ...Struct.28..
+} // end of class Struct28
+
+.class public sequential ansi sealed import beforefieldinit Struct29
+       extends [mscorlib]System.ValueType
+{
+  .pack 0
+  .size 1
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 06 53 74 72 75 63 74 02 32 39 00 00 )       // ...Struct.29..
+} // end of class Struct29
+
+.class interface public abstract auto import ansi EquivalentInterface3
+{
+  .custom instance void [mscorlib]System.Runtime.InteropServices.TypeIdentifierAttribute::.ctor(string,
+                                                                                                string) = ( 01 00 09 49 6E 74 65 72 66 61 63 65 01 33 00 00 ) // ...Interface.3..
+  .method public hidebysig newslot abstract virtual 
+          instance valuetype Struct6  InterfaceFunction(valuetype Struct7 param) cil managed
+  {
+  } // end of method EquivalentInterface3::InterfaceFunction
+
+} // end of class EquivalentInterface3
+
+
+
+
+.class interface public abstract auto ansi TargetInterface8
+{
+  .method public hidebysig newslot abstract virtual 
+          instance valuetype Struct16  InterfaceFunction<T>(valuetype Struct17 param,
+                                                            !!T otherParam) cil managed
+  {
+  } // end of method TargetInterface8::InterfaceFunction
+
+} // end of class TargetInterface8
+
+.class public auto ansi beforefieldinit TargetClassTest1_0
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static valuetype Struct0 
+          NormalFunction1(valuetype Struct1 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct0 V_0,
+             valuetype Struct0 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct0
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest1_0::NormalFunction1
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest1_0::.ctor
+
+} // end of class TargetClassTest1_0
+
+.class public auto ansi beforefieldinit TargetClassTest1_1
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig instance valuetype Struct2 
+          NormalFunction1(valuetype Struct3 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct2 V_0,
+             valuetype Struct2 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct2
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest1_1::NormalFunction1
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest1_1::.ctor
+
+} // end of class TargetClassTest1_1
+
+
+.class public auto ansi beforefieldinit TargetClassTest2
+       extends [basetestclassesil]TargetClassTest2_Base
+{
+  .method public hidebysig virtual instance valuetype Struct4 
+          VirtualFunction(valuetype Struct5 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct4 V_0,
+             valuetype Struct4 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct4
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest2::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [basetestclassesil]TargetClassTest2_Base::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest2::.ctor
+
+} // end of class TargetClassTest2
+
+.class public auto ansi beforefieldinit TargetClassTest3
+       extends [mscorlib]System.Object
+       implements EquivalentInterface3
+{
+  .method private hidebysig newslot virtual final 
+          instance valuetype Struct6  EquivalentInterface3.InterfaceFunction(valuetype Struct7 param) cil managed
+  {
+    .override EquivalentInterface3::InterfaceFunction
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct6 V_0,
+             valuetype Struct6 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct6
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest3::EquivalentInterface3.InterfaceFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest3::.ctor
+
+} // end of class TargetClassTest3
+
+.class public auto ansi beforefieldinit TargetClassTest4
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static valuetype Struct8 
+          GenericFunction<T>(valuetype Struct9 param,
+                             !!T otherParam) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct8 V_0,
+             valuetype Struct8 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct8
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest4::GenericFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest4::.ctor
+
+} // end of class TargetClassTest4
+
+.class public auto ansi beforefieldinit TargetClassTest5
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig instance valuetype Struct10 
+          GenericFunction<T>(valuetype Struct11 param,
+                             !!T otherParam) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct10 V_0,
+             valuetype Struct10 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct10
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest5::GenericFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest5::.ctor
+
+} // end of class TargetClassTest5
+
+.class public auto ansi beforefieldinit TargetClassTest6
+       extends [basetestclassesil]TargetClassTest6_Base
+{
+  .method public hidebysig virtual instance valuetype Struct12 
+          VirtualFunction<T>(valuetype Struct13 param,
+                             !!T paramOther) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct12 V_0,
+             valuetype Struct12 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct12
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest6::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [basetestclassesil]TargetClassTest6_Base::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest6::.ctor
+
+} // end of class TargetClassTest6
+
+.class public auto ansi beforefieldinit TargetClassTest7
+       extends [basetestclassesil]TargetClassTest7_Base
+{
+  .method public hidebysig virtual instance valuetype Struct14 
+          VirtualFunction<T>(valuetype Struct15 param,
+                             !!T paramOther) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct14 V_0,
+             valuetype Struct14 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct14
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest7::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [basetestclassesil]TargetClassTest7_Base::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest7::.ctor
+
+} // end of class TargetClassTest7
+
+.class public auto ansi beforefieldinit TargetClassTest8
+       extends [mscorlib]System.Object
+       implements TargetInterface8
+{
+  .method private hidebysig newslot virtual final 
+          instance valuetype Struct16  TargetInterface8.InterfaceFunction<T>(valuetype Struct17 param,
+                                                                             !!T paramOther) cil managed
+  {
+    .override TargetInterface8::InterfaceFunction
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct16 V_0,
+             valuetype Struct16 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct16
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest8::TargetInterface8.InterfaceFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest8::.ctor
+
+} // end of class TargetClassTest8
+
+.class public auto ansi beforefieldinit TargetClassTest9
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig instance vararg valuetype Struct18 
+          VarargFunction(valuetype Struct19 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct18 V_0,
+             valuetype Struct18 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct18
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest9::VarargFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest9::.ctor
+
+} // end of class TargetClassTest9
+
+.class public auto ansi beforefieldinit TargetClassTest10
+       extends [basetestclassesil]TargetClassTest10_Base
+{
+  .method public hidebysig virtual instance vararg valuetype Struct20 
+          VarargFunction(valuetype Struct21 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct20 V_0,
+             valuetype Struct20 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct20
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest10::VarargFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [basetestclassesil]TargetClassTest10_Base::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest10::.ctor
+
+} // end of class TargetClassTest10
+
+.class public auto ansi beforefieldinit TargetClassTest11`1<T>
+       extends [basetestclassesil]TargetClassTest11_Base
+{
+  .method public hidebysig virtual instance valuetype Struct22 
+          VirtualFunction(valuetype Struct23 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct22 V_0,
+             valuetype Struct22 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct22
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest11`1::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [basetestclassesil]TargetClassTest11_Base::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest11`1::.ctor
+
+} // end of class TargetClassTest11`1
+
+.class public auto ansi beforefieldinit TargetClassTest12`1<T>
+       extends [basetestclassesil]TargetClassTest12_Base
+{
+  .method public hidebysig virtual instance valuetype Struct24 
+          VirtualFunction(valuetype Struct25 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct24 V_0,
+             valuetype Struct24 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct24
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest12`1::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [basetestclassesil]TargetClassTest12_Base::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest12`1::.ctor
+
+} // end of class TargetClassTest12`1
+
+.class public auto ansi beforefieldinit TargetClassTest13
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static valuetype Struct26 
+          NormalFunction(valuetype Struct27 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct26 V_0,
+             valuetype Struct26 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct26
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest13::NormalFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest13::.ctor
+
+} // end of class TargetClassTest13
+
+.class public auto ansi beforefieldinit TargetClassTest14
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig newslot virtual 
+          instance valuetype Struct28  VirtualFunction(valuetype Struct29 param) cil managed
+  {
+    // Code size       15 (0xf)
+    .maxstack  1
+    .locals init (valuetype Struct28 V_0,
+             valuetype Struct28 V_1)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_1
+    IL_0003:  initobj    Struct28
+    IL_0009:  ldloc.1
+    IL_000a:  stloc.0
+    IL_000b:  br.s       IL_000d
+
+    IL_000d:  ldloc.0
+    IL_000e:  ret
+  } // end of method TargetClassTest14::VirtualFunction
+
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldarg.0
+    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_0006:  ret
+  } // end of method TargetClassTest14::.ctor
+
+} // end of class TargetClassTest14
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file foo.res
diff --git a/src/tests/baseservices/typeequivalence/signatures/testclassesil.ilproj b/src/tests/baseservices/typeequivalence/signatures/testclassesil.ilproj
new file mode 100644 (file)
index 0000000..2300ba9
--- /dev/null
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk.IL">
+  <PropertyGroup>
+    <OutputType>Library</OutputType>
+    <CLRTestKind>SharedLibrary</CLRTestKind>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="testclassesil.il" />
+  </ItemGroup>
+</Project>
index 33b3e53..082544b 100644 (file)
         <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/eventsourceerror/eventsourceerror/*">
             <Issue>https://github.com/dotnet/runtime/issues/80666</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/signatures/nopiatestil/*">
+            <Issue>CoreCLR doesn't support type equivalence on Unix</Issue>
+        </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/istypeequivalent/istypeequivalent/*">
+            <Issue>CoreCLR doesn't support type equivalence on Unix</Issue>
+        </ExcludeList>
     </ItemGroup>
 
     <!-- Arm32 All OS -->
         <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/simple/Simple/*">
             <Issue>https://github.com/dotnet/runtimelab/issues/155: Type equivalence</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/signatures/nopiatestil/*">
+            <Issue>https://github.com/dotnet/runtimelab/issues/155: Type equivalence</Issue>
+        </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/istypeequivalent/istypeequivalent/*">
+            <Issue>https://github.com/dotnet/runtimelab/issues/155: Type equivalence</Issue>
+        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/GC/API/WeakReference/Finalize2/*">
             <Issue>Expectations about finalization order</Issue>
         </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/simple/Simple/*">
             <Issue>Mono doesn't support type equivalence on types implemented in different assemblies</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/signatures/nopiatestil/*">
+            <Issue>Mono doesn't support type equivalence on types implemented in different assemblies</Issue>
+        </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/istypeequivalent/istypeequivalent/*">
+            <Issue>Mono doesn't support type equivalence on types implemented in different assemblies</Issue>
+        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/Interop/ArrayMarshalling/SafeArray/SafeArrayTest/*">
             <Issue>Requires COM support, disabled on all Mono platforms.</Issue>
         </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/simple/Simple/**">
             <Issue>Doesn't compile with LLVM AOT.</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/signatures/nopiatestil/nopiatestil/**">
+            <Issue>Doesn't compile with LLVM AOT.</Issue>
+        </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/baseservices/typeequivalence/istypeequivalent/istypeequivalent/*">
+            <Issue>Doesn't compile with LLVM AOT.</Issue>
+        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/Loader/classloader/generics/Variance/IL/Unbox002/**">
             <Issue>Doesn't compile with LLVM AOT.</Issue>
         </ExcludeList>