Exemple #1
0
        /*
            See if standard reference equality applies. Make sure not to return true if another == operator
            may be applicable and better (or ambiguous)! This also handles == on System.Delegate, since
            it has special rules as well.
        */
        protected bool GetRefEqualSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
        {
            if (info.mask != BinOpMask.Equal)
            {
                return false;
            }

            if (info.type1 != info.typeRaw1 || info.type2 != info.typeRaw2)
            {
                return false;
            }

            bool fRet = false;
            CType type1 = info.type1;
            CType type2 = info.type2;
            CType typeObj = GetReqPDT(PredefinedType.PT_OBJECT);
            CType typeCls = null;

            if (type1.IsNullType() && type2.IsNullType())
            {
                typeCls = typeObj;
                fRet = true;
                goto LRecord;
            }

            // Check for: operator ==(System.Delegate, System.Delegate).
            CType typeDel;
            typeDel = GetReqPDT(PredefinedType.PT_DELEGATE);

            if (canConvert(info.arg1, typeDel) && canConvert(info.arg2, typeDel) &&
                !type1.isDelegateType() && !type2.isDelegateType())
            {
                prgbofs.Add(new BinOpFullSig(typeDel, typeDel, BindDelBinOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.DelBinOp));
            }

            // The reference type equality operators only handle reference types.
            FUNDTYPE ft1;
            ft1 = type1.fundType();
            FUNDTYPE ft2;
            ft2 = type2.fundType();

            switch (ft1)
            {
                default:
                    return false;
                case FUNDTYPE.FT_REF:
                    break;
                case FUNDTYPE.FT_VAR:
                    if (type1.AsTypeParameterType().IsValueType() || (!type1.AsTypeParameterType().IsReferenceType() && !type2.IsNullType()))
                        return false;
                    type1 = type1.AsTypeParameterType().GetEffectiveBaseClass();
                    break;
            }
            if (type2.IsNullType())
            {
                fRet = true;
                // We don't need to determine the actual best type since we're
                // returning true - indicating that we've found the best operator.
                typeCls = typeObj;
                goto LRecord;
            }

            switch (ft2)
            {
                default:
                    return false;
                case FUNDTYPE.FT_REF:
                    break;
                case FUNDTYPE.FT_VAR:
                    if (type2.AsTypeParameterType().IsValueType() || (!type2.AsTypeParameterType().IsReferenceType() && !type1.IsNullType()))
                        return false;
                    type2 = type2.AsTypeParameterType().GetEffectiveBaseClass();
                    break;
            }
            if (type1.IsNullType())
            {
                fRet = true;
                // We don't need to determine the actual best type since we're
                // returning true - indicating that we've found the best operator.
                typeCls = typeObj;
                goto LRecord;
            }

            if (!canCast(type1, type2, CONVERTTYPE.NOUDC) && !canCast(type2, type1, CONVERTTYPE.NOUDC))
                return false;

            if (type1.isInterfaceType() || type1.isPredefType(PredefinedType.PT_STRING) || GetSymbolLoader().HasBaseConversion(type1, typeDel))
                type1 = typeObj;
            else if (type1.IsArrayType())
                type1 = GetReqPDT(PredefinedType.PT_ARRAY);
            else if (!type1.isClassType())
                return false;

            if (type2.isInterfaceType() || type2.isPredefType(PredefinedType.PT_STRING) || GetSymbolLoader().HasBaseConversion(type2, typeDel))
                type2 = typeObj;
            else if (type2.IsArrayType())
                type2 = GetReqPDT(PredefinedType.PT_ARRAY);
            else if (!type2.isClassType())
                return false;

            Debug.Assert(type1.isClassType() && !type1.isPredefType(PredefinedType.PT_STRING) && !type1.isPredefType(PredefinedType.PT_DELEGATE));
            Debug.Assert(type2.isClassType() && !type2.isPredefType(PredefinedType.PT_STRING) && !type2.isPredefType(PredefinedType.PT_DELEGATE));

            if (GetSymbolLoader().HasBaseConversion(type2, type1))
                typeCls = type1;
            else if (GetSymbolLoader().HasBaseConversion(type1, type2))
                typeCls = type2;

            LRecord:
            prgbofs.Add(new BinOpFullSig(typeCls, typeCls, BindRefCmpOp, OpSigFlags.None, LiftFlags.None, BinOpFuncKind.RefCmpOp));
            return fRet;
        }
