Пример #1
0
        public static ExprMemberGroup CreateMemGroup(Expr obj, MethPropWithInst method)
        {
            Name name = method.Sym?.name;

            return(CreateMemGroup(
                       0, name, method.TypeArgs, method.MethProp()?.getKind() ?? SYMKIND.SK_MethodSymbol, method.GetType(),
                       obj, new CMemberLookupResults(TypeArray.Allocate((CType)method.GetType()), name)));
        }
Пример #2
0
        public ExprMemberGroup CreateMemGroup(
            Expr pObject,
            MethPropWithInst mwi)
        {
            Name pName = mwi.Sym?.name;
            MethodOrPropertySymbol methProp = mwi.MethProp();

            CType pType = mwi.GetType() ?? (CType)GetTypes().GetErrorSym();

            return(CreateMemGroup(0, pName, mwi.TypeArgs, methProp?.getKind() ?? SYMKIND.SK_MethodSymbol, mwi.GetType(), methProp, pObject, new CMemberLookupResults(GetGlobalSymbols().AllocParams(1, new CType[] { pType }), pName)));
        }
Пример #3
0
        public ExprMemberGroup CreateMemGroup(Expr obj, MethPropWithInst method)
        {
            Name name = method.Sym?.name;
            MethodOrPropertySymbol methProp = method.MethProp();

            CType type = method.GetType() ?? (CType)Types.GetErrorSym();

            return(CreateMemGroup(
                       0, name, method.TypeArgs, methProp?.getKind() ?? SYMKIND.SK_MethodSymbol, method.GetType(), methProp,
                       obj, new CMemberLookupResults(GlobalSymbols.AllocParams(1, new[] { type }), name)));
        }
        public EXPRMEMGRP CreateMemGroup(
            EXPR pObject,
            MethPropWithInst mwi)
        {
            Name pName = mwi.Sym != null ? mwi.Sym.name : null;
            MethodOrPropertySymbol methProp = mwi.MethProp();

            CType pType = mwi.GetType();

            if (pType == null)
            {
                pType = GetTypes().GetErrorSym();
            }

            return(CreateMemGroup(0, pName, mwi.TypeArgs, methProp != null ? methProp.getKind() : SYMKIND.SK_MethodSymbol, mwi.GetType(), methProp, pObject, new CMemberLookupResults(GetGlobalSymbols().AllocParams(1, new CType[] { pType }), pName)));
        }
Пример #5
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);
        }
Пример #6
0
        ////////////////////////////////////////////////////////////////////////////////
        // We need to rearange the method parameters so that the type of any specified named argument
        // appears in the same place as the named argument. Consider the example below:
        //    Foo(int x = 4, string y = "", long l = 4)
        //    Foo(string y = "", string x="", long l = 5)
        // and the call site:
        //    Foo(y:"a")
        // After rearranging the parameter types we will have:
        //   (string, int, long) and (string, string, long)
        // By rearranging the arguments as such we make sure that any specified named arguments appear in the same position for both
        // methods and we also maintain the relative order of the other parameters (the type long appears after int in the above example)

        private TypeArray RearrangeNamedArguments(TypeArray pta, MethPropWithInst mpwi,
                                                  CType pTypeThrough, ArgInfos args)
        {
            if (!args.fHasExprs)
            {
                return(pta);
            }

#if DEBUG
            // We never have a named argument that is in a position in the argument
            // list past the end of what would be the formal parameter list.
            for (int i = pta.Count; i < args.carg; i++)
            {
                Debug.Assert(!(args.prgexpr[i] is ExprNamedArgumentSpecification));
            }
#endif

            CType   type     = pTypeThrough != null ? pTypeThrough : mpwi.GetType();
            CType[] typeList = new CType[pta.Count];
            MethodOrPropertySymbol methProp = GroupToArgsBinder.FindMostDerivedMethod(GetSymbolLoader(), mpwi.MethProp(), type);

            // We initialize the new type array with the parameters for the method.
            for (int iParam = 0; iParam < pta.Count; iParam++)
            {
                typeList[iParam] = pta[iParam];
            }

            var prgexpr = args.prgexpr;
            // We then go over the specified arguments and put the type for any named argument in the right position in the array.
            for (int iParam = 0; iParam < args.carg; iParam++)
            {
                if (prgexpr[iParam] is ExprNamedArgumentSpecification named)
                {
                    // We find the index of the type of the argument in the method parameter list and store that in a temp
                    int   index    = FindName(methProp.ParameterNames, named.Name);
                    CType tempType = pta[index];

                    // Starting from the current position in the type list up until the location of the type of the optional argument
                    //  We shift types by one:
                    //   before: (int, string, long)
                    //   after: (string, int, long)
                    // We only touch the types between the current position and the position of the type we need to move
                    for (int iShift = iParam; iShift < index; iShift++)
                    {
                        typeList[iShift + 1] = typeList[iShift];
                    }

                    typeList[iParam] = tempType;
                }
            }

            return(GetSymbolLoader().getBSymmgr().AllocParams(pta.Count, typeList));
        }
