// 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[] {
- TypeManager.decimal_type, TypeManager.double_type, TypeManager.float_type,
- TypeManager.uint64_type, TypeManager.int64_type, TypeManager.uint32_type };
+ static TypeSpec[] binary_promotions;
+
+ public static TypeSpec[] BinaryPromotionsTypes {
+ get {
+ if (binary_promotions == null) {
+ binary_promotions = new TypeSpec[] {
+ TypeManager.decimal_type, TypeManager.double_type, TypeManager.float_type,
+ TypeManager.uint64_type, TypeManager.int64_type, TypeManager.uint32_type };
+ }
+
+ return binary_promotions;
+ }
+ }
+
+ public static void Reset ()
+ {
+ binary_promotions = null;
+ }
//
// Performs the numeric promotions on the left and right expresions
- // and desposits the results on `lc' and `rc'.
+ // and deposits the results on `lc' and `rc'.
//
// 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)
+ // TODO: BinaryFold should be called as an optimization step only,
+ // error checking here is weak
+ //
+ static bool DoBinaryNumericPromotions (ResolveContext rc, 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;
- }
+ TypeSpec ltype = left.Type;
+ TypeSpec rtype = right.Type;
+
+ foreach (TypeSpec t in BinaryPromotionsTypes) {
+ if (t == ltype)
+ return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
+
+ if (t == rtype)
+ return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
}
- left = left.ConvertImplicitly (TypeManager.int32_type);
- right = right.ConvertImplicitly (TypeManager.int32_type);
+ left = left.ConvertImplicitly (rc, TypeManager.int32_type);
+ right = right.ConvertImplicitly (rc, TypeManager.int32_type);
+ return left != null && right != null;
}
- internal static void Error_CompileTimeOverflow (Location loc)
+ static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
{
- Report.Error (220, loc, "The operation overflows at compile time in checked mode");
+ Constant c = prim.ConvertImplicitly (rc, type);
+ if (c != null) {
+ prim = c;
+ return true;
+ }
+
+ if (type == TypeManager.uint32_type) {
+ type = TypeManager.int64_type;
+ prim = prim.ConvertImplicitly (rc, type);
+ second = second.ConvertImplicitly (rc, type);
+ return prim != null && second != null;
+ }
+
+ return false;
+ }
+
+ internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc)
+ {
+ rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode");
}
/// <summary>
///
/// Returns null if the expression can not be folded.
/// </summary>
- static public Constant BinaryFold (EmitContext ec, Binary.Operator oper,
+ static public Constant BinaryFold (ResolveContext 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)
- return BinaryFold (ec, oper, ((SideEffectConstant) left).left, 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)
- return BinaryFold (ec, oper, left, ((SideEffectConstant) right).left, 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;
+ TypeSpec lt = left.Type;
+ TypeSpec rt = right.Type;
bool bool_res;
- Constant result = null;
if (lt == TypeManager.bool_type && lt == rt) {
- bool lv = ((BoolConstant) left ).Value;
- bool rv = ((BoolConstant) right).Value;
+ bool lv = (bool) left.GetValue ();
+ bool rv = (bool) right.GetValue ();
switch (oper) {
case Binary.Operator.BitwiseAnd:
case Binary.Operator.LogicalAnd:
// During an enum evaluation, none of the rules are valid
// Not sure whether it is bug in csc or in documentation
//
- if (ec.InEnumContext){
+ if (ec.HasSet (ResolveContext.Options.EnumScope)){
if (left is EnumConstant)
left = ((EnumConstant) left).Child;
case Binary.Operator.BitwiseOr:
case Binary.Operator.BitwiseAnd:
case Binary.Operator.ExclusiveOr:
- return BinaryFold (ec, oper, ((EnumConstant)left).Child,
- ((EnumConstant)right).Child, loc).TryReduce (ec, lt, loc);
+ result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
+ if (result != null)
+ result = result.Resolve (ec).TryReduce (ec, lt, loc);
+ return result;
///
/// U operator -(E x, E y);
///
case Binary.Operator.Subtraction:
result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
- return result.TryReduce (ec, ((EnumConstant)left).Child.Type, loc);
+ if (result != null)
+ result = result.Resolve (ec).TryReduce (ec, ((EnumConstant)left).Child.Type, loc);
+ return result;
///
/// bool operator ==(E x, E y);
switch (oper){
case Binary.Operator.BitwiseOr:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, 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 (ec, ref left, ref right))
return null;
///
break;
case Binary.Operator.ExclusiveOr:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
if (left is IntConstant){
break;
case Binary.Operator.Addition:
+ if (lt == TypeManager.null_type)
+ return right;
+
+ if (rt == TypeManager.null_type)
+ return left;
+
//
// If both sides are strings, then concatenate, if
// one is a string, and the other is not, then defer
// to runtime concatenation
//
if (lt == TypeManager.string_type || rt == TypeManager.string_type){
- if (lt == TypeManager.string_type && rt == TypeManager.string_type)
- return new StringConstant (
- ((StringConstant) left).Value +
- ((StringConstant) right).Value, left.Location);
+ if (lt == rt)
+ return new StringConstant ((string)left.GetValue () + (string)right.GetValue (),
+ left.Location);
return null;
}
}
// U has to be implicitly convetible to E.base
- right = right.ConvertImplicitly (lc.Child.Type);
+ right = right.ConvertImplicitly (ec, lc.Child.Type);
if (right == null)
return null;
if (result == null)
return null;
- result = result.TryReduce (ec, lt, loc);
+ result = result.Resolve (ec).TryReduce (ec, lt, loc);
if (result == null)
return null;
return new EnumConstant (result, lt);
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
try {
((DecimalConstant) right).Value);
result = new DecimalConstant (res, left.Location);
- } else {
- throw new Exception ( "Unexepected addition input: " + left);
}
} catch (OverflowException){
- Error_CompileTimeOverflow (loc);
+ Error_CompileTimeOverflow (ec, loc);
}
return result;
}
// U has to be implicitly convetible to E.base
- right = right.ConvertImplicitly (lc.Child.Type);
+ right = right.ConvertImplicitly (ec, lc.Child.Type);
if (right == null)
return null;
if (result == null)
return null;
- result = result.TryReduce (ec, lt, loc);
+ result = result.Resolve (ec).TryReduce (ec, lt, loc);
if (result == null)
return null;
return new EnumConstant (result, lt);
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
try {
throw new Exception ( "Unexepected subtraction input: " + left);
}
} catch (OverflowException){
- Error_CompileTimeOverflow (loc);
+ Error_CompileTimeOverflow (ec, loc);
}
return result;
case Binary.Operator.Multiply:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
try {
throw new Exception ( "Unexepected multiply input: " + left);
}
} catch (OverflowException){
- Error_CompileTimeOverflow (loc);
+ Error_CompileTimeOverflow (ec, loc);
}
break;
case Binary.Operator.Division:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
try {
throw new Exception ( "Unexepected division input: " + left);
}
} catch (OverflowException){
- Error_CompileTimeOverflow (loc);
+ Error_CompileTimeOverflow (ec, loc);
} catch (DivideByZeroException) {
- Report.Error (020, loc, "Division by constant zero");
+ ec.Report.Error (20, loc, "Division by constant zero");
}
break;
case Binary.Operator.Modulus:
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, ref left, ref right))
return null;
try {
throw new Exception ( "Unexepected modulus input: " + left);
}
} catch (DivideByZeroException){
- Report.Error (020, loc, "Division by constant zero");
+ ec.Report.Error (20, loc, "Division by constant zero");
} catch (OverflowException){
- Error_CompileTimeOverflow (loc);
+ Error_CompileTimeOverflow (ec, loc);
}
break;
// There is no overflow checking on left shift
//
case Binary.Operator.LeftShift:
- IntConstant ic = right.ConvertImplicitly (TypeManager.int32_type) as IntConstant;
+ IntConstant ic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
if (ic == null){
- Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
+ Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
return null;
}
if (left.Type == TypeManager.uint32_type)
return new UIntConstant (((UIntConstant)left).Value << lshift_val, left.Location);
- left = left.ConvertImplicitly (TypeManager.int32_type);
+ left = left.ConvertImplicitly (ec, TypeManager.int32_type);
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 (ec, left, right, oper, loc);
break;
//
// There is no overflow checking on right shift
//
case Binary.Operator.RightShift:
- IntConstant sic = right.ConvertImplicitly (TypeManager.int32_type) as IntConstant;
+ IntConstant sic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
if (sic == null){
- Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
+ Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
return null;
}
int rshift_val = sic.Value;
if (left.Type == TypeManager.uint32_type)
return new UIntConstant (((UIntConstant)left).Value >> rshift_val, left.Location);
- left = left.ConvertImplicitly (TypeManager.int32_type);
+ left = left.ConvertImplicitly (ec, TypeManager.int32_type);
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 (ec, left, right, oper, loc);
break;
case Binary.Operator.Equality:
- if (left is NullConstant){
- if (right is NullConstant)
- 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)
- return new BoolConstant (true, left.Location);
- else if (left is StringConstant)
+ if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (lt)) {
+ if (left.IsNull || right.IsNull) {
+ return ReducedExpression.Create (
+ new BoolConstant (left.IsNull == right.IsNull, left.Location).Resolve (ec),
+ new Binary (oper, left, right, loc));
+ }
+
+ if (left is StringConstant && right is StringConstant)
return new BoolConstant (
- ((StringConstant) left).Value == null, left.Location);
- }
- if (left is StringConstant && right is StringConstant){
- return new BoolConstant (
- ((StringConstant) left).Value ==
- ((StringConstant) right).Value, left.Location);
-
+ ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
+
+ return null;
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, 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)
- 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)
- return new BoolConstant (false, left.Location);
- else if (left is StringConstant)
+ if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (lt)) {
+ if (left.IsNull || right.IsNull) {
+ return ReducedExpression.Create (
+ new BoolConstant (left.IsNull != right.IsNull, left.Location).Resolve (ec),
+ new Binary (oper, left, right, loc));
+ }
+
+ if (left is StringConstant && right is StringConstant)
return new BoolConstant (
- ((StringConstant) left).Value != null, left.Location);
- }
- if (left is StringConstant && right is StringConstant){
- return new BoolConstant (
- ((StringConstant) left).Value !=
- ((StringConstant) right).Value, left.Location);
-
+ ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
+
+ return null;
}
- DoBinaryNumericPromotions (ref left, ref right);
- if (left == null || right == null)
+ if (!DoBinaryNumericPromotions (ec, 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 (ec, 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 (ec, 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 (ec, 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 (ec, ref left, ref right))
return null;
bool_res = false;