Example #1
0
            public GroupToArgsBinder(ExpressionBinder exprBinder, BindingFlag bindFlags, EXPRMEMGRP grp, ArgInfos args, ArgInfos originalArgs, bool bHasNamedArguments, AggregateType atsDelegate)
            {
                Debug.Assert(grp != null);
                Debug.Assert(exprBinder != null);
                Debug.Assert(args != null);

                _pExprBinder = exprBinder;
                _fCandidatesUnsupported = false;
                _fBindFlags = bindFlags;
                _pGroup = grp;
                _pArguments = args;
                _pOriginalArguments = originalArgs;
                _bHasNamedArguments = bHasNamedArguments;
                _pDelegate = atsDelegate;
                _pCurrentType = null;
                _pCurrentSym = null;
                _pCurrentTypeArgs = null;
                _pCurrentParameters = null;
                _pBestParameters = null;
                _nArgBest = -1;
                _nWrongCount = 0;
                _bIterateToEndOfNsList = false;
                _bBindingCollectionAddArgs = false;
                _results = new GroupToArgsBinderResult();
                _methList = new List<CandidateFunctionMember>();
                _mpwiParamTypeConstraints = new MethPropWithInst();
                _mpwiBogus = new MethPropWithInst();
                _mpwiCantInferInstArg = new MethPropWithInst();
                _mwtBadArity = new MethWithType();
                _HiddenTypes = new List<CType>();
            }
Example #2
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        // Fixed, unfixed and bounded CType parameters
        //
        // SPEC: During the process of inference each CType parameter is either fixed to
        // SPEC: a particular CType or unfixed with an associated set of bounds. Each of
        // SPEC: the bounds is of some CType T. Initially each CType parameter is unfixed
        // SPEC: with an empty set of bounds.

        private MethodTypeInferrer(
            ExpressionBinder exprBinder, SymbolLoader symLoader,
            TypeArray pMethodFormalParameterTypes, ArgInfos pMethodArguments,
            TypeArray pMethodTypeParameters, TypeArray pClassTypeArguments)
        {
            _binder = exprBinder;
            _symbolLoader = symLoader;
            _pMethodFormalParameterTypes = pMethodFormalParameterTypes;
            _pMethodArguments = pMethodArguments;
            _pMethodTypeParameters = pMethodTypeParameters;
            _pClassTypeArguments = pClassTypeArguments;
            _pFixedResults = new CType[pMethodTypeParameters.size];
            _pLowerBounds = new List<CType>[pMethodTypeParameters.size];
            _pUpperBounds = new List<CType>[pMethodTypeParameters.size];
            _pExactBounds = new List<CType>[pMethodTypeParameters.size];
            for (int iBound = 0; iBound < pMethodTypeParameters.size; ++iBound)
            {
                _pLowerBounds[iBound] = new List<CType>();
                _pUpperBounds[iBound] = new List<CType>();
                _pExactBounds[iBound] = new List<CType>();
            }
            _ppDependencies = null;
        }
