X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fcfold.cs;h=7580124ceead35f46cd9af384fdc17b2fe99dcb8;hb=f574f7b447e29c6f083fcad4e6dc5f89d3cb4b4d;hp=f8d1f424a9bf4ae9b95e2b4f40a8336ba7c6c171;hpb=8eaed0c3dfb48a6b2639e028a7fd8ae5bfa652b2;p=mono.git diff --git a/mcs/mcs/cfold.cs b/mcs/mcs/cfold.cs index f8d1f424a9b..7580124ceea 100644 --- a/mcs/mcs/cfold.cs +++ b/mcs/mcs/cfold.cs @@ -5,166 +5,72 @@ // Miguel de Icaza (miguel@ximian.com) // Marek Safar (marek.safar@seznam.cz) // -// (C) 2002, 2003 Ximian, Inc. -// - +// Copyright 2002, 2003 Ximian, Inc. +// Copyright 2003-2011, Novell, Inc. +// using System; namespace Mono.CSharp { - public class ConstantFold { + public static class ConstantFold + { + public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types) + { + return new TypeSpec[] { + types.Decimal, types.Double, types.Float, + types.ULong, types.Long, types.UInt + }; + } // // 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: // - // (double, double) - // (float, float) - // (ulong, ulong) - // (long, long) - // (uint, uint) - // (int, int) - // (short, short) (Happens with enumerations with underlying short type) - // (ushort, ushort) (Happens with enumerations with underlying short type) - // - static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper, - ref Constant left, ref Constant right, - Location loc) + // 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) { - if (left is DoubleConstant || right is DoubleConstant){ - // - // If either side is a double, convert the other to a double - // - if (!(left is DoubleConstant)) - left = left.ToDouble (loc); - - if (!(right is DoubleConstant)) - right = right.ToDouble (loc); - return; - } else if (left is FloatConstant || right is FloatConstant) { - // - // If either side is a float, convert the other to a float - // - if (!(left is FloatConstant)) - left = left.ToFloat (loc); + TypeSpec ltype = left.Type; + TypeSpec rtype = right.Type; - if (!(right is FloatConstant)) - right = right.ToFloat (loc); -; return; - } else if (left is ULongConstant || right is ULongConstant){ - // - // 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 WRONG - Constant match, other; -#endif - - if (left is ULongConstant){ -#if WRONG - other = right; - match = left; -#endif - if (!(right is ULongConstant)) - right = right.ToULong (loc); - } else { -#if WRONG - other = left; - match = right; -#endif - left = left.ToULong (loc); - } + foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) { + if (t == ltype) + return t == rtype || ConvertPromotion (rc, ref right, ref left, t); -#if WRONG - if (other is SByteConstant || other is ShortConstant || - other is IntConstant || other is LongConstant){ - Binary.Error_OperatorAmbiguous - (loc, oper, other.Type, match.Type); - left = null; - right = null; - } -#endif - return; - } else if (left is LongConstant || right is LongConstant){ - // - // If either operand is of type long, the other operand is converted - // to type long. - // - if (!(left is LongConstant)) - left = left.ToLong (loc); - else if (!(right is LongConstant)) - right = right.ToLong (loc); - return; - } else if (left is UIntConstant || right is UIntConstant){ - // - // If either operand is of type uint, and the other - // operand is of type sbyte, short or int, the operands are - // converted to type long. - // - Constant other; - if (left is UIntConstant) - other = right; - else - other = left; - - // Nothing to do. - if (other is UIntConstant) - return; - - IntConstant ic = other as IntConstant; - if (ic != null){ - if (ic.Value >= 0){ - if (left == other) - left = new UIntConstant ((uint) ic.Value, ic.Location); - else - right = new UIntConstant ((uint) ic.Value, ic.Location); - return; - } - } - - if (other is SByteConstant || other is ShortConstant || ic != null){ - left = left.ToLong (loc); - right = right.ToLong (loc); - } else { - left = left.ToUInt (loc); - right = left.ToUInt (loc); - } + if (t == rtype) + return t == ltype || ConvertPromotion (rc, ref left, ref right, t); + } - return; - } else if (left is DecimalConstant || right is DecimalConstant) { - if (!(left is DecimalConstant)) - left = left.ToDecimal (loc); - else if (!(right is DecimalConstant)) - right = right.ToDecimal (loc); - return; - } else if (left is EnumConstant || right is EnumConstant){ - if (left is EnumConstant) - left = ((EnumConstant) left).Child; - if (right is EnumConstant) - right = ((EnumConstant) right).Child; + left = left.ConvertImplicitly (rc.BuiltinTypes.Int); + right = right.ConvertImplicitly (rc.BuiltinTypes.Int); + return left != null && right != null; + } - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - return; + static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type) + { + Constant c = prim.ConvertImplicitly (type); + if (c != null) { + prim = c; + return true; + } - } else { - // - // Force conversions to int32 - // - if (!(left is IntConstant)) - left = left.ToInt (loc); - if (!(right is IntConstant)) - right = right.ToInt (loc); + if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) { + type = rc.BuiltinTypes.Long; + prim = prim.ConvertImplicitly (type); + second = second.ConvertImplicitly (type); + return prim != null && second != null; } - return; + + return false; } - internal static void Error_CompileTimeOverflow (Location loc) + internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc) { - Report.Error (220, loc, "The operation overflows at compile time in checked mode"); + rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode"); } /// @@ -172,270 +78,242 @@ namespace Mono.CSharp { /// /// Returns null if the expression can not be folded. /// - static public Expression 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) { + 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); - Type lt = left.Type; - Type rt = right.Type; - Type result_type = null; - bool bool_res; - - // - // Enumerator folding - // - if (rt == lt && left is EnumConstant) - result_type = lt; - - // - // During an enum evaluation, we need to unwrap enumerations - // - if (ec.InEnumContext){ - if (left is EnumConstant) - left = ((EnumConstant) left).Child; - - if (right is EnumConstant) - right = ((EnumConstant) right).Child; + if (right is SideEffectConstant) { + result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc); + if (result == null) + return null; + return new SideEffectConstant (result, right, loc); } - if (left is BoolConstant && right is BoolConstant) { - bool lv = ((BoolConstant) left ).Value; - bool rv = ((BoolConstant) right).Value; + TypeSpec lt = left.Type; + TypeSpec rt = right.Type; + bool bool_res; + + if (lt.BuiltinType == BuiltinTypeSpec.Type.Bool && lt == rt) { + bool lv = (bool) left.GetValue (); + bool rv = (bool) right.GetValue (); switch (oper) { case Binary.Operator.BitwiseAnd: case Binary.Operator.LogicalAnd: - return new BoolConstant (lv && rv, left.Location); + return new BoolConstant (ec.BuiltinTypes, lv && rv, left.Location); case Binary.Operator.BitwiseOr: case Binary.Operator.LogicalOr: - return new BoolConstant (lv || rv, left.Location); + return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location); case Binary.Operator.ExclusiveOr: - return new BoolConstant (lv ^ rv, left.Location); + return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location); case Binary.Operator.Equality: - return new BoolConstant (lv == rv, left.Location); + return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location); case Binary.Operator.Inequality: - return new BoolConstant (lv != rv, left.Location); + return new BoolConstant (ec.BuiltinTypes, lv != rv, left.Location); + } + return null; + } + + // + // During an enum evaluation, none of the rules are valid + // Not sure whether it is bug in csc or in documentation + // + if (ec.HasSet (ResolveContext.Options.EnumScope)){ + if (left is EnumConstant) + left = ((EnumConstant) left).Child; + + if (right is EnumConstant) + right = ((EnumConstant) right).Child; + } else if (left is EnumConstant && rt == lt) { + switch (oper){ + /// + /// E operator |(E x, E y); + /// E operator &(E x, E y); + /// E operator ^(E x, E y); + /// + case Binary.Operator.BitwiseOr: + case Binary.Operator.BitwiseAnd: + case Binary.Operator.ExclusiveOr: + result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc); + if (result != null) + result = result.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); + if (result != null) + result = result.TryReduce (ec, EnumSpec.GetUnderlyingType (lt), loc); + return result; + + /// + /// bool operator ==(E x, E y); + /// bool operator !=(E x, E y); + /// bool operator <(E x, E y); + /// bool operator >(E x, E y); + /// bool operator <=(E x, E y); + /// bool operator >=(E x, E y); + /// + case Binary.Operator.Equality: + case Binary.Operator.Inequality: + case Binary.Operator.LessThan: + case Binary.Operator.GreaterThan: + case Binary.Operator.LessThanOrEqual: + case Binary.Operator.GreaterThanOrEqual: + return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc); } return null; } - Type wrap_as; - Constant result = null; switch (oper){ case Binary.Operator.BitwiseOr: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + // + // bool? operator &(bool? x, bool? y); + // + if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) || + (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) { + var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + + // false | null => null + // null | false => null + if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue)) + return Nullable.LiftedNull.CreateFromExpression (ec, b); + + // true | null => true + // null | true => true + return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, true, loc), b); + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; if (left is IntConstant){ - IntConstant v; int res = ((IntConstant) left).Value | ((IntConstant) right).Value; - - v = new IntConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is UIntConstant){ - UIntConstant v; + + return new IntConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is UIntConstant){ uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value; - - v = new UIntConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is LongConstant){ - LongConstant v; + + return new UIntConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is LongConstant){ long res = ((LongConstant)left).Value | ((LongConstant)right).Value; - - v = new LongConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is ULongConstant){ - ULongConstant v; + + return new LongConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is ULongConstant){ ulong res = ((ULongConstant)left).Value | ((ULongConstant)right).Value; - - v = new ULongConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is UShortConstant){ - UShortConstant v; - ushort res = (ushort) (((UShortConstant)left).Value | - ((UShortConstant)right).Value); - - v = new UShortConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is ShortConstant){ - ShortConstant v; - short res = (short) (((ShortConstant)left).Value | - ((ShortConstant)right).Value); - - v = new ShortConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); + + return new ULongConstant (ec.BuiltinTypes, res, left.Location); } break; case Binary.Operator.BitwiseAnd: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + // + // bool? operator &(bool? x, bool? y); + // + if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) || + (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) { + var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + + // false & null => false + // null & false => false + if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue)) + return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, false, loc), b); + + // true & null => null + // null & true => null + return Nullable.LiftedNull.CreateFromExpression (ec, b); + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; + /// + /// int operator &(int x, int y); + /// uint operator &(uint x, uint y); + /// long operator &(long x, long y); + /// ulong operator &(ulong x, ulong y); + /// if (left is IntConstant){ - IntConstant v; int res = ((IntConstant) left).Value & ((IntConstant) right).Value; - - v = new IntConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is UIntConstant){ - UIntConstant v; + return new IntConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is UIntConstant){ uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value; - - v = new UIntConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is LongConstant){ - LongConstant v; + return new UIntConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is LongConstant){ long res = ((LongConstant)left).Value & ((LongConstant)right).Value; - - v = new LongConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is ULongConstant){ - ULongConstant v; + return new LongConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is ULongConstant){ ulong res = ((ULongConstant)left).Value & ((ULongConstant)right).Value; - - v = new ULongConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is UShortConstant){ - UShortConstant v; - ushort res = (ushort) (((UShortConstant)left).Value & - ((UShortConstant)right).Value); - - v = new UShortConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is ShortConstant){ - ShortConstant v; - short res = (short) (((ShortConstant)left).Value & - ((ShortConstant)right).Value); - - v = new ShortConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); + + return new ULongConstant (ec.BuiltinTypes, res, left.Location); } break; case Binary.Operator.ExclusiveOr: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; if (left is IntConstant){ - IntConstant v; int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value; - - v = new IntConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is UIntConstant){ - UIntConstant v; + return new IntConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is UIntConstant){ uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value; - - v = new UIntConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is LongConstant){ - LongConstant v; + + return new UIntConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is LongConstant){ long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value; - - v = new LongConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is ULongConstant){ - ULongConstant v; + + return new LongConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is ULongConstant){ ulong res = ((ULongConstant)left).Value ^ ((ULongConstant)right).Value; - - v = new ULongConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is UShortConstant){ - UShortConstant v; - ushort res = (ushort) (((UShortConstant)left).Value ^ - ((UShortConstant)right).Value); - - v = new UShortConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); - } else if (left is ShortConstant){ - ShortConstant v; - short res = (short)(((ShortConstant)left).Value ^ - ((ShortConstant)right).Value); - - v = new ShortConstant (res, left.Location); - if (result_type == null) - return v; - else - return new EnumConstant (v, result_type); + + return new ULongConstant (ec.BuiltinTypes, res, left.Location); } break; case Binary.Operator.Addition: - bool left_is_string = left is StringConstant; - bool right_is_string = right is StringConstant; + if (lt == InternalType.NullLiteral) + return right; + + if (rt == InternalType.NullLiteral) + return left; // // If both sides are strings, then concatenate, if // one is a string, and the other is not, then defer // to runtime concatenation // - wrap_as = null; - if (left_is_string || right_is_string){ - if (left_is_string && right_is_string) - return new StringConstant ( - ((StringConstant) left).Value + - ((StringConstant) right).Value, left.Location); + if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){ + if (lt == rt) + return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (), + left.Location); return null; } @@ -444,29 +322,32 @@ namespace Mono.CSharp { // handle "E operator + (E x, U y)" // handle "E operator + (Y y, E x)" // - // note that E operator + (E x, E y) is invalid - // - if (left is EnumConstant){ - if (right is EnumConstant){ - return null; + EnumConstant lc = left as EnumConstant; + EnumConstant rc = right as EnumConstant; + if (lc != null || rc != null){ + if (lc == null) { + lc = rc; + lt = lc.Type; + right = left; } - right = right.ToType (((EnumConstant) left).Child.Type); + // U has to be implicitly convetible to E.base + right = right.ConvertImplicitly (lc.Child.Type); if (right == null) return null; - wrap_as = left.Type; - } else if (right is EnumConstant){ - left = left.ToType (((EnumConstant) right).Child.Type); - if (left == null) + result = BinaryFold (ec, oper, lc.Child, right, loc); + if (result == null) + return null; + + result = result.TryReduce (ec, lt, loc); + if (result == null) return null; - wrap_as = right.Type; + return new EnumConstant (result, lt); } - result = null; - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; try { @@ -479,9 +360,10 @@ namespace Mono.CSharp { else res = unchecked (((DoubleConstant) left).Value + ((DoubleConstant) right).Value); - - result = new DoubleConstant (res, left.Location); - } else if (left is FloatConstant){ + + return new DoubleConstant (ec.BuiltinTypes, res, left.Location); + } + if (left is FloatConstant){ float res; if (ec.ConstantCheckState) @@ -490,8 +372,8 @@ namespace Mono.CSharp { else res = unchecked (((FloatConstant) left).Value + ((FloatConstant) right).Value); - - result = new FloatConstant (res, left.Location); + + result = new FloatConstant (ec.BuiltinTypes, res, left.Location); } else if (left is ULongConstant){ ulong res; @@ -502,7 +384,7 @@ namespace Mono.CSharp { res = unchecked (((ULongConstant) left).Value + ((ULongConstant) right).Value); - result = new ULongConstant (res, left.Location); + result = new ULongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is LongConstant){ long res; @@ -512,8 +394,8 @@ namespace Mono.CSharp { else res = unchecked (((LongConstant) left).Value + ((LongConstant) right).Value); - - result = new LongConstant (res, left.Location); + + result = new LongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is UIntConstant){ uint res; @@ -523,8 +405,8 @@ namespace Mono.CSharp { else res = unchecked (((UIntConstant) left).Value + ((UIntConstant) right).Value); - - result = new UIntConstant (res, left.Location); + + result = new UIntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is IntConstant){ int res; @@ -535,7 +417,7 @@ namespace Mono.CSharp { res = unchecked (((IntConstant) left).Value + ((IntConstant) right).Value); - result = new IntConstant (res, left.Location); + result = new IntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is DecimalConstant) { decimal res; @@ -546,65 +428,51 @@ namespace Mono.CSharp { res = unchecked (((DecimalConstant) left).Value + ((DecimalConstant) right).Value); - result = new DecimalConstant (res, left.Location); - } else { - throw new Exception ( "Unexepected addition input: " + left); + result = new DecimalConstant (ec.BuiltinTypes, res, left.Location); } } catch (OverflowException){ - Error_CompileTimeOverflow (loc); + Error_CompileTimeOverflow (ec, loc); } - if (wrap_as != null) { - try { - return result.TryReduce (ec, wrap_as, loc); - } - catch (OverflowException) { - return null; - } - } - else - return result; + return result; case Binary.Operator.Subtraction: // // handle "E operator - (E x, U y)" // handle "E operator - (Y y, E x)" - // handle "U operator - (E x, E y)" // - wrap_as = null; - if (left is EnumConstant){ - if (right is EnumConstant){ - if (left.Type != right.Type) { - Binary.Error_OperatorCannotBeApplied (loc, "-", left.Type, right.Type); - return null; - } - - wrap_as = TypeManager.EnumToUnderlying (left.Type); - right = ((EnumConstant) right).Child.ToType (wrap_as); - if (right == null) - return null; - - left = ((EnumConstant) left).Child.ToType (wrap_as); - if (left == null) - return null; + lc = left as EnumConstant; + rc = right as EnumConstant; + if (lc != null || rc != null){ + if (lc == null) { + lc = rc; + lt = lc.Type; + right = left; } - else { - right = right.ToType (((EnumConstant) left).Child.Type); - if (right == null) - return null; - wrap_as = left.Type; - } - } else if (right is EnumConstant){ - left = left.ToType (((EnumConstant) right).Child.Type); - if (left == null) + // U has to be implicitly convetible to E.base + right = right.ConvertImplicitly (lc.Child.Type); + if (right == null) + return null; + + result = BinaryFold (ec, oper, lc.Child, right, loc); + if (result == null) + return null; + + result = result.TryReduce (ec, lt, loc); + if (result == null) return null; - wrap_as = right.Type; + return new EnumConstant (result, lt); } - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (left is NullLiteral && right is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; try { @@ -617,8 +485,8 @@ namespace Mono.CSharp { else res = unchecked (((DoubleConstant) left).Value - ((DoubleConstant) right).Value); - - result = new DoubleConstant (res, left.Location); + + result = new DoubleConstant (ec.BuiltinTypes, res, left.Location); } else if (left is FloatConstant){ float res; @@ -628,8 +496,8 @@ namespace Mono.CSharp { else res = unchecked (((FloatConstant) left).Value - ((FloatConstant) right).Value); - - result = new FloatConstant (res, left.Location); + + result = new FloatConstant (ec.BuiltinTypes, res, left.Location); } else if (left is ULongConstant){ ulong res; @@ -639,8 +507,8 @@ namespace Mono.CSharp { else res = unchecked (((ULongConstant) left).Value - ((ULongConstant) right).Value); - - result = new ULongConstant (res, left.Location); + + result = new ULongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is LongConstant){ long res; @@ -650,8 +518,8 @@ namespace Mono.CSharp { else res = unchecked (((LongConstant) left).Value - ((LongConstant) right).Value); - - result = new LongConstant (res, left.Location); + + result = new LongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is UIntConstant){ uint res; @@ -661,8 +529,8 @@ namespace Mono.CSharp { else res = unchecked (((UIntConstant) left).Value - ((UIntConstant) right).Value); - - result = new UIntConstant (res, left.Location); + + result = new UIntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is IntConstant){ int res; @@ -673,7 +541,7 @@ namespace Mono.CSharp { res = unchecked (((IntConstant) left).Value - ((IntConstant) right).Value); - result = new IntConstant (res, left.Location); + result = new IntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is DecimalConstant) { decimal res; @@ -684,28 +552,24 @@ namespace Mono.CSharp { res = unchecked (((DecimalConstant) left).Value - ((DecimalConstant) right).Value); - return new DecimalConstant (res, left.Location); + return new DecimalConstant (ec.BuiltinTypes, res, left.Location); } else { throw new Exception ( "Unexepected subtraction input: " + left); } } catch (OverflowException){ - Error_CompileTimeOverflow (loc); - } - - if (wrap_as != null) { - try { - return result.TryReduce (ec, wrap_as, loc); - } - catch (OverflowException) { - return null; - } + Error_CompileTimeOverflow (ec, loc); } return result; case Binary.Operator.Multiply: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (left is NullLiteral && right is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; try { @@ -718,8 +582,8 @@ namespace Mono.CSharp { else res = unchecked (((DoubleConstant) left).Value * ((DoubleConstant) right).Value); - - return new DoubleConstant (res, left.Location); + + return new DoubleConstant (ec.BuiltinTypes, res, left.Location); } else if (left is FloatConstant){ float res; @@ -729,8 +593,8 @@ namespace Mono.CSharp { else res = unchecked (((FloatConstant) left).Value * ((FloatConstant) right).Value); - - return new FloatConstant (res, left.Location); + + return new FloatConstant (ec.BuiltinTypes, res, left.Location); } else if (left is ULongConstant){ ulong res; @@ -740,8 +604,8 @@ namespace Mono.CSharp { else res = unchecked (((ULongConstant) left).Value * ((ULongConstant) right).Value); - - return new ULongConstant (res, left.Location); + + return new ULongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is LongConstant){ long res; @@ -751,8 +615,8 @@ namespace Mono.CSharp { else res = unchecked (((LongConstant) left).Value * ((LongConstant) right).Value); - - return new LongConstant (res, left.Location); + + return new LongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is UIntConstant){ uint res; @@ -762,8 +626,8 @@ namespace Mono.CSharp { else res = unchecked (((UIntConstant) left).Value * ((UIntConstant) right).Value); - - return new UIntConstant (res, left.Location); + + return new UIntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is IntConstant){ int res; @@ -774,7 +638,7 @@ namespace Mono.CSharp { res = unchecked (((IntConstant) left).Value * ((IntConstant) right).Value); - return new IntConstant (res, left.Location); + return new IntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is DecimalConstant) { decimal res; @@ -785,18 +649,23 @@ namespace Mono.CSharp { res = unchecked (((DecimalConstant) left).Value * ((DecimalConstant) right).Value); - return new DecimalConstant (res, left.Location); + return new DecimalConstant (ec.BuiltinTypes, res, left.Location); } else { throw new Exception ( "Unexepected multiply input: " + left); } } catch (OverflowException){ - Error_CompileTimeOverflow (loc); + Error_CompileTimeOverflow (ec, loc); } break; case Binary.Operator.Division: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (left is NullLiteral && right is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; try { @@ -809,8 +678,8 @@ namespace Mono.CSharp { else res = unchecked (((DoubleConstant) left).Value / ((DoubleConstant) right).Value); - - return new DoubleConstant (res, left.Location); + + return new DoubleConstant (ec.BuiltinTypes, res, left.Location); } else if (left is FloatConstant){ float res; @@ -820,8 +689,8 @@ namespace Mono.CSharp { else res = unchecked (((FloatConstant) left).Value / ((FloatConstant) right).Value); - - return new FloatConstant (res, left.Location); + + return new FloatConstant (ec.BuiltinTypes, res, left.Location); } else if (left is ULongConstant){ ulong res; @@ -831,8 +700,8 @@ namespace Mono.CSharp { else res = unchecked (((ULongConstant) left).Value / ((ULongConstant) right).Value); - - return new ULongConstant (res, left.Location); + + return new ULongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is LongConstant){ long res; @@ -842,8 +711,8 @@ namespace Mono.CSharp { else res = unchecked (((LongConstant) left).Value / ((LongConstant) right).Value); - - return new LongConstant (res, left.Location); + + return new LongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is UIntConstant){ uint res; @@ -853,8 +722,8 @@ namespace Mono.CSharp { else res = unchecked (((UIntConstant) left).Value / ((UIntConstant) right).Value); - - return new UIntConstant (res, left.Location); + + return new UIntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is IntConstant){ int res; @@ -865,7 +734,7 @@ namespace Mono.CSharp { res = unchecked (((IntConstant) left).Value / ((IntConstant) right).Value); - return new IntConstant (res, left.Location); + return new IntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is DecimalConstant) { decimal res; @@ -876,22 +745,27 @@ namespace Mono.CSharp { res = unchecked (((DecimalConstant) left).Value / ((DecimalConstant) right).Value); - return new DecimalConstant (res, left.Location); + return new DecimalConstant (ec.BuiltinTypes, res, left.Location); } else { 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: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (left is NullLiteral && right is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; try { @@ -904,8 +778,8 @@ namespace Mono.CSharp { else res = unchecked (((DoubleConstant) left).Value % ((DoubleConstant) right).Value); - - return new DoubleConstant (res, left.Location); + + return new DoubleConstant (ec.BuiltinTypes, res, left.Location); } else if (left is FloatConstant){ float res; @@ -915,8 +789,8 @@ namespace Mono.CSharp { else res = unchecked (((FloatConstant) left).Value % ((FloatConstant) right).Value); - - return new FloatConstant (res, left.Location); + + return new FloatConstant (ec.BuiltinTypes, res, left.Location); } else if (left is ULongConstant){ ulong res; @@ -926,8 +800,8 @@ namespace Mono.CSharp { else res = unchecked (((ULongConstant) left).Value % ((ULongConstant) right).Value); - - return new ULongConstant (res, left.Location); + + return new ULongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is LongConstant){ long res; @@ -937,8 +811,8 @@ namespace Mono.CSharp { else res = unchecked (((LongConstant) left).Value % ((LongConstant) right).Value); - - return new LongConstant (res, left.Location); + + return new LongConstant (ec.BuiltinTypes, res, left.Location); } else if (left is UIntConstant){ uint res; @@ -948,8 +822,8 @@ namespace Mono.CSharp { else res = unchecked (((UIntConstant) left).Value % ((UIntConstant) right).Value); - - return new UIntConstant (res, left.Location); + + return new UIntConstant (ec.BuiltinTypes, res, left.Location); } else if (left is IntConstant){ int res; @@ -960,14 +834,14 @@ namespace Mono.CSharp { res = unchecked (((IntConstant) left).Value % ((IntConstant) right).Value); - return new IntConstant (res, left.Location); + return new IntConstant (ec.BuiltinTypes, res, left.Location); } else { 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; @@ -975,85 +849,93 @@ namespace Mono.CSharp { // There is no overflow checking on left shift // case Binary.Operator.LeftShift: - IntConstant ic = right.ToInt (loc); + if (left is NullLiteral && right is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant; if (ic == null){ - Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt); + Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); return null; } - int lshift_val = ic.Value; - IntConstant lic; - if ((lic = left.ConvertToInt ()) != null) - return new IntConstant (lic.Value << lshift_val, left.Location); - - UIntConstant luic; - if ((luic = left.ConvertToUInt ()) != null) - return new UIntConstant (luic.Value << lshift_val, left.Location); + int lshift_val = ic.Value; + switch (left.Type.BuiltinType) { + case BuiltinTypeSpec.Type.ULong: + return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location); + case BuiltinTypeSpec.Type.Long: + return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location); + case BuiltinTypeSpec.Type.UInt: + return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location); + } - LongConstant llc; - if ((llc = left.ConvertToLong ()) != null) - return new LongConstant (llc.Value << lshift_val, left.Location); + // null << value => null + if (left is NullLiteral) + return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); - ULongConstant lulc; - if ((lulc = left.ConvertToULong ()) != null) - return new ULongConstant (lulc.Value << lshift_val, left.Location); + left = left.ConvertImplicitly (ec.BuiltinTypes.Int); + if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int) + return new IntConstant (ec.BuiltinTypes, ((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.ToInt (loc); + if (left is NullLiteral && right is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) 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; + switch (left.Type.BuiltinType) { + case BuiltinTypeSpec.Type.ULong: + return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location); + case BuiltinTypeSpec.Type.Long: + return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location); + case BuiltinTypeSpec.Type.UInt: + return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location); + } - IntConstant ric; - if ((ric = left.ConvertToInt ()) != null) - return new IntConstant (ric.Value >> rshift_val, left.Location); - - UIntConstant ruic; - if ((ruic = left.ConvertToUInt ()) != null) - return new UIntConstant (ruic.Value >> rshift_val, left.Location); - - LongConstant rlc; - if ((rlc = left.ConvertToLong ()) != null) - return new LongConstant (rlc.Value >> rshift_val, left.Location); + // null >> value => null + if (left is NullLiteral) + return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); - ULongConstant rulc; - if ((rulc = left.ConvertToULong ()) != null) - return new ULongConstant (rulc.Value >> rshift_val, left.Location); + left = left.ConvertImplicitly (ec.BuiltinTypes.Int); + if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int) + return new IntConstant (ec.BuiltinTypes, ((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) - 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); - + if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) || + (left is Nullable.LiftedNull && right.IsNull) || + (right is Nullable.LiftedNull && left.IsNull)) { + if (left.IsNull || right.IsNull) { + return ReducedExpression.Create ( + new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location), + new Binary (oper, left, right, loc)); + } + + if (left is StringConstant && right is StringConstant) + return new BoolConstant (ec.BuiltinTypes, + ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location); + + return null; } - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; bool_res = false; @@ -1078,30 +960,26 @@ namespace Mono.CSharp { else return null; - return new BoolConstant (bool_res, left.Location); + return new BoolConstant (ec.BuiltinTypes, 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) - 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); - + if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) || + (left is Nullable.LiftedNull && right.IsNull) || + (right is Nullable.LiftedNull && left.IsNull)) { + if (left.IsNull || right.IsNull) { + return ReducedExpression.Create ( + new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location), + new Binary (oper, left, right, loc)); + } + + if (left is StringConstant && right is StringConstant) + return new BoolConstant (ec.BuiltinTypes, + ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location); + + return null; } - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; bool_res = false; @@ -1126,11 +1004,22 @@ namespace Mono.CSharp { else return null; - return new BoolConstant (bool_res, left.Location); + return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); case Binary.Operator.LessThan: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (right is NullLiteral) { + if (left is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (left is Nullable.LiftedNull) { + return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + } + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; bool_res = false; @@ -1155,11 +1044,22 @@ namespace Mono.CSharp { else return null; - return new BoolConstant (bool_res, left.Location); + return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); case Binary.Operator.GreaterThan: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (right is NullLiteral) { + if (left is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (left is Nullable.LiftedNull) { + return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + } + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; bool_res = false; @@ -1184,11 +1084,22 @@ namespace Mono.CSharp { else return null; - return new BoolConstant (bool_res, left.Location); + return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); case Binary.Operator.GreaterThanOrEqual: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (right is NullLiteral) { + if (left is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (left is Nullable.LiftedNull) { + return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + } + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; bool_res = false; @@ -1213,11 +1124,22 @@ namespace Mono.CSharp { else return null; - return new BoolConstant (bool_res, left.Location); + return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); case Binary.Operator.LessThanOrEqual: - DoConstantNumericPromotions (ec, oper, ref left, ref right, loc); - if (left == null || right == null) + if (right is NullLiteral) { + if (left is NullLiteral) { + var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc); + lifted_int.ResolveAsType (ec); + return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec); + } + + if (left is Nullable.LiftedNull) { + return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + } + } + + if (!DoBinaryNumericPromotions (ec, ref left, ref right)) return null; bool_res = false; @@ -1242,7 +1164,7 @@ namespace Mono.CSharp { else return null; - return new BoolConstant (bool_res, left.Location); + return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location); } return null;