2 // cfold.cs: Constant Folding
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2011, Novell, Inc.
13 namespace Mono.CSharp {
15 public static class ConstantFold
17 public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types)
19 return new TypeSpec[] {
20 types.Decimal, types.Double, types.Float,
21 types.ULong, types.Long, types.UInt
26 // Performs the numeric promotions on the left and right expresions
27 // and deposits the results on `lc' and `rc'.
29 // On success, the types of `lc' and `rc' on output will always match,
30 // and the pair will be one of:
32 // TODO: BinaryFold should be called as an optimization step only,
33 // error checking here is weak
35 static bool DoBinaryNumericPromotions (ResolveContext rc, ref Constant left, ref Constant right)
37 TypeSpec ltype = left.Type;
38 TypeSpec rtype = right.Type;
40 foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) {
42 return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
45 return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
48 left = left.ConvertImplicitly (rc.BuiltinTypes.Int);
49 right = right.ConvertImplicitly (rc.BuiltinTypes.Int);
50 return left != null && right != null;
53 static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
55 Constant c = prim.ConvertImplicitly (type);
61 if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
62 type = rc.BuiltinTypes.Long;
63 prim = prim.ConvertImplicitly (type);
64 second = second.ConvertImplicitly (type);
65 return prim != null && second != null;
71 internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc)
73 rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode");
77 /// Constant expression folder for binary operations.
79 /// Returns null if the expression can not be folded.
81 static public Constant BinaryFold (ResolveContext ec, Binary.Operator oper,
82 Constant left, Constant right, Location loc)
84 Constant result = null;
86 if (left is EmptyConstantCast)
87 return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
89 if (left is SideEffectConstant) {
90 result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc);
93 return new SideEffectConstant (result, left, loc);
96 if (right is EmptyConstantCast)
97 return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
99 if (right is SideEffectConstant) {
100 result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc);
103 return new SideEffectConstant (result, right, loc);
106 TypeSpec lt = left.Type;
107 TypeSpec rt = right.Type;
110 if (lt.BuiltinType == BuiltinTypeSpec.Type.Bool && lt == rt) {
111 bool lv = (bool) left.GetValue ();
112 bool rv = (bool) right.GetValue ();
114 case Binary.Operator.BitwiseAnd:
115 case Binary.Operator.LogicalAnd:
116 return new BoolConstant (ec.BuiltinTypes, lv && rv, left.Location);
117 case Binary.Operator.BitwiseOr:
118 case Binary.Operator.LogicalOr:
119 return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location);
120 case Binary.Operator.ExclusiveOr:
121 return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location);
122 case Binary.Operator.Equality:
123 return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location);
124 case Binary.Operator.Inequality:
125 return new BoolConstant (ec.BuiltinTypes, lv != rv, left.Location);
131 // During an enum evaluation, none of the rules are valid
132 // Not sure whether it is bug in csc or in documentation
134 if (ec.HasSet (ResolveContext.Options.EnumScope)){
135 if (left is EnumConstant)
136 left = ((EnumConstant) left).Child;
138 if (right is EnumConstant)
139 right = ((EnumConstant) right).Child;
140 } else if (left is EnumConstant && rt == lt) {
143 /// E operator |(E x, E y);
144 /// E operator &(E x, E y);
145 /// E operator ^(E x, E y);
147 case Binary.Operator.BitwiseOr:
148 case Binary.Operator.BitwiseAnd:
149 case Binary.Operator.ExclusiveOr:
150 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
152 result = result.Reduce (ec, lt);
156 /// U operator -(E x, E y);
158 case Binary.Operator.Subtraction:
159 result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
161 result = result.Reduce (ec, EnumSpec.GetUnderlyingType (lt));
165 /// bool operator ==(E x, E y);
166 /// bool operator !=(E x, E y);
167 /// bool operator <(E x, E y);
168 /// bool operator >(E x, E y);
169 /// bool operator <=(E x, E y);
170 /// bool operator >=(E x, E y);
172 case Binary.Operator.Equality:
173 case Binary.Operator.Inequality:
174 case Binary.Operator.LessThan:
175 case Binary.Operator.GreaterThan:
176 case Binary.Operator.LessThanOrEqual:
177 case Binary.Operator.GreaterThanOrEqual:
178 return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
184 case Binary.Operator.BitwiseOr:
186 // bool? operator |(bool? x, bool? y);
188 if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
189 (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
190 var b = new Binary (oper, left, right).ResolveOperator (ec);
192 // false | null => null
193 // null | false => null
194 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
195 return Nullable.LiftedNull.CreateFromExpression (ec, b);
197 // true | null => true
198 // null | true => true
199 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, true, loc), b);
202 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
205 if (left is IntConstant){
206 int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
208 return new IntConstant (ec.BuiltinTypes, res, left.Location);
210 if (left is UIntConstant){
211 uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
213 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
215 if (left is LongConstant){
216 long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
218 return new LongConstant (ec.BuiltinTypes, res, left.Location);
220 if (left is ULongConstant){
221 ulong res = ((ULongConstant)left).Value |
222 ((ULongConstant)right).Value;
224 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
228 case Binary.Operator.BitwiseAnd:
230 // bool? operator &(bool? x, bool? y);
232 if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
233 (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
234 var b = new Binary (oper, left, right).ResolveOperator (ec);
236 // false & null => false
237 // null & false => false
238 if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
239 return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, false, loc), b);
241 // true & null => null
242 // null & true => null
243 return Nullable.LiftedNull.CreateFromExpression (ec, b);
246 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
250 /// int operator &(int x, int y);
251 /// uint operator &(uint x, uint y);
252 /// long operator &(long x, long y);
253 /// ulong operator &(ulong x, ulong y);
255 if (left is IntConstant){
256 int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
257 return new IntConstant (ec.BuiltinTypes, res, left.Location);
259 if (left is UIntConstant){
260 uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
261 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
263 if (left is LongConstant){
264 long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
265 return new LongConstant (ec.BuiltinTypes, res, left.Location);
267 if (left is ULongConstant){
268 ulong res = ((ULongConstant)left).Value &
269 ((ULongConstant)right).Value;
271 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
275 case Binary.Operator.ExclusiveOr:
276 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
279 if (left is IntConstant){
280 int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
281 return new IntConstant (ec.BuiltinTypes, res, left.Location);
283 if (left is UIntConstant){
284 uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
286 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
288 if (left is LongConstant){
289 long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
291 return new LongConstant (ec.BuiltinTypes, res, left.Location);
293 if (left is ULongConstant){
294 ulong res = ((ULongConstant)left).Value ^
295 ((ULongConstant)right).Value;
297 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
301 case Binary.Operator.Addition:
303 // If both sides are strings, then concatenate
305 // string operator + (string x, string y)
307 if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
309 return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
312 if (lt == InternalType.NullLiteral || left.IsNull)
313 return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
315 if (rt == InternalType.NullLiteral || right.IsNull)
316 return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location);
322 // string operator + (string x, object y)
324 if (lt == InternalType.NullLiteral) {
325 if (rt.BuiltinType == BuiltinTypeSpec.Type.Object)
326 return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
329 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
330 "+", lt.GetSignatureForError (), rt.GetSignatureForError ());
338 // string operator + (object x, string y)
340 if (rt == InternalType.NullLiteral) {
341 if (lt.BuiltinType == BuiltinTypeSpec.Type.Object)
342 return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location);
348 // handle "E operator + (E x, U y)"
349 // handle "E operator + (Y y, E x)"
351 EnumConstant lc = left as EnumConstant;
352 EnumConstant rc = right as EnumConstant;
353 if (lc != null || rc != null){
360 // U has to be implicitly convetible to E.base
361 right = right.ConvertImplicitly (lc.Child.Type);
365 result = BinaryFold (ec, oper, lc.Child, right, loc);
369 result = result.Reduce (ec, lt);
370 if (result == null || lt.IsEnum)
373 return new EnumConstant (result, lt);
376 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
380 if (left is DoubleConstant){
383 if (ec.ConstantCheckState)
384 res = checked (((DoubleConstant) left).Value +
385 ((DoubleConstant) right).Value);
387 res = unchecked (((DoubleConstant) left).Value +
388 ((DoubleConstant) right).Value);
390 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
392 if (left is FloatConstant){
394 a = ((FloatConstant) left).DoubleValue;
395 b = ((FloatConstant) right).DoubleValue;
397 if (ec.ConstantCheckState)
398 res = checked (a + b);
400 res = unchecked (a + b);
402 result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
403 } else if (left is ULongConstant){
406 if (ec.ConstantCheckState)
407 res = checked (((ULongConstant) left).Value +
408 ((ULongConstant) right).Value);
410 res = unchecked (((ULongConstant) left).Value +
411 ((ULongConstant) right).Value);
413 result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
414 } else if (left is LongConstant){
417 if (ec.ConstantCheckState)
418 res = checked (((LongConstant) left).Value +
419 ((LongConstant) right).Value);
421 res = unchecked (((LongConstant) left).Value +
422 ((LongConstant) right).Value);
424 result = new LongConstant (ec.BuiltinTypes, res, left.Location);
425 } else if (left is UIntConstant){
428 if (ec.ConstantCheckState)
429 res = checked (((UIntConstant) left).Value +
430 ((UIntConstant) right).Value);
432 res = unchecked (((UIntConstant) left).Value +
433 ((UIntConstant) right).Value);
435 result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
436 } else if (left is IntConstant){
439 if (ec.ConstantCheckState)
440 res = checked (((IntConstant) left).Value +
441 ((IntConstant) right).Value);
443 res = unchecked (((IntConstant) left).Value +
444 ((IntConstant) right).Value);
446 result = new IntConstant (ec.BuiltinTypes, res, left.Location);
447 } else if (left is DecimalConstant) {
450 if (ec.ConstantCheckState)
451 res = checked (((DecimalConstant) left).Value +
452 ((DecimalConstant) right).Value);
454 res = unchecked (((DecimalConstant) left).Value +
455 ((DecimalConstant) right).Value);
457 result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
459 } catch (OverflowException){
460 Error_CompileTimeOverflow (ec, loc);
465 case Binary.Operator.Subtraction:
467 // handle "E operator - (E x, U y)"
468 // handle "E operator - (Y y, E x)"
470 lc = left as EnumConstant;
471 rc = right as EnumConstant;
472 if (lc != null || rc != null) {
475 res_type = right.Type;
477 // Y has to be implicitly convertible to E.base
478 left = left.ConvertImplicitly (rc.Child.Type);
484 res_type = left.Type;
486 // U has to be implicitly convertible to E.base
487 right = right.ConvertImplicitly (lc.Child.Type);
494 result = BinaryFold (ec, oper, left, right, loc);
498 result = result.Reduce (ec, res_type);
502 return new EnumConstant (result, res_type);
505 if (left is NullLiteral && right is NullLiteral) {
506 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
507 lifted_int.ResolveAsType (ec);
508 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
511 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
515 if (left is DoubleConstant){
518 if (ec.ConstantCheckState)
519 res = checked (((DoubleConstant) left).Value -
520 ((DoubleConstant) right).Value);
522 res = unchecked (((DoubleConstant) left).Value -
523 ((DoubleConstant) right).Value);
525 result = new DoubleConstant (ec.BuiltinTypes, res, left.Location);
526 } else if (left is FloatConstant){
528 a = ((FloatConstant) left).DoubleValue;
529 b = ((FloatConstant) right).DoubleValue;
531 if (ec.ConstantCheckState)
532 res = checked (a - b);
534 res = unchecked (a - b);
536 result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
537 } else if (left is ULongConstant){
540 if (ec.ConstantCheckState)
541 res = checked (((ULongConstant) left).Value -
542 ((ULongConstant) right).Value);
544 res = unchecked (((ULongConstant) left).Value -
545 ((ULongConstant) right).Value);
547 result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
548 } else if (left is LongConstant){
551 if (ec.ConstantCheckState)
552 res = checked (((LongConstant) left).Value -
553 ((LongConstant) right).Value);
555 res = unchecked (((LongConstant) left).Value -
556 ((LongConstant) right).Value);
558 result = new LongConstant (ec.BuiltinTypes, res, left.Location);
559 } else if (left is UIntConstant){
562 if (ec.ConstantCheckState)
563 res = checked (((UIntConstant) left).Value -
564 ((UIntConstant) right).Value);
566 res = unchecked (((UIntConstant) left).Value -
567 ((UIntConstant) right).Value);
569 result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
570 } else if (left is IntConstant){
573 if (ec.ConstantCheckState)
574 res = checked (((IntConstant) left).Value -
575 ((IntConstant) right).Value);
577 res = unchecked (((IntConstant) left).Value -
578 ((IntConstant) right).Value);
580 result = new IntConstant (ec.BuiltinTypes, res, left.Location);
581 } else if (left is DecimalConstant) {
584 if (ec.ConstantCheckState)
585 res = checked (((DecimalConstant) left).Value -
586 ((DecimalConstant) right).Value);
588 res = unchecked (((DecimalConstant) left).Value -
589 ((DecimalConstant) right).Value);
591 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
593 throw new Exception ( "Unexepected subtraction input: " + left);
595 } catch (OverflowException){
596 Error_CompileTimeOverflow (ec, loc);
601 case Binary.Operator.Multiply:
602 if (left is NullLiteral && right is NullLiteral) {
603 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
604 lifted_int.ResolveAsType (ec);
605 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
608 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
612 if (left is DoubleConstant){
615 if (ec.ConstantCheckState)
616 res = checked (((DoubleConstant) left).Value *
617 ((DoubleConstant) right).Value);
619 res = unchecked (((DoubleConstant) left).Value *
620 ((DoubleConstant) right).Value);
622 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
623 } else if (left is FloatConstant){
625 a = ((FloatConstant) left).DoubleValue;
626 b = ((FloatConstant) right).DoubleValue;
628 if (ec.ConstantCheckState)
629 res = checked (a * b);
631 res = unchecked (a * b);
633 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
634 } else if (left is ULongConstant){
637 if (ec.ConstantCheckState)
638 res = checked (((ULongConstant) left).Value *
639 ((ULongConstant) right).Value);
641 res = unchecked (((ULongConstant) left).Value *
642 ((ULongConstant) right).Value);
644 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
645 } else if (left is LongConstant){
648 if (ec.ConstantCheckState)
649 res = checked (((LongConstant) left).Value *
650 ((LongConstant) right).Value);
652 res = unchecked (((LongConstant) left).Value *
653 ((LongConstant) right).Value);
655 return new LongConstant (ec.BuiltinTypes, res, left.Location);
656 } else if (left is UIntConstant){
659 if (ec.ConstantCheckState)
660 res = checked (((UIntConstant) left).Value *
661 ((UIntConstant) right).Value);
663 res = unchecked (((UIntConstant) left).Value *
664 ((UIntConstant) right).Value);
666 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
667 } else if (left is IntConstant){
670 if (ec.ConstantCheckState)
671 res = checked (((IntConstant) left).Value *
672 ((IntConstant) right).Value);
674 res = unchecked (((IntConstant) left).Value *
675 ((IntConstant) right).Value);
677 return new IntConstant (ec.BuiltinTypes, res, left.Location);
678 } else if (left is DecimalConstant) {
681 if (ec.ConstantCheckState)
682 res = checked (((DecimalConstant) left).Value *
683 ((DecimalConstant) right).Value);
685 res = unchecked (((DecimalConstant) left).Value *
686 ((DecimalConstant) right).Value);
688 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
690 throw new Exception ( "Unexepected multiply input: " + left);
692 } catch (OverflowException){
693 Error_CompileTimeOverflow (ec, loc);
697 case Binary.Operator.Division:
698 if (left is NullLiteral && right is NullLiteral) {
699 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
700 lifted_int.ResolveAsType (ec);
701 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
704 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
708 if (left is DoubleConstant){
711 if (ec.ConstantCheckState)
712 res = checked (((DoubleConstant) left).Value /
713 ((DoubleConstant) right).Value);
715 res = unchecked (((DoubleConstant) left).Value /
716 ((DoubleConstant) right).Value);
718 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
719 } else if (left is FloatConstant){
721 a = ((FloatConstant) left).DoubleValue;
722 b = ((FloatConstant) right).DoubleValue;
724 if (ec.ConstantCheckState)
725 res = checked (a / b);
727 res = unchecked (a / b);
729 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
730 } else if (left is ULongConstant){
733 if (ec.ConstantCheckState)
734 res = checked (((ULongConstant) left).Value /
735 ((ULongConstant) right).Value);
737 res = unchecked (((ULongConstant) left).Value /
738 ((ULongConstant) right).Value);
740 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
741 } else if (left is LongConstant){
744 if (ec.ConstantCheckState)
745 res = checked (((LongConstant) left).Value /
746 ((LongConstant) right).Value);
748 res = unchecked (((LongConstant) left).Value /
749 ((LongConstant) right).Value);
751 return new LongConstant (ec.BuiltinTypes, res, left.Location);
752 } else if (left is UIntConstant){
755 if (ec.ConstantCheckState)
756 res = checked (((UIntConstant) left).Value /
757 ((UIntConstant) right).Value);
759 res = unchecked (((UIntConstant) left).Value /
760 ((UIntConstant) right).Value);
762 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
763 } else if (left is IntConstant){
766 if (ec.ConstantCheckState)
767 res = checked (((IntConstant) left).Value /
768 ((IntConstant) right).Value);
770 res = unchecked (((IntConstant) left).Value /
771 ((IntConstant) right).Value);
773 return new IntConstant (ec.BuiltinTypes, res, left.Location);
774 } else if (left is DecimalConstant) {
777 if (ec.ConstantCheckState)
778 res = checked (((DecimalConstant) left).Value /
779 ((DecimalConstant) right).Value);
781 res = unchecked (((DecimalConstant) left).Value /
782 ((DecimalConstant) right).Value);
784 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
786 throw new Exception ( "Unexepected division input: " + left);
788 } catch (OverflowException){
789 Error_CompileTimeOverflow (ec, loc);
791 } catch (DivideByZeroException) {
792 ec.Report.Error (20, loc, "Division by constant zero");
797 case Binary.Operator.Modulus:
798 if (left is NullLiteral && right is NullLiteral) {
799 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
800 lifted_int.ResolveAsType (ec);
801 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
804 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
808 if (left is DoubleConstant){
811 if (ec.ConstantCheckState)
812 res = checked (((DoubleConstant) left).Value %
813 ((DoubleConstant) right).Value);
815 res = unchecked (((DoubleConstant) left).Value %
816 ((DoubleConstant) right).Value);
818 return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
819 } else if (left is FloatConstant){
821 a = ((FloatConstant) left).DoubleValue;
822 b = ((FloatConstant) right).DoubleValue;
824 if (ec.ConstantCheckState)
825 res = checked (a % b);
827 res = unchecked (a % b);
829 return new FloatConstant (ec.BuiltinTypes, res, left.Location);
830 } else if (left is ULongConstant){
833 if (ec.ConstantCheckState)
834 res = checked (((ULongConstant) left).Value %
835 ((ULongConstant) right).Value);
837 res = unchecked (((ULongConstant) left).Value %
838 ((ULongConstant) right).Value);
840 return new ULongConstant (ec.BuiltinTypes, res, left.Location);
841 } else if (left is LongConstant){
844 if (ec.ConstantCheckState)
845 res = checked (((LongConstant) left).Value %
846 ((LongConstant) right).Value);
848 res = unchecked (((LongConstant) left).Value %
849 ((LongConstant) right).Value);
851 return new LongConstant (ec.BuiltinTypes, res, left.Location);
852 } else if (left is UIntConstant){
855 if (ec.ConstantCheckState)
856 res = checked (((UIntConstant) left).Value %
857 ((UIntConstant) right).Value);
859 res = unchecked (((UIntConstant) left).Value %
860 ((UIntConstant) right).Value);
862 return new UIntConstant (ec.BuiltinTypes, res, left.Location);
863 } else if (left is IntConstant){
866 if (ec.ConstantCheckState)
867 res = checked (((IntConstant) left).Value %
868 ((IntConstant) right).Value);
870 res = unchecked (((IntConstant) left).Value %
871 ((IntConstant) right).Value);
873 return new IntConstant (ec.BuiltinTypes, res, left.Location);
876 if (left is DecimalConstant) {
879 if (ec.ConstantCheckState)
880 res = checked (((DecimalConstant) left).Value %
881 ((DecimalConstant) right).Value);
883 res = unchecked (((DecimalConstant) left).Value %
884 ((DecimalConstant) right).Value);
886 return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
889 throw new Exception ( "Unexepected modulus input: " + left);
890 } catch (DivideByZeroException){
891 ec.Report.Error (20, loc, "Division by constant zero");
892 } catch (OverflowException){
893 Error_CompileTimeOverflow (ec, loc);
898 // There is no overflow checking on left shift
900 case Binary.Operator.LeftShift:
901 if (left is NullLiteral && right is NullLiteral) {
902 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
903 lifted_int.ResolveAsType (ec);
904 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
907 IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
912 int lshift_val = ic.Value;
913 switch (left.Type.BuiltinType) {
914 case BuiltinTypeSpec.Type.ULong:
915 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location);
916 case BuiltinTypeSpec.Type.Long:
917 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location);
918 case BuiltinTypeSpec.Type.UInt:
919 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location);
922 // null << value => null
923 if (left is NullLiteral)
924 return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
926 left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
927 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
928 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location);
933 // There is no overflow checking on right shift
935 case Binary.Operator.RightShift:
936 if (left is NullLiteral && right is NullLiteral) {
937 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
938 lifted_int.ResolveAsType (ec);
939 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
942 IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
946 int rshift_val = sic.Value;
947 switch (left.Type.BuiltinType) {
948 case BuiltinTypeSpec.Type.ULong:
949 return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location);
950 case BuiltinTypeSpec.Type.Long:
951 return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location);
952 case BuiltinTypeSpec.Type.UInt:
953 return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location);
956 // null >> value => null
957 if (left is NullLiteral)
958 return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
960 left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
961 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
962 return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location);
966 case Binary.Operator.Equality:
967 if (TypeSpec.IsReferenceType (lt) && TypeSpec.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 (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
973 new Binary (oper, left, right));
976 if (left is StringConstant && right is StringConstant)
977 return new BoolConstant (ec.BuiltinTypes,
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).DoubleValue ==
992 ((FloatConstant) right).DoubleValue;
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 (ec.BuiltinTypes, bool_res, left.Location);
1010 case Binary.Operator.Inequality:
1011 if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
1012 (left is Nullable.LiftedNull && right.IsNull) ||
1013 (right is Nullable.LiftedNull && left.IsNull)) {
1014 if (left.IsNull || right.IsNull) {
1015 return ReducedExpression.Create (
1016 new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
1017 new Binary (oper, left, right));
1020 if (left is StringConstant && right is StringConstant)
1021 return new BoolConstant (ec.BuiltinTypes,
1022 ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
1027 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1031 if (left is DoubleConstant)
1032 bool_res = ((DoubleConstant) left).Value !=
1033 ((DoubleConstant) right).Value;
1034 else if (left is FloatConstant)
1035 bool_res = ((FloatConstant) left).DoubleValue !=
1036 ((FloatConstant) right).DoubleValue;
1037 else if (left is ULongConstant)
1038 bool_res = ((ULongConstant) left).Value !=
1039 ((ULongConstant) right).Value;
1040 else if (left is LongConstant)
1041 bool_res = ((LongConstant) left).Value !=
1042 ((LongConstant) right).Value;
1043 else if (left is UIntConstant)
1044 bool_res = ((UIntConstant) left).Value !=
1045 ((UIntConstant) right).Value;
1046 else if (left is IntConstant)
1047 bool_res = ((IntConstant) left).Value !=
1048 ((IntConstant) right).Value;
1052 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1054 case Binary.Operator.LessThan:
1055 if (right is NullLiteral) {
1056 if (left is NullLiteral) {
1057 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1058 lifted_int.ResolveAsType (ec);
1059 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1063 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1067 if (left is DoubleConstant)
1068 bool_res = ((DoubleConstant) left).Value <
1069 ((DoubleConstant) right).Value;
1070 else if (left is FloatConstant)
1071 bool_res = ((FloatConstant) left).DoubleValue <
1072 ((FloatConstant) right).DoubleValue;
1073 else if (left is ULongConstant)
1074 bool_res = ((ULongConstant) left).Value <
1075 ((ULongConstant) right).Value;
1076 else if (left is LongConstant)
1077 bool_res = ((LongConstant) left).Value <
1078 ((LongConstant) right).Value;
1079 else if (left is UIntConstant)
1080 bool_res = ((UIntConstant) left).Value <
1081 ((UIntConstant) right).Value;
1082 else if (left is IntConstant)
1083 bool_res = ((IntConstant) left).Value <
1084 ((IntConstant) right).Value;
1088 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1090 case Binary.Operator.GreaterThan:
1091 if (right is NullLiteral) {
1092 if (left is NullLiteral) {
1093 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1094 lifted_int.ResolveAsType (ec);
1095 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1099 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1103 if (left is DoubleConstant)
1104 bool_res = ((DoubleConstant) left).Value >
1105 ((DoubleConstant) right).Value;
1106 else if (left is FloatConstant)
1107 bool_res = ((FloatConstant) left).DoubleValue >
1108 ((FloatConstant) right).DoubleValue;
1109 else if (left is ULongConstant)
1110 bool_res = ((ULongConstant) left).Value >
1111 ((ULongConstant) right).Value;
1112 else if (left is LongConstant)
1113 bool_res = ((LongConstant) left).Value >
1114 ((LongConstant) right).Value;
1115 else if (left is UIntConstant)
1116 bool_res = ((UIntConstant) left).Value >
1117 ((UIntConstant) right).Value;
1118 else if (left is IntConstant)
1119 bool_res = ((IntConstant) left).Value >
1120 ((IntConstant) right).Value;
1124 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1126 case Binary.Operator.GreaterThanOrEqual:
1127 if (right is NullLiteral) {
1128 if (left is NullLiteral) {
1129 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1130 lifted_int.ResolveAsType (ec);
1131 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1135 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1139 if (left is DoubleConstant)
1140 bool_res = ((DoubleConstant) left).Value >=
1141 ((DoubleConstant) right).Value;
1142 else if (left is FloatConstant)
1143 bool_res = ((FloatConstant) left).DoubleValue >=
1144 ((FloatConstant) right).DoubleValue;
1145 else if (left is ULongConstant)
1146 bool_res = ((ULongConstant) left).Value >=
1147 ((ULongConstant) right).Value;
1148 else if (left is LongConstant)
1149 bool_res = ((LongConstant) left).Value >=
1150 ((LongConstant) right).Value;
1151 else if (left is UIntConstant)
1152 bool_res = ((UIntConstant) left).Value >=
1153 ((UIntConstant) right).Value;
1154 else if (left is IntConstant)
1155 bool_res = ((IntConstant) left).Value >=
1156 ((IntConstant) right).Value;
1160 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1162 case Binary.Operator.LessThanOrEqual:
1163 if (right is NullLiteral) {
1164 if (left is NullLiteral) {
1165 var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1166 lifted_int.ResolveAsType (ec);
1167 return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1171 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1175 if (left is DoubleConstant)
1176 bool_res = ((DoubleConstant) left).Value <=
1177 ((DoubleConstant) right).Value;
1178 else if (left is FloatConstant)
1179 bool_res = ((FloatConstant) left).DoubleValue <=
1180 ((FloatConstant) right).DoubleValue;
1181 else if (left is ULongConstant)
1182 bool_res = ((ULongConstant) left).Value <=
1183 ((ULongConstant) right).Value;
1184 else if (left is LongConstant)
1185 bool_res = ((LongConstant) left).Value <=
1186 ((LongConstant) right).Value;
1187 else if (left is UIntConstant)
1188 bool_res = ((UIntConstant) left).Value <=
1189 ((UIntConstant) right).Value;
1190 else if (left is IntConstant)
1191 bool_res = ((IntConstant) left).Value <=
1192 ((IntConstant) right).Value;
1196 return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);