public void TestVirtualDispatchOnGenericType()
        {
            // Verifies that virtual dispatch to a non-generic method on a generic instantiation works
            DefType         objectType     = _context.GetWellKnownType(WellKnownType.Object);
            MethodSignature toStringSig    = new MethodSignature(MethodSignatureFlags.None, 0, _stringType, Array.Empty <TypeDesc>());
            MethodDesc      objectToString = objectType.GetMethod("ToString", toStringSig);

            Assert.NotNull(objectToString);
            MetadataType     openTestType     = _testModule.GetType("VirtualFunctionOverride", "SimpleGeneric`1");
            InstantiatedType testInstance     = openTestType.MakeInstantiatedType(new Instantiation(new TypeDesc[] { objectType }));
            MethodDesc       targetOnInstance = testInstance.GetMethod("ToString", toStringSig);

            MethodDesc targetMethod = testInstance.FindVirtualFunctionTargetMethodOnObjectType(objectToString);

            Assert.Equal(targetOnInstance, targetMethod);
        }
        public void TestConstructedMethodAdjustment()
        {
            TypeDesc intType    = _context.GetWellKnownType(WellKnownType.Int32);
            TypeDesc stringType = _context.GetWellKnownType(WellKnownType.String);
            TypeDesc charType   = _context.GetWellKnownType(WellKnownType.Char);
            TypeDesc objectType = _context.GetWellKnownType(WellKnownType.Object);

            MetadataType genericOpenType = _testModule.GetType("GenericTypes", "TwoParamGenericClass`2");
            MetadataType nonGenericType  = _testModule.GetType("GenericTypes", "NonGenericClass");

            MethodDesc nonGenericOnGeneric = genericOpenType.GetMethod("NonGenericFunction", null);
            MethodDesc genericOnGeneric    = genericOpenType.GetMethod("GenericFunction", null);
            MethodDesc genericOnNonGeneric = nonGenericType.GetMethod("GenericFunction", null);

            InstantiatedType genericIntString  = genericOpenType.MakeInstantiatedType(intType, stringType);
            InstantiatedType genericCharString = genericOpenType.MakeInstantiatedType(charType, stringType);
            InstantiatedType genericCharObject = genericOpenType.MakeInstantiatedType(charType, objectType);

            MethodDesc nonGenericOnGenericIntString  = genericIntString.GetMethod("NonGenericFunction", null);
            MethodDesc nonGenericOnGenericCharString = genericCharString.GetMethod("NonGenericFunction", null);
            MethodDesc nonGenericOnGenericCharObject = genericCharObject.GetMethod("NonGenericFunction", null);

            MethodDesc genericIntStringOnGenericIntString   = genericIntString.GetMethod("GenericFunction", null).MakeInstantiatedMethod(intType, stringType);
            MethodDesc genericCharStringOnGenericCharString = genericCharString.GetMethod("GenericFunction", null).MakeInstantiatedMethod(charType, stringType);
            MethodDesc genericCharObjectOnGenericCharObject = genericCharObject.GetMethod("GenericFunction", null).MakeInstantiatedMethod(charType, objectType);

            MethodDesc genericIntStringOnNonGeneric  = genericOnNonGeneric.MakeInstantiatedMethod(intType, stringType);
            MethodDesc genericCharStringOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(charType, stringType);
            MethodDesc genericCharObjectOnNonGeneric = genericOnNonGeneric.MakeInstantiatedMethod(charType, objectType);

            // Test complete replacement
            MethodDesc testDirectReplacementNonGenericOnGeneric = nonGenericOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType });

            Assert.Equal(nonGenericOnGenericCharObject, testDirectReplacementNonGenericOnGeneric);
            MethodDesc testDirectReplacementGenericOnGeneric = genericIntStringOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType });

            Assert.Equal(genericCharObjectOnGenericCharObject, testDirectReplacementGenericOnGeneric);
            MethodDesc testDirectReplacementGenericOnNonGeneric = genericIntStringOnNonGeneric.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType, stringType }, new TypeDesc[] { charType, objectType });

            Assert.Equal(genericCharObjectOnNonGeneric, testDirectReplacementGenericOnNonGeneric);

            // Test replace first type in instantiation
            MethodDesc testPartialReplacementNonGenericOnGeneric = nonGenericOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });

            Assert.Equal(nonGenericOnGenericCharString, testPartialReplacementNonGenericOnGeneric);
            MethodDesc testPartialReplacementGenericOnGeneric = genericIntStringOnGenericIntString.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });

            Assert.Equal(genericCharStringOnGenericCharString, testPartialReplacementGenericOnGeneric);
            MethodDesc testPartialReplacementGenericOnNonGeneric = genericIntStringOnNonGeneric.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });

            Assert.Equal(genericCharStringOnNonGeneric, testPartialReplacementGenericOnNonGeneric);

            // Test ArrayMethod case
            ArrayType mdArrayChar = _context.GetArrayType(charType, 3);
            ArrayType mdArrayInt  = _context.GetArrayType(intType, 3);

            MethodDesc getMethodOnMDIntArray  = mdArrayInt.GetArrayMethod(ArrayMethodKind.Get);
            MethodDesc getMethodOnMDCharArray = mdArrayChar.GetArrayMethod(ArrayMethodKind.Get);

            MethodDesc testArrayMethodCase = getMethodOnMDIntArray.ReplaceTypesInConstructionOfMethod(new TypeDesc[] { intType }, new TypeDesc[] { charType });

            Assert.Equal(getMethodOnMDCharArray, testArrayMethodCase);
        }