Exemple #2
0
        /*
            Get the special signatures when at least one of the args is a pointer. Since pointers can't be
            type arguments, a nullable pointer is illegal, so no sense trying to lift any of these.
         
            NOTE: We don't filter out bad operators on void pointers since BindPtrBinOp gives better
            error messages than the operator overload resolution does.
        */
        protected bool GetPtrBinOpSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
        {
            if (!info.type1.IsPointerType() && !info.type2.IsPointerType())
            {
                return false;
            }

            // (ptr,       ptr)        :         -
            // (ptr,       int)        :       + -
            // (ptr,       uint)       :       + -
            // (ptr,       long)       :       + -
            // (ptr,       ulong)      :       + -
            // (int,       ptr)        :       +
            // (uint,      ptr)        :       +
            // (long,      ptr)        :       +
            // (ulong,     ptr)        :       +
            // (void,     void)      :                   == != < > <= >=

            // Check the common case first.
            if (info.type1.IsPointerType() && info.type2.IsPointerType())
            {
                if (info.ValidForVoidPointer())
                {
                    prgbofs.Add(new BinOpFullSig(info.type1, info.type2, BindPtrCmpOp, OpSigFlags.None, LiftFlags.None, BinOpFuncKind.PtrCmpOp));
                    return true;
                }
                if (info.type1 == info.type2 && info.ValidForPointer())
                {
                    prgbofs.Add(new BinOpFullSig(info.type1, info.type2, BindPtrBinOp, OpSigFlags.None, LiftFlags.None, BinOpFuncKind.PtrBinOp));
                    return true;
                }
                return false;
            }

            CType typeT;

            if (info.type1.IsPointerType())
            {
                if (info.type2.IsNullType())
                {
                    if (!info.ValidForVoidPointer())
                    {
                        return false;
                    }
                    prgbofs.Add(new BinOpFullSig(info.type1, info.type1, BindPtrCmpOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.PtrCmpOp));
                    return true;
                }
                if (!info.ValidForPointerAndNumber())
                {
                    return false;
                }

                for (uint i = 0; i < s_rgptIntOp.Length; i++)
                {
                    if (canConvert(info.arg2, typeT = GetReqPDT(s_rgptIntOp[i])))
                    {
                        prgbofs.Add(new BinOpFullSig(info.type1, typeT, BindPtrBinOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.PtrBinOp));
                        return true;
                    }
                }
                return false;
            }

            Debug.Assert(info.type2.IsPointerType());
            if (info.type1.IsNullType())
            {
                if (!info.ValidForVoidPointer())
                {
                    return false;
                }
                prgbofs.Add(new BinOpFullSig(info.type2, info.type2, BindPtrCmpOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.PtrCmpOp));
                return true;
            }
            if (!info.ValidForNumberAndPointer())
            {
                return false;
            }

            for (uint i = 0; i < s_rgptIntOp.Length; i++)
            {
                if (canConvert(info.arg1, typeT = GetReqPDT(s_rgptIntOp[i])))
                {
                    prgbofs.Add(new BinOpFullSig(typeT, info.type2, BindPtrBinOp, OpSigFlags.Convert, LiftFlags.None, BinOpFuncKind.PtrBinOp));
                    return true;
                }
            }
            return false;
        }
