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; }