Example #3
0
        ////////////////////////////////////////////////////////////////////////////////

        private bool MethodGroupReturnTypeInference(EXPR pSource, CType pType)
        {
            // SPEC:  Otherwise, if E is a method group and T is a delegate CType or
            // SPEC:   expression tree CType with parameter types T1...Tk and return
            // SPEC:   CType Tb and overload resolution of E with the types T1...Tk
            // SPEC:   yields a single method with return CType U then a lower-bound
            // SPEC:   inference is made from U to Tb.

            if (!pSource.isMEMGRP())
            {
                return false;
            }
            pType = pType.GetDelegateTypeOfPossibleExpression();
            if (!pType.isDelegateType())
            {
                return false;
            }
            AggregateType pDelegateType = pType.AsAggregateType();
            CType pDelegateReturnType = pDelegateType.GetDelegateReturnType(GetSymbolLoader());
            if (pDelegateReturnType == null)
            {
                return false;
            }
            if (pDelegateReturnType.IsVoidType())
            {
                return false;
            }

            // At this point we are in the second phase; we know that all the input types are fixed.

            TypeArray pDelegateParameters = GetFixedDelegateParameters(pDelegateType);
            if (pDelegateParameters == null)
            {
                return false;
            }

            ArgInfos argInfo = new ArgInfos() { carg = pDelegateParameters.size, types = pDelegateParameters, fHasExprs = false, prgexpr = null };

            var argsBinder = new ExpressionBinder.GroupToArgsBinder(_binder, 0/* flags */, pSource.asMEMGRP(), argInfo, null, false, pDelegateType);

            bool success = argsBinder.Bind(false);
            if (!success)
            {
                return false;
            }

            MethPropWithInst mwi = argsBinder.GetResultsOfBind().GetBestResult();
            CType pMethodReturnType = GetTypeManager().SubstType(mwi.Meth().RetType,
                mwi.GetType(), mwi.TypeArgs);
            if (pMethodReturnType.IsVoidType())
            {
                return false;
            }

            LowerBoundInference(pMethodReturnType, pDelegateReturnType);
            return true;
        }
Example #4
0
            /////////////////////////////////////////////////////////////////////////////////

            private static EXPR FindArgumentWithName(ArgInfos pArguments, Name pName)
            {
                for (int i = 0; i < pArguments.carg; i++)
                {
                    if (pArguments.prgexpr[i].isNamedArgumentSpecification() &&
                            pArguments.prgexpr[i].asNamedArgumentSpecification().Name == pName)
                    {
                        return pArguments.prgexpr[i];
                    }
                }
                return null;
            }
Example #5
0
            private void CopyArgInfos(ArgInfos src, ArgInfos dst)
            {
                dst.carg = src.carg;
                dst.types = src.types;
                dst.fHasExprs = src.fHasExprs;

                dst.prgexpr.Clear();
                for (int i = 0; i < src.prgexpr.Count; i++)
                {
                    dst.prgexpr.Add(src.prgexpr[i]);
                }
            }
Example #6
0
            internal static bool ReOrderArgsForNamedArguments(
                    MethodOrPropertySymbol methprop,
                    TypeArray pCurrentParameters,
                    AggregateType pCurrentType,
                    EXPRMEMGRP pGroup,
                    ArgInfos pArguments,
                    TypeManager typeManager,
                    ExprFactory exprFactory,
                    SymbolLoader symbolLoader)
            {
                // We use the param count from pCurrentParameters because they may have been resized 
                // for param arrays.
                int numParameters = pCurrentParameters.size;

                EXPR[] pExprArguments = new EXPR[numParameters];

                // Now go through the parameters. First set all positional arguments in the new argument
                // set, then for the remainder, look for a named argument with a matching name.
                int index = 0;
                EXPR paramArrayArgument = null;
                TypeArray @params = typeManager.SubstTypeArray(
                    pCurrentParameters,
                    pCurrentType,
                    pGroup.typeArgs);
                foreach (Name name in methprop.ParameterNames)
                {
                    // This can happen if we had expanded our param array to size 0.
                    if (index >= pCurrentParameters.size)
                    {
                        break;
                    }

                    // If:
                    // (1) we have a param array method
                    // (2) we're on the last arg
                    // (3) the thing we have is an array init thats generated for param array
                    // then let us through.
                    if (methprop.isParamArray &&
                        index < pArguments.carg &&
                        pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray)
                    {
                        paramArrayArgument = pArguments.prgexpr[index];
                    }

                    // Positional.
                    if (index < pArguments.carg &&
                        !pArguments.prgexpr[index].isNamedArgumentSpecification() &&
                        !(pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray))
                    {
                        pExprArguments[index] = pArguments.prgexpr[index++];
                        continue;
                    }

                    // Look for names.
                    EXPR pNewArg = FindArgumentWithName(pArguments, name);
                    if (pNewArg == null)
                    {
                        if (methprop.IsParameterOptional(index))
                        {
                            pNewArg = GenerateOptionalArgument(symbolLoader, exprFactory, methprop, @params.Item(index), index);
                        }
                        else if (paramArrayArgument != null && index == methprop.Params.Count - 1)
                        {
                            // If we have a param array argument and we're on the last one, then use it.
                            pNewArg = paramArrayArgument;
                        }
                        else
                        {
                            // No name and no default value.
                            return false;
                        }
                    }
                    pExprArguments[index++] = pNewArg;
                }

                // Here we've found all the arguments, or have default values for them.
                CType[] prgTypes = new CType[pCurrentParameters.size];
                for (int i = 0; i < numParameters; i++)
                {
                    if (i < pArguments.prgexpr.Count)
                    {
                        pArguments.prgexpr[i] = pExprArguments[i];
                    }
                    else
                    {
                        pArguments.prgexpr.Add(pExprArguments[i]);
                    }
                    prgTypes[i] = pArguments.prgexpr[i].type;
                }
                pArguments.carg = pCurrentParameters.size;
                pArguments.types = symbolLoader.getBSymmgr().AllocParams(pCurrentParameters.size, prgTypes);
                return true;
            }