Пример #7
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;
            CType                  type1        = pTypeThrough != null ? pTypeThrough : mpwi1.GetType();
            CType                  type2        = pTypeThrough != null ? pTypeThrough : mpwi2.GetType();
            MethodOrPropertySymbol methProp1    = GroupToArgsBinder.FindMostDerivedMethod(GetSymbolLoader(), mpwi1.MethProp(), type1);
            MethodOrPropertySymbol methProp2    = GroupToArgsBinder.FindMostDerivedMethod(GetSymbolLoader(), mpwi2.MethProp(), type2);
            List <Name>            names1       = methProp1.ParameterNames;
            List <Name>            names2       = methProp2.ParameterNames;

            for (int i = 0; i < args.carg; i++)
            {
                EXPR  arg     = args.fHasExprs ? args.prgexpr[i] : null;
                CType argType = args.types[i];
                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

                if (arg.RuntimeObjectActualType != null)
                {
                    argType = arg.RuntimeObjectActualType;
                }

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

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

                if (betterMethod == BetterType.Right && betterConversion == BetterType.Left)
                {
                    betterMethod = BetterType.Neither;
                    break;
                }
                else if (betterMethod == BetterType.Left && betterConversion == BetterType.Right)
                {
                    betterMethod = BetterType.Neither;
                    break;
                }
                else if (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 && !node2.fExpanded)
                {
                    return(BetterType.Right);
                }
                else if (node2.fExpanded && !node1.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 == args.carg)
                {
                    return(BetterType.Left);
                }
                else if (pta2.Count == args.carg)
                {
                    return(BetterType.Right);
                }
                return(BetterType.Neither);
            }

            return(betterMethod);
        }
Пример #8
0
        ////////////////////////////////////////////////////////////////////////////////
        // We need to rearange the method parameters so that the type of any specified named argument
        // appears in the same place as the named argument. Consider the example below:
        //    Foo(int x = 4, string y = "", long l = 4)
        //    Foo(string y = "", string x="", long l = 5)
        // and the call site:
        //    Foo(y:"a")
        // After rearranging the parameter types we will have:
        //   (string, int, long) and (string, string, long)
        // By rearranging the arguments as such we make sure that any specified named arguments appear in the same position for both
        // methods and we also maintain the relative order of the other parameters (the type long appears after int in the above example)

        private TypeArray RearrangeNamedArguments(TypeArray pta, MethPropWithInst mpwi,
            CType pTypeThrough, ArgInfos args)
        {
            if (!args.fHasExprs)
            {
                return pta;
            }

#if DEBUG
            // We never have a named argument that is in a position in the argument
            // list past the end of what would be the formal parameter list.
            for (int i = pta.size; i < args.carg; i++)
            {
                Debug.Assert(!args.prgexpr[i].isNamedArgumentSpecification());
            }
#endif

            CType type = pTypeThrough != null ? pTypeThrough : mpwi.GetType();
            CType[] typeList = new CType[pta.size];
            MethodOrPropertySymbol methProp = GroupToArgsBinder.FindMostDerivedMethod(GetSymbolLoader(), mpwi.MethProp(), type);

            // We initialize the new type array with the parameters for the method. 
            for (int iParam = 0; iParam < pta.size; iParam++)
            {
                typeList[iParam] = pta.Item(iParam);
            }

            // We then go over the specified arguments and put the type for any named argument in the right position in the array.
            for (int iParam = 0; iParam < args.carg; iParam++)
            {
                EXPR arg = args.prgexpr[iParam];
                if (arg.isNamedArgumentSpecification())
                {
                    // We find the index of the type of the argument in the method parameter list and store that in a temp
                    int index = FindName(methProp.ParameterNames, arg.asNamedArgumentSpecification().Name);
                    CType tempType = pta.Item(index);

                    // Starting from the current position in the type list up until the location of the type of the optional argument
                    //  We shift types by one:
                    //   before: (int, string, long)
                    //   after: (string, int, long)
                    // We only touch the types between the current position and the position of the type we need to move
                    for (int iShift = iParam; iShift < index; iShift++)
                    {
                        typeList[iShift + 1] = typeList[iShift];
                    }

                    typeList[iParam] = tempType;
                }
            }

            return GetSymbolLoader().getBSymmgr().AllocParams(pta.size, typeList);
        }
Пример #9
0
        public EXPRMEMGRP CreateMemGroup(
                EXPR pObject,
                MethPropWithInst mwi)
        {
            Name pName = mwi.Sym != null ? mwi.Sym.name : null;
            MethodOrPropertySymbol methProp = mwi.MethProp();

            CType pType = mwi.GetType();
            if (pType == null)
            {
                pType = GetTypes().GetErrorSym();
            }

            return CreateMemGroup(0, pName, mwi.TypeArgs, methProp != null ? methProp.getKind() : SYMKIND.SK_MethodSymbol, mwi.GetType(), methProp, pObject, new CMemberLookupResults(GetGlobalSymbols().AllocParams(1, new CType[] { pType }), pName));
        }