Exemple #3
0
        protected EXPR bindUserDefinedBinOp(ExpressionKind ek, BinOpArgInfo info)
        {
            MethPropWithInst pmpwi = null;
            if (info.pt1 <= PredefinedType.PT_ULONG && info.pt2 <= PredefinedType.PT_ULONG)
            {
                return null;
            }

            EXPR expr = null;

            switch (info.binopKind)
            {
                case BinOpKind.Logical:
                    {
                        // Logical operators cannot be overloaded, but use the bitwise overloads.
                        EXPRCALL call = BindUDBinop((ExpressionKind)(ek - ExpressionKind.EK_LOGAND + ExpressionKind.EK_BITAND), info.arg1, info.arg2, true, out pmpwi);
                        if (call != null)
                        {
                            if (call.isOK())
                            {
                                expr = BindUserBoolOp(ek, call);
                            }
                            else
                            {
                                expr = call;
                            }
                        }
                        break;
                    }
                default:
                    expr = BindUDBinop(ek, info.arg1, info.arg2, false, out pmpwi);
                    break;
            }

            if (expr == null)
            {
                return null;
            }

            return GetExprFactory().CreateUserDefinedBinop(ek, expr.type, info.arg1, info.arg2, expr, pmpwi);
        }
Exemple #4
0
        /*
            Record the appropriate binary operator full signature from the given BinOpArgInfo. This assumes
            that any NullableType valued args should be lifted.
        */
        private void RecordBinOpSigFromArgs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
        {
            LiftFlags grflt = LiftFlags.None;
            CType typeSig1;
            CType typeSig2;

            if (info.type1 != info.typeRaw1)
            {
                Debug.Assert(info.type1.IsNullableType());
                grflt = grflt | LiftFlags.Lift1;
                typeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(info.typeRaw1);
            }
            else
                typeSig1 = info.typeRaw1;

            if (info.type2 != info.typeRaw2)
            {
                Debug.Assert(info.type2.IsNullableType());
                grflt = grflt | LiftFlags.Lift2;
                typeSig2 = GetSymbolLoader().GetTypeManager().GetNullable(info.typeRaw2);
            }
            else
                typeSig2 = info.typeRaw2;

            prgbofs.Add(new BinOpFullSig(typeSig1, typeSig2, BindEnumBinOp, OpSigFlags.Value, grflt, BinOpFuncKind.EnumBinOp));
        }
Exemple #5
0
        /*
            Get the special signatures when at least one of the args is an enum.  Return true if
            we find an exact match.
        */
        protected bool GetEnumBinOpSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
        {
            if (!info.typeRaw1.isEnumType() && !info.typeRaw2.isEnumType())
            {
                return false;
            }

            // (enum,      enum)       :         -         == != < > <= >=&| ^
            // (enum,      under)      :       + -
            // (under,     enum)       :       +
            CType typeSig1 = null;
            CType typeSig2 = null;
            LiftFlags grflt = LiftFlags.None;

            // Look for the no conversions cases. Still need to determine the lifting. These are the common case.
            if (info.typeRaw1 == info.typeRaw2)
            {
                if (!info.ValidForEnum())
                {
                    return false;
                }
                RecordBinOpSigFromArgs(prgbofs, info);
                return true;
            }

            bool isValidForEnum;

            if (info.typeRaw1.isEnumType())
            {
                isValidForEnum = (info.typeRaw2 == info.typeRaw1.underlyingEnumType() && info.ValidForEnumAndUnderlyingType());
            }
            else
            {
                isValidForEnum = (info.typeRaw1 == info.typeRaw2.underlyingEnumType() && info.ValidForUnderlyingTypeAndEnum());
            }

            if (isValidForEnum)
            {
                RecordBinOpSigFromArgs(prgbofs, info);
                return true;
            }

            // Now deal with the conversion cases. Since there are no conversions from enum types to other
            // enum types we never need to do both cases.

            if (info.typeRaw1.isEnumType())
            {
                isValidForEnum = info.ValidForEnum() && CanConvertArg2(info, info.typeRaw1, out grflt, out typeSig1, out typeSig2) ||
                    info.ValidForEnumAndUnderlyingType() && CanConvertArg2(info, info.typeRaw1.underlyingEnumType(), out grflt, out typeSig1, out typeSig2);
            }
            else
            {
                isValidForEnum = info.ValidForEnum() && CanConvertArg1(info, info.typeRaw2, out grflt, out typeSig1, out typeSig2) ||
                    info.ValidForEnumAndUnderlyingType() && CanConvertArg1(info, info.typeRaw2.underlyingEnumType(), out grflt, out typeSig1, out typeSig2);
            }

            if (isValidForEnum)
            {
                prgbofs.Add(new BinOpFullSig(typeSig1, typeSig2, BindEnumBinOp, OpSigFlags.Value, grflt, BinOpFuncKind.EnumBinOp));
            }
            return false;
        }
