Ejemplo n.º 1
0
        public BetterType CompareTypes(TypeArray ta1, TypeArray ta2)
        {
            if (ta1 == ta2)
            {
                return(BetterType.Same);
            }
            if (ta1.Size != ta2.Size)
            {
                // The one with more parameters is more specific.
                return(ta1.Size > ta2.Size ? BetterType.Left : BetterType.Right);
            }

            BetterType nTot = BetterType.Neither;

            for (int i = 0; i < ta1.Size; i++)
            {
                CType      type1  = ta1.Item(i);
                CType      type2  = ta2.Item(i);
                BetterType nParam = BetterType.Neither;

LAgain:
                if (type1.GetTypeKind() != type2.GetTypeKind())
                {
                    if (type1.IsTypeParameterType())
                    {
                        nParam = BetterType.Right;
                    }
                    else if (type2.IsTypeParameterType())
                    {
                        nParam = BetterType.Left;
                    }
                }
                else
                {
                    switch (type1.GetTypeKind())
                    {
                    default:
                        Debug.Assert(false, "Bad kind in CompareTypes");
                        break;

                    case TypeKind.TK_TypeParameterType:
                    case TypeKind.TK_ErrorType:
                        break;

                    case TypeKind.TK_PointerType:
                    case TypeKind.TK_ParameterModifierType:
                    case TypeKind.TK_ArrayType:
                    case TypeKind.TK_NullableType:
                        type1 = type1.GetBaseOrParameterOrElementType();
                        type2 = type2.GetBaseOrParameterOrElementType();
                        goto LAgain;

                    case TypeKind.TK_AggregateType:
                        nParam = CompareTypes(type1.AsAggregateType().GetTypeArgsAll(), type2.AsAggregateType().GetTypeArgsAll());
                        break;
                    }
                }

                if (nParam == BetterType.Right || nParam == BetterType.Left)
                {
                    if (nTot == BetterType.Same || nTot == BetterType.Neither)
                    {
                        nTot = nParam;
                    }
                    else if (nParam != nTot)
                    {
                        return(BetterType.Neither);
                    }
                }
            }

            return(nTot);
        }
Ejemplo n.º 2
0
        private BetterType WhichMethodIsBetterTieBreaker(
            CandidateFunctionMember node1,
            CandidateFunctionMember node2,
            CType pTypeThrough,
            ArgInfos args)
        {
            MethPropWithInst mpwi1 = node1.mpwi;
            MethPropWithInst mpwi2 = node2.mpwi;

            // Same signatures. If they have different lifting numbers, the smaller number wins.
            // Otherwise, if one is generic and the other isn't then the non-generic wins.
            // Otherwise, if one is expanded and the other isn't then the non-expanded wins.
            // Otherwise, if one has fewer modopts than the other then it wins.
            if (node1.ctypeLift != node2.ctypeLift)
            {
                return(node1.ctypeLift < node2.ctypeLift ? BetterType.Left : BetterType.Right);
            }

            // Non-generic wins.
            if (mpwi1.TypeArgs.Count != 0)
            {
                if (mpwi2.TypeArgs.Count == 0)
                {
                    return(BetterType.Right);
                }
            }
            else if (mpwi2.TypeArgs.Count != 0)
            {
                return(BetterType.Left);
            }

            // Non-expanded wins
            if (node1.fExpanded)
            {
                if (!node2.fExpanded)
                {
                    return(BetterType.Right);
                }
            }
            else if (node2.fExpanded)
            {
                return(BetterType.Left);
            }

            // See if one's parameter types (un-instantiated) are more specific.
            BetterType nT = GetGlobalSymbols().CompareTypes(
                RearrangeNamedArguments(mpwi1.MethProp().Params, mpwi1, pTypeThrough, args),
                RearrangeNamedArguments(mpwi2.MethProp().Params, mpwi2, pTypeThrough, args));

            if (nT == BetterType.Left || nT == BetterType.Right)
            {
                return(nT);
            }

            // Fewer modopts wins.
            if (mpwi1.MethProp().modOptCount != mpwi2.MethProp().modOptCount)
            {
                return(mpwi1.MethProp().modOptCount < mpwi2.MethProp().modOptCount ? BetterType.Left : BetterType.Right);
            }

            // Bona-fide tie.
            return(BetterType.Neither);
        }