Example #7
0
        internal void FillInArgInfoFromArgList(ArgInfos argInfo, EXPR args)
        {
            CType[] prgtype = new CType[argInfo.carg];
            argInfo.fHasExprs = true;
            argInfo.prgexpr = new List<EXPR>();

            int iarg = 0;
            for (EXPR list = args; list != null; iarg++)
            {
                EXPR arg;
                if (list.isLIST())
                {
                    arg = list.asLIST().GetOptionalElement();
                    list = list.asLIST().GetOptionalNextListNode();
                }
                else
                {
                    arg = list;
                    list = null;
                }

                Debug.Assert(arg != null);

                if (arg.type != null)
                {
                    prgtype[iarg] = (CType)arg.type;
                }
                else
                {
                    prgtype[iarg] = GetTypes().GetErrorSym();
                }
                argInfo.prgexpr.Add(arg);
            }
            Debug.Assert(iarg <= argInfo.carg);
            argInfo.types = GetGlobalSymbols().AllocParams(iarg, prgtype);
        }
Example #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);
        }
Example #9
0
        internal EXPR bindUDUnop(ExpressionKind ek, EXPR arg)
        {
            Name pName = ekName(ek);
            Debug.Assert(pName != null);

            CType typeSrc = arg.type;

        LAgain:
            switch (typeSrc.GetTypeKind())
            {
                case TypeKind.TK_NullableType:
                    typeSrc = typeSrc.StripNubs();
                    goto LAgain;
                case TypeKind.TK_TypeParameterType:
                    typeSrc = typeSrc.AsTypeParameterType().GetEffectiveBaseClass();
                    goto LAgain;
                case TypeKind.TK_AggregateType:
                    if (!typeSrc.isClassType() && !typeSrc.isStructType() || typeSrc.AsAggregateType().getAggregate().IsSkipUDOps())
                        return null;
                    break;
                default:
                    return null;
            }

            ArgInfos info = new ArgInfos();

            info.carg = 1;
            FillInArgInfoFromArgList(info, arg);

            List<CandidateFunctionMember> methFirstList = new List<CandidateFunctionMember>();
            MethodSymbol methCur = null;
            AggregateType atsCur = typeSrc.AsAggregateType();

            for (; ;)
            {
                // Find the next operator.
                methCur = (methCur == null) ?
                          GetSymbolLoader().LookupAggMember(pName, atsCur.getAggregate(), symbmask_t.MASK_MethodSymbol).AsMethodSymbol() :
                          GetSymbolLoader().LookupNextSym(methCur, atsCur.getAggregate(), symbmask_t.MASK_MethodSymbol).AsMethodSymbol();

                if (methCur == null)
                {
                    // Find the next type.
                    // If we've found some applicable methods in a class then we don't need to look any further.
                    if (!methFirstList.IsEmpty())
                        break;
                    atsCur = atsCur.GetBaseClass();
                    if (atsCur == null)
                        break;
                    continue;
                }

                // Only look at operators with 1 args.
                if (!methCur.isOperator || methCur.Params.size != 1)
                    continue;
                Debug.Assert(methCur.typeVars.size == 0);

                TypeArray paramsCur = GetTypes().SubstTypeArray(methCur.Params, atsCur);
                CType typeParam = paramsCur.Item(0);
                NullableType nubParam;

                if (canConvert(arg, typeParam))
                {
                    methFirstList.Add(new CandidateFunctionMember(
                                    new MethPropWithInst(methCur, atsCur, BSYMMGR.EmptyTypeArray()),
                                    paramsCur,
                                    0,
                                    false));
                }
                else if (GetSymbolLoader().FCanLift() && typeParam.IsNonNubValType() &&
                         GetTypes().SubstType(methCur.RetType, atsCur).IsNonNubValType() &&
                         canConvert(arg, nubParam = GetTypes().GetNullable(typeParam)))
                {
                    methFirstList.Add(new CandidateFunctionMember(
                                    new MethPropWithInst(methCur, atsCur, BSYMMGR.EmptyTypeArray()),
                                    GetGlobalSymbols().AllocParams(1, new CType[] { nubParam }),
                                    1,
                                    false));
                }
            }

            if (methFirstList.IsEmpty())
                return null;

            CandidateFunctionMember pmethAmbig1;
            CandidateFunctionMember pmethAmbig2;
            CandidateFunctionMember pmethBest = FindBestMethod(methFirstList, null, info, out pmethAmbig1, out pmethAmbig2);

            if (pmethBest == null)
            {
                // No winner, so its an ambiguous call...
                ErrorContext.Error(ErrorCode.ERR_AmbigCall, pmethAmbig1.mpwi, pmethAmbig2.mpwi);

                EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, pmethAmbig1.mpwi);
                EXPRCALL rval = GetExprFactory().CreateCall(0, null, arg, pMemGroup, null);
                rval.SetError();
                return rval;
            }

            if (SemanticChecker.CheckBogus(pmethBest.mpwi.Meth()))
            {
                ErrorContext.ErrorRef(ErrorCode.ERR_BindToBogus, pmethBest.mpwi);

                EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, pmethBest.mpwi);
                EXPRCALL rval = GetExprFactory().CreateCall(0, null, arg, pMemGroup, null);
                rval.SetError();
                return rval;
            }

            EXPRCALL call;

            if (pmethBest.ctypeLift != 0)
            {
                call = BindLiftedUDUnop(arg, [email protected](0), pmethBest.mpwi);
            }
            else
            {
                call = BindUDUnopCall(arg, [email protected](0), pmethBest.mpwi);
            }

            return GetExprFactory().CreateUserDefinedUnaryOperator(ek, call.type, arg, call, pmethBest.mpwi);
        }
