2 // cfold.cs: Constant Folding
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2011, Novell, Inc.
13 namespace Mono.CSharp {
15 public static class ConstantFold
17 public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types)
19 return new TypeSpec[] {
20 types.Decimal, types.Double, types.Float,
21 types.ULong, types.Long, types.UInt
26 // Performs the numeric promotions on the left and right expresions
27 // and deposits the results on `lc' and `rc'.
29 // On success, the types of `lc' and `rc' on output will always match,
30 // and the pair will be one of:
32 // TODO: BinaryFold should be called as an optimization step only,
33 // error checking here is weak
35 static bool DoBinaryNumericPromotions (ResolveContext rc, ref Constant left, ref Constant right)
37 TypeSpec ltype = left.Type;
38 TypeSpec rtype = right.Type;
40 foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) {
42 return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
45 return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
48 left = left.ConvertImplicitly (rc.BuiltinTypes.Int);
49 right = right.ConvertImplicitly (rc.BuiltinTypes.Int);
50 return left != null && right != null;
53 static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
55 Constant c = prim.ConvertImplicitly (type);
61 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
62 type = rc.BuiltinTypes.Long;
63 prim = prim.ConvertImplicitly (type);
64 second = second.ConvertImplicitly (type);
65 return prim != null && second != null;
71 internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc)
73 rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode");
77 /// Constant expression folder for binary operations.
79 /// Returns null if the expression can not be folded.
81 static public Constant BinaryFold (ResolveContext ec, Binary.Operator oper,
82 Constant left, Constant right, Location loc)
84 Constant result = null;
86 if (left is EmptyConstantCast)
87 return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
89 if (left is SideEffectConstant) {
90 result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc);
93 return new SideEffectConstant (result, left, loc);
96 if (right is EmptyConstantCast)
97 return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
99 if (right is SideEffectConstant) {
100 result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc);
103 return new SideEffectConstant (result, right, loc);
106 TypeSpec lt = left.Type;
107 TypeSpec rt = right.Type;
110 if (lt.BuiltinType == BuiltinTypeSpec.Type.Bool && lt == rt) {
111 bool lv = (bool) left.GetValue ();
112 bool rv = (bool) right.GetValue ();
114 case Binary.Operator.BitwiseAnd:
115 case Binary.Operator.LogicalAnd:
116 return new BoolConstant (ec.BuiltinTypes, lv && rv, left.Location);
117 case Binary.Operator.BitwiseOr:
118 case Binary.Operator.LogicalOr:
119 return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location);
120 case Binary.Operator.ExclusiveOr:
121 return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location);
122 case Binary.Operator.Equality:
123 return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location);
124 case Binary.Operator.Inequality:
125 return new BoolConstant (ec.BuiltinTypes, lv != rv, left.Location);
131 // During an enum evaluation, none of the rules are valid
132 // Not sure whether it is bug in csc or in documentation
134 if (ec.HasSet (ResolveContext.Options.EnumScope)){
135 if (left is EnumConstant)
136 left = ((EnumConstant) left).Child;
138 if (right is EnumConstant)
139 right = ((EnumConstant) right).Child;
140 } else if (left is EnumConstant && rt == lt) {
143 /// E operator |(E x, E y);
144 /// E operator &(E x, E y);
145 /// E operator ^(E x, E y);
147 case Binary.Operator.BitwiseOr:
148 case Binary.Operator.BitwiseAnd:
149 case Binary.Operator.ExclusiveOr:
150 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
152 result = result.Reduce (ec, lt);
156 /// U operator -(E x, E y);
158 case Binary.Operator.Subtraction:
159 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
161 result = result.Reduce (ec, EnumSpec.GetUnderlyingType (lt));
165 /// bool operator ==(E x, E y);
166 /// bool operator !=(E x, E y);
167 /// bool operator <(E x, E y);
168 /// bool operator >(E x, E y);
169 /// bool operator <=(E x, E y);
170 /// bool operator >=(E x, E y);
172 case Binary.Operator.Equality:
173 case Binary.Operator.Inequality:
174 case Binary.Operator.LessThan:
175 case Binary.Operator.GreaterThan:
176 case Binary.Operator.LessThanOrEqual:
177 case Binary.Operator.GreaterThanOrEqual:
178 return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
184 case Binary.Operator.BitwiseOr:
186 // bool? operator |(bool? x, bool? y);
188 if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
189 (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
190 var b = new Binary (oper, left, right).ResolveOperator (ec);
192 // false | null => null
193 // null | false => null
194 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
195 return Nullable.LiftedNull.CreateFromExpression (ec, b);
197 // true | null => true
198 // null | true => true
199 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, true, loc), b);
202 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
205 if (left is IntConstant){
206 int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
208 return new IntConstant (ec.BuiltinTypes, res, left.Location);
210 if (left is UIntConstant){
211 uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
213 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
215 if (left is LongConstant){
216 long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
218 return new LongConstant (ec.BuiltinTypes, res, left.Location);
220 if (left is ULongConstant){
221 ulong res = ((ULongConstant)left).Value |
222 ((ULongConstant)right).Value;
224 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
228 case Binary.Operator.BitwiseAnd:
230 // bool? operator &(bool? x, bool? y);
232 if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
233 (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
234 var b = new Binary (oper, left, right).ResolveOperator (ec);
236 // false & null => false
237 // null & false => false
238 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
239 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, false, loc), b);
241 // true & null => null
242 // null & true => null
243 return Nullable.LiftedNull.CreateFromExpression (ec, b);
246 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
250 /// int operator &(int x, int y);
251 /// uint operator &(uint x, uint y);
252 /// long operator &(long x, long y);
253 /// ulong operator &(ulong x, ulong y);
255 if (left is IntConstant){
256 int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
257 return new IntConstant (ec.BuiltinTypes, res, left.Location);
259 if (left is UIntConstant){
260 uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
261 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
263 if (left is LongConstant){
264 long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
265 return new LongConstant (ec.BuiltinTypes, res, left.Location);
267 if (left is ULongConstant){
268 ulong res = ((ULongConstant)left).Value &
269 ((ULongConstant)right).Value;
271 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
275 case Binary.Operator.ExclusiveOr:
276 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
279 if (left is IntConstant){
280 int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
281 return new IntConstant (ec.BuiltinTypes, res, left.Location);
283 if (left is UIntConstant){
284 uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
286 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
288 if (left is LongConstant){
289 long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
291 return new LongConstant (ec.BuiltinTypes, res, left.Location);
293 if (left is ULongConstant){
294 ulong res = ((ULongConstant)left).Value ^
295 ((ULongConstant)right).Value;
297 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
301 case Binary.Operator.Addition:
303 // If both sides are strings, then concatenate
305 // string operator + (string x, string y)
307 if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
309 return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
312 if (lt == InternalType.NullLiteral || left.IsNull)
313 return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
315 if (rt == InternalType.NullLiteral || right.IsNull)
316 return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location);
322 // string operator + (string x, object y)
324 if (lt == InternalType.NullLiteral) {
325 if (rt.BuiltinType == BuiltinTypeSpec.Type.Object)
326 return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
329 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
330 "+", lt.GetSignatureForError (), rt.GetSignatureForError ());
338 // string operator + (object x, string y)
340 if (rt == InternalType.NullLiteral) {
341 if (lt.BuiltinType == BuiltinTypeSpec.Type.Object)
342 return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location);
348 // handle "E operator + (E x, U y)"
349 // handle "E operator + (Y y, E x)"
351 EnumConstant lc = left as EnumConstant;
352 EnumConstant rc = right as EnumConstant;
353 if (lc != null || rc != null){
360 // U has to be implicitly convetible to E.base
361 right = right.ConvertImplicitly (lc.Child.Type);
365 result = BinaryFold (ec, oper, lc.Child, right, loc);
369 result = result.Reduce (ec, lt);
370 if (result == null || lt.IsEnum)
373 return new EnumConstant (result, lt);
376 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
380 if (left is DoubleConstant){
383 if (ec.ConstantCheckState)
384 res = checked (((DoubleConstant) left).Value +
385 ((DoubleConstant) right).Value);
387 res = unchecked (((DoubleConstant) left).Value +
388 ((DoubleConstant) right).Value);
390 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
392 if (left is FloatConstant){
394 a = ((FloatConstant) left).DoubleValue;
395 b = ((FloatConstant) right).DoubleValue;
397 if (ec.ConstantCheckState)
398 res = checked (a + b);
400 res = unchecked (a + b);
402 result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
403 } else if (left is ULongConstant){
406 if (ec.ConstantCheckState)
407 res = checked (((ULongConstant) left).Value +
408 ((ULongConstant) right).Value);
410 res = unchecked (((ULongConstant) left).Value +
411 ((ULongConstant) right).Value);
413 result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
414 } else if (left is LongConstant){
417 if (ec.ConstantCheckState)
418 res = checked (((LongConstant) left).Value +
419 ((LongConstant) right).Value);
421 res = unchecked (((LongConstant) left).Value +
422 ((LongConstant) right).Value);
424 result = new LongConstant (ec.BuiltinTypes, res, left.Location);
425 } else if (left is UIntConstant){
428 if (ec.ConstantCheckState)
429 res = checked (((UIntConstant) left).Value +
430 ((UIntConstant) right).Value);
432 res = unchecked (((UIntConstant) left).Value +
433 ((UIntConstant) right).Value);
435 result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
436 } else if (left is IntConstant){
439 if (ec.ConstantCheckState)
440 res = checked (((IntConstant) left).Value +
441 ((IntConstant) right).Value);
443 res = unchecked (((IntConstant) left).Value +
444 ((IntConstant) right).Value);
446 result = new IntConstant (ec.BuiltinTypes, res, left.Location);
447 } else if (left is DecimalConstant) {
450 if (ec.ConstantCheckState)
451 res = checked (((DecimalConstant) left).Value +
452 ((DecimalConstant) right).Value);
454 res = unchecked (((DecimalConstant) left).Value +
455 ((DecimalConstant) right).Value);
457 result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
459 } catch (OverflowException){
460 Error_CompileTimeOverflow (ec, loc);
465 case Binary.Operator.Subtraction:
467 // handle "E operator - (E x, U y)"
468 // handle "E operator - (Y y, E x)"
470 lc = left as EnumConstant;
471 rc = right as EnumConstant;
472 if (lc != null || rc != null){
479 // U has to be implicitly convetible to E.base
480 right = right.ConvertImplicitly (lc.Child.Type);
484 result = BinaryFold (ec, oper, lc.Child, right, loc);
488 result = result.Reduce (ec, lt);
492 return new EnumConstant (result, lt);
495 if (left is NullLiteral && right is NullLiteral) {
496 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
497 lifted_int.ResolveAsType (ec);
498 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
501 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
505 if (left is DoubleConstant){
508 if (ec.ConstantCheckState)
509 res = checked (((DoubleConstant) left).Value -
510 ((DoubleConstant) right).Value);
512 res = unchecked (((DoubleConstant) left).Value -
513 ((DoubleConstant) right).Value);
515 result = new DoubleConstant (ec.BuiltinTypes, res, left.Location);
516 } else if (left is FloatConstant){
518 a = ((FloatConstant) left).DoubleValue;
519 b = ((FloatConstant) right).DoubleValue;
521 if (ec.ConstantCheckState)
522 res = checked (a - b);
524 res = unchecked (a - b);
526 result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
527 } else if (left is ULongConstant){
530 if (ec.ConstantCheckState)
531 res = checked (((ULongConstant) left).Value -
532 ((ULongConstant) right).Value);
534 res = unchecked (((ULongConstant) left).Value -
535 ((ULongConstant) right).Value);
537 result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
538 } else if (left is LongConstant){
541 if (ec.ConstantCheckState)
542 res = checked (((LongConstant) left).Value -
543 ((LongConstant) right).Value);
545 res = unchecked (((LongConstant) left).Value -
546 ((LongConstant) right).Value);
548 result = new LongConstant (ec.BuiltinTypes, res, left.Location);
549 } else if (left is UIntConstant){
552 if (ec.ConstantCheckState)
553 res = checked (((UIntConstant) left).Value -
554 ((UIntConstant) right).Value);
556 res = unchecked (((UIntConstant) left).Value -
557 ((UIntConstant) right).Value);
559 result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
560 } else if (left is IntConstant){
563 if (ec.ConstantCheckState)
564 res = checked (((IntConstant) left).Value -
565 ((IntConstant) right).Value);
567 res = unchecked (((IntConstant) left).Value -
568 ((IntConstant) right).Value);
570 result = new IntConstant (ec.BuiltinTypes, res, left.Location);
571 } else if (left is DecimalConstant) {
574 if (ec.ConstantCheckState)
575 res = checked (((DecimalConstant) left).Value -
576 ((DecimalConstant) right).Value);
578 res = unchecked (((DecimalConstant) left).Value -
579 ((DecimalConstant) right).Value);
581 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
583 throw new Exception ( "Unexepected subtraction input: " + left);
585 } catch (OverflowException){
586 Error_CompileTimeOverflow (ec, loc);
591 case Binary.Operator.Multiply:
592 if (left is NullLiteral && right is NullLiteral) {
593 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
594 lifted_int.ResolveAsType (ec);
595 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
598 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
602 if (left is DoubleConstant){
605 if (ec.ConstantCheckState)
606 res = checked (((DoubleConstant) left).Value *
607 ((DoubleConstant) right).Value);
609 res = unchecked (((DoubleConstant) left).Value *
610 ((DoubleConstant) right).Value);
612 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
613 } else if (left is FloatConstant){
615 a = ((FloatConstant) left).DoubleValue;
616 b = ((FloatConstant) right).DoubleValue;
618 if (ec.ConstantCheckState)
619 res = checked (a * b);
621 res = unchecked (a * b);
623 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
624 } else if (left is ULongConstant){
627 if (ec.ConstantCheckState)
628 res = checked (((ULongConstant) left).Value *
629 ((ULongConstant) right).Value);
631 res = unchecked (((ULongConstant) left).Value *
632 ((ULongConstant) right).Value);
634 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
635 } else if (left is LongConstant){
638 if (ec.ConstantCheckState)
639 res = checked (((LongConstant) left).Value *
640 ((LongConstant) right).Value);
642 res = unchecked (((LongConstant) left).Value *
643 ((LongConstant) right).Value);
645 return new LongConstant (ec.BuiltinTypes, res, left.Location);
646 } else if (left is UIntConstant){
649 if (ec.ConstantCheckState)
650 res = checked (((UIntConstant) left).Value *
651 ((UIntConstant) right).Value);
653 res = unchecked (((UIntConstant) left).Value *
654 ((UIntConstant) right).Value);
656 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
657 } else if (left is IntConstant){
660 if (ec.ConstantCheckState)
661 res = checked (((IntConstant) left).Value *
662 ((IntConstant) right).Value);
664 res = unchecked (((IntConstant) left).Value *
665 ((IntConstant) right).Value);
667 return new IntConstant (ec.BuiltinTypes, res, left.Location);
668 } else if (left is DecimalConstant) {
671 if (ec.ConstantCheckState)
672 res = checked (((DecimalConstant) left).Value *
673 ((DecimalConstant) right).Value);
675 res = unchecked (((DecimalConstant) left).Value *
676 ((DecimalConstant) right).Value);
678 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
680 throw new Exception ( "Unexepected multiply input: " + left);
682 } catch (OverflowException){
683 Error_CompileTimeOverflow (ec, loc);
687 case Binary.Operator.Division:
688 if (left is NullLiteral && right is NullLiteral) {
689 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
690 lifted_int.ResolveAsType (ec);
691 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
694 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
698 if (left is DoubleConstant){
701 if (ec.ConstantCheckState)
702 res = checked (((DoubleConstant) left).Value /
703 ((DoubleConstant) right).Value);
705 res = unchecked (((DoubleConstant) left).Value /
706 ((DoubleConstant) right).Value);
708 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
709 } else if (left is FloatConstant){
711 a = ((FloatConstant) left).DoubleValue;
712 b = ((FloatConstant) right).DoubleValue;
714 if (ec.ConstantCheckState)
715 res = checked (a / b);
717 res = unchecked (a / b);
719 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
720 } else if (left is ULongConstant){
723 if (ec.ConstantCheckState)
724 res = checked (((ULongConstant) left).Value /
725 ((ULongConstant) right).Value);
727 res = unchecked (((ULongConstant) left).Value /
728 ((ULongConstant) right).Value);
730 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
731 } else if (left is LongConstant){
734 if (ec.ConstantCheckState)
735 res = checked (((LongConstant) left).Value /
736 ((LongConstant) right).Value);
738 res = unchecked (((LongConstant) left).Value /
739 ((LongConstant) right).Value);
741 return new LongConstant (ec.BuiltinTypes, res, left.Location);
742 } else if (left is UIntConstant){
745 if (ec.ConstantCheckState)
746 res = checked (((UIntConstant) left).Value /
747 ((UIntConstant) right).Value);
749 res = unchecked (((UIntConstant) left).Value /
750 ((UIntConstant) right).Value);
752 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
753 } else if (left is IntConstant){
756 if (ec.ConstantCheckState)
757 res = checked (((IntConstant) left).Value /
758 ((IntConstant) right).Value);
760 res = unchecked (((IntConstant) left).Value /
761 ((IntConstant) right).Value);
763 return new IntConstant (ec.BuiltinTypes, res, left.Location);
764 } else if (left is DecimalConstant) {
767 if (ec.ConstantCheckState)
768 res = checked (((DecimalConstant) left).Value /
769 ((DecimalConstant) right).Value);
771 res = unchecked (((DecimalConstant) left).Value /
772 ((DecimalConstant) right).Value);
774 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
776 throw new Exception ( "Unexepected division input: " + left);
778 } catch (OverflowException){
779 Error_CompileTimeOverflow (ec, loc);
781 } catch (DivideByZeroException) {
782 ec.Report.Error (20, loc, "Division by constant zero");
787 case Binary.Operator.Modulus:
788 if (left is NullLiteral && right is NullLiteral) {
789 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
790 lifted_int.ResolveAsType (ec);
791 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
794 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
798 if (left is DoubleConstant){
801 if (ec.ConstantCheckState)
802 res = checked (((DoubleConstant) left).Value %
803 ((DoubleConstant) right).Value);
805 res = unchecked (((DoubleConstant) left).Value %
806 ((DoubleConstant) right).Value);
808 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
809 } else if (left is FloatConstant){
811 a = ((FloatConstant) left).DoubleValue;
812 b = ((FloatConstant) right).DoubleValue;
814 if (ec.ConstantCheckState)
815 res = checked (a % b);
817 res = unchecked (a % b);
819 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
820 } else if (left is ULongConstant){
823 if (ec.ConstantCheckState)
824 res = checked (((ULongConstant) left).Value %
825 ((ULongConstant) right).Value);
827 res = unchecked (((ULongConstant) left).Value %
828 ((ULongConstant) right).Value);
830 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
831 } else if (left is LongConstant){
834 if (ec.ConstantCheckState)
835 res = checked (((LongConstant) left).Value %
836 ((LongConstant) right).Value);
838 res = unchecked (((LongConstant) left).Value %
839 ((LongConstant) right).Value);
841 return new LongConstant (ec.BuiltinTypes, res, left.Location);
842 } else if (left is UIntConstant){
845 if (ec.ConstantCheckState)
846 res = checked (((UIntConstant) left).Value %
847 ((UIntConstant) right).Value);
849 res = unchecked (((UIntConstant) left).Value %
850 ((UIntConstant) right).Value);
852 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
853 } else if (left is IntConstant){
856 if (ec.ConstantCheckState)
857 res = checked (((IntConstant) left).Value %
858 ((IntConstant) right).Value);
860 res = unchecked (((IntConstant) left).Value %
861 ((IntConstant) right).Value);
863 return new IntConstant (ec.BuiltinTypes, res, left.Location);
866 if (left is DecimalConstant) {
869 if (ec.ConstantCheckState)
870 res = checked (((DecimalConstant) left).Value %
871 ((DecimalConstant) right).Value);
873 res = unchecked (((DecimalConstant) left).Value %
874 ((DecimalConstant) right).Value);
876 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
879 throw new Exception ( "Unexepected modulus input: " + left);
880 } catch (DivideByZeroException){
881 ec.Report.Error (20, loc, "Division by constant zero");
882 } catch (OverflowException){
883 Error_CompileTimeOverflow (ec, loc);
888 // There is no overflow checking on left shift
890 case Binary.Operator.LeftShift:
891 if (left is NullLiteral && right is NullLiteral) {
892 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
893 lifted_int.ResolveAsType (ec);
894 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
897 IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
902 int lshift_val = ic.Value;
903 switch (left.Type.BuiltinType) {
904 case BuiltinTypeSpec.Type.ULong:
905 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location);
906 case BuiltinTypeSpec.Type.Long:
907 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location);
908 case BuiltinTypeSpec.Type.UInt:
909 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location);
912 // null << value => null
913 if (left is NullLiteral)
914 return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
916 left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
917 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
918 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location);
923 // There is no overflow checking on right shift
925 case Binary.Operator.RightShift:
926 if (left is NullLiteral && right is NullLiteral) {
927 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
928 lifted_int.ResolveAsType (ec);
929 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
932 IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
936 int rshift_val = sic.Value;
937 switch (left.Type.BuiltinType) {
938 case BuiltinTypeSpec.Type.ULong:
939 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location);
940 case BuiltinTypeSpec.Type.Long:
941 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location);
942 case BuiltinTypeSpec.Type.UInt:
943 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location);
946 // null >> value => null
947 if (left is NullLiteral)
948 return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
950 left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
951 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
952 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location);
956 case Binary.Operator.Equality:
957 if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
958 (left is Nullable.LiftedNull && right.IsNull) ||
959 (right is Nullable.LiftedNull && left.IsNull)) {
960 if (left.IsNull || right.IsNull) {
961 return ReducedExpression.Create (
962 new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
963 new Binary (oper, left, right));
966 if (left is StringConstant && right is StringConstant)
967 return new BoolConstant (ec.BuiltinTypes,
968 ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
973 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
977 if (left is DoubleConstant)
978 bool_res = ((DoubleConstant) left).Value ==
979 ((DoubleConstant) right).Value;
980 else if (left is FloatConstant)
981 bool_res = ((FloatConstant) left).DoubleValue ==
982 ((FloatConstant) right).DoubleValue;
983 else if (left is ULongConstant)
984 bool_res = ((ULongConstant) left).Value ==
985 ((ULongConstant) right).Value;
986 else if (left is LongConstant)
987 bool_res = ((LongConstant) left).Value ==
988 ((LongConstant) right).Value;
989 else if (left is UIntConstant)
990 bool_res = ((UIntConstant) left).Value ==
991 ((UIntConstant) right).Value;
992 else if (left is IntConstant)
993 bool_res = ((IntConstant) left).Value ==
994 ((IntConstant) right).Value;
998 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1000 case Binary.Operator.Inequality:
1001 if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
1002 (left is Nullable.LiftedNull && right.IsNull) ||
1003 (right is Nullable.LiftedNull && left.IsNull)) {
1004 if (left.IsNull || right.IsNull) {
1005 return ReducedExpression.Create (
1006 new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
1007 new Binary (oper, left, right));
1010 if (left is StringConstant && right is StringConstant)
1011 return new BoolConstant (ec.BuiltinTypes,
1012 ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
1017 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1021 if (left is DoubleConstant)
1022 bool_res = ((DoubleConstant) left).Value !=
1023 ((DoubleConstant) right).Value;
1024 else if (left is FloatConstant)
1025 bool_res = ((FloatConstant) left).DoubleValue !=
1026 ((FloatConstant) right).DoubleValue;
1027 else if (left is ULongConstant)
1028 bool_res = ((ULongConstant) left).Value !=
1029 ((ULongConstant) right).Value;
1030 else if (left is LongConstant)
1031 bool_res = ((LongConstant) left).Value !=
1032 ((LongConstant) right).Value;
1033 else if (left is UIntConstant)
1034 bool_res = ((UIntConstant) left).Value !=
1035 ((UIntConstant) right).Value;
1036 else if (left is IntConstant)
1037 bool_res = ((IntConstant) left).Value !=
1038 ((IntConstant) right).Value;
1042 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1044 case Binary.Operator.LessThan:
1045 if (right is NullLiteral) {
1046 if (left is NullLiteral) {
1047 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1048 lifted_int.ResolveAsType (ec);
1049 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1053 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1057 if (left is DoubleConstant)
1058 bool_res = ((DoubleConstant) left).Value <
1059 ((DoubleConstant) right).Value;
1060 else if (left is FloatConstant)
1061 bool_res = ((FloatConstant) left).DoubleValue <
1062 ((FloatConstant) right).DoubleValue;
1063 else if (left is ULongConstant)
1064 bool_res = ((ULongConstant) left).Value <
1065 ((ULongConstant) right).Value;
1066 else if (left is LongConstant)
1067 bool_res = ((LongConstant) left).Value <
1068 ((LongConstant) right).Value;
1069 else if (left is UIntConstant)
1070 bool_res = ((UIntConstant) left).Value <
1071 ((UIntConstant) right).Value;
1072 else if (left is IntConstant)
1073 bool_res = ((IntConstant) left).Value <
1074 ((IntConstant) right).Value;
1078 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1080 case Binary.Operator.GreaterThan:
1081 if (right is NullLiteral) {
1082 if (left is NullLiteral) {
1083 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1084 lifted_int.ResolveAsType (ec);
1085 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1089 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1093 if (left is DoubleConstant)
1094 bool_res = ((DoubleConstant) left).Value >
1095 ((DoubleConstant) right).Value;
1096 else if (left is FloatConstant)
1097 bool_res = ((FloatConstant) left).DoubleValue >
1098 ((FloatConstant) right).DoubleValue;
1099 else if (left is ULongConstant)
1100 bool_res = ((ULongConstant) left).Value >
1101 ((ULongConstant) right).Value;
1102 else if (left is LongConstant)
1103 bool_res = ((LongConstant) left).Value >
1104 ((LongConstant) right).Value;
1105 else if (left is UIntConstant)
1106 bool_res = ((UIntConstant) left).Value >
1107 ((UIntConstant) right).Value;
1108 else if (left is IntConstant)
1109 bool_res = ((IntConstant) left).Value >
1110 ((IntConstant) right).Value;
1114 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1116 case Binary.Operator.GreaterThanOrEqual:
1117 if (right is NullLiteral) {
1118 if (left is NullLiteral) {
1119 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1120 lifted_int.ResolveAsType (ec);
1121 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1125 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1129 if (left is DoubleConstant)
1130 bool_res = ((DoubleConstant) left).Value >=
1131 ((DoubleConstant) right).Value;
1132 else if (left is FloatConstant)
1133 bool_res = ((FloatConstant) left).DoubleValue >=
1134 ((FloatConstant) right).DoubleValue;
1135 else if (left is ULongConstant)
1136 bool_res = ((ULongConstant) left).Value >=
1137 ((ULongConstant) right).Value;
1138 else if (left is LongConstant)
1139 bool_res = ((LongConstant) left).Value >=
1140 ((LongConstant) right).Value;
1141 else if (left is UIntConstant)
1142 bool_res = ((UIntConstant) left).Value >=
1143 ((UIntConstant) right).Value;
1144 else if (left is IntConstant)
1145 bool_res = ((IntConstant) left).Value >=
1146 ((IntConstant) right).Value;
1150 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1152 case Binary.Operator.LessThanOrEqual:
1153 if (right is NullLiteral) {
1154 if (left is NullLiteral) {
1155 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1156 lifted_int.ResolveAsType (ec);
1157 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1161 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1165 if (left is DoubleConstant)
1166 bool_res = ((DoubleConstant) left).Value <=
1167 ((DoubleConstant) right).Value;
1168 else if (left is FloatConstant)
1169 bool_res = ((FloatConstant) left).DoubleValue <=
1170 ((FloatConstant) right).DoubleValue;
1171 else if (left is ULongConstant)
1172 bool_res = ((ULongConstant) left).Value <=
1173 ((ULongConstant) right).Value;
1174 else if (left is LongConstant)
1175 bool_res = ((LongConstant) left).Value <=
1176 ((LongConstant) right).Value;
1177 else if (left is UIntConstant)
1178 bool_res = ((UIntConstant) left).Value <=
1179 ((UIntConstant) right).Value;
1180 else if (left is IntConstant)
1181 bool_res = ((IntConstant) left).Value <=
1182 ((IntConstant) right).Value;
1186 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);