Exemple #6
0
        /*
            Get the special signatures when at least one of the args is a delegate instance.
            Returns true iff an exact signature match is found.
        */
        protected bool GetDelBinOpSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
        {
            if (!info.ValidForDelegate())
            {
                return false;
            }
            if (!info.type1.isDelegateType() && !info.type2.isDelegateType())
            {
                return false;
            }

            // Don't allow comparison with an anonymous method or lambda. It's just too weird.
            if (((info.mask & BinOpMask.Equal) != 0) && (info.type1.IsBoundLambdaType() || info.type2.IsBoundLambdaType()))
                return false;

            // No conversions needed. Determine the lifting. This is the common case.
            if (info.type1 == info.type2)
            {
                prgbofs.Add(new BinOpFullSig(info.type1, info.type2, BindDelBinOp, OpSigFlags.Reference, LiftFlags.None, BinOpFuncKind.DelBinOp));
                return true;
            }

            // Now, for each delegate type, if both arguments convert to that delegate type, that is a candidate
            // for this binary operator. It's possible that we add two candidates, in which case they will compete
            // in overload resolution. Or we could add no candidates.

            bool t1tot2 = info.type2.isDelegateType() && canConvert(info.arg1, info.type2);
            bool t2tot1 = info.type1.isDelegateType() && canConvert(info.arg2, info.type1);

            if (t1tot2)
            {
                prgbofs.Add(new BinOpFullSig(info.type2, info.type2, BindDelBinOp, OpSigFlags.Reference, LiftFlags.None, BinOpFuncKind.DelBinOp));
            }

            if (t2tot1)
            {
                prgbofs.Add(new BinOpFullSig(info.type1, info.type1, BindDelBinOp, OpSigFlags.Reference, LiftFlags.None, BinOpFuncKind.DelBinOp));
            }

            // Might be ambiguous so return false.
            return false;
        }
Exemple #7
0
        /*
            Same as CanConvertArg1 but with the indices interchanged!
        */
        private bool CanConvertArg2(BinOpArgInfo info, CType typeDst, out LiftFlags pgrflt,
                                      out CType ptypeSig1, out CType ptypeSig2)
        {
            Debug.Assert(!typeDst.IsNullableType());
            ptypeSig1 = null;
            ptypeSig2 = null;

            if (canConvert(info.arg2, typeDst))
                pgrflt = LiftFlags.None;
            else
            {
                pgrflt = LiftFlags.None;
                if (!GetSymbolLoader().FCanLift())
                    return false;
                typeDst = GetSymbolLoader().GetTypeManager().GetNullable(typeDst);
                if (!canConvert(info.arg2, typeDst))
                    return false;
                pgrflt = LiftFlags.Convert2;
            }
            ptypeSig2 = typeDst;

            if (info.type1.IsNullableType())
            {
                pgrflt = pgrflt | LiftFlags.Lift1;
                ptypeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(info.typeRaw1);
            }
            else
                ptypeSig1 = info.typeRaw1;

            return true;
        }