Example #10
0
        ////////////////////////////////////////////////////////////////////////////////
        // Given a method group or indexer group, bind it to the arguments for an 
        // invocation. This method can change the arguments to bind with Extension 
        // Methods
        private bool BindMethodGroupToArgumentsCore(out GroupToArgsBinderResult pResults, BindingFlag bindFlags, EXPRMEMGRP grp, ref EXPR args, int carg, bool bindingCollectionAdd, bool bHasNamedArgumentSpecifiers)
        {
            ArgInfos pargInfo = new ArgInfos {carg = carg};
            FillInArgInfoFromArgList(pargInfo, args);

            ArgInfos pOriginalArgInfo = new ArgInfos {carg = carg};
            FillInArgInfoFromArgList(pOriginalArgInfo, args);

            GroupToArgsBinder binder = new GroupToArgsBinder(this, bindFlags, grp, pargInfo, pOriginalArgInfo, bHasNamedArgumentSpecifiers, null/*atsDelegate*/);
            bool retval = bindingCollectionAdd ? binder.BindCollectionAddArgs() : binder.Bind(true /*ReportErrors*/);

            pResults = binder.GetResultsOfBind();
            return retval;
        }
Example #11
0
        ////////////////////////////////////////////////////////////////////////////////
        // Determine best method for overload resolution. Returns null if no best 
        // method, in which case two tying methods are returned for error reporting.

        protected 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;
        }
