<commit_before>﻿using Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.PooledObjects;

namespace Microsoft.CodeAnalysis.CSharp
{
    internal sealed partial class MethodTypeInferrer
    {
        /// <summary>
        /// Performs the concept phase of type inference.
        /// <para>
        /// This phase occurs when the vanilla C# first and second phases have
        /// both failed.
        /// </para>
        /// <para>
        /// In this phase, we check to see whether the remaining unbound
        /// type parameters are concept witnesses.  If they are, then we
        /// find all currently visible implementations of the witnessed
        /// concept in scope, and check whether the set of implementations
        /// yields a viable type for the missing argument.
        /// </para>
        /// </summary>
        /// <param name="binder">
        /// The binder for the scope in which the type-inferred method
        /// resides.
        /// </param>
        /// <param name="useSiteDiagnostics">
        /// The diagnostics set for this use site.
        /// </param>
        /// <returns></returns>
        private bool InferTypeArgsConceptPhase(Binder binder, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(!AllFixed(),
                "Concept witness inference is pointless if there is nothing to infer");

            var inferrer = ConceptWitnessInferrer.ForBinder(binder);
            var fixedMap = inferrer.Infer(_methodTypeParameters, _fixedResults.AsImmutable(), new ImmutableTypeMap(), ImmutableHashSet<NamedTypeSymbol>.Empty, ref useSiteDiagnostics);
            if (fixedMap == null)
            {
                return false;
            }

            for (int i = 0; i < _fixedResults.Length; i++)
            {
                if (_fixedResults[i] != null)
                {
                    // This type parameter was already fixed.
                    continue;
                }

                /* Note: One might be tempted to put in an assertion here that
                   the map can't assign to _fixedResults[i] the same thing as
                   _methodTypeParameters[i].  However, sometimes it can!

                   For example, consider

                   private static void Qsort<T, implicit OrdT>
                       (T[] xs, int lo, int hi) where OrdT : Ord<T>
                   {
                       if (lo < hi)
                       {
                           var p = Partition(xs, lo, hi);
                           Qsort(xs, lo, p - 1);
                           Qsort(xs, p + 1, hi);
                       }
                  }

                  In this case, the map will resolve the missing
                  type parameters in each Qsort call as T->T, OrdT->OrdT.
                  These are exactly the same symbols. */
                _fixedResults[i] = fixedMap.SubstituteType(_methodTypeParameters[i]).AsTypeSymbolOnly();
            }

            return true;
        }
    }

    /// <summary>
    /// An object that, given a series of viable instances and bound type
    /// parameters, can perform concept witness inference.
    /// </summary>
    internal class ConceptWitnessInferrer
    {
        /// <summary>
        /// The list of all instances in scope for this inferrer.
        /// These can be either type parameters (eg. witnesses passed in
        /// through constraints at the method or class level) or named
        /// types (instance declarations).
        /// </summary>
        private readonly ImmutableArray<TypeSymbol> _allInstances;

        /// <summary>
        /// The set of all type parameters in scope that are bound:
        /// we cannot substitute for them in unification.  Usually this is
        /// the set of type parameters introduced through type parameter
        /// lists on methods and classes in scope.
        /// </summary>
        private readonly ImmutableHashSet<TypeParameterSymbol> _boundParams;

        /// <summary>
        /// A candidate instance and its unification.
        /// </summary>
        internal struct Candidate
        {
            /// <summary>
            /// Whether the candidate is viable.
            /// </summary>
            public bool Viable;

            /// <summary>
            /// The candidate instance.
            /// </summary>
            public readonly TypeSymbol Instance;

            /// <summary>
            /// The unification that must be made to accept this instance.
            /// </summary>
            public readonly ImmutableTypeMap Unification;

            /// <summary>
            /// The diagnostics, if any, that killed off this candidate.
            /// </summary>
            public HashSet<DiagnosticInfo> Diagnostics;

            /// <summary>
            /// Constructs a Candidate.
            /// </summary>
            /// <param name="instance">
            /// The candidate instance.
            /// </param>
            /// <param name="unification">
            /// The unification that must be made to accept this instance.
            /// </param>
            public Candidate(TypeSymbol instance, ImmutableTypeMap unification)
            {
                Instance = instance;
                Unification = unification;
                Diagnostics = null;
                Viable = true;
            }

            /// <summary>
            /// Constructs a failing Candidate with a given diagnostic.
            /// </summary>
            /// <param name="errors">
            /// The set of errors that caused this Candidate to fail.
            /// </param>
            public Candidate(HashSet<DiagnosticInfo> errors)
            {
                Instance = null;
                Unification = null;
                Diagnostics = errors;
                Viable = false;
            }
        }

