- //
- // Note that handling the case l == Decimal || r == Decimal
- // is taken care of by the Step 1 Operator Overload resolution.
- //
- // If `check_user_conv' is true, we also check whether a user-defined conversion
- // exists. Note that we only need to do this if both arguments are of a user-defined
- // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
- // so we don't explicitly check for performance reasons.
- //
- bool DoNumericPromotions (EmitContext ec, Type l, Type r, Expression lexpr, Expression rexpr, bool check_user_conv)
- {
- if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
- //
- // If either operand is of type double, the other operand is
- // conveted to type double.
- //
- if (r != TypeManager.double_type)
- right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
- if (l != TypeManager.double_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
-
- type = TypeManager.double_type;
- } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
- //
- // if either operand is of type float, the other operand is
- // converted to type float.
- //
- if (r != TypeManager.double_type)
- right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
- if (l != TypeManager.double_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
- type = TypeManager.float_type;
- } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
- Expression e;
- Type other;
- //
- // If either operand is of type ulong, the other operand is
- // converted to type ulong. or an error ocurrs if the other
- // operand is of type sbyte, short, int or long
- //
- if (l == TypeManager.uint64_type){
- if (r != TypeManager.uint64_type){
- if (right is IntConstant){
- IntConstant ic = (IntConstant) right;
-
- e = Convert.TryImplicitIntConversion (l, ic);
- if (e != null)
- right = e;
- } else if (right is LongConstant){
- long ll = ((LongConstant) right).Value;
-
- if (ll >= 0)
- right = new ULongConstant ((ulong) ll, right.Location);
- } else {
- e = Convert.ImplicitNumericConversion (ec, right, l);
- if (e != null)
- right = e;
- }
- }
- other = right.Type;
- } else {
- if (left is IntConstant){
- e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
- if (e != null)
- left = e;
- } else if (left is LongConstant){
- long ll = ((LongConstant) left).Value;
-
- if (ll > 0)
- left = new ULongConstant ((ulong) ll, right.Location);
- } else {
- e = Convert.ImplicitNumericConversion (ec, left, r);
- if (e != null)
- left = e;
- }
- other = left.Type;
- }
-
- if ((other == TypeManager.sbyte_type) ||
- (other == TypeManager.short_type) ||
- (other == TypeManager.int32_type) ||
- (other == TypeManager.int64_type))
- Error_OperatorAmbiguous (loc, oper, l, r);
- else {
- left = ForceConversion (ec, left, TypeManager.uint64_type);
- right = ForceConversion (ec, right, TypeManager.uint64_type);
- }
- type = TypeManager.uint64_type;
- } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
- //
- // If either operand is of type long, the other operand is converted
- // to type long.
- //
- if (l != TypeManager.int64_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
- if (r != TypeManager.int64_type)
- right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
-
- type = TypeManager.int64_type;
- } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
- //
- // If either operand is of type uint, and the other
- // operand is of type sbyte, short or int, othe operands are
- // converted to type long (unless we have an int constant).
- //
- Type other = null;
-
- if (l == TypeManager.uint32_type){
- if (right is IntConstant){
- IntConstant ic = (IntConstant) right;
- int val = ic.Value;
-
- if (val >= 0){
- right = new UIntConstant ((uint) val, ic.Location);
- type = l;
-
- return true;
- }
- }
- other = r;
- } else if (r == TypeManager.uint32_type){
- if (left is IntConstant){
- IntConstant ic = (IntConstant) left;
- int val = ic.Value;
-
- if (val >= 0){
- left = new UIntConstant ((uint) val, ic.Location);
- type = r;
- return true;
- }
- }
-
- other = l;
- }
-
- if ((other == TypeManager.sbyte_type) ||
- (other == TypeManager.short_type) ||
- (other == TypeManager.int32_type)){
- left = ForceConversion (ec, left, TypeManager.int64_type);
- right = ForceConversion (ec, right, TypeManager.int64_type);
- type = TypeManager.int64_type;
- } else {
- //
- // if either operand is of type uint, the other
- // operand is converd to type uint
- //
- left = ForceConversion (ec, left, TypeManager.uint32_type);
- right = ForceConversion (ec, right, TypeManager.uint32_type);
- type = TypeManager.uint32_type;
- }
- } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
- if (l != TypeManager.decimal_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);