private EXPRMULTI BindLiftedIncOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg, UnaOpFullSig uofs) { Debug.Assert(ek == ExpressionKind.EK_ADD || ek == ExpressionKind.EK_SUB); Debug.Assert(uofs.isLifted()); NullableType type = uofs.GetType().AsNullableType(); Debug.Assert(arg != null); EXPR exprVal; #if ! CSEE EXPRMULTIGET exprGet = GetExprFactory().CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.type, null); exprVal = exprGet; #else exprVal = arg; #endif EXPR nonLiftedResult = null; EXPR nonLiftedArg = exprVal; // We want to give the lifted argument as the binop, but use the non-lifted argument as the // argument of the call. //Debug.Assert(uofs.LiftArg() || type.IsValType()); nonLiftedArg = mustCast(nonLiftedArg, type.GetUnderlyingType()); nonLiftedResult = BindIncOpCore(ek, flags, nonLiftedArg, type.GetUnderlyingType()); exprVal = mustCast(exprVal, type); EXPRUNARYOP exprRes = GetExprFactory().CreateUnaryOp((ek == ExpressionKind.EK_ADD) ? ExpressionKind.EK_INC : ExpressionKind.EK_DEC, arg.type/* type */, exprVal); mustCast(mustCast(nonLiftedResult, type), arg.type); exprRes.flags |= flags; EXPRMULTI exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.type, arg, exprRes); #if ! CSEE exprGet.SetOptionalMulti(exprMulti); #endif return exprMulti; }
private EXPRMULTI BindNonliftedIncOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg, UnaOpFullSig uofs) { Debug.Assert(ek == ExpressionKind.EK_ADD || ek == ExpressionKind.EK_SUB); Debug.Assert(!uofs.isLifted()); Debug.Assert(arg != null); EXPR exprVal; #if ! CSEE EXPRMULTIGET exprGet = GetExprFactory().CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.type, null); exprVal = exprGet; #else exprVal = arg; #endif CType type = uofs.GetType(); Debug.Assert(!type.IsNullableType()); // These used to be converts, but we're making them casts now - this is because // we need to remove the ability to call inc(sbyte) etc for all types smaller than int. // Note however, that this will give us different error messages on compile time versus runtime // for checked increments. // // Also, we changed it so that we now generate the cast to and from enum for enum increments. exprVal = mustCast(exprVal, type); exprVal = BindIncOpCore(ek, flags, exprVal, type); EXPR op = mustCast(exprVal, arg.type, CONVERTTYPE.NOUDC); EXPRMULTI exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.type, arg, op); #if ! CSEE exprGet.SetOptionalMulti(exprMulti); #endif return exprMulti; }
/* Handles standard increment and decrement operators. */ private EXPR BindIncOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg, UnaOpFullSig uofs) { Debug.Assert(ek == ExpressionKind.EK_ADD || ek == ExpressionKind.EK_SUB); if (!checkLvalue(arg, CheckLvalueKind.Increment)) { EXPR rval = GetExprFactory().CreateBinop(ek, arg.type, arg, null); rval.SetError(); return rval; } CType typeRaw = uofs.GetType().StripNubs(); FUNDTYPE ft = typeRaw.fundType(); if (ft == FUNDTYPE.FT_R8 || ft == FUNDTYPE.FT_R4) { flags = ~EXPRFLAG.EXF_CHECKOVERFLOW; } if (uofs.isLifted()) { return BindLiftedIncOp(ek, flags, arg, uofs); } else { return BindNonliftedIncOp(ek, flags, arg, uofs); } }
/* Determine which UnaOpSig is better for overload resolution. Returns negative if iuos1 is better, positive if iuos2 is better, 0 if neither. */ private int WhichUofsIsBetter(UnaOpFullSig uofs1, UnaOpFullSig uofs2, CType typeArg) { BetterType bt; if (uofs1.FPreDef() && uofs2.FPreDef()) { // Faster to compare predefs. bt = WhichTypeIsBetter(uofs1.pt, uofs2.pt, typeArg); } else { bt = WhichTypeIsBetter(uofs1.GetType(), uofs2.GetType(), typeArg); } switch (bt) { default: VSFAIL("Shouldn't happen"); return 0; case BetterType.Same: case BetterType.Neither: return 0; case BetterType.Left: return -1; case BetterType.Right: return +1; } }
private EXPR BindLiftedStandardUnop(ExpressionKind ek, EXPRFLAG flags, EXPR arg, UnaOpFullSig uofs) { NullableType type = uofs.GetType().AsNullableType(); Debug.Assert(arg != null && arg.type != null); if (arg.type.IsNullType()) { return BadOperatorTypesError(ek, arg, null, type); } EXPR pArgument = null; EXPR nonLiftedArg = null; LiftArgument(arg, uofs.GetType(), uofs.Convert(), out pArgument, out nonLiftedArg); // Now call the function with the non lifted arguments to report errors. EXPR nonLiftedResult = uofs.pfn(ek, flags, nonLiftedArg); EXPRUNARYOP exprRes = GetExprFactory().CreateUnaryOp(ek, type, pArgument); mustCast(nonLiftedResult, type, 0); exprRes.flags |= flags; Debug.Assert((exprRes.flags & EXPRFLAG.EXF_LVALUE) == 0); return exprRes; }
///////////////////////////////////////////////////////////////////////////////// private bool FindApplicableSignatures( EXPR pArgument, UnaOpMask unaryOpMask, List<UnaOpFullSig> pSignatures) { // All callers should already assert this to be the case. Debug.Assert(pArgument != null); Debug.Assert(pArgument.type != null); long iuosMinLift = GetSymbolLoader().FCanLift() ? 0 : g_rguos.Length; CType pArgumentType = pArgument.type; CType pRawType = pArgumentType.StripNubs(); PredefinedType pt = pArgumentType.isPredefined() ? pArgumentType.getPredefType() : PredefinedType.PT_COUNT; PredefinedType ptRaw = pRawType.isPredefined() ? pRawType.getPredefType() : PredefinedType.PT_COUNT; for (int index = 0; index < g_rguos.Length; index++) { UnaOpSig uos = g_rguos[index]; if ((uos.grfuom & unaryOpMask) == 0) { continue; } ConvKind cv = GetConvKind(pt, g_rguos[index].pt); CType typeSig = null; switch (cv) { default: VSFAIL("Shouldn't happen!"); continue; case ConvKind.None: continue; case ConvKind.Explicit: if (!pArgument.isCONSTANT_OK()) { continue; } if (canConvert(pArgument, typeSig = GetOptPDT(uos.pt))) { break; } if (index < iuosMinLift) { continue; } typeSig = GetSymbolLoader().GetTypeManager().GetNullable(typeSig); if (!canConvert(pArgument, typeSig)) { continue; } break; case ConvKind.Unknown: if (canConvert(pArgument, typeSig = GetOptPDT(uos.pt))) { break; } if (index < iuosMinLift) { continue; } typeSig = GetSymbolLoader().GetTypeManager().GetNullable(typeSig); if (!canConvert(pArgument, typeSig)) { continue; } break; case ConvKind.Implicit: break; case ConvKind.Identity: { UnaOpFullSig result = new UnaOpFullSig(this, uos); if (result.GetType() != null) { pSignatures.Add(result); return true; } } break; } if (typeSig != null && typeSig.IsNullableType()) { // Need to use a lifted signature. LiftFlags grflt = LiftFlags.None; switch (GetConvKind(ptRaw, uos.pt)) { default: grflt = grflt | LiftFlags.Convert1; break; case ConvKind.Implicit: case ConvKind.Identity: grflt = grflt | LiftFlags.Lift1; break; } pSignatures.Add(new UnaOpFullSig(typeSig, uos.pfn, grflt, uos.fnkind)); // NOTE: Can't skip any if we use the 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.... iuosMinLift = index + uos.cuosSkip + 1; } else { // Record it as applicable and skip accordingly. UnaOpFullSig newResult = new UnaOpFullSig(this, uos); if (newResult.GetType() != null) { pSignatures.Add(newResult); } index += uos.cuosSkip; } } return false; }