public InterfaceGVMEntryInfo(MethodDesc callingMethod, MethodDesc implementationMethod,
                              TypeDesc implementationType, DefaultInterfaceMethodResolution defaultResolution)
     : base(callingMethod, implementationMethod)
 {
     ImplementationType = implementationType;
     DefaultResolution  = defaultResolution;
 }
        public IEnumerable <InterfaceGVMEntryInfo> ScanForInterfaceGenericVirtualMethodEntries()
        {
            foreach (var iface in _associatedType.RuntimeInterfaces)
            {
                foreach (var method in iface.GetVirtualMethods())
                {
                    Debug.Assert(!method.Signature.IsStatic);

                    if (!method.HasInstantiation)
                    {
                        continue;
                    }

                    DefaultInterfaceMethodResolution resolution = DefaultInterfaceMethodResolution.None;
                    MethodDesc slotDecl = _associatedType.ResolveInterfaceMethodTarget(method);
                    if (slotDecl == null)
                    {
                        resolution = _associatedType.ResolveInterfaceMethodToDefaultImplementationOnType(method, out slotDecl);
                        if (resolution != DefaultInterfaceMethodResolution.DefaultImplementation)
                        {
                            slotDecl = null;
                        }
                    }

                    if (slotDecl != null ||
                        resolution == DefaultInterfaceMethodResolution.Diamond ||
                        resolution == DefaultInterfaceMethodResolution.Reabstraction)
                    {
                        yield return(new InterfaceGVMEntryInfo(method, slotDecl, _associatedType, resolution));
                    }
                }
            }
        }
Exemple #3
0
        public static DefaultInterfaceMethodResolution ResolveVariantInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, MetadataType currentType, out MethodDesc impl)
        {
            Debug.Assert(interfaceMethod.Signature.IsStatic);

            MetadataType interfaceType  = (MetadataType)interfaceMethod.OwningType;
            bool         foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType);

            if (foundInterface)
            {
                DefaultInterfaceMethodResolution resolution = ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, currentType, out impl);
                if (resolution != DefaultInterfaceMethodResolution.None)
                {
                    return(resolution);
                }
            }

            MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition();

            foreach (TypeDesc iface in currentType.RuntimeInterfaces)
            {
                if (iface.HasSameTypeDefinition(interfaceType) && iface.CanCastTo(interfaceType))
                {
                    MethodDesc variantMethod = iface.FindMethodOnTypeWithMatchingTypicalMethod(interfaceMethodDefinition);
                    Debug.Assert(variantMethod != null);
                    if (interfaceMethod != interfaceMethodDefinition)
                    {
                        variantMethod = variantMethod.MakeInstantiatedMethod(interfaceMethod.Instantiation);
                    }
                    DefaultInterfaceMethodResolution resolution = ResolveInterfaceMethodToDefaultImplementationOnType(variantMethod, currentType, out impl);
                    if (resolution != DefaultInterfaceMethodResolution.None)
                    {
                        return(resolution);
                    }
                }
            }

            impl = null;
            return(DefaultInterfaceMethodResolution.None);
        }