Exemple #8
0
        protected EXPR BindStandardBinopCore(BinOpArgInfo info, BinOpFullSig bofs, ExpressionKind ek, EXPRFLAG flags)
        {
            if (bofs.pfn == null)
            {
                return BadOperatorTypesError(ek, info.arg1, info.arg2);
            }

            if (!bofs.isLifted() || !bofs.AutoLift())
            {
                EXPR expr1 = info.arg1;
                EXPR expr2 = info.arg2;
                if (bofs.ConvertOperandsBeforeBinding())
                {
                    expr1 = mustConvert(expr1, bofs.Type1());
                    expr2 = mustConvert(expr2, bofs.Type2());
                }
                if (bofs.fnkind == BinOpFuncKind.BoolBitwiseOp)
                {
                    return BindBoolBitwiseOp(ek, flags, expr1, expr2, bofs);
                }
                return bofs.pfn(ek, flags, expr1, expr2);
            }
            Debug.Assert(bofs.fnkind != BinOpFuncKind.BoolBitwiseOp);
            return BindLiftedStandardBinOp(info, bofs, ek, flags);
        }
Exemple #9
0
        private EXPR BindLiftedStandardBinOp(BinOpArgInfo info, BinOpFullSig bofs, ExpressionKind ek, EXPRFLAG flags)
        {
            Debug.Assert(bofs.Type1().IsNullableType() || bofs.Type2().IsNullableType());

            EXPR arg1 = info.arg1;
            EXPR arg2 = info.arg2;

            // We want to get the base types of the arguments and attempt to bind the non-lifted form of the
            // method so that we error report (ie divide by zero etc), and then we store in the resulting
            // binop that we have a lifted operator.

            EXPR pArgument1 = null;
            EXPR pArgument2 = null;
            EXPR nonLiftedArg1 = null;
            EXPR nonLiftedArg2 = null;
            EXPR nonLiftedResult = null;
            CType resultType = null;

            LiftArgument(arg1, bofs.Type1(), bofs.ConvertFirst(), out pArgument1, out nonLiftedArg1);
            LiftArgument(arg2, bofs.Type2(), bofs.ConvertSecond(), out pArgument2, out nonLiftedArg2);

            // Now call the non-lifted method to generate errors, and stash the result.
            if (!nonLiftedArg1.isNull() && !nonLiftedArg2.isNull())
            {
                // Only compute the method if theres no nulls. If there are, we'll special case it
                // later, since operations with a null operand are null.
                nonLiftedResult = bofs.pfn(ek, flags, nonLiftedArg1, nonLiftedArg2);
            }

            // Check if we have a comparison. If so, set the result type to bool.
            if (info.binopKind == BinOpKind.Compare || info.binopKind == BinOpKind.Equal)
            {
                resultType = GetReqPDT(PredefinedType.PT_BOOL);
            }
            else
            {
                if (bofs.fnkind == BinOpFuncKind.EnumBinOp)
                {
                    AggregateType enumType;
                    resultType = GetEnumBinOpType(ek, nonLiftedArg1.type, nonLiftedArg2.type, out enumType);
                }
                else
                {
                    resultType = pArgument1.type;
                }
                resultType = resultType.IsNullableType() ? resultType : GetSymbolLoader().GetTypeManager().GetNullable(resultType);
            }

            EXPRBINOP exprRes = GetExprFactory().CreateBinop(ek, resultType, pArgument1, pArgument2);
            mustCast(nonLiftedResult, resultType, 0);
            exprRes.isLifted = true;
            exprRes.flags |= flags;
            Debug.Assert((exprRes.flags & EXPRFLAG.EXF_LVALUE) == 0);

            return exprRes;
        }