        /// <summary>
        /// Constructs a new ConceptWitnessInferrer.
        /// </summary>
        /// <param name="allInstances">
        /// The list of all instances in scope for this inferrer.
        /// </param>
        /// <param name="boundParams">
        /// The set of all type parameters in scope that are bound, and
        /// cannot be substituted out in unification.<commit_msg>Concept-C#'17: debug display for Candidate<commit_after>﻿using Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.PooledObjects;
using System.Text;

namespace Microsoft.CodeAnalysis.CSharp
{
    internal sealed partial class MethodTypeInferrer
    {
        /// <summary>
        /// Performs the concept phase of type inference.
        /// <para>
        /// This phase occurs when the vanilla C# first and second phases have
        /// both failed.
        /// </para>
        /// <para>
        /// In this phase, we check to see whether the remaining unbound
        /// type parameters are concept witnesses.  If they are, then we
        /// find all currently visible implementations of the witnessed
        /// concept in scope, and check whether the set of implementations
        /// yields a viable type for the missing argument.
        /// </para>
        /// </summary>
        /// <param name="binder">
        /// The binder for the scope in which the type-inferred method
        /// resides.
        /// </param>
        /// <param name="useSiteDiagnostics">
        /// The diagnostics set for this use site.
        /// </param>
        /// <returns></returns>
        private bool InferTypeArgsConceptPhase(Binder binder, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(!AllFixed(),
                "Concept witness inference is pointless if there is nothing to infer");

            var inferrer = ConceptWitnessInferrer.ForBinder(binder);
            var fixedMap = inferrer.Infer(_methodTypeParameters, _fixedResults.AsImmutable(), new ImmutableTypeMap(), ImmutableHashSet<NamedTypeSymbol>.Empty, ref useSiteDiagnostics);
            if (fixedMap == null)
            {
                return false;
            }

            for (int i = 0; i < _fixedResults.Length; i++)
            {
                if (_fixedResults[i] != null)
                {
                    // This type parameter was already fixed.
                    continue;
                }

                /* Note: One might be tempted to put in an assertion here that
                   the map can't assign to _fixedResults[i] the same thing as
                   _methodTypeParameters[i].  However, sometimes it can!

                   For example, consider

                   private static void Qsort<T, implicit OrdT>
                       (T[] xs, int lo, int hi) where OrdT : Ord<T>
                   {
                       if (lo < hi)
                       {
                           var p = Partition(xs, lo, hi);
                           Qsort(xs, lo, p - 1);
                           Qsort(xs, p + 1, hi);
                       }
                  }

                  In this case, the map will resolve the missing
                  type parameters in each Qsort call as T->T, OrdT->OrdT.
                  These are exactly the same symbols. */
                _fixedResults[i] = fixedMap.SubstituteType(_methodTypeParameters[i]).AsTypeSymbolOnly();
            }

            return true;
        }
    }

    /// <summary>
    /// An object that, given a series of viable instances and bound type
    /// parameters, can perform concept witness inference.
    /// </summary>
    internal class ConceptWitnessInferrer
    {
        /// <summary>
        /// The list of all instances in scope for this inferrer.
        /// These can be either type parameters (eg. witnesses passed in
        /// through constraints at the method or class level) or named
        /// types (instance declarations).
        /// </summary>
        private readonly ImmutableArray<TypeSymbol> _allInstances;

        /// <summary>
        /// The set of all type parameters in scope that are bound:
        /// we cannot substitute for them in unification.  Usually this is
        /// the set of type parameters introduced through type parameter
        /// lists on methods and classes in scope.
        /// </summary>
        private readonly ImmutableHashSet<TypeParameterSymbol> _boundParams;

        /// <summary>
        /// A candidate instance and its unification.
        /// </summary>
        [DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
        internal struct Candidate
        {
            /// <summary>
            /// Whether the candidate is viable.
            /// </summary>
            public bool Viable;

            /// <summary>
            /// The candidate instance.
            /// </summary>
            public readonly TypeSymbol Instance;

            /// <summary>
            /// The unification that must be made to accept this instance.
            /// </summary>
            public readonly ImmutableTypeMap Unification;

            /// <summary>
            /// The diagnostics, if any, that killed off this candidate.
            /// </summary>
            public HashSet<DiagnosticInfo> Diagnostics;

            /// <summary>
            /// Constructs a Candidate.
            /// </summary>
            /// <param name="instance">
            /// The candidate instance.
            /// </param>
            /// <param name="unification">
            /// The unification that must be made to accept this instance.
            /// </param>
            public Candidate(TypeSymbol instance, ImmutableTypeMap unification)
            {
                Instance = instance;
                Unification = unification;
                Diagnostics = null;
                Viable = true;
            }

            /// <summary>
            /// Constructs a failing Candidate with a given diagnostic.
            /// </summary>
            /// <param name="errors">
            /// The set of errors that caused this Candidate to fail.
            /// </param>
            public Candidate(HashSet<DiagnosticInfo> errors)
            {
                Instance = null;
                Unification = null;
                Diagnostics = errors;
                Viable = false;
            }

            private string GetDebuggerDisplay()
            {
                var result = new StringBuilder("[");
                result.Append(GetType().Name);

                result.Append(" (");
                if (Viable)
                {
                    result.Append("viable: ");
                    result.Append(Instance.GetDebuggerDisplay());

                }
                else
                {
                    result.Append("not viable");
                }
                return result.Append(")]").ToString();
            }
        }

        /// <summary>
        /// Constructs a new ConceptWitnessInferrer.
        /// </summary>
        /// <param name="allInstances">
        /// The list of all instances in scope for this inferrer.
        /// </param>
        /// <param name="boundParams">
        /// The set of all type parameters in scope that are bound, and
        /// cannot be substituted out in unification.
{'fraction_non_alphanumeric': 0.09615671085952629, 'fraction_numerical': 0.0005958587814687919, 'mean_word_length': 1.4045487106017192, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 109, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3115252', 'n_tokens_mistral': 3155, 'n_tokens_neox': 3018, 'n_words': 1095}