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 (BuildinTypes 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.BuildinTypes.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, rc.BuildinTypes.Int);
49 right = right.ConvertImplicitly (rc, rc.BuildinTypes.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 (rc, type);
61 if (type.BuildinType == BuildinTypeSpec.Type.UInt) {
62 type = rc.BuildinTypes.Long;
63 prim = prim.ConvertImplicitly (rc, type);
64 second = second.ConvertImplicitly (rc, 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.BuildinType == BuildinTypeSpec.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 (lv && rv, left.Location);
117 case Binary.Operator.BitwiseOr:
118 case Binary.Operator.LogicalOr:
119 return new BoolConstant (lv || rv, left.Location);
120 case Binary.Operator.ExclusiveOr:
121 return new BoolConstant (lv ^ rv, left.Location);
122 case Binary.Operator.Equality:
123 return new BoolConstant (lv == rv, left.Location);
124 case Binary.Operator.Inequality:
125 return new BoolConstant (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.Resolve (ec).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.Resolve (ec).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.BuildinType == BuildinTypeSpec.Type.Bool && right is NullLiteral) ||
189 (rt.BuildinType == BuildinTypeSpec.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 (true, loc).Resolve (ec), 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 (res, left.Location);
210 if (left is UIntConstant){
211 uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
213 return new UIntConstant (res, left.Location);
215 if (left is LongConstant){
216 long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
218 return new LongConstant (res, left.Location);
220 if (left is ULongConstant){
221 ulong res = ((ULongConstant)left).Value |
222 ((ULongConstant)right).Value;
224 return new ULongConstant (res, left.Location);
228 case Binary.Operator.BitwiseAnd:
230 // bool? operator &(bool? x, bool? y);
232 if ((lt.BuildinType == BuildinTypeSpec.Type.Bool && right is NullLiteral) ||
233 (rt.BuildinType == BuildinTypeSpec.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 (false, loc).Resolve (ec), 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 (res, left.Location);
259 if (left is UIntConstant){
260 uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
261 return new UIntConstant (res, left.Location);
263 if (left is LongConstant){
264 long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
265 return new LongConstant (res, left.Location);
267 if (left is ULongConstant){
268 ulong res = ((ULongConstant)left).Value &
269 ((ULongConstant)right).Value;
271 return new ULongConstant (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 (res, left.Location);
283 if (left is UIntConstant){
284 uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
286 return new UIntConstant (res, left.Location);
288 if (left is LongConstant){
289 long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
291 return new LongConstant (res, left.Location);
293 if (left is ULongConstant){
294 ulong res = ((ULongConstant)left).Value ^
295 ((ULongConstant)right).Value;
297 return new ULongConstant (res, left.Location);
301 case Binary.Operator.Addition:
302 if (lt == InternalType.Null)
305 if (rt == InternalType.Null)
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.BuildinType == BuildinTypeSpec.Type.String || rt.BuildinType == BuildinTypeSpec.Type.String){
315 return new StringConstant ((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 (ec, lc.Child.Type);
339 result = BinaryFold (ec, oper, lc.Child, right, loc);
343 result = result.Resolve (ec).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 (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 (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 (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 (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 (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 (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 (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 (ec, lc.Child.Type);
458 result = BinaryFold (ec, oper, lc.Child, right, loc);
462 result = result.Resolve (ec).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.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
471 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
474 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
478 if (left is DoubleConstant){
481 if (ec.ConstantCheckState)
482 res = checked (((DoubleConstant) left).Value -
483 ((DoubleConstant) right).Value);
485 res = unchecked (((DoubleConstant) left).Value -
486 ((DoubleConstant) right).Value);
488 result = new DoubleConstant (res, left.Location);
489 } else if (left is FloatConstant){
492 if (ec.ConstantCheckState)
493 res = checked (((FloatConstant) left).Value -
494 ((FloatConstant) right).Value);
496 res = unchecked (((FloatConstant) left).Value -
497 ((FloatConstant) right).Value);
499 result = new FloatConstant (res, left.Location);
500 } else if (left is ULongConstant){
503 if (ec.ConstantCheckState)
504 res = checked (((ULongConstant) left).Value -
505 ((ULongConstant) right).Value);
507 res = unchecked (((ULongConstant) left).Value -
508 ((ULongConstant) right).Value);
510 result = new ULongConstant (res, left.Location);
511 } else if (left is LongConstant){
514 if (ec.ConstantCheckState)
515 res = checked (((LongConstant) left).Value -
516 ((LongConstant) right).Value);
518 res = unchecked (((LongConstant) left).Value -
519 ((LongConstant) right).Value);
521 result = new LongConstant (res, left.Location);
522 } else if (left is UIntConstant){
525 if (ec.ConstantCheckState)
526 res = checked (((UIntConstant) left).Value -
527 ((UIntConstant) right).Value);
529 res = unchecked (((UIntConstant) left).Value -
530 ((UIntConstant) right).Value);
532 result = new UIntConstant (res, left.Location);
533 } else if (left is IntConstant){
536 if (ec.ConstantCheckState)
537 res = checked (((IntConstant) left).Value -
538 ((IntConstant) right).Value);
540 res = unchecked (((IntConstant) left).Value -
541 ((IntConstant) right).Value);
543 result = new IntConstant (res, left.Location);
544 } else if (left is DecimalConstant) {
547 if (ec.ConstantCheckState)
548 res = checked (((DecimalConstant) left).Value -
549 ((DecimalConstant) right).Value);
551 res = unchecked (((DecimalConstant) left).Value -
552 ((DecimalConstant) right).Value);
554 return new DecimalConstant (res, left.Location);
556 throw new Exception ( "Unexepected subtraction input: " + left);
558 } catch (OverflowException){
559 Error_CompileTimeOverflow (ec, loc);
564 case Binary.Operator.Multiply:
565 if (left is NullLiteral && right is NullLiteral) {
566 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
567 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
570 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
574 if (left is DoubleConstant){
577 if (ec.ConstantCheckState)
578 res = checked (((DoubleConstant) left).Value *
579 ((DoubleConstant) right).Value);
581 res = unchecked (((DoubleConstant) left).Value *
582 ((DoubleConstant) right).Value);
584 return new DoubleConstant (res, left.Location);
585 } else if (left is FloatConstant){
588 if (ec.ConstantCheckState)
589 res = checked (((FloatConstant) left).Value *
590 ((FloatConstant) right).Value);
592 res = unchecked (((FloatConstant) left).Value *
593 ((FloatConstant) right).Value);
595 return new FloatConstant (res, left.Location);
596 } else if (left is ULongConstant){
599 if (ec.ConstantCheckState)
600 res = checked (((ULongConstant) left).Value *
601 ((ULongConstant) right).Value);
603 res = unchecked (((ULongConstant) left).Value *
604 ((ULongConstant) right).Value);
606 return new ULongConstant (res, left.Location);
607 } else if (left is LongConstant){
610 if (ec.ConstantCheckState)
611 res = checked (((LongConstant) left).Value *
612 ((LongConstant) right).Value);
614 res = unchecked (((LongConstant) left).Value *
615 ((LongConstant) right).Value);
617 return new LongConstant (res, left.Location);
618 } else if (left is UIntConstant){
621 if (ec.ConstantCheckState)
622 res = checked (((UIntConstant) left).Value *
623 ((UIntConstant) right).Value);
625 res = unchecked (((UIntConstant) left).Value *
626 ((UIntConstant) right).Value);
628 return new UIntConstant (res, left.Location);
629 } else if (left is IntConstant){
632 if (ec.ConstantCheckState)
633 res = checked (((IntConstant) left).Value *
634 ((IntConstant) right).Value);
636 res = unchecked (((IntConstant) left).Value *
637 ((IntConstant) right).Value);
639 return new IntConstant (res, left.Location);
640 } else if (left is DecimalConstant) {
643 if (ec.ConstantCheckState)
644 res = checked (((DecimalConstant) left).Value *
645 ((DecimalConstant) right).Value);
647 res = unchecked (((DecimalConstant) left).Value *
648 ((DecimalConstant) right).Value);
650 return new DecimalConstant (res, left.Location);
652 throw new Exception ( "Unexepected multiply input: " + left);
654 } catch (OverflowException){
655 Error_CompileTimeOverflow (ec, loc);
659 case Binary.Operator.Division:
660 if (left is NullLiteral && right is NullLiteral) {
661 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
662 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
665 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
669 if (left is DoubleConstant){
672 if (ec.ConstantCheckState)
673 res = checked (((DoubleConstant) left).Value /
674 ((DoubleConstant) right).Value);
676 res = unchecked (((DoubleConstant) left).Value /
677 ((DoubleConstant) right).Value);
679 return new DoubleConstant (res, left.Location);
680 } else if (left is FloatConstant){
683 if (ec.ConstantCheckState)
684 res = checked (((FloatConstant) left).Value /
685 ((FloatConstant) right).Value);
687 res = unchecked (((FloatConstant) left).Value /
688 ((FloatConstant) right).Value);
690 return new FloatConstant (res, left.Location);
691 } else if (left is ULongConstant){
694 if (ec.ConstantCheckState)
695 res = checked (((ULongConstant) left).Value /
696 ((ULongConstant) right).Value);
698 res = unchecked (((ULongConstant) left).Value /
699 ((ULongConstant) right).Value);
701 return new ULongConstant (res, left.Location);
702 } else if (left is LongConstant){
705 if (ec.ConstantCheckState)
706 res = checked (((LongConstant) left).Value /
707 ((LongConstant) right).Value);
709 res = unchecked (((LongConstant) left).Value /
710 ((LongConstant) right).Value);
712 return new LongConstant (res, left.Location);
713 } else if (left is UIntConstant){
716 if (ec.ConstantCheckState)
717 res = checked (((UIntConstant) left).Value /
718 ((UIntConstant) right).Value);
720 res = unchecked (((UIntConstant) left).Value /
721 ((UIntConstant) right).Value);
723 return new UIntConstant (res, left.Location);
724 } else if (left is IntConstant){
727 if (ec.ConstantCheckState)
728 res = checked (((IntConstant) left).Value /
729 ((IntConstant) right).Value);
731 res = unchecked (((IntConstant) left).Value /
732 ((IntConstant) right).Value);
734 return new IntConstant (res, left.Location);
735 } else if (left is DecimalConstant) {
738 if (ec.ConstantCheckState)
739 res = checked (((DecimalConstant) left).Value /
740 ((DecimalConstant) right).Value);
742 res = unchecked (((DecimalConstant) left).Value /
743 ((DecimalConstant) right).Value);
745 return new DecimalConstant (res, left.Location);
747 throw new Exception ( "Unexepected division input: " + left);
749 } catch (OverflowException){
750 Error_CompileTimeOverflow (ec, loc);
752 } catch (DivideByZeroException) {
753 ec.Report.Error (20, loc, "Division by constant zero");
758 case Binary.Operator.Modulus:
759 if (left is NullLiteral && right is NullLiteral) {
760 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
761 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
764 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
768 if (left is DoubleConstant){
771 if (ec.ConstantCheckState)
772 res = checked (((DoubleConstant) left).Value %
773 ((DoubleConstant) right).Value);
775 res = unchecked (((DoubleConstant) left).Value %
776 ((DoubleConstant) right).Value);
778 return new DoubleConstant (res, left.Location);
779 } else if (left is FloatConstant){
782 if (ec.ConstantCheckState)
783 res = checked (((FloatConstant) left).Value %
784 ((FloatConstant) right).Value);
786 res = unchecked (((FloatConstant) left).Value %
787 ((FloatConstant) right).Value);
789 return new FloatConstant (res, left.Location);
790 } else if (left is ULongConstant){
793 if (ec.ConstantCheckState)
794 res = checked (((ULongConstant) left).Value %
795 ((ULongConstant) right).Value);
797 res = unchecked (((ULongConstant) left).Value %
798 ((ULongConstant) right).Value);
800 return new ULongConstant (res, left.Location);
801 } else if (left is LongConstant){
804 if (ec.ConstantCheckState)
805 res = checked (((LongConstant) left).Value %
806 ((LongConstant) right).Value);
808 res = unchecked (((LongConstant) left).Value %
809 ((LongConstant) right).Value);
811 return new LongConstant (res, left.Location);
812 } else if (left is UIntConstant){
815 if (ec.ConstantCheckState)
816 res = checked (((UIntConstant) left).Value %
817 ((UIntConstant) right).Value);
819 res = unchecked (((UIntConstant) left).Value %
820 ((UIntConstant) right).Value);
822 return new UIntConstant (res, left.Location);
823 } else if (left is IntConstant){
826 if (ec.ConstantCheckState)
827 res = checked (((IntConstant) left).Value %
828 ((IntConstant) right).Value);
830 res = unchecked (((IntConstant) left).Value %
831 ((IntConstant) right).Value);
833 return new IntConstant (res, left.Location);
835 throw new Exception ( "Unexepected modulus input: " + left);
837 } catch (DivideByZeroException){
838 ec.Report.Error (20, loc, "Division by constant zero");
839 } catch (OverflowException){
840 Error_CompileTimeOverflow (ec, loc);
845 // There is no overflow checking on left shift
847 case Binary.Operator.LeftShift:
848 if (left is NullLiteral && right is NullLiteral) {
849 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
850 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
853 IntConstant ic = right.ConvertImplicitly (ec, ec.BuildinTypes.Int) as IntConstant;
855 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
859 int lshift_val = ic.Value;
860 switch (left.Type.BuildinType) {
861 case BuildinTypeSpec.Type.ULong:
862 return new ULongConstant (((ULongConstant) left).Value << lshift_val, left.Location);
863 case BuildinTypeSpec.Type.Long:
864 return new LongConstant (((LongConstant) left).Value << lshift_val, left.Location);
865 case BuildinTypeSpec.Type.UInt:
866 return new UIntConstant (((UIntConstant) left).Value << lshift_val, left.Location);
869 // null << value => null
870 if (left is NullLiteral)
871 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
873 left = left.ConvertImplicitly (ec, ec.BuildinTypes.Int);
874 if (left.Type.BuildinType == BuildinTypeSpec.Type.Int)
875 return new IntConstant (((IntConstant)left).Value << lshift_val, left.Location);
877 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
881 // There is no overflow checking on right shift
883 case Binary.Operator.RightShift:
884 if (left is NullLiteral && right is NullLiteral) {
885 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
886 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
889 IntConstant sic = right.ConvertImplicitly (ec, ec.BuildinTypes.Int) as IntConstant;
891 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
894 int rshift_val = sic.Value;
895 switch (left.Type.BuildinType) {
896 case BuildinTypeSpec.Type.ULong:
897 return new ULongConstant (((ULongConstant) left).Value >> rshift_val, left.Location);
898 case BuildinTypeSpec.Type.Long:
899 return new LongConstant (((LongConstant) left).Value >> rshift_val, left.Location);
900 case BuildinTypeSpec.Type.UInt:
901 return new UIntConstant (((UIntConstant) left).Value >> rshift_val, left.Location);
904 // null >> value => null
905 if (left is NullLiteral)
906 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
908 left = left.ConvertImplicitly (ec, ec.BuildinTypes.Int);
909 if (left.Type.BuildinType == BuildinTypeSpec.Type.Int)
910 return new IntConstant (((IntConstant)left).Value >> rshift_val, left.Location);
912 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
915 case Binary.Operator.Equality:
916 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
917 (left is Nullable.LiftedNull && right.IsNull) ||
918 (right is Nullable.LiftedNull && left.IsNull)) {
919 if (left.IsNull || right.IsNull) {
920 return ReducedExpression.Create (
921 new BoolConstant (left.IsNull == right.IsNull, left.Location).Resolve (ec),
922 new Binary (oper, left, right, loc));
925 if (left is StringConstant && right is StringConstant)
926 return new BoolConstant (
927 ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
932 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
936 if (left is DoubleConstant)
937 bool_res = ((DoubleConstant) left).Value ==
938 ((DoubleConstant) right).Value;
939 else if (left is FloatConstant)
940 bool_res = ((FloatConstant) left).Value ==
941 ((FloatConstant) right).Value;
942 else if (left is ULongConstant)
943 bool_res = ((ULongConstant) left).Value ==
944 ((ULongConstant) right).Value;
945 else if (left is LongConstant)
946 bool_res = ((LongConstant) left).Value ==
947 ((LongConstant) right).Value;
948 else if (left is UIntConstant)
949 bool_res = ((UIntConstant) left).Value ==
950 ((UIntConstant) right).Value;
951 else if (left is IntConstant)
952 bool_res = ((IntConstant) left).Value ==
953 ((IntConstant) right).Value;
957 return new BoolConstant (bool_res, left.Location);
959 case Binary.Operator.Inequality:
960 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
961 (left is Nullable.LiftedNull && right.IsNull) ||
962 (right is Nullable.LiftedNull && left.IsNull)) {
963 if (left.IsNull || right.IsNull) {
964 return ReducedExpression.Create (
965 new BoolConstant (left.IsNull != right.IsNull, left.Location).Resolve (ec),
966 new Binary (oper, left, right, loc));
969 if (left is StringConstant && right is StringConstant)
970 return new BoolConstant (
971 ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
976 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
980 if (left is DoubleConstant)
981 bool_res = ((DoubleConstant) left).Value !=
982 ((DoubleConstant) right).Value;
983 else if (left is FloatConstant)
984 bool_res = ((FloatConstant) left).Value !=
985 ((FloatConstant) right).Value;
986 else if (left is ULongConstant)
987 bool_res = ((ULongConstant) left).Value !=
988 ((ULongConstant) right).Value;
989 else if (left is LongConstant)
990 bool_res = ((LongConstant) left).Value !=
991 ((LongConstant) right).Value;
992 else if (left is UIntConstant)
993 bool_res = ((UIntConstant) left).Value !=
994 ((UIntConstant) right).Value;
995 else if (left is IntConstant)
996 bool_res = ((IntConstant) left).Value !=
997 ((IntConstant) right).Value;
1001 return new BoolConstant (bool_res, left.Location);
1003 case Binary.Operator.LessThan:
1004 if (right is NullLiteral) {
1005 if (left is NullLiteral) {
1006 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
1007 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1010 if (left is Nullable.LiftedNull) {
1011 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1015 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1019 if (left is DoubleConstant)
1020 bool_res = ((DoubleConstant) left).Value <
1021 ((DoubleConstant) right).Value;
1022 else if (left is FloatConstant)
1023 bool_res = ((FloatConstant) left).Value <
1024 ((FloatConstant) right).Value;
1025 else if (left is ULongConstant)
1026 bool_res = ((ULongConstant) left).Value <
1027 ((ULongConstant) right).Value;
1028 else if (left is LongConstant)
1029 bool_res = ((LongConstant) left).Value <
1030 ((LongConstant) right).Value;
1031 else if (left is UIntConstant)
1032 bool_res = ((UIntConstant) left).Value <
1033 ((UIntConstant) right).Value;
1034 else if (left is IntConstant)
1035 bool_res = ((IntConstant) left).Value <
1036 ((IntConstant) right).Value;
1040 return new BoolConstant (bool_res, left.Location);
1042 case Binary.Operator.GreaterThan:
1043 if (right is NullLiteral) {
1044 if (left is NullLiteral) {
1045 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
1046 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1049 if (left is Nullable.LiftedNull) {
1050 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1054 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1058 if (left is DoubleConstant)
1059 bool_res = ((DoubleConstant) left).Value >
1060 ((DoubleConstant) right).Value;
1061 else if (left is FloatConstant)
1062 bool_res = ((FloatConstant) left).Value >
1063 ((FloatConstant) right).Value;
1064 else if (left is ULongConstant)
1065 bool_res = ((ULongConstant) left).Value >
1066 ((ULongConstant) right).Value;
1067 else if (left is LongConstant)
1068 bool_res = ((LongConstant) left).Value >
1069 ((LongConstant) right).Value;
1070 else if (left is UIntConstant)
1071 bool_res = ((UIntConstant) left).Value >
1072 ((UIntConstant) right).Value;
1073 else if (left is IntConstant)
1074 bool_res = ((IntConstant) left).Value >
1075 ((IntConstant) right).Value;
1079 return new BoolConstant (bool_res, left.Location);
1081 case Binary.Operator.GreaterThanOrEqual:
1082 if (right is NullLiteral) {
1083 if (left is NullLiteral) {
1084 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
1085 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1088 if (left is Nullable.LiftedNull) {
1089 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1093 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1097 if (left is DoubleConstant)
1098 bool_res = ((DoubleConstant) left).Value >=
1099 ((DoubleConstant) right).Value;
1100 else if (left is FloatConstant)
1101 bool_res = ((FloatConstant) left).Value >=
1102 ((FloatConstant) right).Value;
1103 else if (left is ULongConstant)
1104 bool_res = ((ULongConstant) left).Value >=
1105 ((ULongConstant) right).Value;
1106 else if (left is LongConstant)
1107 bool_res = ((LongConstant) left).Value >=
1108 ((LongConstant) right).Value;
1109 else if (left is UIntConstant)
1110 bool_res = ((UIntConstant) left).Value >=
1111 ((UIntConstant) right).Value;
1112 else if (left is IntConstant)
1113 bool_res = ((IntConstant) left).Value >=
1114 ((IntConstant) right).Value;
1118 return new BoolConstant (bool_res, left.Location);
1120 case Binary.Operator.LessThanOrEqual:
1121 if (right is NullLiteral) {
1122 if (left is NullLiteral) {
1123 var lifted_int = new Nullable.NullableType (ec.BuildinTypes.Int, loc).ResolveAsTypeTerminal (ec, false);
1124 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1127 if (left is Nullable.LiftedNull) {
1128 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1132 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1136 if (left is DoubleConstant)
1137 bool_res = ((DoubleConstant) left).Value <=
1138 ((DoubleConstant) right).Value;
1139 else if (left is FloatConstant)
1140 bool_res = ((FloatConstant) left).Value <=
1141 ((FloatConstant) right).Value;
1142 else if (left is ULongConstant)
1143 bool_res = ((ULongConstant) left).Value <=
1144 ((ULongConstant) right).Value;
1145 else if (left is LongConstant)
1146 bool_res = ((LongConstant) left).Value <=
1147 ((LongConstant) right).Value;
1148 else if (left is UIntConstant)
1149 bool_res = ((UIntConstant) left).Value <=
1150 ((UIntConstant) right).Value;
1151 else if (left is IntConstant)
1152 bool_res = ((IntConstant) left).Value <=
1153 ((IntConstant) right).Value;
1157 return new BoolConstant (bool_res, left.Location);