Example #12
0
        protected 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.size != 0)
            {
                if (mpwi2.TypeArgs.size == 0)
                {
                    return BetterType.Right;
                }
            }
            else if (mpwi2.TypeArgs.size != 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;
        }
Example #13
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

        protected 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.Item(i);
                CType p1 = pta1.Item(i);
                CType p2 = pta2.Item(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.size != pta2.size && 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.size == args.carg)
                {
                    return BetterType.Left;
                }
                else if (pta2.size == args.carg)
                {
                    return BetterType.Right;
                }
                return BetterType.Neither;
            }

            return betterMethod;
        }
Example #14
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        // In error recovery and reporting scenarios we sometimes end up in a situation
        // like this:
        //
        // x.Foo( y=>
        //
        // and the question is, "is Foo a valid extension method of x?"  If Foo is
        // generic, then Foo will be something like:
        //
        // static Blah Foo<T>(this Bar<T> bar, Func<T, T> f){ ... }
        //
        // What we would like to know is: given _only_ the expression x, can we infer
        // what T is in Bar<T> ?  If we can, then for error recovery and reporting
        // we can provisionally consider Foo to be an extension method of x. If we 
        // cannot deduce this just from x then we should consider Foo to not be an
        // extension method of x, at least until we have more information.
        //
        // Clearly it is pointless to run multiple phases

        public static bool CanObjectOfExtensionBeInferred(
            ExpressionBinder binder,
            SymbolLoader symbolLoader,
            MethodSymbol pMethod,
            TypeArray pClassTypeArguments,
            TypeArray pMethodFormalParameterTypes,
            ArgInfos pMethodArguments)
        {
            Debug.Assert(pMethod != null);
            Debug.Assert(pMethod.typeVars.size > 0);
            Debug.Assert(pMethodFormalParameterTypes != null);
            Debug.Assert(pMethod.isParamArray || pMethod.Params == pMethodFormalParameterTypes);
            // We need at least one formal parameter type and at least one argument.
            if (pMethodFormalParameterTypes.size < 1 || pMethod.InferenceMustFail())
            {
                return false;
            }
            Debug.Assert(pMethodArguments != null);
            Debug.Assert(pMethodArguments.carg <= pMethodFormalParameterTypes.size);
            if (pMethodArguments.carg < 1)
            {
                return false;
            }
            var inferrer = new MethodTypeInferrer(binder, symbolLoader,
            pMethodFormalParameterTypes, pMethodArguments, pMethod.typeVars, pClassTypeArguments);
            return inferrer.CanInferExtensionObject();
        }