Exemple #10
0
        /*
            This handles binding binary operators by first checking for user defined operators, then
            applying overload resolution to the predefined operators. It handles lifting over nullable.
        */
        public EXPR BindStandardBinop(ExpressionKind ek, EXPR arg1, EXPR arg2)
        {
            Debug.Assert(arg1 != null);
            Debug.Assert(arg2 != null);

            EXPRFLAG flags = 0;

            BinOpArgInfo info = new BinOpArgInfo(arg1, arg2);
            if (!GetBinopKindAndFlags(ek, out info.binopKind, out flags))
            {
                // If we don't get the BinopKind and the flags, then we must have had some bad operator types.

                return BadOperatorTypesError(ek, arg1, arg2);
            }

            info.mask = (BinOpMask)(1 << (int)info.binopKind);

            List<BinOpFullSig> binopSignatures = new List<BinOpFullSig>();
            int bestBinopSignature = -1;

            // First check if this is a user defined binop. If it is, return it.
            EXPR exprUD = bindUserDefinedBinOp(ek, info);
            if (exprUD != null)
            {
                return exprUD;
            }

            // Get the special binop signatures. If successful, the special binop signature will be
            // the last item in the array of signatures that we give it.

            bool exactMatch = GetSpecialBinopSignatures(binopSignatures, info);
            if (!exactMatch)
            {
                // No match, try to get standard and lifted binop signatures.

                exactMatch = GetStandardAndLiftedBinopSignatures(binopSignatures, info);
            }

            // If we have an exact match in either the special binop signatures or the standard/lifted binop 
            // signatures, then we set our best match. Otherwise, we check if we had any signatures at all.
            // If we didn't, then its possible where we have x == null, where x is nullable, so try to bind
            // the null equality comparison. Otherwise, we had some ambiguity - we have a match, but its not exact.

            if (exactMatch)
            {
                Debug.Assert(binopSignatures.Count > 0);
                bestBinopSignature = binopSignatures.Count - 1;
            }
            else if (binopSignatures.Count == 0)
            {
                // If we got no matches then it's possible that we're in the case
                // x == null, where x is nullable.
                return bindNullEqualityComparison(ek, info);
            }
            else
            {
                // We had some matches, try to find the best one. FindBestSignatureInList returns < 0 if
                // we don't have a best one, otherwise it returns the index of the best one in our list that 
                // we give it.

                bestBinopSignature = FindBestSignatureInList(binopSignatures, info);
                if (bestBinopSignature < 0)
                {
                    // Ambiguous.

                    return ambiguousOperatorError(ek, arg1, arg2);
                }
            }

            // If we're here, we should have a binop signature that exactly matches.

            Debug.Assert(bestBinopSignature < binopSignatures.Count);

            // We've found the one to use, so lets go and bind it.

            return BindStandardBinopCore(info, binopSignatures[bestBinopSignature], ek, flags);
        }
Exemple #11
0
 protected EXPRBINOP bindNullEqualityComparison(ExpressionKind ek, BinOpArgInfo info)
 {
     EXPR arg1 = info.arg1;
     EXPR arg2 = info.arg2;
     if (info.binopKind == BinOpKind.Equal)
     {
         CType typeBool = GetReqPDT(PredefinedType.PT_BOOL);
         EXPRBINOP exprRes = null;
         if (info.type1.IsNullableType() && info.type2.IsNullType())
         {
             arg2 = GetExprFactory().CreateZeroInit(info.type1);
             exprRes = GetExprFactory().CreateBinop(ek, typeBool, arg1, arg2);
         }
         if (info.type1.IsNullType() && info.type2.IsNullableType())
         {
             arg1 = GetExprFactory().CreateZeroInit(info.type2);
             exprRes = GetExprFactory().CreateBinop(ek, typeBool, arg1, arg2);
         }
         if (exprRes != null)
         {
             exprRes.isLifted = true;
             return exprRes;
         }
     }
     EXPR pExpr = BadOperatorTypesError(ek, info.arg1, info.arg2, GetTypes().GetErrorSym());
     Debug.Assert(pExpr.isBIN());
     return pExpr.asBIN();
 }
