Beispiel #1
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;
        }
Beispiel #2
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);
        }
Beispiel #3
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;
        }
Beispiel #4
0
        private EXPR BindBoolBitwiseOp(ExpressionKind ek, EXPRFLAG flags, EXPR expr1, EXPR expr2, BinOpFullSig bofs)
        {
            Debug.Assert(ek == ExpressionKind.EK_BITAND || ek == ExpressionKind.EK_BITOR);
            Debug.Assert(expr1.type.isPredefType(PredefinedType.PT_BOOL) || expr1.type.IsNullableType() && expr1.type.AsNullableType().GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL));
            Debug.Assert(expr2.type.isPredefType(PredefinedType.PT_BOOL) || expr2.type.IsNullableType() && expr2.type.AsNullableType().GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL));

            if (expr1.type.IsNullableType() || expr2.type.IsNullableType())
            {
                CType typeBool = GetReqPDT(PredefinedType.PT_BOOL);
                CType typeRes = GetSymbolLoader().GetTypeManager().GetNullable(typeBool);

                // Get the non-lifted result.
                EXPR nonLiftedArg1 = CNullable.StripNullableConstructor(expr1);
                EXPR nonLiftedArg2 = CNullable.StripNullableConstructor(expr2);
                EXPR nonLiftedResult = null;

                if (!nonLiftedArg1.type.IsNullableType() && !nonLiftedArg2.type.IsNullableType())
                {
                    nonLiftedResult = BindBoolBinOp(ek, flags, nonLiftedArg1, nonLiftedArg2);
                }

                // Make the binop and set that its lifted.
                EXPRBINOP exprRes = GetExprFactory().CreateBinop(ek, typeRes, expr1, expr2);
                if (nonLiftedResult != null)
                {
                    // Bitwise operators can have null non-lifted results if we have a nub sym somewhere.
                    mustCast(nonLiftedResult, typeRes, 0);
                }
                exprRes.isLifted = true;
                exprRes.flags |= flags;
                Debug.Assert((exprRes.flags & EXPRFLAG.EXF_LVALUE) == 0);
                return exprRes;
            }
            return BindBoolBinOp(ek, flags, expr1, expr2);
        }
Beispiel #5
0
        /*
            Determine which BinOpSig is better for overload resolution.
            Better means: at least as good in all Params, and better in at least one param.
         
            Better w/r to a param means:
            1) same type as argument
            2) implicit conversion from this one's param type to the other's param type
            Because of user defined conversion operators this relation is not transitive.
         
            Returns negative if ibos1 is better, positive if ibos2 is better, 0 if neither.
        */

        private int WhichBofsIsBetter(BinOpFullSig bofs1, BinOpFullSig bofs2, CType type1, CType type2)
        {
            BetterType bt1;
            BetterType bt2;

            if (bofs1.FPreDef() && bofs2.FPreDef())
            {
                // Faster to compare predefs.
                bt1 = WhichTypeIsBetter(bofs1.pt1, bofs2.pt1, type1);
                bt2 = WhichTypeIsBetter(bofs1.pt2, bofs2.pt2, type2);
            }
            else
            {
                bt1 = WhichTypeIsBetter(bofs1.Type1(), bofs2.Type1(), type1);
                bt2 = WhichTypeIsBetter(bofs1.Type2(), bofs2.Type2(), type2);
            }

            int res = 0;

            switch (bt1)
            {
                default:
                    VSFAIL("Shouldn't happen");
                    break;
                case BetterType.Same:
                case BetterType.Neither:
                    break;
                case BetterType.Left:
                    res--;
                    break;
                case BetterType.Right:
                    res++;
                    break;
            }

            switch (bt2)
            {
                default:
                    VSFAIL("Shouldn't happen");
                    break;
                case BetterType.Same:
                case BetterType.Neither:
                    break;
                case BetterType.Left:
                    res--;
                    break;
                case BetterType.Right:
                    res++;
                    break;
            }

            return res;
        }