Ejemplo n.º 3
0
        private static BetterType CompareTypes(TypeArray ta1, TypeArray ta2)
        {
            if (ta1 == ta2)
            {
                return(BetterType.Same);
            }

            if (ta1.Count != ta2.Count)
            {
                // The one with more parameters is more specific.
                return(ta1.Count > ta2.Count ? BetterType.Left : BetterType.Right);
            }

            BetterType nTot = BetterType.Neither;

            for (int i = 0; i < ta1.Count; i++)
            {
                CType      type1  = ta1[i];
                CType      type2  = ta2[i];
                BetterType nParam = BetterType.Neither;

LAgain:
                if (type1.TypeKind != type2.TypeKind)
                {
                    if (type1 is TypeParameterType)
                    {
                        nParam = BetterType.Right;
                    }
                    else if (type2 is TypeParameterType)
                    {
                        nParam = BetterType.Left;
                    }
                }
                else
                {
                    switch (type1.TypeKind)
                    {
                    default:
                        Debug.Fail("Bad kind in CompareTypes");
                        break;

                    case TypeKind.TK_TypeParameterType:
                        break;

                    case TypeKind.TK_PointerType:
                    case TypeKind.TK_ParameterModifierType:
                    case TypeKind.TK_ArrayType:
                    case TypeKind.TK_NullableType:
                        type1 = type1.BaseOrParameterOrElementType;
                        type2 = type2.BaseOrParameterOrElementType;
                        goto LAgain;

                    case TypeKind.TK_AggregateType:
                        nParam = CompareTypes(((AggregateType)type1).TypeArgsAll, ((AggregateType)type2).TypeArgsAll);
                        break;
                    }
                }

                if (nParam == BetterType.Right || nParam == BetterType.Left)
                {
                    if (nTot == BetterType.Same || nTot == BetterType.Neither)
                    {
                        nTot = nParam;
                    }
                    else if (nParam != nTot)
                    {
                        return(BetterType.Neither);
                    }
                }
            }

            return(nTot);
        }
Ejemplo n.º 4
0
        ////////////////////////////////////////////////////////////////////////////////
        // Determine which method is better for the purposes of overload resolution.
        // Better means: as least as good in all params, and better in at least one param.
        // Better w/r to a param means is an ordering, from best down:
        // 1) same type as argument
        // 2) implicit conversion from argument to formal type
        // Because of user defined conversion opers this relation is not transitive.
        //
        // If there is a tie because of identical signatures, the tie may be broken by the
        // following rules:
        // 1) If one is generic and the other isn't, the non-generic wins.
        // 2) Otherwise if one is expanded (params) and the other isn't, the non-expanded wins.
        // 3) Otherwise if one has more specific parameter types (at the declaration) it wins:
        //    This occurs if at least on parameter type is more specific and no parameter type is
        //    less specific.
        //* A type parameter is less specific than a non-type parameter.
        //* A constructed type is more specific than another constructed type if at least
        //      one type argument is more specific and no type argument is less specific than
        //      the corresponding type args in the other.
        // 4) Otherwise if one has more modopts than the other does, the smaller number of modopts wins.
        //
        // Returns Left if m1 is better, Right if m2 is better, or Neither/Same

        private BetterType WhichMethodIsBetter(
            CandidateFunctionMember node1,
            CandidateFunctionMember node2,
            CType pTypeThrough,
            ArgInfos args)
        {
            MethPropWithInst mpwi1 = node1.mpwi;
            MethPropWithInst mpwi2 = node2.mpwi;

            // Substitutions should have already been done on these!
            TypeArray pta1 = RearrangeNamedArguments(node1.@params, mpwi1, pTypeThrough, args);
            TypeArray pta2 = RearrangeNamedArguments(node2.@params, mpwi2, pTypeThrough, args);

            // If the parameter types for both candidate methods are identical,
            // use the tie breaking rules.

            if (pta1 == pta2)
            {
                return(WhichMethodIsBetterTieBreaker(node1, node2, pTypeThrough, args));
            }

            //  Otherwise, do a parameter-by-parameter comparison:
            //
            // Given an argument list A with a set of argument expressions {E1, ... En} and
            // two applicable function members Mp and Mq with parameter types {P1,... Pn} and
            // {Q1, ... Qn}, Mp is defined to be a better function member than Mq if:
            //* for each argument the implicit conversion from Ex to Qx is not better than
            //   the implicit conversion from Ex to Px.
            //* for at least one argument, the conversion from Ex to Px is better than the
            //   conversion from Ex to Qx.

            BetterType betterMethod = BetterType.Neither;
            int        carg         = args.carg;

            for (int i = 0; i < carg; i++)
            {
                Expr  arg = args.fHasExprs ? args.prgexpr[i] : null;
                CType p1  = pta1[i];
                CType p2  = pta2[i];

                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // RUNTIME BINDER ONLY CHANGE
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                //
                // We need to consider conversions from the actual runtime type
                // since we could have private interfaces that we are converting

                CType argType = arg?.RuntimeObjectActualType ?? args.types[i];

                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // END RUNTIME BINDER ONLY CHANGE
                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                BetterType betterConversion = WhichConversionIsBetter(argType, p1, p2);

                if (betterMethod == BetterType.Right)
                {
                    if (betterConversion == BetterType.Left)
                    {
                        betterMethod = BetterType.Neither;
                        break;
                    }
                }
                else if (betterMethod == BetterType.Left)
                {
                    if (betterConversion == BetterType.Right)
                    {
                        betterMethod = BetterType.Neither;
                        break;
                    }
                }
                else
                {
                    Debug.Assert(betterMethod == BetterType.Neither);
                    if (betterConversion == BetterType.Right || betterConversion == BetterType.Left)
                    {
                        betterMethod = betterConversion;
                    }
                }
            }

            // We may have different sizes if we had optional parameters. If thats the case,
            // the one with fewer parameters wins (ie less optional parameters) unless it is
            // expanded. If so, the one with more parameters wins (ie option beats expanded).
            if (pta1.Count != pta2.Count && betterMethod == BetterType.Neither)
            {
                if (node1.fExpanded)
                {
                    if (!node2.fExpanded)
                    {
                        return(BetterType.Right);
                    }
                }
                else if (node2.fExpanded)
                {
                    return(BetterType.Left);
                }

                // Here, if both methods needed to use optionals to fill in the signatures,
                // then we are ambiguous. Otherwise, take the one that didn't need any
                // optionals.

                if (pta1.Count == carg)
                {
                    return(BetterType.Left);
                }

                if (pta2.Count == carg)
                {
                    return(BetterType.Right);
                }

                return(BetterType.Neither);
            }

            return(betterMethod);
        }