Exemple #4
0
        /// <summary>
        /// Gets a value indicating whether '<paramref name="type"/>' might have a non-empty dispatch map.
        /// Note that this is only an approximation because we might not be able to take into account
        /// whether the interface methods are actually used.
        /// </summary>
        public static bool MightHaveInterfaceDispatchMap(TypeDesc type, NodeFactory factory)
        {
            if (type.IsArrayTypeWithoutGenericInterfaces())
            {
                return(false);
            }

            if (!type.IsArray && !type.IsDefType)
            {
                return(false);
            }

            // Interfaces don't have a dispatch map because we dispatch them based on the
            // dispatch map of the implementing class.
            // The only exception are IDynamicInterfaceCastable scenarios that dispatch
            // using the interface dispatch map.
            // We generate the dispatch map irrespective of whether the interface actually
            // implements any methods (we don't run the for loop below) so that at runtime
            // we can distinguish between "the interface returned by IDynamicInterfaceCastable
            // wasn't marked as [DynamicInterfaceCastableImplementation]" and "we couldn't find an
            // implementation". We don't want to use the custom attribute for that at runtime because
            // that's reflection and this should work without reflection.
            if (type.IsInterface)
            {
                return(((MetadataType)type).IsDynamicInterfaceCastableImplementation());
            }

            TypeDesc declType = type.GetClosestDefType();

            for (int interfaceIndex = 0; interfaceIndex < declType.RuntimeInterfaces.Length; interfaceIndex++)
            {
                DefType          interfaceType             = declType.RuntimeInterfaces[interfaceIndex];
                InstantiatedType interfaceOnDefinitionType = interfaceType.IsTypeDefinition ?
                                                             null :
                                                             (InstantiatedType)declType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex];

                IEnumerable <MethodDesc> slots;

                // If the vtable has fixed slots, we can query it directly.
                // If it's a lazily built vtable, we might not be able to query slots
                // just yet, so approximate by looking at all methods.
                VTableSliceNode vtableSlice = factory.VTable(interfaceType);
                if (vtableSlice.HasFixedSlots)
                {
                    slots = vtableSlice.Slots;
                }
                else
                {
                    slots = interfaceType.GetAllVirtualMethods();
                }

                foreach (MethodDesc slotMethod in slots)
                {
                    MethodDesc declMethod = slotMethod;

                    Debug.Assert(!declMethod.Signature.IsStatic && declMethod.IsVirtual);

                    if (interfaceOnDefinitionType != null)
                    {
                        declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), interfaceOnDefinitionType);
                    }

                    var implMethod = declType.GetTypeDefinition().ResolveInterfaceMethodToVirtualMethodOnType(declMethod);
                    if (implMethod != null)
                    {
                        return(true);
                    }
                    else
                    {
                        DefaultInterfaceMethodResolution result = declType.ResolveInterfaceMethodToDefaultImplementationOnType(slotMethod, out _);
                        if (result != DefaultInterfaceMethodResolution.None)
                        {
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Exemple #5
0
        void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory)
        {
            var entryCountReservation        = builder.ReserveShort();
            var defaultEntryCountReservation = builder.ReserveShort();
            int entryCount = 0;

            TypeDesc declType           = _type.GetClosestDefType();
            TypeDesc declTypeDefinition = declType.GetTypeDefinition();

            DefType[] declTypeRuntimeInterfaces           = declType.RuntimeInterfaces;
            DefType[] declTypeDefinitionRuntimeInterfaces = declTypeDefinition.RuntimeInterfaces;

            // Catch any runtime interface collapsing. We shouldn't have any
            Debug.Assert(declTypeRuntimeInterfaces.Length == declTypeDefinitionRuntimeInterfaces.Length);

            var defaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot)>();

            // Resolve all the interfaces, but only emit non-default implementations
            for (int interfaceIndex = 0; interfaceIndex < declTypeRuntimeInterfaces.Length; interfaceIndex++)
            {
                var interfaceType           = declTypeRuntimeInterfaces[interfaceIndex];
                var interfaceDefinitionType = declTypeDefinitionRuntimeInterfaces[interfaceIndex];
                Debug.Assert(interfaceType.IsInterface);

                IReadOnlyList <MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots;

                for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++)
                {
                    MethodDesc declMethod = virtualSlots[interfaceMethodSlot];
                    if (!interfaceType.IsTypeDefinition)
                    {
                        declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType);
                    }

                    var implMethod = declTypeDefinition.ResolveInterfaceMethodToVirtualMethodOnType(declMethod);

                    // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface
                    // dispatch will walk the inheritance chain).
                    if (implMethod != null)
                    {
                        TypeDesc implType = declType;
                        while (!implType.HasSameTypeDefinition(implMethod.OwningType))
                        {
                            implType = implType.BaseType;
                        }

                        MethodDesc targetMethod = implMethod;
                        if (!implType.IsTypeDefinition)
                        {
                            targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType);
                        }

                        builder.EmitShort((short)checked ((ushort)interfaceIndex));
                        builder.EmitShort((short)checked ((ushort)(interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0))));
                        builder.EmitShort((short)checked ((ushort)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType)));
                        entryCount++;
                    }
                    else
                    {
                        // Is there a default implementation?

                        int?implSlot = null;

                        DefaultInterfaceMethodResolution result = declTypeDefinition.ResolveInterfaceMethodToDefaultImplementationOnType(declMethod, out implMethod);
                        if (result == DefaultInterfaceMethodResolution.DefaultImplementation)
                        {
                            DefType providingInterfaceDefinitionType = (DefType)implMethod.OwningType;
                            implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty);
                            implSlot   = VirtualMethodSlotHelper.GetDefaultInterfaceMethodSlot(factory, implMethod, declType, providingInterfaceDefinitionType);
                        }
                        else if (result == DefaultInterfaceMethodResolution.Reabstraction)
                        {
                            implSlot = SpecialDispatchMapSlot.Reabstraction;
                        }
                        else if (result == DefaultInterfaceMethodResolution.Diamond)
                        {
                            implSlot = SpecialDispatchMapSlot.Diamond;
                        }

                        if (implSlot.HasValue)
                        {
                            defaultImplementations.Add((
                                                           interfaceIndex,
                                                           interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0),
                                                           implSlot.Value));
                        }
                    }
                }
            }

            // Now emit the default implementations
            foreach (var defaultImplementation in defaultImplementations)
            {
                builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceIndex));
                builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceMethodSlot));
                builder.EmitShort((short)checked ((ushort)defaultImplementation.ImplMethodSlot));
            }

            // Update the header
            builder.EmitShort(entryCountReservation, (short)checked ((ushort)entryCount));
            builder.EmitShort(defaultEntryCountReservation, (short)checked ((ushort)defaultImplementations.Count));
        }
        void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory)
        {
            var entryCountReservation              = builder.ReserveShort();
            var defaultEntryCountReservation       = builder.ReserveShort();
            var staticEntryCountReservation        = builder.ReserveShort();
            var defaultStaticEntryCountReservation = builder.ReserveShort();
            int entryCount = 0;

            TypeDesc declType           = _type.GetClosestDefType();
            TypeDesc declTypeDefinition = declType.GetTypeDefinition();

            DefType[] declTypeRuntimeInterfaces           = declType.RuntimeInterfaces;
            DefType[] declTypeDefinitionRuntimeInterfaces = declTypeDefinition.RuntimeInterfaces;

            // Catch any runtime interface collapsing. We shouldn't have any
            Debug.Assert(declTypeRuntimeInterfaces.Length == declTypeDefinitionRuntimeInterfaces.Length);

            var defaultImplementations       = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot)>();
            var staticImplementations        = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>();
            var staticDefaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>();

            // Resolve all the interfaces, but only emit non-static and non-default implementations
            for (int interfaceIndex = 0; interfaceIndex < declTypeRuntimeInterfaces.Length; interfaceIndex++)
            {
                var interfaceType           = declTypeRuntimeInterfaces[interfaceIndex];
                var interfaceDefinitionType = declTypeDefinitionRuntimeInterfaces[interfaceIndex];
                Debug.Assert(interfaceType.IsInterface);

                IReadOnlyList <MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots;

                for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++)
                {
                    MethodDesc declMethod = virtualSlots[interfaceMethodSlot];
                    if (!interfaceType.IsTypeDefinition)
                    {
                        declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType);
                    }

                    var implMethod = declMethod.Signature.IsStatic ?
                                     declTypeDefinition.ResolveInterfaceMethodToStaticVirtualMethodOnType(declMethod) :
                                     declTypeDefinition.ResolveInterfaceMethodToVirtualMethodOnType(declMethod);

                    // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface
                    // dispatch will walk the inheritance chain).
                    if (implMethod != null)
                    {
                        TypeDesc implType = declType;
                        while (!implType.HasSameTypeDefinition(implMethod.OwningType))
                        {
                            implType = implType.BaseType;
                        }

                        MethodDesc targetMethod = implMethod;
                        if (!implType.IsTypeDefinition)
                        {
                            targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType);
                        }

                        int emittedInterfaceSlot = interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0);
                        int emittedImplSlot      = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType);
                        if (targetMethod.Signature.IsStatic)
                        {
                            // If this is a static virtual, also remember whether we need generic context.
                            // The implementation is not callable without the generic context.
                            // Instance methods acquire the generic context from `this` and don't need it.
                            // The pointer to the generic context is stored in the owning type's vtable.
                            int genericContext = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()
                                ? StaticVirtualMethodContextSource.ContextFromThisClass
                                : StaticVirtualMethodContextSource.None;
                            staticImplementations.Add((interfaceIndex, emittedInterfaceSlot, emittedImplSlot, genericContext));
                        }
                        else
                        {
                            builder.EmitShort((short)checked ((ushort)interfaceIndex));
                            builder.EmitShort((short)checked ((ushort)emittedInterfaceSlot));
                            builder.EmitShort((short)checked ((ushort)emittedImplSlot));
                            entryCount++;
                        }
                    }
                    else
                    {
                        // Is there a default implementation?

                        int?implSlot = null;

                        DefaultInterfaceMethodResolution result  = declTypeDefinition.ResolveInterfaceMethodToDefaultImplementationOnType(declMethod, out implMethod);
                        DefType providingInterfaceDefinitionType = null;
                        if (result == DefaultInterfaceMethodResolution.DefaultImplementation)
                        {
                            providingInterfaceDefinitionType = (DefType)implMethod.OwningType;
                            implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty);
                            implSlot   = VirtualMethodSlotHelper.GetDefaultInterfaceMethodSlot(factory, implMethod, declType, providingInterfaceDefinitionType);
                        }
                        else if (result == DefaultInterfaceMethodResolution.Reabstraction)
                        {
                            implSlot = SpecialDispatchMapSlot.Reabstraction;
                        }
                        else if (result == DefaultInterfaceMethodResolution.Diamond)
                        {
                            implSlot = SpecialDispatchMapSlot.Diamond;
                        }

                        if (implSlot.HasValue)
                        {
                            int emittedInterfaceSlot = interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0);
                            if (declMethod.Signature.IsStatic)
                            {
                                int genericContext = StaticVirtualMethodContextSource.None;
                                if (result == DefaultInterfaceMethodResolution.DefaultImplementation &&
                                    implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
                                {
                                    // If this is a static virtual, also remember whether we need generic context.
                                    // The implementation is not callable without the generic context.
                                    // Instance methods acquire the generic context from `this` and don't need it.
                                    // For default interface methods, the generic context is acquired by indexing
                                    // into the interface list of the owning type.
                                    Debug.Assert(providingInterfaceDefinitionType != null);
                                    int indexOfInterface = Array.IndexOf(declTypeDefinitionRuntimeInterfaces, providingInterfaceDefinitionType);
                                    Debug.Assert(indexOfInterface >= 0);
                                    genericContext = StaticVirtualMethodContextSource.ContextFromFirstInterface + indexOfInterface;
                                }
                                staticDefaultImplementations.Add((
                                                                     interfaceIndex,
                                                                     emittedInterfaceSlot,
                                                                     implSlot.Value,
                                                                     genericContext));
                            }
                            else
                            {
                                defaultImplementations.Add((
                                                               interfaceIndex,
                                                               emittedInterfaceSlot,
                                                               implSlot.Value));
                            }
                        }
                    }
                }
            }

            // Now emit the default implementations
            foreach (var defaultImplementation in defaultImplementations)
            {
                builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceIndex));
                builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceMethodSlot));
                builder.EmitShort((short)checked ((ushort)defaultImplementation.ImplMethodSlot));
            }

            // Now emit the static implementations
            foreach (var staticImplementation in staticImplementations)
            {
                builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceIndex));
                builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceMethodSlot));
                builder.EmitShort((short)checked ((ushort)staticImplementation.ImplMethodSlot));
                builder.EmitShort((short)checked ((ushort)staticImplementation.Context));
            }

            // Now emit the static default implementations
            foreach (var staticImplementation in staticDefaultImplementations)
            {
                builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceIndex));
                builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceMethodSlot));
                builder.EmitShort((short)checked ((ushort)staticImplementation.ImplMethodSlot));
                builder.EmitShort((short)checked ((ushort)staticImplementation.Context));
            }

            // Update the header
            builder.EmitShort(entryCountReservation, (short)checked ((ushort)entryCount));
            builder.EmitShort(defaultEntryCountReservation, (short)checked ((ushort)defaultImplementations.Count));
            builder.EmitShort(staticEntryCountReservation, (short)checked ((ushort)staticImplementations.Count));
            builder.EmitShort(defaultStaticEntryCountReservation, (short)checked ((ushort)staticDefaultImplementations.Count));
        }
        private void AddGenericVirtualMethodImplementation(NodeFactory factory, MethodDesc callingMethod, TypeDesc implementationType, MethodDesc implementationMethod, DefaultInterfaceMethodResolution resolution)
        {
            Debug.Assert(callingMethod.OwningType.IsInterface);

            // Compute the open method signatures
            MethodDesc openCallingMethod        = callingMethod.GetTypicalMethodDefinition();
            object     openImplementationMethod = implementationMethod == null ? resolution : implementationMethod.GetTypicalMethodDefinition();
            TypeDesc   openImplementationType   = implementationType.GetTypeDefinition();

            // Add the entry to the interface GVM slots mapping table
            if (!_interfaceGvmSlots.ContainsKey(openCallingMethod))
            {
                _interfaceGvmSlots[openCallingMethod] = new HashSet <object>();
            }
            _interfaceGvmSlots[openCallingMethod].Add(openImplementationMethod);

            // If the implementation method is implementing some interface method, compute which
            // interface explicitly implemented on the type that the current method implements an interface method for.
            // We need this because at runtime, the interfaces explicitly implemented on the type will have
            // runtime-determined signatures that we can use to make generic substitutions and check for interface matching.
            if (!openImplementationType.IsInterface)
            {
                if (!_interfaceImpls.ContainsKey(openImplementationMethod))
                {
                    _interfaceImpls[openImplementationMethod] = new Dictionary <TypeDesc, HashSet <int> >();
                }
                if (!_interfaceImpls[openImplementationMethod].ContainsKey(openImplementationType))
                {
                    _interfaceImpls[openImplementationMethod][openImplementationType] = new HashSet <int>();
                }

                int numIfacesAdded = 0;
                for (int index = 0; index < openImplementationType.RuntimeInterfaces.Length; index++)
                {
                    if (openImplementationType.RuntimeInterfaces[index] == callingMethod.OwningType)
                    {
                        _interfaceImpls[openImplementationMethod][openImplementationType].Add(index);
                        numIfacesAdded++;
                    }
                }

                Debug.Assert(numIfacesAdded > 0);
            }
        }