Exemple #12
0
        // Returns the index of the best match, or -1 if there is no best match.
        protected int FindBestSignatureInList(
                List<BinOpFullSig> binopSignatures,
                BinOpArgInfo info)
        {
            Debug.Assert(binopSignatures != null);

            if (binopSignatures.Count == 1)
            {
                return 0;
            }

            int bestSignature = 0;
            int index;
            // Try to find a candidate for the best.
            for (index = 1; index < binopSignatures.Count; index++)
            {
                if (bestSignature < 0)
                {
                    bestSignature = index;
                }
                else
                {
                    int nT = WhichBofsIsBetter(binopSignatures[bestSignature], binopSignatures[index], info.type1, info.type2);
                    if (nT == 0)
                    {
                        bestSignature = -1;
                    }
                    else if (nT > 0)
                    {
                        bestSignature = index;
                    }
                }
            }

            if (bestSignature == -1)
            {
                return -1;
            }

            // Verify that the candidate really is not worse than all others.
            // Do we need to loop over the whole list here, or just
            // from 0 . bestSignature - 1?
            for (index = 0; index < binopSignatures.Count; index++)
            {
                if (index == bestSignature)
                {
                    continue;
                }
                if (WhichBofsIsBetter(binopSignatures[bestSignature], binopSignatures[index], info.type1, info.type2) >= 0)
                {
                    return -1;
                }
            }
            return bestSignature;
        }