Ejemplo n.º 5
0
        ////////////////////////////////////////////////////////////////////////////////
        // Determine best method for overload resolution. Returns null if no best
        // method, in which case two tying methods are returned for error reporting.
        private CandidateFunctionMember FindBestMethod(
            List <CandidateFunctionMember> list,
            CType pTypeThrough,
            ArgInfos args,
            out CandidateFunctionMember methAmbig1,
            out CandidateFunctionMember methAmbig2)
        {
            Debug.Assert(list.Any());
            Debug.Assert(list.First().mpwi != null);
            Debug.Assert(list.Count > 0);

            // select the best method:

            /*
             * Effectively, we pick the best item from a set using a non-transitive ranking function
             * So, pick the first item (candidate) and compare against next (contender), if there is
             *  no next, goto phase 2
             * If first is better, move to next contender, if none proceed to phase 2
             * If second is better, make the contender the candidate and make the item following
             *  contender into the new contender, if there is none, goto phase 2
             * If neither, make contender+1 into candidate and contender+2 into contender, if possible,
             *  otherwise, if contender was last, return null, otherwise if new candidate is last,
             *  goto phase 2
             * Phase 2: compare all items before candidate to candidate
             *  If candidate always better, return it, otherwise return null
             *
             */
            // Record two method that are ambiguous for error reporting.
            CandidateFunctionMember ambig1 = null;
            CandidateFunctionMember ambig2 = null;
            bool ambiguous = false;
            CandidateFunctionMember candidate = list[0];

            for (int i = 1; i < list.Count; i++)
            {
                CandidateFunctionMember contender = list[i];
                Debug.Assert(candidate != contender);

                BetterType result = WhichMethodIsBetter(candidate, contender, pTypeThrough, args);
                if (result == BetterType.Left)
                {
                    ambiguous = false;
                    continue;  // (meaning m1 is better...)
                }
                else if (result == BetterType.Right)
                {
                    ambiguous = false;
                    candidate = contender;
                }
                else
                {
                    // in case of tie we don't want to bother with the contender who tied...
                    ambig1 = candidate;
                    ambig2 = contender;

                    i++;
                    if (i < list.Count)
                    {
                        contender = list[i];
                        candidate = contender;
                    }
                    else
                    {
                        ambiguous = true;
                    }
                }
            }
            if (ambiguous)
            {
                goto AMBIG;
            }

            // Now, compare the candidate with items previous to it...
            foreach (CandidateFunctionMember contender in list)
            {
                if (contender == candidate)
                {
                    // We hit our winner, so its good enough...
                    methAmbig1 = null;
                    methAmbig2 = null;
                    return(candidate);
                }
                BetterType result = WhichMethodIsBetter(contender, candidate, pTypeThrough, args);
                if (result == BetterType.Right)
                { // meaning m2 is better
                    continue;
                }
                else if (result == BetterType.Same || result == BetterType.Neither)
                {
                    ambig1 = candidate;
                    ambig2 = contender;
                }
                break;
            }

AMBIG:
            // an ambig call. Return two of the ambiguous set.
            if (ambig1 != null && ambig2 != null)
            {
                methAmbig1 = ambig1;
                methAmbig2 = ambig2;
            }
            else
            {
                // For some reason, we have an ambiguity but never had a tie.
                // This can easily happen in a circular graph of candidate methods.
                methAmbig1 = list.First();
                methAmbig2 = list.Skip(1).First();
            }

            return(null);
        }