Exemple #8
0
        /// <summary>
        /// Attempts to resolve constrained call to <paramref name="interfaceMethod"/> into a concrete non-unboxing
        /// method on <paramref name="constrainedType"/>.
        /// The ability to resolve constraint methods is affected by the degree of code sharing we are performing
        /// for generic code.
        /// </summary>
        /// <returns>The resolved method or null if the constraint couldn't be resolved.</returns>
        public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrainedType, TypeDesc interfaceType, MethodDesc interfaceMethod, out bool forceRuntimeLookup, ref DefaultInterfaceMethodResolution staticResolution)
        {
            forceRuntimeLookup = false;

            bool isStaticVirtualMethod = interfaceMethod.Signature.IsStatic;

            // We can't resolve constraint calls effectively for reference types, and there's
            // not a lot of perf. benefit in doing it anyway.
            if (!constrainedType.IsValueType && (!isStaticVirtualMethod || constrainedType.IsCanonicalDefinitionType(CanonicalFormKind.Any)))
            {
                return(null);
            }

            // Interface method may or may not be fully canonicalized here.
            // It would be canonical on the CoreCLR side so canonicalize here to keep the algorithms similar.
            Instantiation methodInstantiation = interfaceMethod.Instantiation;

            interfaceMethod = interfaceMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);

            // 1. Find the (possibly generic) method that would implement the
            // constraint if we were making a call on a boxed value type.

            TypeDesc          canonType = constrainedType.ConvertToCanonForm(CanonicalFormKind.Specific);
            TypeSystemContext context   = constrainedType.Context;

            MethodDesc genInterfaceMethod = interfaceMethod.GetMethodDefinition();
            MethodDesc method             = null;

            if (genInterfaceMethod.OwningType.IsInterface)
            {
                // Sometimes (when compiling shared generic code)
                // we don't have enough exact type information at JIT time
                // even to decide whether we will be able to resolve to an unboxed entry point...
                // To cope with this case we always go via the helper function if there's any
                // chance of this happening by checking for all interfaces which might possibly
                // be compatible with the call (verification will have ensured that
                // at least one of them will be)

                // Enumerate all potential interface instantiations
                int potentialMatchingInterfaces = 0;
                foreach (DefType potentialInterfaceType in canonType.RuntimeInterfaces)
                {
                    if (potentialInterfaceType.ConvertToCanonForm(CanonicalFormKind.Specific) ==
                        interfaceType.ConvertToCanonForm(CanonicalFormKind.Specific))
                    {
                        potentialMatchingInterfaces++;

                        // The below code is just trying to prevent one of the matches from requiring boxing
                        // It doesn't apply to static virtual methods.
                        if (isStaticVirtualMethod)
                        {
                            continue;
                        }

                        MethodDesc potentialInterfaceMethod = genInterfaceMethod;
                        if (potentialInterfaceMethod.OwningType != potentialInterfaceType)
                        {
                            potentialInterfaceMethod = context.GetMethodForInstantiatedType(
                                potentialInterfaceMethod.GetTypicalMethodDefinition(), (InstantiatedType)potentialInterfaceType);
                        }

                        method = canonType.ResolveInterfaceMethodToVirtualMethodOnType(potentialInterfaceMethod);

                        // See code:#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
                        if (method != null && !method.OwningType.IsValueType)
                        {
                            // We explicitly wouldn't want to abort if we found a default implementation.
                            // The above resolution doesn't consider the default methods.
                            Debug.Assert(!method.OwningType.IsInterface);
                            return(null);
                        }
                    }
                }

                Debug.Assert(potentialMatchingInterfaces != 0);

                if (potentialMatchingInterfaces > 1)
                {
                    // We have more potentially matching interfaces
                    Debug.Assert(interfaceType.HasInstantiation);

                    bool isExactMethodResolved = false;

                    if (!interfaceType.IsCanonicalSubtype(CanonicalFormKind.Any) &&
                        !interfaceType.IsGenericDefinition &&
                        !constrainedType.IsCanonicalSubtype(CanonicalFormKind.Any) &&
                        !constrainedType.IsGenericDefinition)
                    {
                        // We have exact interface and type instantiations (no generic variables and __Canon used
                        // anywhere)
                        if (constrainedType.CanCastTo(interfaceType))
                        {
                            // We can resolve to exact method
                            MethodDesc exactInterfaceMethod = context.GetMethodForInstantiatedType(
                                genInterfaceMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceType);
                            if (isStaticVirtualMethod)
                            {
                                method = constrainedType.ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(exactInterfaceMethod);
                                if (method == null)
                                {
                                    staticResolution = constrainedType.ResolveVariantInterfaceMethodToDefaultImplementationOnType(exactInterfaceMethod, out method);
                                    if (staticResolution != DefaultInterfaceMethodResolution.DefaultImplementation)
                                    {
                                        method = null;
                                    }
                                }
                            }
                            else
                            {
                                method = constrainedType.ResolveVariantInterfaceMethodToVirtualMethodOnType(exactInterfaceMethod);
                            }
                            isExactMethodResolved = method != null;
                        }
                    }

                    if (!isExactMethodResolved)
                    {
                        // We couldn't resolve the interface statically
                        // Notify the caller that it should use runtime lookup
                        // Note that we can leave pMD incorrect, because we will use runtime lookup
                        forceRuntimeLookup = true;
                    }
                }
                else
                {
                    // If we can resolve the interface exactly then do so (e.g. when doing the exact
                    // lookup at runtime, or when not sharing generic code).
                    if (constrainedType.CanCastTo(interfaceType))
                    {
                        MethodDesc exactInterfaceMethod = genInterfaceMethod;
                        if (genInterfaceMethod.OwningType != interfaceType)
                        {
                            exactInterfaceMethod = context.GetMethodForInstantiatedType(
                                genInterfaceMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceType);
                        }
                        if (isStaticVirtualMethod)
                        {
                            method = constrainedType.ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(exactInterfaceMethod);
                            if (method == null)
                            {
                                staticResolution = constrainedType.ResolveVariantInterfaceMethodToDefaultImplementationOnType(exactInterfaceMethod, out method);
                                if (staticResolution != DefaultInterfaceMethodResolution.DefaultImplementation)
                                {
                                    method = null;
                                }
                            }
                        }
                        else
                        {
                            method = constrainedType.ResolveVariantInterfaceMethodToVirtualMethodOnType(exactInterfaceMethod);
                        }
                    }
                }
            }
            else if (genInterfaceMethod.IsVirtual)
            {
                MethodDesc targetMethod = interfaceType.FindMethodOnTypeWithMatchingTypicalMethod(genInterfaceMethod);
                method = constrainedType.FindVirtualFunctionTargetMethodOnObjectType(targetMethod);
            }
            else
            {
                // The method will be null if calling a non-virtual instance
                // methods on System.Object, i.e. when these are used as a constraint.
                method = null;
            }

            if (method == null)
            {
                // Fall back to VSD
                return(null);
            }

            //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
            // Only return a method if the value type itself declares the method,
            // otherwise we might get a method from Object or System.ValueType
            if (!isStaticVirtualMethod && !method.OwningType.IsValueType)
            {
                // Fall back to VSD
                return(null);
            }

            // We've resolved the method, ignoring its generic method arguments
            // If the method is a generic method then go and get the instantiated descriptor
            if (methodInstantiation.Length != 0)
            {
                method = method.MakeInstantiatedMethod(methodInstantiation);
            }

            // It's difficult to discern what runtime determined form the interface method
            // is on later so fail the resolution if this would be that.
            // This is pretty conservative and can be narrowed down.
            if (method.IsCanonicalMethod(CanonicalFormKind.Any) &&
                !method.OwningType.IsValueType)
            {
                Debug.Assert(method.Signature.IsStatic);
                return(null);
            }

            Debug.Assert(method != null);

            return(method);
        }