<commit_before>﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Internal.TypeSystem
{
    public static class VirtualFunctionResolution
    {
        class UnificationGroup
        {
            public UnificationGroup(MethodDesc definingMethod)
            {
                DefiningMethod = definingMethod;
                // TODO! Add assertion that DefiningMethod is a slot defining method
            }

            public MethodDesc DefiningMethod;
            public List<MethodDesc> Members = new List<MethodDesc>();

            public void SetDefiningMethod(MethodDesc newDefiningMethod)
            {
                // Do not change the defining method if its the same as
                // one of the members, or it isn't a change at all
                if (!Members.Contains(newDefiningMethod) &&
                    DefiningMethod != newDefiningMethod)
                {
                    DefiningMethod = newDefiningMethod;
                    // TODO! Add assertion that DefiningMethod is a slot defining method
                }
            }

            public void AddToGroup(MethodDesc method)
            {
                if (method == DefiningMethod)
                    return;

                if (!Members.Contains(method))
                    Members.Add(method);
            }

            public void RemoveFromGroup(MethodDesc method)
            {
                if (method == DefiningMethod)
                    throw new BadImageFormatException();

                Members.Remove(method);
            }

            public bool IsInGroupOrIsDefiningSlot(MethodDesc method)
            {
                if (DefiningMethod == method)
                    return true;

                return IsInGroup(method);
            }

            public bool IsInGroup(MethodDesc method)
            {
                return Members.Contains(method);
            }
        }

        /// <summary>
        /// Resolve a virtual function call (to a virtual method, not an interface method)
        /// </summary>
        /// <param name="targetMethod"></param>
        /// <param name="objectType"></param>
        /// <returns>The override of the virtual method that should be called</returns>
        public static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, MetadataType objectType)
        {
            // Step 1, convert objectType to uninstantiated form
            TypeDesc uninstantiatedType = objectType;
            MethodDesc initialTargetMethod = targetMethod;
            InstantiatedType initialInstantiatedType = objectType as InstantiatedType;
            if (initialInstantiatedType != null)
            {
                uninstantiatedType = initialInstantiatedType.GetTypeDefinition();
            }

            // Step 2, convert targetMethod to method in type hierarchy of uninstantiated form
            targetMethod = targetMethod.GetMethodDefinition();
            if (uninstantiatedType != objectType)
            {
                targetMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod);
            }

            // Step 3, find unification group of target method
            UnificationGroup group = new UnificationGroup(FindSlotDefiningMethodForVirtualMethod(targetMethod));
            FindBaseUnificationGroup(objectType, group);

            // Step 4, name/sig match virtual function resolve
            MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, objectType);

            // Step 5, convert resolution target from uninstantiated form target to objecttype target,
            // and instantiate as appropriate
            if (uninstantiatedType != objectType)
            {
                resolutionTarget = objectType.FindMethodOnTypeWithMatchingTypicalMethod(resolutionTarget);
            }
            if (initialTargetMethod.HasInstantiation)
            {
                resolutionTarget = resolutionTarget.MakeInstantiatedMethod(initialTargetMethod.Instantiation);
            }

            return resolutionTarget;
        }

        private static bool IsInterfaceImplementedOnType(MetadataType type, MetadataType interfaceType)
        {
            // TODO! This function is the same as IsInterfaceExplicitlyImplementedOnType which isn't quite right.
            // Fix the concept of implemented/explictly implemented interfaces and make these methods right.
            foreach (TypeDesc iface in type.ImplementedInterfaces)
            {
                if (iface == interfaceType)
                    return true;
            }
            return false;
        }

        private static MethodDesc FindImplFromDeclFromMethodImpls(MetadataType type, MethodDesc decl)
        {<commit_msg>Workaround infinite recursion in virtual function resolution (#48)<commit_after>﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Internal.TypeSystem
{
    public static class VirtualFunctionResolution
    {
        class UnificationGroup
        {
            public UnificationGroup(MethodDesc definingMethod)
            {
                DefiningMethod = definingMethod;
                // TODO! Add assertion that DefiningMethod is a slot defining method
            }

            public MethodDesc DefiningMethod;
            public List<MethodDesc> Members = new List<MethodDesc>();

            public void SetDefiningMethod(MethodDesc newDefiningMethod)
            {
                // Do not change the defining method if its the same as
                // one of the members, or it isn't a change at all
                if (!Members.Contains(newDefiningMethod) &&
                    DefiningMethod != newDefiningMethod)
                {
                    DefiningMethod = newDefiningMethod;
                    // TODO! Add assertion that DefiningMethod is a slot defining method
                }
            }

            public void AddToGroup(MethodDesc method)
            {
                if (method == DefiningMethod)
                    return;

                if (!Members.Contains(method))
                    Members.Add(method);
            }

            public void RemoveFromGroup(MethodDesc method)
            {
                if (method == DefiningMethod)
                    throw new BadImageFormatException();

                Members.Remove(method);
            }

            public bool IsInGroupOrIsDefiningSlot(MethodDesc method)
            {
                if (DefiningMethod == method)
                    return true;

                return IsInGroup(method);
            }

            public bool IsInGroup(MethodDesc method)
            {
                return Members.Contains(method);
            }
        }

        /// <summary>
        /// Resolve a virtual function call (to a virtual method, not an interface method)
        /// </summary>
        /// <param name="targetMethod"></param>
        /// <param name="objectType"></param>
        /// <returns>The override of the virtual method that should be called</returns>
        public static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, MetadataType objectType)
        {
            // Workaround for https://github.com/dotnet/corert/issues/48
#if true
            string name = targetMethod.Name;
            MethodSignature sig = targetMethod.Signature;

            TypeDesc t = objectType;
            for (;;)
            {
                MethodDesc implMethod = t.GetMethod(name, sig);
                if (implMethod != null)
                    return implMethod;
                t = t.BaseType;
            }
#else
            // Step 1, convert objectType to uninstantiated form
            TypeDesc uninstantiatedType = objectType;
            MethodDesc initialTargetMethod = targetMethod;
            InstantiatedType initialInstantiatedType = objectType as InstantiatedType;
            if (initialInstantiatedType != null)
            {
                uninstantiatedType = initialInstantiatedType.GetTypeDefinition();
            }

            // Step 2, convert targetMethod to method in type hierarchy of uninstantiated form
            targetMethod = targetMethod.GetMethodDefinition();
            if (uninstantiatedType != objectType)
            {
                targetMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod);
            }

            // Step 3, find unification group of target method
            UnificationGroup group = new UnificationGroup(FindSlotDefiningMethodForVirtualMethod(targetMethod));
            FindBaseUnificationGroup(objectType, group);

            // Step 4, name/sig match virtual function resolve
            MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, objectType);

            // Step 5, convert resolution target from uninstantiated form target to objecttype target,
            // and instantiate as appropriate
            if (uninstantiatedType != objectType)
            {
                resolutionTarget = objectType.FindMethodOnTypeWithMatchingTypicalMethod(resolutionTarget);
            }
            if (initialTargetMethod.HasInstantiation)
            {
                resolutionTarget = resolutionTarget.MakeInstantiatedMethod(initialTargetMethod.Instantiation);
            }

            return resolutionTarget;
#endif
        }

        private static bool IsInterfaceImplementedOnType(MetadataType type, MetadataType interfaceType)
        {
            // TODO! This function is the same as IsInterfaceExplicitlyImplementedOnType which isn't quite right.
            // Fix the concept of implemented/explictly implemented interfaces and make these methods right.
            foreach (TypeDesc iface in type.ImplementedInterfaces)
            {
                if (iface == interfaceType)
                    return true;
            }
            return false;
        }

        private static MethodDesc FindImplFromDeclFromMethodImpls(MetadataType type, MethodDesc decl)
        {
{'fraction_non_alphanumeric': 0.060820503012336234, 'fraction_numerical': 0.0013388161040451371, 'mean_word_length': 1.8620689655172413, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3314047', 'n_tokens_mistral': 2369, 'n_tokens_neox': 2232, 'n_words': 677}