private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type lhtype = Convert.ToType(this.operand1.InferType(null)); Type rhtype = Convert.ToType(this.operand2.InferType(null)); Type rt = Typeob.Object; if (lhtype == Typeob.String || rhtype == Typeob.String) { rt = Typeob.String; } else if (rtype == Typeob.Void || rtype == lhtype || Convert.IsPrimitiveNumericType(lhtype) && (Convert.IsPromotableTo(rhtype, lhtype) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(lhtype)))) { rt = lhtype; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16) { rt = Typeob.UInt32; } // If we have "unsigned += signed" or "signed += unsigned" then generating the // correct code gets quite complicated. Just go late-bound for this edge case. if (this.operand2 is ConstantWrapper) { if (!((ConstantWrapper)this.operand2).IsAssignableTo(rt)) { // eg: "var u : byte = 123; u += -100;" should go late bound because // of signed/unsigned mismatch but "u += 1" should not. rt = Typeob.Object; } } else { if ((Convert.IsPrimitiveSignedNumericType(rhtype) && Convert.IsPrimitiveUnsignedIntegerType(lhtype)) || (Convert.IsPrimitiveUnsignedIntegerType(rhtype) && Convert.IsPrimitiveSignedIntegerType(lhtype))) { rt = Typeob.Object; } } this.operand1.TranslateToILPreSetPlusGet(il); Convert.Emit(this, il, lhtype, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object || rt == Typeob.String) { il.Emit(OpCodes.Call, CompilerGlobals.plusDoOpMethod); rt = Typeob.Object; } else if (rt == Typeob.Double || rt == Typeob.Single) { il.Emit(OpCodes.Add); } else if (rt == Typeob.Int32 || rt == Typeob.Int64 || rt == Typeob.Int16 || rt == Typeob.SByte) { il.Emit(OpCodes.Add_Ovf); } else { il.Emit(OpCodes.Add_Ovf_Un); } if (rtype != Typeob.Void) { LocalBuilder result = il.DeclareLocal(rt); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, result); Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); Convert.Emit(this, il, rt, rtype); } else { Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); } }
private void TranslateToILForNoOverloadCase(ILGenerator il, Type rtype) { Type lhtype = Convert.ToType(this.operand1.InferType(null)); Type rhtype = Convert.ToType(this.operand2.InferType(null)); Type rt = Typeob.Double; if (this.operatorTok != JSToken.Divide && (rtype == Typeob.Void || rtype == lhtype || Convert.IsPrimitiveNumericType(lhtype)) && (Convert.IsPromotableTo(rhtype, lhtype) || ((this.operand2 is ConstantWrapper) && ((ConstantWrapper)this.operand2).IsAssignableTo(lhtype)))) { rt = lhtype; } if (rt == Typeob.SByte || rt == Typeob.Int16) { rt = Typeob.Int32; } else if (rt == Typeob.Byte || rt == Typeob.UInt16 || rt == Typeob.Char) { rt = Typeob.UInt32; } // If we have "unsigned -= signed" or "signed -= unsigned" then generating the // correct code gets quite complicated. Just go late-bound for this edge case. if (this.operand2 is ConstantWrapper) { if (!((ConstantWrapper)this.operand2).IsAssignableTo(rt)) { // eg: "var u : byte = 123; u -= -100;" should go late bound because // of signed/unsigned mismatch but "u -= 1" should not. rt = Typeob.Object; } } else { if ((Convert.IsPrimitiveSignedNumericType(rhtype) && Convert.IsPrimitiveUnsignedIntegerType(lhtype)) || (Convert.IsPrimitiveUnsignedIntegerType(rhtype) && Convert.IsPrimitiveSignedIntegerType(lhtype))) { rt = Typeob.Object; } } this.operand1.TranslateToILPreSetPlusGet(il); Convert.Emit(this, il, lhtype, rt); this.operand2.TranslateToIL(il, rt); if (rt == Typeob.Object) { il.Emit(OpCodes.Ldc_I4, (int)this.operatorTok); il.Emit(OpCodes.Call, CompilerGlobals.numericbinaryDoOpMethod); } else if (rt == Typeob.Double || rt == Typeob.Single) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else if (rt == Typeob.Int32 || rt == Typeob.Int64 || rt == Typeob.Int16 || rt == Typeob.SByte) { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf); break; default: throw new JScriptException(JSError.InternalError, this.context); } } else { switch (this.operatorTok) { case JSToken.Divide: il.Emit(OpCodes.Div); break; case JSToken.Minus: il.Emit(OpCodes.Sub_Ovf_Un); break; case JSToken.Modulo: il.Emit(OpCodes.Rem); break; case JSToken.Multiply: il.Emit(OpCodes.Mul_Ovf_Un); break; default: throw new JScriptException(JSError.InternalError, this.context); } } if (rtype != Typeob.Void) { LocalBuilder result = il.DeclareLocal(rt); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, result); Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); il.Emit(OpCodes.Ldloc, result); Convert.Emit(this, il, rt, rtype); } else { Convert.Emit(this, il, rt, lhtype); this.operand1.TranslateToILSet(il); } }