Example #15
0
        private EXPR ReorderArgumentsForNamedAndOptional(EXPR callingObject, EXPR pResult)
        {
            EXPR arguments;
            AggregateType type;
            MethodOrPropertySymbol methprop;
            EXPRMEMGRP memgroup;
            TypeArray typeArgs;

            if (pResult.isCALL())
            {
                EXPRCALL call = pResult.asCALL();
                arguments = call.GetOptionalArguments();
                type = call.mwi.Ats;
                methprop = call.mwi.Meth();
                memgroup = call.GetMemberGroup();
                typeArgs = call.mwi.TypeArgs;
            }
            else
            {
                Debug.Assert(pResult.isPROP());
                EXPRPROP prop = pResult.asPROP();
                arguments = prop.GetOptionalArguments();
                type = prop.pwtSlot.Ats;
                methprop = prop.pwtSlot.Prop();
                memgroup = prop.GetMemberGroup();
                typeArgs = null;
            }

            ArgInfos argInfo = new ArgInfos();
            bool b;
            argInfo.carg = ExpressionBinder.CountArguments(arguments, out b);
            _binder.FillInArgInfoFromArgList(argInfo, arguments);

            // We need to substitute type parameters BEFORE getting the most derived one because
            // we're binding against the base method, and the derived method may change the 
            // generic arguments. 
            TypeArray parameters = SymbolLoader.GetTypeManager().SubstTypeArray(methprop.Params, type, typeArgs);
            methprop = ExpressionBinder.GroupToArgsBinder.FindMostDerivedMethod(SymbolLoader, methprop, callingObject.type);
            ExpressionBinder.GroupToArgsBinder.ReOrderArgsForNamedArguments(
                methprop,
                parameters,
                type,
                memgroup,
                argInfo,
                _semanticChecker.GetTypeManager(),
                _exprFactory,
                SymbolLoader);
            {
                EXPR pList = null;

                // We reordered, so make a new list of them and set them on the constructor.
                // Go backwards cause lists are right-flushed.
                // Also perform the conversions to the right types.
                for (int i = argInfo.carg - 1; i >= 0; i--)
                {
                    EXPR pArg = argInfo.prgexpr[i];

                    // Strip the name-ness away, since we don't need it.
                    pArg = StripNamedArgument(pArg);

                    // Perform the correct conversion.
                    pArg = _binder.tryConvert(pArg, parameters[i]);
                    if (pList == null)
                    {
                        pList = pArg;
                    }
                    else
                    {
                        pList = _exprFactory.CreateList(pArg, pList);
                    }
                }
                if (pResult.isCALL())
                {
                    pResult.asCALL().SetOptionalArguments(pList);
                }
                else
                {
                    pResult.asPROP().SetOptionalArguments(pList);
                }
            }
            return pResult;
        }
Example #16
0
        /*
        SPEC:

        CType inference occurs as part of the compile-time processing of a method invocation
        and takes place before the overload resolution step of the invocation. When a
        particular method group is specified in a method invocation, and no CType arguments
        are specified as part of the method invocation, CType inference is applied to each
        generic method in the method group. If CType inference succeeds, then the inferred
        CType arguments are used to determine the types of formal parameters for subsequent 
        overload resolution. If overload resolution chooses a generic method as the one to
        invoke then the inferred CType arguments are used as the actual CType arguments for the
        invocation. If CType inference for a particular method fails, that method does not
        participate in overload resolution. The failure of CType inference, in and of itself,
        does not cause a compile-time error. However, it often leads to a compile-time error
        when overload resolution then fails to find any applicable methods.

        If the supplied number of arguments is different than the number of parameters in
        the method, then inference immediately fails. Otherwise, assume that the generic
        method has the following signature:

        Tr M<X1...Xn>(T1 x1 ... Tm xm)

        With a method call of the form M(E1...Em) the task of CType inference is to find
        unique CType arguments S1...Sn for each of the CType parameters X1...Xn so that the
        call M<S1...Sn>(E1...Em)becomes valid.

        During the process of inference each CType parameter Xi is either fixed to a particular
        CType Si or unfixed with an associated set of bounds. Each of the bounds is some CType T.
        Each bound is classified as an upper bound, lower bound or exact bound.
        Initially each CType variable Xi is unfixed with an empty set of bounds.


        */

        // This file contains the implementation for method CType inference on calls (with
        // arguments, and method CType inference on conversion of method groups to delegate
        // types (which will not have arguments.)

        ////////////////////////////////////////////////////////////////////////////////

        public static bool Infer(
            ExpressionBinder binder,
            SymbolLoader symbolLoader,
            MethodSymbol pMethod,
            TypeArray pClassTypeArguments,
            TypeArray pMethodFormalParameterTypes,
            ArgInfos pMethodArguments,
            out TypeArray ppInferredTypeArguments)
        {
            Debug.Assert(pMethod != null);
            Debug.Assert(pMethod.typeVars.size > 0);
            Debug.Assert(pMethod.isParamArray || pMethod.Params == pMethodFormalParameterTypes);
            ppInferredTypeArguments = null;
            if (pMethodFormalParameterTypes.size == 0 || pMethod.InferenceMustFail())
            {
                return false;
            }
            Debug.Assert(pMethodArguments != null);
            Debug.Assert(pMethodFormalParameterTypes != null);
            Debug.Assert(pMethodArguments.carg <= pMethodFormalParameterTypes.size);

            var inferrer = new MethodTypeInferrer(binder, symbolLoader,
                pMethodFormalParameterTypes, pMethodArguments,
                pMethod.typeVars, pClassTypeArguments);
            bool success;
            if (pMethodArguments.fHasExprs)
            {
                success = inferrer.InferTypeArgs();
            }
            else
            {
                success = inferrer.InferForMethodGroupConversion();
            }

            ppInferredTypeArguments = inferrer.GetResults();
            return success;
        }
