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-2008, 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.TryReduce (ec, lt, loc);
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.TryReduce (ec, EnumSpec.GetUnderlyingType (lt), loc);
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 Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (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 Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (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:
302 if (lt == InternalType.NullLiteral)
305 if (rt == InternalType.NullLiteral)
309 // If both sides are strings, then concatenate, if
310 // one is a string, and the other is not, then defer
311 // to runtime concatenation
313 if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
315 return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
322 // handle "E operator + (E x, U y)"
323 // handle "E operator + (Y y, E x)"
325 EnumConstant lc = left as EnumConstant;
326 EnumConstant rc = right as EnumConstant;
327 if (lc != null || rc != null){
334 // U has to be implicitly convetible to E.base
335 right = right.ConvertImplicitly (lc.Child.Type);
339 result = BinaryFold (ec, oper, lc.Child, right, loc);
343 result = result.TryReduce (ec, lt, loc);
347 return new EnumConstant (result, lt);
350 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
354 if (left is DoubleConstant){
357 if (ec.ConstantCheckState)
358 res = checked (((DoubleConstant) left).Value +
359 ((DoubleConstant) right).Value);
361 res = unchecked (((DoubleConstant) left).Value +
362 ((DoubleConstant) right).Value);
364 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
366 if (left is FloatConstant){
369 if (ec.ConstantCheckState)
370 res = checked (((FloatConstant) left).Value +
371 ((FloatConstant) right).Value);
373 res = unchecked (((FloatConstant) left).Value +
374 ((FloatConstant) right).Value);
376 result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
377 } else if (left is ULongConstant){
380 if (ec.ConstantCheckState)
381 res = checked (((ULongConstant) left).Value +
382 ((ULongConstant) right).Value);
384 res = unchecked (((ULongConstant) left).Value +
385 ((ULongConstant) right).Value);
387 result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
388 } else if (left is LongConstant){
391 if (ec.ConstantCheckState)
392 res = checked (((LongConstant) left).Value +
393 ((LongConstant) right).Value);
395 res = unchecked (((LongConstant) left).Value +
396 ((LongConstant) right).Value);
398 result = new LongConstant (ec.BuiltinTypes, res, left.Location);
399 } else if (left is UIntConstant){
402 if (ec.ConstantCheckState)
403 res = checked (((UIntConstant) left).Value +
404 ((UIntConstant) right).Value);
406 res = unchecked (((UIntConstant) left).Value +
407 ((UIntConstant) right).Value);
409 result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
410 } else if (left is IntConstant){
413 if (ec.ConstantCheckState)
414 res = checked (((IntConstant) left).Value +
415 ((IntConstant) right).Value);
417 res = unchecked (((IntConstant) left).Value +
418 ((IntConstant) right).Value);
420 result = new IntConstant (ec.BuiltinTypes, res, left.Location);
421 } else if (left is DecimalConstant) {
424 if (ec.ConstantCheckState)
425 res = checked (((DecimalConstant) left).Value +
426 ((DecimalConstant) right).Value);
428 res = unchecked (((DecimalConstant) left).Value +
429 ((DecimalConstant) right).Value);
431 result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
433 } catch (OverflowException){
434 Error_CompileTimeOverflow (ec, loc);
439 case Binary.Operator.Subtraction:
441 // handle "E operator - (E x, U y)"
442 // handle "E operator - (Y y, E x)"
444 lc = left as EnumConstant;
445 rc = right as EnumConstant;
446 if (lc != null || rc != null){
453 // U has to be implicitly convetible to E.base
454 right = right.ConvertImplicitly (lc.Child.Type);
458 result = BinaryFold (ec, oper, lc.Child, right, loc);
462 result = result.TryReduce (ec, lt, loc);
466 return new EnumConstant (result, lt);
469 if (left is NullLiteral && right is NullLiteral) {
470 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
471 lifted_int.ResolveAsType (ec);
472 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
475 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
479 if (left is DoubleConstant){
482 if (ec.ConstantCheckState)
483 res = checked (((DoubleConstant) left).Value -
484 ((DoubleConstant) right).Value);
486 res = unchecked (((DoubleConstant) left).Value -
487 ((DoubleConstant) right).Value);
489 result = new DoubleConstant (ec.BuiltinTypes, res, left.Location);
490 } else if (left is FloatConstant){
493 if (ec.ConstantCheckState)
494 res = checked (((FloatConstant) left).Value -
495 ((FloatConstant) right).Value);
497 res = unchecked (((FloatConstant) left).Value -
498 ((FloatConstant) right).Value);
500 result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
501 } else if (left is ULongConstant){
504 if (ec.ConstantCheckState)
505 res = checked (((ULongConstant) left).Value -
506 ((ULongConstant) right).Value);
508 res = unchecked (((ULongConstant) left).Value -
509 ((ULongConstant) right).Value);
511 result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
512 } else if (left is LongConstant){
515 if (ec.ConstantCheckState)
516 res = checked (((LongConstant) left).Value -
517 ((LongConstant) right).Value);
519 res = unchecked (((LongConstant) left).Value -
520 ((LongConstant) right).Value);
522 result = new LongConstant (ec.BuiltinTypes, res, left.Location);
523 } else if (left is UIntConstant){
526 if (ec.ConstantCheckState)
527 res = checked (((UIntConstant) left).Value -
528 ((UIntConstant) right).Value);
530 res = unchecked (((UIntConstant) left).Value -
531 ((UIntConstant) right).Value);
533 result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
534 } else if (left is IntConstant){
537 if (ec.ConstantCheckState)
538 res = checked (((IntConstant) left).Value -
539 ((IntConstant) right).Value);
541 res = unchecked (((IntConstant) left).Value -
542 ((IntConstant) right).Value);
544 result = new IntConstant (ec.BuiltinTypes, res, left.Location);
545 } else if (left is DecimalConstant) {
548 if (ec.ConstantCheckState)
549 res = checked (((DecimalConstant) left).Value -
550 ((DecimalConstant) right).Value);
552 res = unchecked (((DecimalConstant) left).Value -
553 ((DecimalConstant) right).Value);
555 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
557 throw new Exception ( "Unexepected subtraction input: " + left);
559 } catch (OverflowException){
560 Error_CompileTimeOverflow (ec, loc);
565 case Binary.Operator.Multiply:
566 if (left is NullLiteral && right is NullLiteral) {
567 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
568 lifted_int.ResolveAsType (ec);
569 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
572 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
576 if (left is DoubleConstant){
579 if (ec.ConstantCheckState)
580 res = checked (((DoubleConstant) left).Value *
581 ((DoubleConstant) right).Value);
583 res = unchecked (((DoubleConstant) left).Value *
584 ((DoubleConstant) right).Value);
586 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
587 } else if (left is FloatConstant){
590 if (ec.ConstantCheckState)
591 res = checked (((FloatConstant) left).Value *
592 ((FloatConstant) right).Value);
594 res = unchecked (((FloatConstant) left).Value *
595 ((FloatConstant) right).Value);
597 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
598 } else if (left is ULongConstant){
601 if (ec.ConstantCheckState)
602 res = checked (((ULongConstant) left).Value *
603 ((ULongConstant) right).Value);
605 res = unchecked (((ULongConstant) left).Value *
606 ((ULongConstant) right).Value);
608 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
609 } else if (left is LongConstant){
612 if (ec.ConstantCheckState)
613 res = checked (((LongConstant) left).Value *
614 ((LongConstant) right).Value);
616 res = unchecked (((LongConstant) left).Value *
617 ((LongConstant) right).Value);
619 return new LongConstant (ec.BuiltinTypes, res, left.Location);
620 } else if (left is UIntConstant){
623 if (ec.ConstantCheckState)
624 res = checked (((UIntConstant) left).Value *
625 ((UIntConstant) right).Value);
627 res = unchecked (((UIntConstant) left).Value *
628 ((UIntConstant) right).Value);
630 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
631 } else if (left is IntConstant){
634 if (ec.ConstantCheckState)
635 res = checked (((IntConstant) left).Value *
636 ((IntConstant) right).Value);
638 res = unchecked (((IntConstant) left).Value *
639 ((IntConstant) right).Value);
641 return new IntConstant (ec.BuiltinTypes, res, left.Location);
642 } else if (left is DecimalConstant) {
645 if (ec.ConstantCheckState)
646 res = checked (((DecimalConstant) left).Value *
647 ((DecimalConstant) right).Value);
649 res = unchecked (((DecimalConstant) left).Value *
650 ((DecimalConstant) right).Value);
652 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
654 throw new Exception ( "Unexepected multiply input: " + left);
656 } catch (OverflowException){
657 Error_CompileTimeOverflow (ec, loc);
661 case Binary.Operator.Division:
662 if (left is NullLiteral && right is NullLiteral) {
663 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
664 lifted_int.ResolveAsType (ec);
665 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
668 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
672 if (left is DoubleConstant){
675 if (ec.ConstantCheckState)
676 res = checked (((DoubleConstant) left).Value /
677 ((DoubleConstant) right).Value);
679 res = unchecked (((DoubleConstant) left).Value /
680 ((DoubleConstant) right).Value);
682 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
683 } else if (left is FloatConstant){
686 if (ec.ConstantCheckState)
687 res = checked (((FloatConstant) left).Value /
688 ((FloatConstant) right).Value);
690 res = unchecked (((FloatConstant) left).Value /
691 ((FloatConstant) right).Value);
693 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
694 } else if (left is ULongConstant){
697 if (ec.ConstantCheckState)
698 res = checked (((ULongConstant) left).Value /
699 ((ULongConstant) right).Value);
701 res = unchecked (((ULongConstant) left).Value /
702 ((ULongConstant) right).Value);
704 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
705 } else if (left is LongConstant){
708 if (ec.ConstantCheckState)
709 res = checked (((LongConstant) left).Value /
710 ((LongConstant) right).Value);
712 res = unchecked (((LongConstant) left).Value /
713 ((LongConstant) right).Value);
715 return new LongConstant (ec.BuiltinTypes, res, left.Location);
716 } else if (left is UIntConstant){
719 if (ec.ConstantCheckState)
720 res = checked (((UIntConstant) left).Value /
721 ((UIntConstant) right).Value);
723 res = unchecked (((UIntConstant) left).Value /
724 ((UIntConstant) right).Value);
726 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
727 } else if (left is IntConstant){
730 if (ec.ConstantCheckState)
731 res = checked (((IntConstant) left).Value /
732 ((IntConstant) right).Value);
734 res = unchecked (((IntConstant) left).Value /
735 ((IntConstant) right).Value);
737 return new IntConstant (ec.BuiltinTypes, res, left.Location);
738 } else if (left is DecimalConstant) {
741 if (ec.ConstantCheckState)
742 res = checked (((DecimalConstant) left).Value /
743 ((DecimalConstant) right).Value);
745 res = unchecked (((DecimalConstant) left).Value /
746 ((DecimalConstant) right).Value);
748 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
750 throw new Exception ( "Unexepected division input: " + left);
752 } catch (OverflowException){
753 Error_CompileTimeOverflow (ec, loc);
755 } catch (DivideByZeroException) {
756 ec.Report.Error (20, loc, "Division by constant zero");
761 case Binary.Operator.Modulus:
762 if (left is NullLiteral && right is NullLiteral) {
763 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
764 lifted_int.ResolveAsType (ec);
765 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
768 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
772 if (left is DoubleConstant){
775 if (ec.ConstantCheckState)
776 res = checked (((DoubleConstant) left).Value %
777 ((DoubleConstant) right).Value);
779 res = unchecked (((DoubleConstant) left).Value %
780 ((DoubleConstant) right).Value);
782 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
783 } else if (left is FloatConstant){
786 if (ec.ConstantCheckState)
787 res = checked (((FloatConstant) left).Value %
788 ((FloatConstant) right).Value);
790 res = unchecked (((FloatConstant) left).Value %
791 ((FloatConstant) right).Value);
793 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
794 } else if (left is ULongConstant){
797 if (ec.ConstantCheckState)
798 res = checked (((ULongConstant) left).Value %
799 ((ULongConstant) right).Value);
801 res = unchecked (((ULongConstant) left).Value %
802 ((ULongConstant) right).Value);
804 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
805 } else if (left is LongConstant){
808 if (ec.ConstantCheckState)
809 res = checked (((LongConstant) left).Value %
810 ((LongConstant) right).Value);
812 res = unchecked (((LongConstant) left).Value %
813 ((LongConstant) right).Value);
815 return new LongConstant (ec.BuiltinTypes, res, left.Location);
816 } else if (left is UIntConstant){
819 if (ec.ConstantCheckState)
820 res = checked (((UIntConstant) left).Value %
821 ((UIntConstant) right).Value);
823 res = unchecked (((UIntConstant) left).Value %
824 ((UIntConstant) right).Value);
826 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
827 } else if (left is IntConstant){
830 if (ec.ConstantCheckState)
831 res = checked (((IntConstant) left).Value %
832 ((IntConstant) right).Value);
834 res = unchecked (((IntConstant) left).Value %
835 ((IntConstant) right).Value);
837 return new IntConstant (ec.BuiltinTypes, res, left.Location);
839 throw new Exception ( "Unexepected modulus input: " + left);
841 } catch (DivideByZeroException){
842 ec.Report.Error (20, loc, "Division by constant zero");
843 } catch (OverflowException){
844 Error_CompileTimeOverflow (ec, loc);
849 // There is no overflow checking on left shift
851 case Binary.Operator.LeftShift:
852 if (left is NullLiteral && right is NullLiteral) {
853 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
854 lifted_int.ResolveAsType (ec);
855 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
858 IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
860 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
864 int lshift_val = ic.Value;
865 switch (left.Type.BuiltinType) {
866 case BuiltinTypeSpec.Type.ULong:
867 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location);
868 case BuiltinTypeSpec.Type.Long:
869 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location);
870 case BuiltinTypeSpec.Type.UInt:
871 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location);
874 // null << value => null
875 if (left is NullLiteral)
876 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
878 left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
879 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
880 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location);
882 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
886 // There is no overflow checking on right shift
888 case Binary.Operator.RightShift:
889 if (left is NullLiteral && right is NullLiteral) {
890 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
891 lifted_int.ResolveAsType (ec);
892 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
895 IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
897 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
900 int rshift_val = sic.Value;
901 switch (left.Type.BuiltinType) {
902 case BuiltinTypeSpec.Type.ULong:
903 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location);
904 case BuiltinTypeSpec.Type.Long:
905 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location);
906 case BuiltinTypeSpec.Type.UInt:
907 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location);
910 // null >> value => null
911 if (left is NullLiteral)
912 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
914 left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
915 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
916 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location);
918 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
921 case Binary.Operator.Equality:
922 if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
923 (left is Nullable.LiftedNull && right.IsNull) ||
924 (right is Nullable.LiftedNull && left.IsNull)) {
925 if (left.IsNull || right.IsNull) {
926 return ReducedExpression.Create (
927 new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
928 new Binary (oper, left, right, loc));
931 if (left is StringConstant && right is StringConstant)
932 return new BoolConstant (ec.BuiltinTypes,
933 ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
938 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
942 if (left is DoubleConstant)
943 bool_res = ((DoubleConstant) left).Value ==
944 ((DoubleConstant) right).Value;
945 else if (left is FloatConstant)
946 bool_res = ((FloatConstant) left).Value ==
947 ((FloatConstant) right).Value;
948 else if (left is ULongConstant)
949 bool_res = ((ULongConstant) left).Value ==
950 ((ULongConstant) right).Value;
951 else if (left is LongConstant)
952 bool_res = ((LongConstant) left).Value ==
953 ((LongConstant) right).Value;
954 else if (left is UIntConstant)
955 bool_res = ((UIntConstant) left).Value ==
956 ((UIntConstant) right).Value;
957 else if (left is IntConstant)
958 bool_res = ((IntConstant) left).Value ==
959 ((IntConstant) right).Value;
963 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
965 case Binary.Operator.Inequality:
966 if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
967 (left is Nullable.LiftedNull && right.IsNull) ||
968 (right is Nullable.LiftedNull && left.IsNull)) {
969 if (left.IsNull || right.IsNull) {
970 return ReducedExpression.Create (
971 new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
972 new Binary (oper, left, right, loc));
975 if (left is StringConstant && right is StringConstant)
976 return new BoolConstant (ec.BuiltinTypes,
977 ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
982 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
986 if (left is DoubleConstant)
987 bool_res = ((DoubleConstant) left).Value !=
988 ((DoubleConstant) right).Value;
989 else if (left is FloatConstant)
990 bool_res = ((FloatConstant) left).Value !=
991 ((FloatConstant) right).Value;
992 else if (left is ULongConstant)
993 bool_res = ((ULongConstant) left).Value !=
994 ((ULongConstant) right).Value;
995 else if (left is LongConstant)
996 bool_res = ((LongConstant) left).Value !=
997 ((LongConstant) right).Value;
998 else if (left is UIntConstant)
999 bool_res = ((UIntConstant) left).Value !=
1000 ((UIntConstant) right).Value;
1001 else if (left is IntConstant)
1002 bool_res = ((IntConstant) left).Value !=
1003 ((IntConstant) right).Value;
1007 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1009 case Binary.Operator.LessThan:
1010 if (right is NullLiteral) {
1011 if (left is NullLiteral) {
1012 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1013 lifted_int.ResolveAsType (ec);
1014 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1017 if (left is Nullable.LiftedNull) {
1018 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1022 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1026 if (left is DoubleConstant)
1027 bool_res = ((DoubleConstant) left).Value <
1028 ((DoubleConstant) right).Value;
1029 else if (left is FloatConstant)
1030 bool_res = ((FloatConstant) left).Value <
1031 ((FloatConstant) right).Value;
1032 else if (left is ULongConstant)
1033 bool_res = ((ULongConstant) left).Value <
1034 ((ULongConstant) right).Value;
1035 else if (left is LongConstant)
1036 bool_res = ((LongConstant) left).Value <
1037 ((LongConstant) right).Value;
1038 else if (left is UIntConstant)
1039 bool_res = ((UIntConstant) left).Value <
1040 ((UIntConstant) right).Value;
1041 else if (left is IntConstant)
1042 bool_res = ((IntConstant) left).Value <
1043 ((IntConstant) right).Value;
1047 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1049 case Binary.Operator.GreaterThan:
1050 if (right is NullLiteral) {
1051 if (left is NullLiteral) {
1052 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1053 lifted_int.ResolveAsType (ec);
1054 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1057 if (left is Nullable.LiftedNull) {
1058 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1062 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1066 if (left is DoubleConstant)
1067 bool_res = ((DoubleConstant) left).Value >
1068 ((DoubleConstant) right).Value;
1069 else if (left is FloatConstant)
1070 bool_res = ((FloatConstant) left).Value >
1071 ((FloatConstant) right).Value;
1072 else if (left is ULongConstant)
1073 bool_res = ((ULongConstant) left).Value >
1074 ((ULongConstant) right).Value;
1075 else if (left is LongConstant)
1076 bool_res = ((LongConstant) left).Value >
1077 ((LongConstant) right).Value;
1078 else if (left is UIntConstant)
1079 bool_res = ((UIntConstant) left).Value >
1080 ((UIntConstant) right).Value;
1081 else if (left is IntConstant)
1082 bool_res = ((IntConstant) left).Value >
1083 ((IntConstant) right).Value;
1087 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1089 case Binary.Operator.GreaterThanOrEqual:
1090 if (right is NullLiteral) {
1091 if (left is NullLiteral) {
1092 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1093 lifted_int.ResolveAsType (ec);
1094 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1097 if (left is Nullable.LiftedNull) {
1098 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1102 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1106 if (left is DoubleConstant)
1107 bool_res = ((DoubleConstant) left).Value >=
1108 ((DoubleConstant) right).Value;
1109 else if (left is FloatConstant)
1110 bool_res = ((FloatConstant) left).Value >=
1111 ((FloatConstant) right).Value;
1112 else if (left is ULongConstant)
1113 bool_res = ((ULongConstant) left).Value >=
1114 ((ULongConstant) right).Value;
1115 else if (left is LongConstant)
1116 bool_res = ((LongConstant) left).Value >=
1117 ((LongConstant) right).Value;
1118 else if (left is UIntConstant)
1119 bool_res = ((UIntConstant) left).Value >=
1120 ((UIntConstant) right).Value;
1121 else if (left is IntConstant)
1122 bool_res = ((IntConstant) left).Value >=
1123 ((IntConstant) right).Value;
1127 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1129 case Binary.Operator.LessThanOrEqual:
1130 if (right is NullLiteral) {
1131 if (left is NullLiteral) {
1132 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1133 lifted_int.ResolveAsType (ec);
1134 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1137 if (left is Nullable.LiftedNull) {
1138 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1142 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1146 if (left is DoubleConstant)
1147 bool_res = ((DoubleConstant) left).Value <=
1148 ((DoubleConstant) right).Value;
1149 else if (left is FloatConstant)
1150 bool_res = ((FloatConstant) left).Value <=
1151 ((FloatConstant) right).Value;
1152 else if (left is ULongConstant)
1153 bool_res = ((ULongConstant) left).Value <=
1154 ((ULongConstant) right).Value;
1155 else if (left is LongConstant)
1156 bool_res = ((LongConstant) left).Value <=
1157 ((LongConstant) right).Value;
1158 else if (left is UIntConstant)
1159 bool_res = ((UIntConstant) left).Value <=
1160 ((UIntConstant) right).Value;
1161 else if (left is IntConstant)
1162 bool_res = ((IntConstant) left).Value <=
1163 ((IntConstant) right).Value;
1167 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);