// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
-// (C) 2002, 2003 Ximian, Inc.
-//
-
+// Copyright 2002, 2003 Ximian, Inc.
+// Copyright 2003-2008, Novell, Inc.
+//
using System;
namespace Mono.CSharp {
public class ConstantFold {
- static Type[] binary_promotions = new Type[] {
+ public static readonly Type[] binary_promotions = new Type[] {
TypeManager.decimal_type, TypeManager.double_type, TypeManager.float_type,
TypeManager.uint64_type, TypeManager.int64_type, TypeManager.uint32_type };
// On success, the types of `lc' and `rc' on output will always match,
// and the pair will be one of:
//
- static void DoBinaryNumericPromotions (ref Constant left, ref Constant right)
+ static bool DoBinaryNumericPromotions (ref Constant left, ref Constant right)
{
Type ltype = left.Type;
Type rtype = right.Type;
foreach (Type t in binary_promotions) {
- if (t == ltype || t == rtype) {
- left = left.ConvertImplicitly (t);
- right = right.ConvertImplicitly (t);
- return;
- }
+ if (t == ltype)
+ return t == rtype || ConvertPromotion (ref right, ref left, t);
+
+ if (t == rtype)
+ return t == ltype || ConvertPromotion (ref left, ref right, t);
}
left = left.ConvertImplicitly (TypeManager.int32_type);
right = right.ConvertImplicitly (TypeManager.int32_type);
+ return left != null && right != null;
+ }
+
+ static bool ConvertPromotion (ref Constant prim, ref Constant second, Type type)
+ {
+ Constant c = prim.ConvertImplicitly (type);
+ if (c != null) {
+ prim = c;
+ return true;
+ }
+
+ if (type == TypeManager.uint32_type) {
+ type = TypeManager.int64_type;
+ prim = prim.ConvertImplicitly (type);
+ second = second.ConvertImplicitly (type);
+ return prim != null && second != null;
+ }
+
+ return false;
}
internal static void Error_CompileTimeOverflow (Location loc)
static public Constant BinaryFold (EmitContext ec, Binary.Operator oper,
Constant left, Constant right, Location loc)
{
+ Constant result = null;
+
if (left is EmptyConstantCast)
return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
+ if (left is SideEffectConstant) {
+ result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc);
+ if (result == null)
+ return null;
+ return new SideEffectConstant (result, left, loc);
+ }
+
if (right is EmptyConstantCast)
return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
+ if (right is SideEffectConstant) {
+ result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc);
+ if (result == null)
+ return null;
+ return new SideEffectConstant (result, right, loc);
+ }
+
Type lt = left.Type;
Type rt = right.Type;
bool bool_res;
- Constant result = null;
if (lt == TypeManager.bool_type && lt == rt) {
bool lv = ((BoolConstant) left ).Value;
switch (oper){
case Binary.Operator.BitwiseOr:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
if (left is IntConstant){
break;
case Binary.Operator.BitwiseAnd:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
///
break;
case Binary.Operator.ExclusiveOr:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
if (left is IntConstant){
return null;
}
+ if (lt == TypeManager.null_type && lt == rt)
+ return left;
+
//
// handle "E operator + (E x, U y)"
// handle "E operator + (Y y, E x)"
return new EnumConstant (result, lt);
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
try {
return new EnumConstant (result, lt);
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
try {
return result;
case Binary.Operator.Multiply:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
try {
break;
case Binary.Operator.Division:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
try {
break;
case Binary.Operator.Modulus:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
try {
case Binary.Operator.LeftShift:
IntConstant ic = right.ConvertImplicitly (TypeManager.int32_type) as IntConstant;
if (ic == null){
- Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
+ Binary.Error_OperatorCannotBeApplied (left, right, oper, loc);
return null;
}
if (left.Type == TypeManager.int32_type)
return new IntConstant (((IntConstant)left).Value << lshift_val, left.Location);
- Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
+ Binary.Error_OperatorCannotBeApplied (left, right, oper, loc);
break;
//
case Binary.Operator.RightShift:
IntConstant sic = right.ConvertImplicitly (TypeManager.int32_type) as IntConstant;
if (sic == null){
- Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
+ Binary.Error_OperatorCannotBeApplied (left, right, oper, loc); ;
return null;
}
int rshift_val = sic.Value;
if (left.Type == TypeManager.int32_type)
return new IntConstant (((IntConstant)left).Value >> rshift_val, left.Location);
- Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
+ Binary.Error_OperatorCannotBeApplied (left, right, oper, loc);
break;
case Binary.Operator.Equality:
- if (left is NullConstant){
- if (right is NullConstant)
+ if (left is NullLiteral){
+ if (right is NullLiteral)
return new BoolConstant (true, left.Location);
else if (right is StringConstant)
return new BoolConstant (
((StringConstant) right).Value == null, left.Location);
- } else if (right is NullConstant){
- if (left is NullConstant)
+ } else if (right is NullLiteral) {
+ if (left is NullLiteral)
return new BoolConstant (true, left.Location);
else if (left is StringConstant)
return new BoolConstant (
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
bool_res = false;
return new BoolConstant (bool_res, left.Location);
case Binary.Operator.Inequality:
- if (left is NullConstant){
- if (right is NullConstant)
+ if (left is NullLiteral) {
+ if (right is NullLiteral)
return new BoolConstant (false, left.Location);
else if (right is StringConstant)
return new BoolConstant (
((StringConstant) right).Value != null, left.Location);
- } else if (right is NullConstant){
- if (left is NullConstant)
+ } else if (right is NullLiteral) {
+ if (left is NullLiteral)
return new BoolConstant (false, left.Location);
else if (left is StringConstant)
return new BoolConstant (
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
bool_res = false;
return new BoolConstant (bool_res, left.Location);
case Binary.Operator.LessThan:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
bool_res = false;
return new BoolConstant (bool_res, left.Location);
case Binary.Operator.GreaterThan:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
bool_res = false;
return new BoolConstant (bool_res, left.Location);
case Binary.Operator.GreaterThanOrEqual:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
bool_res = false;
return new BoolConstant (bool_res, left.Location);
case Binary.Operator.LessThanOrEqual:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ref left, ref right))
return null;
bool_res = false;