Exemple #13
0
        // Adds standard and lifted signatures to the candidate list.  If we find an exact match
        // then it will be the last item on the list and we return true.

        protected bool GetStandardAndLiftedBinopSignatures(List<BinOpFullSig> rgbofs, BinOpArgInfo info)
        {
            Debug.Assert(rgbofs != null);

            int ibos;
            int ibosMinLift;

            ibosMinLift = GetSymbolLoader().FCanLift() ? 0 : g_binopSignatures.Length;
            for (ibos = 0; ibos < g_binopSignatures.Length; ibos++)
            {
                BinOpSig bos = g_binopSignatures[ibos];
                if ((bos.mask & info.mask) == 0)
                {
                    continue;
                }

                CType typeSig1 = GetOptPDT(bos.pt1, PredefinedTypes.isRequired(bos.pt1));
                CType typeSig2 = GetOptPDT(bos.pt2, PredefinedTypes.isRequired(bos.pt2));
                if (typeSig1 == null || typeSig2 == null)
                    continue;

                ConvKind cv1 = GetConvKind(info.pt1, bos.pt1);
                ConvKind cv2 = GetConvKind(info.pt2, bos.pt2);
                LiftFlags grflt = LiftFlags.None;

                switch (cv1)
                {
                    default:
                        VSFAIL("Shouldn't happen!");
                        continue;

                    case ConvKind.None:
                        continue;
                    case ConvKind.Explicit:
                        if (!info.arg1.isCONSTANT_OK())
                        {
                            continue;
                        }
                        // Need to try to convert.
                        if (canConvert(info.arg1, typeSig1))
                        {
                            break;
                        }
                        if (ibos < ibosMinLift || !bos.CanLift())
                        {
                            continue;
                        }
                        Debug.Assert(typeSig1.IsValType());

                        typeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig1);
                        if (!canConvert(info.arg1, typeSig1))
                        {
                            continue;
                        }
                        switch (GetConvKind(info.ptRaw1, bos.pt1))
                        {
                            default:
                                grflt = grflt | LiftFlags.Convert1;
                                break;
                            case ConvKind.Implicit:
                            case ConvKind.Identity:
                                grflt = grflt | LiftFlags.Lift1;
                                break;
                        }
                        break;
                    case ConvKind.Unknown:
                        if (canConvert(info.arg1, typeSig1))
                        {
                            break;
                        }
                        if (ibos < ibosMinLift || !bos.CanLift())
                        {
                            continue;
                        }
                        Debug.Assert(typeSig1.IsValType());

                        typeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig1);
                        if (!canConvert(info.arg1, typeSig1))
                        {
                            continue;
                        }
                        switch (GetConvKind(info.ptRaw1, bos.pt1))
                        {
                            default:
                                grflt = grflt | LiftFlags.Convert1;
                                break;
                            case ConvKind.Implicit:
                            case ConvKind.Identity:
                                grflt = grflt | LiftFlags.Lift1;
                                break;
                        }
                        break;
                    case ConvKind.Implicit:
                        break;
                    case ConvKind.Identity:
                        if (cv2 == ConvKind.Identity)
                        {
                            BinOpFullSig newsig = new BinOpFullSig(this, bos);
                            if (newsig.Type1() != null && newsig.Type2() != null)
                            {
                                // Exact match.
                                rgbofs.Add(newsig);
                                return true;
                            }
                        }
                        break;
                }

                switch (cv2)
                {
                    default:
                        VSFAIL("Shouldn't happen!");
                        continue;
                    case ConvKind.None:
                        continue;
                    case ConvKind.Explicit:
                        if (!info.arg2.isCONSTANT_OK())
                        {
                            continue;
                        }
                        // Need to try to convert.
                        if (canConvert(info.arg2, typeSig2))
                        {
                            break;
                        }
                        if (ibos < ibosMinLift || !bos.CanLift())
                        {
                            continue;
                        }
                        Debug.Assert(typeSig2.IsValType());

                        typeSig2 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig2);
                        if (!canConvert(info.arg2, typeSig2))
                        {
                            continue;
                        }
                        switch (GetConvKind(info.ptRaw2, bos.pt2))
                        {
                            default:
                                grflt = grflt | LiftFlags.Convert2;
                                break;
                            case ConvKind.Implicit:
                            case ConvKind.Identity:
                                grflt = grflt | LiftFlags.Lift2;
                                break;
                        }
                        break;
                    case ConvKind.Unknown:
                        if (canConvert(info.arg2, typeSig2))
                        {
                            break;
                        }
                        if (ibos < ibosMinLift || !bos.CanLift())
                        {
                            continue;
                        }
                        Debug.Assert(typeSig2.IsValType());

                        typeSig2 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig2);
                        if (!canConvert(info.arg2, typeSig2))
                        {
                            continue;
                        }
                        switch (GetConvKind(info.ptRaw2, bos.pt2))
                        {
                            default:
                                grflt = grflt | LiftFlags.Convert2;
                                break;
                            case ConvKind.Implicit:
                            case ConvKind.Identity:
                                grflt = grflt | LiftFlags.Lift2;
                                break;
                        }
                        break;
                    case ConvKind.Identity:
                    case ConvKind.Implicit:
                        break;
                }

                if (grflt != LiftFlags.None)
                {
                    // We have a lifted signature.
                    rgbofs.Add(new BinOpFullSig(typeSig1, typeSig2, bos.pfn, bos.grfos, grflt, bos.fnkind));

                    // NOTE: Can't skip any if we use a lifted signature because the
                    // type might convert to int? and to long (but not to int) in which
                    // case we should get an ambiguity. But we can skip the lifted ones....
                    ibosMinLift = ibos + bos.cbosSkip + 1;
                }
                else
                {
                    // Record it as applicable and skip accordingly.
                    rgbofs.Add(new BinOpFullSig(this, bos));
                    ibos += bos.cbosSkip;
                }
            }
            return false;
        }
Exemple #14
0
 // Adds special signatures to the candidate list.  If we find an exact match
 // then it will be the last item on the list and we return true.
 protected bool GetSpecialBinopSignatures(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
 {
     Debug.Assert(prgbofs != null);
     if (info.pt1 <= PredefinedType.PT_ULONG && info.pt2 <= PredefinedType.PT_ULONG)
     {
         return false;
     }
     return GetDelBinOpSigs(prgbofs, info) ||
            GetEnumBinOpSigs(prgbofs, info) ||
            GetPtrBinOpSigs(prgbofs, info) ||
            GetRefEqualSigs(prgbofs, info);
 }