Example #17
0
        private EXPRCALL BindUDBinop(ExpressionKind ek, EXPR arg1, EXPR arg2, bool fDontLift, out MethPropWithInst ppmpwi)
        {
            List<CandidateFunctionMember> methFirst = new List<CandidateFunctionMember>();

            ppmpwi = null;

            AggregateType[] rgats = { null, null };
            int cats = GetUserDefinedBinopArgumentTypes(arg1.type, arg2.type, rgats);
            if (cats == 0)
            {
                return null;
            }
            else if (cats == 1)
            {
                GetApplicableUserDefinedBinaryOperatorCandidatesInBaseTypes(methFirst, ek,
                    rgats[0], arg1, arg2, fDontLift, null);
            }
            else
            {
                Debug.Assert(cats == 2);
                AggregateType atsStop = GetApplicableUserDefinedBinaryOperatorCandidatesInBaseTypes(methFirst, ek,
                    rgats[0], arg1, arg2, fDontLift, null);
                GetApplicableUserDefinedBinaryOperatorCandidatesInBaseTypes(methFirst, ek,
                    rgats[1], arg1, arg2, fDontLift, atsStop);
            }
            if (methFirst.IsEmpty())
            {
                return null;
            }

            EXPRLIST args = GetExprFactory().CreateList(arg1, arg2);
            ArgInfos info = new ArgInfos();
            info.carg = 2;
            FillInArgInfoFromArgList(info, args);
            CandidateFunctionMember pmethAmbig1;
            CandidateFunctionMember pmethAmbig2;
            CandidateFunctionMember pmethBest = FindBestMethod(methFirst, null, info, out pmethAmbig1, out pmethAmbig2);

            if (pmethBest == null)
            {
                // No winner, so its an ambiguous call...
                GetErrorContext().Error(ErrorCode.ERR_AmbigCall, pmethAmbig1.mpwi, pmethAmbig2.mpwi);

                EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, pmethAmbig1.mpwi);
                EXPRCALL rval = GetExprFactory().CreateCall(0, null, GetExprFactory().CreateList(arg1, arg2), pMemGroup, null);
                rval.SetError();
                return rval;
            }

            if (GetSemanticChecker().CheckBogus(pmethBest.mpwi.Meth()))
            {
                GetErrorContext().ErrorRef(ErrorCode.ERR_BindToBogus, pmethBest.mpwi);

                EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, pmethBest.mpwi);
                EXPRCALL rval = GetExprFactory().CreateCall(0, null, GetExprFactory().CreateList(arg1, arg2), pMemGroup, null);
                rval.SetError();
                return rval;
            }

            ppmpwi = pmethBest.mpwi;

            if (pmethBest.ctypeLift != 0)
            {
                Debug.Assert(pmethBest.ctypeLift == 2);

                return BindLiftedUDBinop(ek, arg1, arg2, pmethBest.@params, pmethBest.mpwi);
            }

            CType typeRetRaw = GetTypes().SubstType(pmethBest.mpwi.Meth().RetType, pmethBest.mpwi.GetType());

            return BindUDBinopCall(arg1, arg2, pmethBest.@params, typeRetRaw, pmethBest.mpwi);
        }