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 class ConstantFold {
17 static TypeSpec[] binary_promotions;
19 public static TypeSpec[] BinaryPromotionsTypes {
21 if (binary_promotions == null) {
22 binary_promotions = new TypeSpec[] {
23 TypeManager.decimal_type, TypeManager.double_type, TypeManager.float_type,
24 TypeManager.uint64_type, TypeManager.int64_type, TypeManager.uint32_type };
27 return binary_promotions;
31 public static void Reset ()
33 binary_promotions = null;
37 // Performs the numeric promotions on the left and right expresions
38 // and deposits the results on `lc' and `rc'.
40 // On success, the types of `lc' and `rc' on output will always match,
41 // and the pair will be one of:
43 // TODO: BinaryFold should be called as an optimization step only,
44 // error checking here is weak
46 static bool DoBinaryNumericPromotions (ResolveContext rc, ref Constant left, ref Constant right)
48 TypeSpec ltype = left.Type;
49 TypeSpec rtype = right.Type;
51 foreach (TypeSpec t in BinaryPromotionsTypes) {
53 return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
56 return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
59 left = left.ConvertImplicitly (rc, TypeManager.int32_type);
60 right = right.ConvertImplicitly (rc, TypeManager.int32_type);
61 return left != null && right != null;
64 static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
66 Constant c = prim.ConvertImplicitly (rc, type);
72 if (type == TypeManager.uint32_type) {
73 type = TypeManager.int64_type;
74 prim = prim.ConvertImplicitly (rc, type);
75 second = second.ConvertImplicitly (rc, type);
76 return prim != null && second != null;
82 internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc)
84 rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode");
88 /// Constant expression folder for binary operations.
90 /// Returns null if the expression can not be folded.
92 static public Constant BinaryFold (ResolveContext ec, Binary.Operator oper,
93 Constant left, Constant right, Location loc)
95 Constant result = null;
97 if (left is EmptyConstantCast)
98 return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
100 if (left is SideEffectConstant) {
101 result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc);
104 return new SideEffectConstant (result, left, loc);
107 if (right is EmptyConstantCast)
108 return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
110 if (right is SideEffectConstant) {
111 result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc);
114 return new SideEffectConstant (result, right, loc);
117 TypeSpec lt = left.Type;
118 TypeSpec rt = right.Type;
121 if (lt == TypeManager.bool_type && lt == rt) {
122 bool lv = (bool) left.GetValue ();
123 bool rv = (bool) right.GetValue ();
125 case Binary.Operator.BitwiseAnd:
126 case Binary.Operator.LogicalAnd:
127 return new BoolConstant (lv && rv, left.Location);
128 case Binary.Operator.BitwiseOr:
129 case Binary.Operator.LogicalOr:
130 return new BoolConstant (lv || rv, left.Location);
131 case Binary.Operator.ExclusiveOr:
132 return new BoolConstant (lv ^ rv, left.Location);
133 case Binary.Operator.Equality:
134 return new BoolConstant (lv == rv, left.Location);
135 case Binary.Operator.Inequality:
136 return new BoolConstant (lv != rv, left.Location);
142 // During an enum evaluation, none of the rules are valid
143 // Not sure whether it is bug in csc or in documentation
145 if (ec.HasSet (ResolveContext.Options.EnumScope)){
146 if (left is EnumConstant)
147 left = ((EnumConstant) left).Child;
149 if (right is EnumConstant)
150 right = ((EnumConstant) right).Child;
151 } else if (left is EnumConstant && rt == lt) {
154 /// E operator |(E x, E y);
155 /// E operator &(E x, E y);
156 /// E operator ^(E x, E y);
158 case Binary.Operator.BitwiseOr:
159 case Binary.Operator.BitwiseAnd:
160 case Binary.Operator.ExclusiveOr:
161 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
163 result = result.Resolve (ec).TryReduce (ec, lt, loc);
167 /// U operator -(E x, E y);
169 case Binary.Operator.Subtraction:
170 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
172 result = result.Resolve (ec).TryReduce (ec, EnumSpec.GetUnderlyingType (lt), loc);
176 /// bool operator ==(E x, E y);
177 /// bool operator !=(E x, E y);
178 /// bool operator <(E x, E y);
179 /// bool operator >(E x, E y);
180 /// bool operator <=(E x, E y);
181 /// bool operator >=(E x, E y);
183 case Binary.Operator.Equality:
184 case Binary.Operator.Inequality:
185 case Binary.Operator.LessThan:
186 case Binary.Operator.GreaterThan:
187 case Binary.Operator.LessThanOrEqual:
188 case Binary.Operator.GreaterThanOrEqual:
189 return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
195 case Binary.Operator.BitwiseOr:
197 // bool? operator &(bool? x, bool? y);
199 if ((lt == TypeManager.bool_type && right is NullLiteral) ||
200 (rt == TypeManager.bool_type && left is NullLiteral)) {
201 var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
203 // false | null => null
204 // null | false => null
205 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
206 return Nullable.LiftedNull.CreateFromExpression (ec, b);
208 // true | null => true
209 // null | true => true
210 return ReducedExpression.Create (new BoolConstant (true, loc).Resolve (ec), b);
213 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
216 if (left is IntConstant){
217 int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
219 return new IntConstant (res, left.Location);
221 if (left is UIntConstant){
222 uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
224 return new UIntConstant (res, left.Location);
226 if (left is LongConstant){
227 long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
229 return new LongConstant (res, left.Location);
231 if (left is ULongConstant){
232 ulong res = ((ULongConstant)left).Value |
233 ((ULongConstant)right).Value;
235 return new ULongConstant (res, left.Location);
239 case Binary.Operator.BitwiseAnd:
241 // bool? operator &(bool? x, bool? y);
243 if ((lt == TypeManager.bool_type && right is NullLiteral) ||
244 (rt == TypeManager.bool_type && left is NullLiteral)) {
245 var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
247 // false & null => false
248 // null & false => false
249 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
250 return ReducedExpression.Create (new BoolConstant (false, loc).Resolve (ec), b);
252 // true & null => null
253 // null & true => null
254 return Nullable.LiftedNull.CreateFromExpression (ec, b);
257 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
261 /// int operator &(int x, int y);
262 /// uint operator &(uint x, uint y);
263 /// long operator &(long x, long y);
264 /// ulong operator &(ulong x, ulong y);
266 if (left is IntConstant){
267 int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
268 return new IntConstant (res, left.Location);
270 if (left is UIntConstant){
271 uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
272 return new UIntConstant (res, left.Location);
274 if (left is LongConstant){
275 long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
276 return new LongConstant (res, left.Location);
278 if (left is ULongConstant){
279 ulong res = ((ULongConstant)left).Value &
280 ((ULongConstant)right).Value;
282 return new ULongConstant (res, left.Location);
286 case Binary.Operator.ExclusiveOr:
287 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
290 if (left is IntConstant){
291 int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
292 return new IntConstant (res, left.Location);
294 if (left is UIntConstant){
295 uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
297 return new UIntConstant (res, left.Location);
299 if (left is LongConstant){
300 long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
302 return new LongConstant (res, left.Location);
304 if (left is ULongConstant){
305 ulong res = ((ULongConstant)left).Value ^
306 ((ULongConstant)right).Value;
308 return new ULongConstant (res, left.Location);
312 case Binary.Operator.Addition:
313 if (lt == InternalType.Null)
316 if (rt == InternalType.Null)
320 // If both sides are strings, then concatenate, if
321 // one is a string, and the other is not, then defer
322 // to runtime concatenation
324 if (lt == TypeManager.string_type || rt == TypeManager.string_type){
326 return new StringConstant ((string)left.GetValue () + (string)right.GetValue (),
333 // handle "E operator + (E x, U y)"
334 // handle "E operator + (Y y, E x)"
336 EnumConstant lc = left as EnumConstant;
337 EnumConstant rc = right as EnumConstant;
338 if (lc != null || rc != null){
345 // U has to be implicitly convetible to E.base
346 right = right.ConvertImplicitly (ec, lc.Child.Type);
350 result = BinaryFold (ec, oper, lc.Child, right, loc);
354 result = result.Resolve (ec).TryReduce (ec, lt, loc);
358 return new EnumConstant (result, lt);
361 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
365 if (left is DoubleConstant){
368 if (ec.ConstantCheckState)
369 res = checked (((DoubleConstant) left).Value +
370 ((DoubleConstant) right).Value);
372 res = unchecked (((DoubleConstant) left).Value +
373 ((DoubleConstant) right).Value);
375 return new DoubleConstant (res, left.Location);
377 if (left is FloatConstant){
380 if (ec.ConstantCheckState)
381 res = checked (((FloatConstant) left).Value +
382 ((FloatConstant) right).Value);
384 res = unchecked (((FloatConstant) left).Value +
385 ((FloatConstant) right).Value);
387 result = new FloatConstant (res, left.Location);
388 } else if (left is ULongConstant){
391 if (ec.ConstantCheckState)
392 res = checked (((ULongConstant) left).Value +
393 ((ULongConstant) right).Value);
395 res = unchecked (((ULongConstant) left).Value +
396 ((ULongConstant) right).Value);
398 result = new ULongConstant (res, left.Location);
399 } else if (left is LongConstant){
402 if (ec.ConstantCheckState)
403 res = checked (((LongConstant) left).Value +
404 ((LongConstant) right).Value);
406 res = unchecked (((LongConstant) left).Value +
407 ((LongConstant) right).Value);
409 result = new LongConstant (res, left.Location);
410 } else if (left is UIntConstant){
413 if (ec.ConstantCheckState)
414 res = checked (((UIntConstant) left).Value +
415 ((UIntConstant) right).Value);
417 res = unchecked (((UIntConstant) left).Value +
418 ((UIntConstant) right).Value);
420 result = new UIntConstant (res, left.Location);
421 } else if (left is IntConstant){
424 if (ec.ConstantCheckState)
425 res = checked (((IntConstant) left).Value +
426 ((IntConstant) right).Value);
428 res = unchecked (((IntConstant) left).Value +
429 ((IntConstant) right).Value);
431 result = new IntConstant (res, left.Location);
432 } else if (left is DecimalConstant) {
435 if (ec.ConstantCheckState)
436 res = checked (((DecimalConstant) left).Value +
437 ((DecimalConstant) right).Value);
439 res = unchecked (((DecimalConstant) left).Value +
440 ((DecimalConstant) right).Value);
442 result = new DecimalConstant (res, left.Location);
444 } catch (OverflowException){
445 Error_CompileTimeOverflow (ec, loc);
450 case Binary.Operator.Subtraction:
452 // handle "E operator - (E x, U y)"
453 // handle "E operator - (Y y, E x)"
455 lc = left as EnumConstant;
456 rc = right as EnumConstant;
457 if (lc != null || rc != null){
464 // U has to be implicitly convetible to E.base
465 right = right.ConvertImplicitly (ec, lc.Child.Type);
469 result = BinaryFold (ec, oper, lc.Child, right, loc);
473 result = result.Resolve (ec).TryReduce (ec, lt, loc);
477 return new EnumConstant (result, lt);
480 if (left is NullLiteral && right is NullLiteral) {
481 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
482 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
485 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
489 if (left is DoubleConstant){
492 if (ec.ConstantCheckState)
493 res = checked (((DoubleConstant) left).Value -
494 ((DoubleConstant) right).Value);
496 res = unchecked (((DoubleConstant) left).Value -
497 ((DoubleConstant) right).Value);
499 result = new DoubleConstant (res, left.Location);
500 } else if (left is FloatConstant){
503 if (ec.ConstantCheckState)
504 res = checked (((FloatConstant) left).Value -
505 ((FloatConstant) right).Value);
507 res = unchecked (((FloatConstant) left).Value -
508 ((FloatConstant) right).Value);
510 result = new FloatConstant (res, left.Location);
511 } else if (left is ULongConstant){
514 if (ec.ConstantCheckState)
515 res = checked (((ULongConstant) left).Value -
516 ((ULongConstant) right).Value);
518 res = unchecked (((ULongConstant) left).Value -
519 ((ULongConstant) right).Value);
521 result = new ULongConstant (res, left.Location);
522 } else if (left is LongConstant){
525 if (ec.ConstantCheckState)
526 res = checked (((LongConstant) left).Value -
527 ((LongConstant) right).Value);
529 res = unchecked (((LongConstant) left).Value -
530 ((LongConstant) right).Value);
532 result = new LongConstant (res, left.Location);
533 } else if (left is UIntConstant){
536 if (ec.ConstantCheckState)
537 res = checked (((UIntConstant) left).Value -
538 ((UIntConstant) right).Value);
540 res = unchecked (((UIntConstant) left).Value -
541 ((UIntConstant) right).Value);
543 result = new UIntConstant (res, left.Location);
544 } else if (left is IntConstant){
547 if (ec.ConstantCheckState)
548 res = checked (((IntConstant) left).Value -
549 ((IntConstant) right).Value);
551 res = unchecked (((IntConstant) left).Value -
552 ((IntConstant) right).Value);
554 result = new IntConstant (res, left.Location);
555 } else if (left is DecimalConstant) {
558 if (ec.ConstantCheckState)
559 res = checked (((DecimalConstant) left).Value -
560 ((DecimalConstant) right).Value);
562 res = unchecked (((DecimalConstant) left).Value -
563 ((DecimalConstant) right).Value);
565 return new DecimalConstant (res, left.Location);
567 throw new Exception ( "Unexepected subtraction input: " + left);
569 } catch (OverflowException){
570 Error_CompileTimeOverflow (ec, loc);
575 case Binary.Operator.Multiply:
576 if (left is NullLiteral && right is NullLiteral) {
577 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
578 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
581 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
585 if (left is DoubleConstant){
588 if (ec.ConstantCheckState)
589 res = checked (((DoubleConstant) left).Value *
590 ((DoubleConstant) right).Value);
592 res = unchecked (((DoubleConstant) left).Value *
593 ((DoubleConstant) right).Value);
595 return new DoubleConstant (res, left.Location);
596 } else if (left is FloatConstant){
599 if (ec.ConstantCheckState)
600 res = checked (((FloatConstant) left).Value *
601 ((FloatConstant) right).Value);
603 res = unchecked (((FloatConstant) left).Value *
604 ((FloatConstant) right).Value);
606 return new FloatConstant (res, left.Location);
607 } else if (left is ULongConstant){
610 if (ec.ConstantCheckState)
611 res = checked (((ULongConstant) left).Value *
612 ((ULongConstant) right).Value);
614 res = unchecked (((ULongConstant) left).Value *
615 ((ULongConstant) right).Value);
617 return new ULongConstant (res, left.Location);
618 } else if (left is LongConstant){
621 if (ec.ConstantCheckState)
622 res = checked (((LongConstant) left).Value *
623 ((LongConstant) right).Value);
625 res = unchecked (((LongConstant) left).Value *
626 ((LongConstant) right).Value);
628 return new LongConstant (res, left.Location);
629 } else if (left is UIntConstant){
632 if (ec.ConstantCheckState)
633 res = checked (((UIntConstant) left).Value *
634 ((UIntConstant) right).Value);
636 res = unchecked (((UIntConstant) left).Value *
637 ((UIntConstant) right).Value);
639 return new UIntConstant (res, left.Location);
640 } else if (left is IntConstant){
643 if (ec.ConstantCheckState)
644 res = checked (((IntConstant) left).Value *
645 ((IntConstant) right).Value);
647 res = unchecked (((IntConstant) left).Value *
648 ((IntConstant) right).Value);
650 return new IntConstant (res, left.Location);
651 } else if (left is DecimalConstant) {
654 if (ec.ConstantCheckState)
655 res = checked (((DecimalConstant) left).Value *
656 ((DecimalConstant) right).Value);
658 res = unchecked (((DecimalConstant) left).Value *
659 ((DecimalConstant) right).Value);
661 return new DecimalConstant (res, left.Location);
663 throw new Exception ( "Unexepected multiply input: " + left);
665 } catch (OverflowException){
666 Error_CompileTimeOverflow (ec, loc);
670 case Binary.Operator.Division:
671 if (left is NullLiteral && right is NullLiteral) {
672 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
673 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
676 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
680 if (left is DoubleConstant){
683 if (ec.ConstantCheckState)
684 res = checked (((DoubleConstant) left).Value /
685 ((DoubleConstant) right).Value);
687 res = unchecked (((DoubleConstant) left).Value /
688 ((DoubleConstant) right).Value);
690 return new DoubleConstant (res, left.Location);
691 } else if (left is FloatConstant){
694 if (ec.ConstantCheckState)
695 res = checked (((FloatConstant) left).Value /
696 ((FloatConstant) right).Value);
698 res = unchecked (((FloatConstant) left).Value /
699 ((FloatConstant) right).Value);
701 return new FloatConstant (res, left.Location);
702 } else if (left is ULongConstant){
705 if (ec.ConstantCheckState)
706 res = checked (((ULongConstant) left).Value /
707 ((ULongConstant) right).Value);
709 res = unchecked (((ULongConstant) left).Value /
710 ((ULongConstant) right).Value);
712 return new ULongConstant (res, left.Location);
713 } else if (left is LongConstant){
716 if (ec.ConstantCheckState)
717 res = checked (((LongConstant) left).Value /
718 ((LongConstant) right).Value);
720 res = unchecked (((LongConstant) left).Value /
721 ((LongConstant) right).Value);
723 return new LongConstant (res, left.Location);
724 } else if (left is UIntConstant){
727 if (ec.ConstantCheckState)
728 res = checked (((UIntConstant) left).Value /
729 ((UIntConstant) right).Value);
731 res = unchecked (((UIntConstant) left).Value /
732 ((UIntConstant) right).Value);
734 return new UIntConstant (res, left.Location);
735 } else if (left is IntConstant){
738 if (ec.ConstantCheckState)
739 res = checked (((IntConstant) left).Value /
740 ((IntConstant) right).Value);
742 res = unchecked (((IntConstant) left).Value /
743 ((IntConstant) right).Value);
745 return new IntConstant (res, left.Location);
746 } else if (left is DecimalConstant) {
749 if (ec.ConstantCheckState)
750 res = checked (((DecimalConstant) left).Value /
751 ((DecimalConstant) right).Value);
753 res = unchecked (((DecimalConstant) left).Value /
754 ((DecimalConstant) right).Value);
756 return new DecimalConstant (res, left.Location);
758 throw new Exception ( "Unexepected division input: " + left);
760 } catch (OverflowException){
761 Error_CompileTimeOverflow (ec, loc);
763 } catch (DivideByZeroException) {
764 ec.Report.Error (20, loc, "Division by constant zero");
769 case Binary.Operator.Modulus:
770 if (left is NullLiteral && right is NullLiteral) {
771 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
772 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
775 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
779 if (left is DoubleConstant){
782 if (ec.ConstantCheckState)
783 res = checked (((DoubleConstant) left).Value %
784 ((DoubleConstant) right).Value);
786 res = unchecked (((DoubleConstant) left).Value %
787 ((DoubleConstant) right).Value);
789 return new DoubleConstant (res, left.Location);
790 } else if (left is FloatConstant){
793 if (ec.ConstantCheckState)
794 res = checked (((FloatConstant) left).Value %
795 ((FloatConstant) right).Value);
797 res = unchecked (((FloatConstant) left).Value %
798 ((FloatConstant) right).Value);
800 return new FloatConstant (res, left.Location);
801 } else if (left is ULongConstant){
804 if (ec.ConstantCheckState)
805 res = checked (((ULongConstant) left).Value %
806 ((ULongConstant) right).Value);
808 res = unchecked (((ULongConstant) left).Value %
809 ((ULongConstant) right).Value);
811 return new ULongConstant (res, left.Location);
812 } else if (left is LongConstant){
815 if (ec.ConstantCheckState)
816 res = checked (((LongConstant) left).Value %
817 ((LongConstant) right).Value);
819 res = unchecked (((LongConstant) left).Value %
820 ((LongConstant) right).Value);
822 return new LongConstant (res, left.Location);
823 } else if (left is UIntConstant){
826 if (ec.ConstantCheckState)
827 res = checked (((UIntConstant) left).Value %
828 ((UIntConstant) right).Value);
830 res = unchecked (((UIntConstant) left).Value %
831 ((UIntConstant) right).Value);
833 return new UIntConstant (res, left.Location);
834 } else if (left is IntConstant){
837 if (ec.ConstantCheckState)
838 res = checked (((IntConstant) left).Value %
839 ((IntConstant) right).Value);
841 res = unchecked (((IntConstant) left).Value %
842 ((IntConstant) right).Value);
844 return new IntConstant (res, left.Location);
846 throw new Exception ( "Unexepected modulus input: " + left);
848 } catch (DivideByZeroException){
849 ec.Report.Error (20, loc, "Division by constant zero");
850 } catch (OverflowException){
851 Error_CompileTimeOverflow (ec, loc);
856 // There is no overflow checking on left shift
858 case Binary.Operator.LeftShift:
859 if (left is NullLiteral && right is NullLiteral) {
860 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
861 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
864 IntConstant ic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
866 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
870 int lshift_val = ic.Value;
871 if (left.Type == TypeManager.uint64_type)
872 return new ULongConstant (((ULongConstant)left).Value << lshift_val, left.Location);
873 if (left.Type == TypeManager.int64_type)
874 return new LongConstant (((LongConstant)left).Value << lshift_val, left.Location);
875 if (left.Type == TypeManager.uint32_type)
876 return new UIntConstant (((UIntConstant)left).Value << lshift_val, left.Location);
878 // null << value => null
879 if (left is NullLiteral)
880 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
882 left = left.ConvertImplicitly (ec, TypeManager.int32_type);
883 if (left.Type == TypeManager.int32_type)
884 return new IntConstant (((IntConstant)left).Value << lshift_val, left.Location);
886 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
890 // There is no overflow checking on right shift
892 case Binary.Operator.RightShift:
893 if (left is NullLiteral && right is NullLiteral) {
894 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
895 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
898 IntConstant sic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
900 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
903 int rshift_val = sic.Value;
904 if (left.Type == TypeManager.uint64_type)
905 return new ULongConstant (((ULongConstant)left).Value >> rshift_val, left.Location);
906 if (left.Type == TypeManager.int64_type)
907 return new LongConstant (((LongConstant)left).Value >> rshift_val, left.Location);
908 if (left.Type == TypeManager.uint32_type)
909 return new UIntConstant (((UIntConstant)left).Value >> rshift_val, left.Location);
911 // null >> value => null
912 if (left is NullLiteral)
913 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
915 left = left.ConvertImplicitly (ec, TypeManager.int32_type);
916 if (left.Type == TypeManager.int32_type)
917 return new IntConstant (((IntConstant)left).Value >> rshift_val, left.Location);
919 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
922 case Binary.Operator.Equality:
923 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
924 (left is Nullable.LiftedNull && right.IsNull) ||
925 (right is Nullable.LiftedNull && left.IsNull)) {
926 if (left.IsNull || right.IsNull) {
927 return ReducedExpression.Create (
928 new BoolConstant (left.IsNull == right.IsNull, left.Location).Resolve (ec),
929 new Binary (oper, left, right, loc));
932 if (left is StringConstant && right is StringConstant)
933 return new BoolConstant (
934 ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
939 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
943 if (left is DoubleConstant)
944 bool_res = ((DoubleConstant) left).Value ==
945 ((DoubleConstant) right).Value;
946 else if (left is FloatConstant)
947 bool_res = ((FloatConstant) left).Value ==
948 ((FloatConstant) right).Value;
949 else if (left is ULongConstant)
950 bool_res = ((ULongConstant) left).Value ==
951 ((ULongConstant) right).Value;
952 else if (left is LongConstant)
953 bool_res = ((LongConstant) left).Value ==
954 ((LongConstant) right).Value;
955 else if (left is UIntConstant)
956 bool_res = ((UIntConstant) left).Value ==
957 ((UIntConstant) right).Value;
958 else if (left is IntConstant)
959 bool_res = ((IntConstant) left).Value ==
960 ((IntConstant) right).Value;
964 return new BoolConstant (bool_res, left.Location);
966 case Binary.Operator.Inequality:
967 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
968 (left is Nullable.LiftedNull && right.IsNull) ||
969 (right is Nullable.LiftedNull && left.IsNull)) {
970 if (left.IsNull || right.IsNull) {
971 return ReducedExpression.Create (
972 new BoolConstant (left.IsNull != right.IsNull, left.Location).Resolve (ec),
973 new Binary (oper, left, right, loc));
976 if (left is StringConstant && right is StringConstant)
977 return new BoolConstant (
978 ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
983 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
987 if (left is DoubleConstant)
988 bool_res = ((DoubleConstant) left).Value !=
989 ((DoubleConstant) right).Value;
990 else if (left is FloatConstant)
991 bool_res = ((FloatConstant) left).Value !=
992 ((FloatConstant) right).Value;
993 else if (left is ULongConstant)
994 bool_res = ((ULongConstant) left).Value !=
995 ((ULongConstant) right).Value;
996 else if (left is LongConstant)
997 bool_res = ((LongConstant) left).Value !=
998 ((LongConstant) right).Value;
999 else if (left is UIntConstant)
1000 bool_res = ((UIntConstant) left).Value !=
1001 ((UIntConstant) right).Value;
1002 else if (left is IntConstant)
1003 bool_res = ((IntConstant) left).Value !=
1004 ((IntConstant) right).Value;
1008 return new BoolConstant (bool_res, left.Location);
1010 case Binary.Operator.LessThan:
1011 if (right is NullLiteral) {
1012 if (left is NullLiteral) {
1013 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
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 (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 (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
1053 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1056 if (left is Nullable.LiftedNull) {
1057 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1061 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1065 if (left is DoubleConstant)
1066 bool_res = ((DoubleConstant) left).Value >
1067 ((DoubleConstant) right).Value;
1068 else if (left is FloatConstant)
1069 bool_res = ((FloatConstant) left).Value >
1070 ((FloatConstant) right).Value;
1071 else if (left is ULongConstant)
1072 bool_res = ((ULongConstant) left).Value >
1073 ((ULongConstant) right).Value;
1074 else if (left is LongConstant)
1075 bool_res = ((LongConstant) left).Value >
1076 ((LongConstant) right).Value;
1077 else if (left is UIntConstant)
1078 bool_res = ((UIntConstant) left).Value >
1079 ((UIntConstant) right).Value;
1080 else if (left is IntConstant)
1081 bool_res = ((IntConstant) left).Value >
1082 ((IntConstant) right).Value;
1086 return new BoolConstant (bool_res, left.Location);
1088 case Binary.Operator.GreaterThanOrEqual:
1089 if (right is NullLiteral) {
1090 if (left is NullLiteral) {
1091 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
1092 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1095 if (left is Nullable.LiftedNull) {
1096 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1100 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1104 if (left is DoubleConstant)
1105 bool_res = ((DoubleConstant) left).Value >=
1106 ((DoubleConstant) right).Value;
1107 else if (left is FloatConstant)
1108 bool_res = ((FloatConstant) left).Value >=
1109 ((FloatConstant) right).Value;
1110 else if (left is ULongConstant)
1111 bool_res = ((ULongConstant) left).Value >=
1112 ((ULongConstant) right).Value;
1113 else if (left is LongConstant)
1114 bool_res = ((LongConstant) left).Value >=
1115 ((LongConstant) right).Value;
1116 else if (left is UIntConstant)
1117 bool_res = ((UIntConstant) left).Value >=
1118 ((UIntConstant) right).Value;
1119 else if (left is IntConstant)
1120 bool_res = ((IntConstant) left).Value >=
1121 ((IntConstant) right).Value;
1125 return new BoolConstant (bool_res, left.Location);
1127 case Binary.Operator.LessThanOrEqual:
1128 if (right is NullLiteral) {
1129 if (left is NullLiteral) {
1130 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
1131 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1134 if (left is Nullable.LiftedNull) {
1135 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1139 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1143 if (left is DoubleConstant)
1144 bool_res = ((DoubleConstant) left).Value <=
1145 ((DoubleConstant) right).Value;
1146 else if (left is FloatConstant)
1147 bool_res = ((FloatConstant) left).Value <=
1148 ((FloatConstant) right).Value;
1149 else if (left is ULongConstant)
1150 bool_res = ((ULongConstant) left).Value <=
1151 ((ULongConstant) right).Value;
1152 else if (left is LongConstant)
1153 bool_res = ((LongConstant) left).Value <=
1154 ((LongConstant) right).Value;
1155 else if (left is UIntConstant)
1156 bool_res = ((UIntConstant) left).Value <=
1157 ((UIntConstant) right).Value;
1158 else if (left is IntConstant)
1159 bool_res = ((IntConstant) left).Value <=
1160 ((IntConstant) right).Value;
1164 return new BoolConstant (bool_res, left.Location);