In mcs and gmcs:
[mono.git] / mcs / mcs / cfold.cs
1 //
2 // cfold.cs: Constant Folding
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2002, 2003 Ximian, Inc.
8 //
9
10 using System;
11
12 namespace Mono.CSharp {
13
14         public class ConstantFold {
15
16                 //
17                 // Performs the numeric promotions on the left and right expresions
18                 // and desposits the results on `lc' and `rc'.
19                 //
20                 // On success, the types of `lc' and `rc' on output will always match,
21                 // and the pair will be one of:
22                 //
23                 //   (double, double)
24                 //   (float, float)
25                 //   (ulong, ulong)
26                 //   (long, long)
27                 //   (uint, uint)
28                 //   (int, int)
29                 //   (short, short)   (Happens with enumerations with underlying short type)
30                 //   (ushort, ushort) (Happens with enumerations with underlying short type)
31                 //
32                 static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper,
33                                                          ref Constant left, ref Constant right,
34                                                          Location loc)
35                 {
36                         if (left is DoubleConstant || right is DoubleConstant){
37                                 //
38                                 // If either side is a double, convert the other to a double
39                                 //
40                                 if (!(left is DoubleConstant))
41                                         left = left.ToDouble (loc);
42
43                                 if (!(right is DoubleConstant))
44                                         right = right.ToDouble (loc);
45                                 return;
46                         } else if (left is FloatConstant || right is FloatConstant) {
47                                 //
48                                 // If either side is a float, convert the other to a float
49                                 //
50                                 if (!(left is FloatConstant))
51                                         left = left.ToFloat (loc);
52
53                                 if (!(right is FloatConstant))
54                                         right = right.ToFloat (loc);
55 ;                               return;
56                         } else if (left is ULongConstant || right is ULongConstant){
57                                 //
58                                 // If either operand is of type ulong, the other operand is
59                                 // converted to type ulong.  or an error ocurrs if the other
60                                 // operand is of type sbyte, short, int or long
61                                 //
62 #if WRONG
63                                 Constant match, other;
64 #endif
65                                         
66                                 if (left is ULongConstant){
67 #if WRONG
68                                         other = right;
69                                         match = left;
70 #endif
71                                         if (!(right is ULongConstant))
72                                                 right = right.ToULong (loc);
73                                 } else {
74 #if WRONG
75                                         other = left;
76                                         match = right;
77 #endif
78                                         left = left.ToULong (loc);
79                                 }
80
81 #if WRONG
82                                 if (other is SByteConstant || other is ShortConstant ||
83                                     other is IntConstant || other is LongConstant){
84                                         Binary.Error_OperatorAmbiguous
85                                                 (loc, oper, other.Type, match.Type);
86                                         left = null;
87                                         right = null;
88                                 }
89 #endif
90                                 return;
91                         } else if (left is LongConstant || right is LongConstant){
92                                 //
93                                 // If either operand is of type long, the other operand is converted
94                                 // to type long.
95                                 //
96                                 if (!(left is LongConstant))
97                                         left = left.ToLong (loc);
98                                 else if (!(right is LongConstant))
99                                         right = right.ToLong (loc);
100                                 return;
101                         } else if (left is UIntConstant || right is UIntConstant){
102                                 //
103                                 // If either operand is of type uint, and the other
104                                 // operand is of type sbyte, short or int, the operands are
105                                 // converted to type long.
106                                 //
107                                 Constant other;
108                                 if (left is UIntConstant)
109                                         other = right;
110                                 else
111                                         other = left;
112
113                                 // Nothing to do.
114                                 if (other is UIntConstant)
115                                         return;
116
117                                 IntConstant ic = other as IntConstant;
118                                 if (ic != null){
119                                         if (ic.Value >= 0){
120                                                 if (left == other)
121                                                         left = new UIntConstant ((uint) ic.Value, ic.Location);
122                                                 else
123                                                         right = new UIntConstant ((uint) ic.Value, ic.Location);
124                                                 return;
125                                         }
126                                 }
127                                 
128                                 if (other is SByteConstant || other is ShortConstant || ic != null){
129                                         left = left.ToLong (loc);
130                                         right = right.ToLong (loc);
131                                 } else {
132                                         left = left.ToUInt (loc);
133                                         right = left.ToUInt (loc);
134                                 }
135
136                                 return;
137                         } else if (left is DecimalConstant || right is DecimalConstant) {
138                                 if (!(left is DecimalConstant))
139                                         left = left.ToDecimal (loc);
140                                 else if (!(right is DecimalConstant))
141                                         right = right.ToDecimal (loc);
142                                 return;
143                         } else if (left is EnumConstant || right is EnumConstant){
144                                 if (left is EnumConstant)
145                                         left = ((EnumConstant) left).Child;
146                                 if (right is EnumConstant)
147                                         right = ((EnumConstant) right).Child;
148
149                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
150                                 return;
151
152                         } else {
153                                 //
154                                 // Force conversions to int32
155                                 //
156                                 if (!(left is IntConstant))
157                                         left = left.ToInt (loc);
158                                 if (!(right is IntConstant))
159                                         right = right.ToInt (loc);
160                         }
161                         return;
162                 }
163
164                 static void Error_CompileTimeOverflow (Location loc)
165                 {
166                         Report.Error (220, loc, "The operation overflows at compile time in checked mode");
167                 }
168                 
169                 /// <summary>
170                 ///   Constant expression folder for binary operations.
171                 ///
172                 ///   Returns null if the expression can not be folded.
173                 /// </summary>
174                 static public Expression BinaryFold (EmitContext ec, Binary.Operator oper,
175                                                      Constant left, Constant right, Location loc)
176                 {
177                         if (left is NullCast)
178                                 return BinaryFold (ec, oper, ((NullCast)left).child, right, loc);
179
180                         if (right is NullCast)
181                                 return BinaryFold (ec, oper, left, ((NullCast)right).child, loc);
182
183                         Type lt = left.Type;
184                         Type rt = right.Type;
185                         Type result_type = null;
186                         bool bool_res;
187
188                         //
189                         // Enumerator folding
190                         //
191                         if (rt == lt && left is EnumConstant)
192                                 result_type = lt;
193
194                         //
195                         // During an enum evaluation, we need to unwrap enumerations
196                         //
197                         if (ec.InEnumContext){
198                                 if (left is EnumConstant)
199                                         left = ((EnumConstant) left).Child;
200                                 
201                                 if (right is EnumConstant)
202                                         right = ((EnumConstant) right).Child;
203                         }
204
205                         if (left is BoolConstant && right is BoolConstant) {
206                                 bool lv = ((BoolConstant) left ).Value;
207                                 bool rv = ((BoolConstant) right).Value;
208                                 switch (oper) {
209                                 case Binary.Operator.BitwiseAnd:
210                                 case Binary.Operator.LogicalAnd:
211                                         return new BoolConstant (lv && rv, left.Location);
212                                 case Binary.Operator.BitwiseOr:
213                                 case Binary.Operator.LogicalOr:
214                                         return new BoolConstant (lv || rv, left.Location);
215                                 case Binary.Operator.ExclusiveOr:
216                                         return new BoolConstant (lv ^ rv, left.Location);
217                                 default:
218                                         throw new InternalErrorException ("Invalid operator on booleans: " + oper);
219                                 }
220                         }
221
222                         Type wrap_as;
223                         Constant result = null;
224                         switch (oper){
225                         case Binary.Operator.BitwiseOr:
226                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
227                                 if (left == null || right == null)
228                                         return null;
229
230                                 if (left is IntConstant){
231                                         IntConstant v;
232                                         int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
233                                         
234                                         v = new IntConstant (res, left.Location);
235                                         if (result_type == null)
236                                                 return v;
237                                         else
238                                                 return new EnumConstant (v, result_type);
239                                 } else if (left is UIntConstant){
240                                         UIntConstant v;
241                                         uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
242                                         
243                                         v = new UIntConstant (res, left.Location);
244                                         if (result_type == null)
245                                                 return v;
246                                         else
247                                                 return new EnumConstant (v, result_type);
248                                 } else if (left is LongConstant){
249                                         LongConstant v;
250                                         long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
251                                         
252                                         v = new LongConstant (res, left.Location);
253                                         if (result_type == null)
254                                                 return v;
255                                         else
256                                                 return new EnumConstant (v, result_type);
257                                 } else if (left is ULongConstant){
258                                         ULongConstant v;
259                                         ulong res = ((ULongConstant)left).Value |
260                                                 ((ULongConstant)right).Value;
261                                         
262                                         v = new ULongConstant (res, left.Location);
263                                         if (result_type == null)
264                                                 return v;
265                                         else
266                                                 return new EnumConstant (v, result_type);
267                                 } else if (left is UShortConstant){
268                                         UShortConstant v;
269                                         ushort res = (ushort) (((UShortConstant)left).Value |
270                                                                ((UShortConstant)right).Value);
271                                         
272                                         v = new UShortConstant (res, left.Location);
273                                         if (result_type == null)
274                                                 return v;
275                                         else
276                                                 return new EnumConstant (v, result_type);
277                                 } else if (left is ShortConstant){
278                                         ShortConstant v;
279                                         short res = (short) (((ShortConstant)left).Value |
280                                                              ((ShortConstant)right).Value);
281                                         
282                                         v = new ShortConstant (res, left.Location);
283                                         if (result_type == null)
284                                                 return v;
285                                         else
286                                                 return new EnumConstant (v, result_type);
287                                 }
288                                 break;
289                                 
290                         case Binary.Operator.BitwiseAnd:
291                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
292                                 if (left == null || right == null)
293                                         return null;
294                                 
295                                 if (left is IntConstant){
296                                         IntConstant v;
297                                         int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
298                                         
299                                         v = new IntConstant (res, left.Location);
300                                         if (result_type == null)
301                                                 return v;
302                                         else
303                                                 return new EnumConstant (v, result_type);
304                                 } else if (left is UIntConstant){
305                                         UIntConstant v;
306                                         uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
307                                         
308                                         v = new UIntConstant (res, left.Location);
309                                         if (result_type == null)
310                                                 return v;
311                                         else
312                                                 return new EnumConstant (v, result_type);
313                                 } else if (left is LongConstant){
314                                         LongConstant v;
315                                         long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
316                                         
317                                         v = new LongConstant (res, left.Location);
318                                         if (result_type == null)
319                                                 return v;
320                                         else
321                                                 return new EnumConstant (v, result_type);
322                                 } else if (left is ULongConstant){
323                                         ULongConstant v;
324                                         ulong res = ((ULongConstant)left).Value &
325                                                 ((ULongConstant)right).Value;
326                                         
327                                         v = new ULongConstant (res, left.Location);
328                                         if (result_type == null)
329                                                 return v;
330                                         else
331                                                 return new EnumConstant (v, result_type);
332                                 } else if (left is UShortConstant){
333                                         UShortConstant v;
334                                         ushort res = (ushort) (((UShortConstant)left).Value &
335                                                                ((UShortConstant)right).Value);
336                                         
337                                         v = new UShortConstant (res, left.Location);
338                                         if (result_type == null)
339                                                 return v;
340                                         else
341                                                 return new EnumConstant (v, result_type);
342                                 } else if (left is ShortConstant){
343                                         ShortConstant v;
344                                         short res = (short) (((ShortConstant)left).Value &
345                                                              ((ShortConstant)right).Value);
346                                         
347                                         v = new ShortConstant (res, left.Location);
348                                         if (result_type == null)
349                                                 return v;
350                                         else
351                                                 return new EnumConstant (v, result_type);
352                                 }
353                                 break;
354
355                         case Binary.Operator.ExclusiveOr:
356                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
357                                 if (left == null || right == null)
358                                         return null;
359                                 
360                                 if (left is IntConstant){
361                                         IntConstant v;
362                                         int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
363                                         
364                                         v = new IntConstant (res, left.Location);
365                                         if (result_type == null)
366                                                 return v;
367                                         else
368                                                 return new EnumConstant (v, result_type);
369                                 } else if (left is UIntConstant){
370                                         UIntConstant v;
371                                         uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
372                                         
373                                         v = new UIntConstant (res, left.Location);
374                                         if (result_type == null)
375                                                 return v;
376                                         else
377                                                 return new EnumConstant (v, result_type);
378                                 } else if (left is LongConstant){
379                                         LongConstant v;
380                                         long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
381                                         
382                                         v = new LongConstant (res, left.Location);
383                                         if (result_type == null)
384                                                 return v;
385                                         else
386                                                 return new EnumConstant (v, result_type);
387                                 } else if (left is ULongConstant){
388                                         ULongConstant v;
389                                         ulong res = ((ULongConstant)left).Value ^
390                                                 ((ULongConstant)right).Value;
391                                         
392                                         v = new ULongConstant (res, left.Location);
393                                         if (result_type == null)
394                                                 return v;
395                                         else
396                                                 return new EnumConstant (v, result_type);
397                                 } else if (left is UShortConstant){
398                                         UShortConstant v;
399                                         ushort res = (ushort) (((UShortConstant)left).Value ^
400                                                                ((UShortConstant)right).Value);
401                                         
402                                         v = new UShortConstant (res, left.Location);
403                                         if (result_type == null)
404                                                 return v;
405                                         else
406                                                 return new EnumConstant (v, result_type);
407                                 } else if (left is ShortConstant){
408                                         ShortConstant v;
409                                         short res = (short)(((ShortConstant)left).Value ^
410                                                             ((ShortConstant)right).Value);
411                                         
412                                         v = new ShortConstant (res, left.Location);
413                                         if (result_type == null)
414                                                 return v;
415                                         else
416                                                 return new EnumConstant (v, result_type);
417                                 }
418                                 break;
419
420                         case Binary.Operator.Addition:
421                                 bool left_is_string = left is StringConstant;
422                                 bool right_is_string = right is StringConstant;
423
424                                 //
425                                 // If both sides are strings, then concatenate, if
426                                 // one is a string, and the other is not, then defer
427                                 // to runtime concatenation
428                                 //
429                                 wrap_as = null;
430                                 if (left_is_string || right_is_string){
431                                         if (left_is_string && right_is_string)
432                                                 return new StringConstant (
433                                                         ((StringConstant) left).Value +
434                                                         ((StringConstant) right).Value, left.Location);
435                                         
436                                         return null;
437                                 }
438
439                                 //
440                                 // handle "E operator + (E x, U y)"
441                                 // handle "E operator + (Y y, E x)"
442                                 //
443                                 // note that E operator + (E x, E y) is invalid
444                                 //
445                                 if (left is EnumConstant){
446                                         if (right is EnumConstant){
447                                                 return null;
448                                         }
449
450                                         right = right.ToType (((EnumConstant) left).Child.Type, loc);
451                                         if (right == null)
452                                                 return null;
453
454                                         wrap_as = left.Type;
455                                 } else if (right is EnumConstant){
456                                         left = left.ToType (((EnumConstant) right).Child.Type, loc);
457                                         if (left == null)
458                                                 return null;
459
460                                         wrap_as = right.Type;
461                                 }
462
463                                 result = null;
464                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
465                                 if (left == null || right == null)
466                                         return null;
467
468                                 try {
469                                         if (left is DoubleConstant){
470                                                 double res;
471                                                 
472                                                 if (ec.ConstantCheckState)
473                                                         res = checked (((DoubleConstant) left).Value +
474                                                                        ((DoubleConstant) right).Value);
475                                                 else
476                                                         res = unchecked (((DoubleConstant) left).Value +
477                                                                          ((DoubleConstant) right).Value);
478                                                 
479                                                 result = new DoubleConstant (res, left.Location);
480                                         } else if (left is FloatConstant){
481                                                 float res;
482                                                 
483                                                 if (ec.ConstantCheckState)
484                                                         res = checked (((FloatConstant) left).Value +
485                                                                        ((FloatConstant) right).Value);
486                                                 else
487                                                         res = unchecked (((FloatConstant) left).Value +
488                                                                          ((FloatConstant) right).Value);
489                                                 
490                                                 result = new FloatConstant (res, left.Location);
491                                         } else if (left is ULongConstant){
492                                                 ulong res;
493                                                 
494                                                 if (ec.ConstantCheckState)
495                                                         res = checked (((ULongConstant) left).Value +
496                                                                        ((ULongConstant) right).Value);
497                                                 else
498                                                         res = unchecked (((ULongConstant) left).Value +
499                                                                          ((ULongConstant) right).Value);
500
501                                                 result = new ULongConstant (res, left.Location);
502                                         } else if (left is LongConstant){
503                                                 long res;
504                                                 
505                                                 if (ec.ConstantCheckState)
506                                                         res = checked (((LongConstant) left).Value +
507                                                                        ((LongConstant) right).Value);
508                                                 else
509                                                         res = unchecked (((LongConstant) left).Value +
510                                                                          ((LongConstant) right).Value);
511                                                 
512                                                 result = new LongConstant (res, left.Location);
513                                         } else if (left is UIntConstant){
514                                                 uint res;
515                                                 
516                                                 if (ec.ConstantCheckState)
517                                                         res = checked (((UIntConstant) left).Value +
518                                                                        ((UIntConstant) right).Value);
519                                                 else
520                                                         res = unchecked (((UIntConstant) left).Value +
521                                                                          ((UIntConstant) right).Value);
522                                                 
523                                                 result = new UIntConstant (res, left.Location);
524                                         } else if (left is IntConstant){
525                                                 int res;
526
527                                                 if (ec.ConstantCheckState)
528                                                         res = checked (((IntConstant) left).Value +
529                                                                        ((IntConstant) right).Value);
530                                                 else
531                                                         res = unchecked (((IntConstant) left).Value +
532                                                                          ((IntConstant) right).Value);
533
534                                                 result = new IntConstant (res, left.Location);
535                                         } else if (left is DecimalConstant) {
536                                                 decimal res;
537
538                                                 if (ec.ConstantCheckState)
539                                                         res = checked (((DecimalConstant) left).Value +
540                                                                 ((DecimalConstant) right).Value);
541                                                 else
542                                                         res = unchecked (((DecimalConstant) left).Value +
543                                                                 ((DecimalConstant) right).Value);
544
545                                                 result = new DecimalConstant (res, left.Location);
546                                         } else {
547                                                 throw new Exception ( "Unexepected addition input: " + left);
548                                         }
549                                 } catch (OverflowException){
550                                         Error_CompileTimeOverflow (loc);
551                                 }
552
553                                 if (wrap_as != null) {
554                                         try {
555                                                 return result.TryReduce (ec, wrap_as, loc);
556                                         }
557                                         catch (OverflowException) {
558                                                 return null;
559                                         }
560                                 }
561                                 else
562                                         return result;
563
564                         case Binary.Operator.Subtraction:
565                                 //
566                                 // handle "E operator - (E x, U y)"
567                                 // handle "E operator - (Y y, E x)"
568                                 // handle "U operator - (E x, E y)"
569                                 //
570                                 wrap_as = null;
571                                 if (left is EnumConstant){
572                                         if (right is EnumConstant){
573                                                 if (left.Type != right.Type) {
574                                                         Binary.Error_OperatorCannotBeApplied (loc, "-", left.Type, right.Type);
575                                                         return null;
576                                                 }
577
578                                                 wrap_as = TypeManager.EnumToUnderlying (left.Type);
579                                                 right = ((EnumConstant) right).Child.ToType (wrap_as, loc);
580                                                 if (right == null)
581                                                         return null;
582
583                                                 left = ((EnumConstant) left).Child.ToType (wrap_as, loc);
584                                                 if (left == null)
585                                                         return null;
586                                         }
587                                         else {
588                                                 right = right.ToType (((EnumConstant) left).Child.Type, loc);
589                                                 if (right == null)
590                                                         return null;
591
592                                                 wrap_as = left.Type;
593                                         }
594                                 } else if (right is EnumConstant){
595                                         left = left.ToType (((EnumConstant) right).Child.Type, loc);
596                                         if (left == null)
597                                                 return null;
598
599                                         wrap_as = right.Type;
600                                 }
601
602                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
603                                 if (left == null || right == null)
604                                         return null;
605
606                                 try {
607                                         if (left is DoubleConstant){
608                                                 double res;
609                                                 
610                                                 if (ec.ConstantCheckState)
611                                                         res = checked (((DoubleConstant) left).Value -
612                                                                        ((DoubleConstant) right).Value);
613                                                 else
614                                                         res = unchecked (((DoubleConstant) left).Value -
615                                                                          ((DoubleConstant) right).Value);
616                                                 
617                                                 result = new DoubleConstant (res, left.Location);
618                                         } else if (left is FloatConstant){
619                                                 float res;
620                                                 
621                                                 if (ec.ConstantCheckState)
622                                                         res = checked (((FloatConstant) left).Value -
623                                                                        ((FloatConstant) right).Value);
624                                                 else
625                                                         res = unchecked (((FloatConstant) left).Value -
626                                                                          ((FloatConstant) right).Value);
627                                                 
628                                                 result = new FloatConstant (res, left.Location);
629                                         } else if (left is ULongConstant){
630                                                 ulong res;
631                                                 
632                                                 if (ec.ConstantCheckState)
633                                                         res = checked (((ULongConstant) left).Value -
634                                                                        ((ULongConstant) right).Value);
635                                                 else
636                                                         res = unchecked (((ULongConstant) left).Value -
637                                                                          ((ULongConstant) right).Value);
638                                                 
639                                                 result = new ULongConstant (res, left.Location);
640                                         } else if (left is LongConstant){
641                                                 long res;
642                                                 
643                                                 if (ec.ConstantCheckState)
644                                                         res = checked (((LongConstant) left).Value -
645                                                                        ((LongConstant) right).Value);
646                                                 else
647                                                         res = unchecked (((LongConstant) left).Value -
648                                                                          ((LongConstant) right).Value);
649                                                 
650                                                 result = new LongConstant (res, left.Location);
651                                         } else if (left is UIntConstant){
652                                                 uint res;
653                                                 
654                                                 if (ec.ConstantCheckState)
655                                                         res = checked (((UIntConstant) left).Value -
656                                                                        ((UIntConstant) right).Value);
657                                                 else
658                                                         res = unchecked (((UIntConstant) left).Value -
659                                                                          ((UIntConstant) right).Value);
660                                                 
661                                                 result = new UIntConstant (res, left.Location);
662                                         } else if (left is IntConstant){
663                                                 int res;
664
665                                                 if (ec.ConstantCheckState)
666                                                         res = checked (((IntConstant) left).Value -
667                                                                        ((IntConstant) right).Value);
668                                                 else
669                                                         res = unchecked (((IntConstant) left).Value -
670                                                                          ((IntConstant) right).Value);
671
672                                                 result = new IntConstant (res, left.Location);
673                                         } else if (left is DecimalConstant) {
674                                                 decimal res;
675
676                                                 if (ec.ConstantCheckState)
677                                                         res = checked (((DecimalConstant) left).Value -
678                                                                 ((DecimalConstant) right).Value);
679                                                 else
680                                                         res = unchecked (((DecimalConstant) left).Value -
681                                                                 ((DecimalConstant) right).Value);
682
683                                                 return new DecimalConstant (res, left.Location);
684                                         } else {
685                                                 throw new Exception ( "Unexepected subtraction input: " + left);
686                                         }
687                                 } catch (OverflowException){
688                                         Error_CompileTimeOverflow (loc);
689                                 }
690
691                                 if (wrap_as != null) {
692                                         try {
693                                                 return result.TryReduce (ec, wrap_as, loc);
694                                         }
695                                         catch (OverflowException) {
696                                                 return null;
697                                         }
698                                 }
699
700                                 return result;
701                                 
702                         case Binary.Operator.Multiply:
703                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
704                                 if (left == null || right == null)
705                                         return null;
706
707                                 try {
708                                         if (left is DoubleConstant){
709                                                 double res;
710                                                 
711                                                 if (ec.ConstantCheckState)
712                                                         res = checked (((DoubleConstant) left).Value *
713                                                                 ((DoubleConstant) right).Value);
714                                                 else
715                                                         res = unchecked (((DoubleConstant) left).Value *
716                                                                 ((DoubleConstant) right).Value);
717                                                 
718                                                 return new DoubleConstant (res, left.Location);
719                                         } else if (left is FloatConstant){
720                                                 float res;
721                                                 
722                                                 if (ec.ConstantCheckState)
723                                                         res = checked (((FloatConstant) left).Value *
724                                                                 ((FloatConstant) right).Value);
725                                                 else
726                                                         res = unchecked (((FloatConstant) left).Value *
727                                                                 ((FloatConstant) right).Value);
728                                                 
729                                                 return new FloatConstant (res, left.Location);
730                                         } else if (left is ULongConstant){
731                                                 ulong res;
732                                                 
733                                                 if (ec.ConstantCheckState)
734                                                         res = checked (((ULongConstant) left).Value *
735                                                                 ((ULongConstant) right).Value);
736                                                 else
737                                                         res = unchecked (((ULongConstant) left).Value *
738                                                                 ((ULongConstant) right).Value);
739                                                 
740                                                 return new ULongConstant (res, left.Location);
741                                         } else if (left is LongConstant){
742                                                 long res;
743                                                 
744                                                 if (ec.ConstantCheckState)
745                                                         res = checked (((LongConstant) left).Value *
746                                                                 ((LongConstant) right).Value);
747                                                 else
748                                                         res = unchecked (((LongConstant) left).Value *
749                                                                 ((LongConstant) right).Value);
750                                                 
751                                                 return new LongConstant (res, left.Location);
752                                         } else if (left is UIntConstant){
753                                                 uint res;
754                                                 
755                                                 if (ec.ConstantCheckState)
756                                                         res = checked (((UIntConstant) left).Value *
757                                                                 ((UIntConstant) right).Value);
758                                                 else
759                                                         res = unchecked (((UIntConstant) left).Value *
760                                                                 ((UIntConstant) right).Value);
761                                                 
762                                                 return new UIntConstant (res, left.Location);
763                                         } else if (left is IntConstant){
764                                                 int res;
765
766                                                 if (ec.ConstantCheckState)
767                                                         res = checked (((IntConstant) left).Value *
768                                                                 ((IntConstant) right).Value);
769                                                 else
770                                                         res = unchecked (((IntConstant) left).Value *
771                                                                 ((IntConstant) right).Value);
772
773                                                 return new IntConstant (res, left.Location);
774                                         } else if (left is DecimalConstant) {
775                                                 decimal res;
776
777                                                 if (ec.ConstantCheckState)
778                                                         res = checked (((DecimalConstant) left).Value *
779                                                                 ((DecimalConstant) right).Value);
780                                                 else
781                                                         res = unchecked (((DecimalConstant) left).Value *
782                                                                 ((DecimalConstant) right).Value);
783
784                                                 return new DecimalConstant (res, left.Location);
785                                         } else {
786                                                 throw new Exception ( "Unexepected multiply input: " + left);
787                                         }
788                                 } catch (OverflowException){
789                                         Error_CompileTimeOverflow (loc);
790                                 }
791                                 break;
792
793                         case Binary.Operator.Division:
794                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
795                                 if (left == null || right == null)
796                                         return null;
797
798                                 try {
799                                         if (left is DoubleConstant){
800                                                 double res;
801                                                 
802                                                 if (ec.ConstantCheckState)
803                                                         res = checked (((DoubleConstant) left).Value /
804                                                                 ((DoubleConstant) right).Value);
805                                                 else
806                                                         res = unchecked (((DoubleConstant) left).Value /
807                                                                 ((DoubleConstant) right).Value);
808                                                 
809                                                 return new DoubleConstant (res, left.Location);
810                                         } else if (left is FloatConstant){
811                                                 float res;
812                                                 
813                                                 if (ec.ConstantCheckState)
814                                                         res = checked (((FloatConstant) left).Value /
815                                                                 ((FloatConstant) right).Value);
816                                                 else
817                                                         res = unchecked (((FloatConstant) left).Value /
818                                                                 ((FloatConstant) right).Value);
819                                                 
820                                                 return new FloatConstant (res, left.Location);
821                                         } else if (left is ULongConstant){
822                                                 ulong res;
823                                                 
824                                                 if (ec.ConstantCheckState)
825                                                         res = checked (((ULongConstant) left).Value /
826                                                                 ((ULongConstant) right).Value);
827                                                 else
828                                                         res = unchecked (((ULongConstant) left).Value /
829                                                                 ((ULongConstant) right).Value);
830                                                 
831                                                 return new ULongConstant (res, left.Location);
832                                         } else if (left is LongConstant){
833                                                 long res;
834                                                 
835                                                 if (ec.ConstantCheckState)
836                                                         res = checked (((LongConstant) left).Value /
837                                                                 ((LongConstant) right).Value);
838                                                 else
839                                                         res = unchecked (((LongConstant) left).Value /
840                                                                 ((LongConstant) right).Value);
841                                                 
842                                                 return new LongConstant (res, left.Location);
843                                         } else if (left is UIntConstant){
844                                                 uint res;
845                                                 
846                                                 if (ec.ConstantCheckState)
847                                                         res = checked (((UIntConstant) left).Value /
848                                                                 ((UIntConstant) right).Value);
849                                                 else
850                                                         res = unchecked (((UIntConstant) left).Value /
851                                                                 ((UIntConstant) right).Value);
852                                                 
853                                                 return new UIntConstant (res, left.Location);
854                                         } else if (left is IntConstant){
855                                                 int res;
856
857                                                 if (ec.ConstantCheckState)
858                                                         res = checked (((IntConstant) left).Value /
859                                                                 ((IntConstant) right).Value);
860                                                 else
861                                                         res = unchecked (((IntConstant) left).Value /
862                                                                 ((IntConstant) right).Value);
863
864                                                 return new IntConstant (res, left.Location);
865                                         } else if (left is DecimalConstant) {
866                                                 decimal res;
867
868                                                 if (ec.ConstantCheckState)
869                                                         res = checked (((DecimalConstant) left).Value /
870                                                                 ((DecimalConstant) right).Value);
871                                                 else
872                                                         res = unchecked (((DecimalConstant) left).Value /
873                                                                 ((DecimalConstant) right).Value);
874
875                                                 return new DecimalConstant (res, left.Location);
876                                         } else {
877                                                 throw new Exception ( "Unexepected division input: " + left);
878                                         }
879                                 } catch (OverflowException){
880                                         Error_CompileTimeOverflow (loc);
881
882                                 } catch (DivideByZeroException) {
883                                         Report.Error (020, loc, "Division by constant zero");
884                                 }
885                                 
886                                 break;
887                                 
888                         case Binary.Operator.Modulus:
889                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
890                                 if (left == null || right == null)
891                                         return null;
892
893                                 try {
894                                         if (left is DoubleConstant){
895                                                 double res;
896                                                 
897                                                 if (ec.ConstantCheckState)
898                                                         res = checked (((DoubleConstant) left).Value %
899                                                                        ((DoubleConstant) right).Value);
900                                                 else
901                                                         res = unchecked (((DoubleConstant) left).Value %
902                                                                          ((DoubleConstant) right).Value);
903                                                 
904                                                 return new DoubleConstant (res, left.Location);
905                                         } else if (left is FloatConstant){
906                                                 float res;
907                                                 
908                                                 if (ec.ConstantCheckState)
909                                                         res = checked (((FloatConstant) left).Value %
910                                                                        ((FloatConstant) right).Value);
911                                                 else
912                                                         res = unchecked (((FloatConstant) left).Value %
913                                                                          ((FloatConstant) right).Value);
914                                                 
915                                                 return new FloatConstant (res, left.Location);
916                                         } else if (left is ULongConstant){
917                                                 ulong res;
918                                                 
919                                                 if (ec.ConstantCheckState)
920                                                         res = checked (((ULongConstant) left).Value %
921                                                                        ((ULongConstant) right).Value);
922                                                 else
923                                                         res = unchecked (((ULongConstant) left).Value %
924                                                                          ((ULongConstant) right).Value);
925                                                 
926                                                 return new ULongConstant (res, left.Location);
927                                         } else if (left is LongConstant){
928                                                 long res;
929                                                 
930                                                 if (ec.ConstantCheckState)
931                                                         res = checked (((LongConstant) left).Value %
932                                                                        ((LongConstant) right).Value);
933                                                 else
934                                                         res = unchecked (((LongConstant) left).Value %
935                                                                          ((LongConstant) right).Value);
936                                                 
937                                                 return new LongConstant (res, left.Location);
938                                         } else if (left is UIntConstant){
939                                                 uint res;
940                                                 
941                                                 if (ec.ConstantCheckState)
942                                                         res = checked (((UIntConstant) left).Value %
943                                                                        ((UIntConstant) right).Value);
944                                                 else
945                                                         res = unchecked (((UIntConstant) left).Value %
946                                                                          ((UIntConstant) right).Value);
947                                                 
948                                                 return new UIntConstant (res, left.Location);
949                                         } else if (left is IntConstant){
950                                                 int res;
951
952                                                 if (ec.ConstantCheckState)
953                                                         res = checked (((IntConstant) left).Value %
954                                                                        ((IntConstant) right).Value);
955                                                 else
956                                                         res = unchecked (((IntConstant) left).Value %
957                                                                          ((IntConstant) right).Value);
958
959                                                 return new IntConstant (res, left.Location);
960                                         } else {
961                                                 throw new Exception ( "Unexepected modulus input: " + left);
962                                         }
963                                 } catch (DivideByZeroException){
964                                         Report.Error (020, loc, "Division by constant zero");
965                                 } catch (OverflowException){
966                                         Error_CompileTimeOverflow (loc);
967                                 }
968                                 break;
969
970                                 //
971                                 // There is no overflow checking on left shift
972                                 //
973                         case Binary.Operator.LeftShift:
974                                 IntConstant ic = right.ToInt (loc);
975                                 if (ic == null){
976                                         Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
977                                         return null;
978                                 }
979                                 int lshift_val = ic.Value;
980
981                                 IntConstant lic;
982                                 if ((lic = left.ConvertToInt ()) != null)
983                                         return new IntConstant (lic.Value << lshift_val, left.Location);
984
985                                 UIntConstant luic;
986                                 if ((luic = left.ConvertToUInt ()) != null)
987                                         return new UIntConstant (luic.Value << lshift_val, left.Location);
988
989                                 LongConstant llc;
990                                 if ((llc = left.ConvertToLong ()) != null)
991                                         return new LongConstant (llc.Value << lshift_val, left.Location);
992
993                                 ULongConstant lulc;
994                                 if ((lulc = left.ConvertToULong ()) != null)
995                                         return new ULongConstant (lulc.Value << lshift_val, left.Location);
996
997                                 Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
998                                 break;
999
1000                                 //
1001                                 // There is no overflow checking on right shift
1002                                 //
1003                         case Binary.Operator.RightShift:
1004                                 IntConstant sic = right.ToInt (loc);
1005                                 if (sic == null){
1006                                         Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
1007                                         return null;
1008                                 }
1009                                 int rshift_val = sic.Value;
1010
1011                                 IntConstant ric;
1012                                 if ((ric = left.ConvertToInt ()) != null)
1013                                         return new IntConstant (ric.Value >> rshift_val, left.Location);
1014
1015                                 UIntConstant ruic;
1016                                 if ((ruic = left.ConvertToUInt ()) != null)
1017                                         return new UIntConstant (ruic.Value >> rshift_val, left.Location);
1018
1019                                 LongConstant rlc;
1020                                 if ((rlc = left.ConvertToLong ()) != null)
1021                                         return new LongConstant (rlc.Value >> rshift_val, left.Location);
1022
1023                                 ULongConstant rulc;
1024                                 if ((rulc = left.ConvertToULong ()) != null)
1025                                         return new ULongConstant (rulc.Value >> rshift_val, left.Location);
1026
1027                                 Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
1028                                 break;
1029
1030                         case Binary.Operator.Equality:
1031                                 if (left is BoolConstant && right is BoolConstant){
1032                                         return new BoolConstant (
1033                                                 ((BoolConstant) left).Value ==
1034                                                 ((BoolConstant) right).Value, left.Location);
1035                                 
1036                                 }
1037                                 if (left is NullLiteral){
1038                                         if (right is NullLiteral)
1039                                                 return new BoolConstant (true, left.Location);
1040                                         else if (right is StringConstant)
1041                                                 return new BoolConstant (
1042                                                         ((StringConstant) right).Value == null, left.Location);
1043                                 } else if (right is NullLiteral){
1044                                         if (left is NullLiteral)
1045                                                 return new BoolConstant (true, left.Location);
1046                                         else if (left is StringConstant)
1047                                                 return new BoolConstant (
1048                                                         ((StringConstant) left).Value == null, left.Location);
1049                                 }
1050                                 if (left is StringConstant && right is StringConstant){
1051                                         return new BoolConstant (
1052                                                 ((StringConstant) left).Value ==
1053                                                 ((StringConstant) right).Value, left.Location);
1054                                         
1055                                 }
1056
1057                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1058                                 if (left == null || right == null)
1059                                         return null;
1060
1061                                 bool_res = false;
1062                                 if (left is DoubleConstant)
1063                                         bool_res = ((DoubleConstant) left).Value ==
1064                                                 ((DoubleConstant) right).Value;
1065                                 else if (left is FloatConstant)
1066                                         bool_res = ((FloatConstant) left).Value ==
1067                                                 ((FloatConstant) right).Value;
1068                                 else if (left is ULongConstant)
1069                                         bool_res = ((ULongConstant) left).Value ==
1070                                                 ((ULongConstant) right).Value;
1071                                 else if (left is LongConstant)
1072                                         bool_res = ((LongConstant) left).Value ==
1073                                                 ((LongConstant) right).Value;
1074                                 else if (left is UIntConstant)
1075                                         bool_res = ((UIntConstant) left).Value ==
1076                                                 ((UIntConstant) right).Value;
1077                                 else if (left is IntConstant)
1078                                         bool_res = ((IntConstant) left).Value ==
1079                                                 ((IntConstant) right).Value;
1080                                 else
1081                                         return null;
1082
1083                                 return new BoolConstant (bool_res, left.Location);
1084
1085                         case Binary.Operator.Inequality:
1086                                 if (left is BoolConstant && right is BoolConstant){
1087                                         return new BoolConstant (
1088                                                 ((BoolConstant) left).Value !=
1089                                                 ((BoolConstant) right).Value, left.Location);
1090                                 }
1091                                 if (left is NullLiteral){
1092                                         if (right is NullLiteral)
1093                                                 return new BoolConstant (false, left.Location);
1094                                         else if (right is StringConstant)
1095                                                 return new BoolConstant (
1096                                                         ((StringConstant) right).Value != null, left.Location);
1097                                 } else if (right is NullLiteral){
1098                                         if (left is NullLiteral)
1099                                                 return new BoolConstant (false, left.Location);
1100                                         else if (left is StringConstant)
1101                                                 return new BoolConstant (
1102                                                         ((StringConstant) left).Value != null, left.Location);
1103                                 }
1104                                 if (left is StringConstant && right is StringConstant){
1105                                         return new BoolConstant (
1106                                                 ((StringConstant) left).Value !=
1107                                                 ((StringConstant) right).Value, left.Location);
1108                                         
1109                                 }
1110                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1111                                 if (left == null || right == null)
1112                                         return null;
1113
1114                                 bool_res = false;
1115                                 if (left is DoubleConstant)
1116                                         bool_res = ((DoubleConstant) left).Value !=
1117                                                 ((DoubleConstant) right).Value;
1118                                 else if (left is FloatConstant)
1119                                         bool_res = ((FloatConstant) left).Value !=
1120                                                 ((FloatConstant) right).Value;
1121                                 else if (left is ULongConstant)
1122                                         bool_res = ((ULongConstant) left).Value !=
1123                                                 ((ULongConstant) right).Value;
1124                                 else if (left is LongConstant)
1125                                         bool_res = ((LongConstant) left).Value !=
1126                                                 ((LongConstant) right).Value;
1127                                 else if (left is UIntConstant)
1128                                         bool_res = ((UIntConstant) left).Value !=
1129                                                 ((UIntConstant) right).Value;
1130                                 else if (left is IntConstant)
1131                                         bool_res = ((IntConstant) left).Value !=
1132                                                 ((IntConstant) right).Value;
1133                                 else
1134                                         return null;
1135
1136                                 return new BoolConstant (bool_res, left.Location);
1137
1138                         case Binary.Operator.LessThan:
1139                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1140                                 if (left == null || right == null)
1141                                         return null;
1142
1143                                 bool_res = false;
1144                                 if (left is DoubleConstant)
1145                                         bool_res = ((DoubleConstant) left).Value <
1146                                                 ((DoubleConstant) right).Value;
1147                                 else if (left is FloatConstant)
1148                                         bool_res = ((FloatConstant) left).Value <
1149                                                 ((FloatConstant) right).Value;
1150                                 else if (left is ULongConstant)
1151                                         bool_res = ((ULongConstant) left).Value <
1152                                                 ((ULongConstant) right).Value;
1153                                 else if (left is LongConstant)
1154                                         bool_res = ((LongConstant) left).Value <
1155                                                 ((LongConstant) right).Value;
1156                                 else if (left is UIntConstant)
1157                                         bool_res = ((UIntConstant) left).Value <
1158                                                 ((UIntConstant) right).Value;
1159                                 else if (left is IntConstant)
1160                                         bool_res = ((IntConstant) left).Value <
1161                                                 ((IntConstant) right).Value;
1162                                 else
1163                                         return null;
1164
1165                                 return new BoolConstant (bool_res, left.Location);
1166                                 
1167                         case Binary.Operator.GreaterThan:
1168                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1169                                 if (left == null || right == null)
1170                                         return null;
1171
1172                                 bool_res = false;
1173                                 if (left is DoubleConstant)
1174                                         bool_res = ((DoubleConstant) left).Value >
1175                                                 ((DoubleConstant) right).Value;
1176                                 else if (left is FloatConstant)
1177                                         bool_res = ((FloatConstant) left).Value >
1178                                                 ((FloatConstant) right).Value;
1179                                 else if (left is ULongConstant)
1180                                         bool_res = ((ULongConstant) left).Value >
1181                                                 ((ULongConstant) right).Value;
1182                                 else if (left is LongConstant)
1183                                         bool_res = ((LongConstant) left).Value >
1184                                                 ((LongConstant) right).Value;
1185                                 else if (left is UIntConstant)
1186                                         bool_res = ((UIntConstant) left).Value >
1187                                                 ((UIntConstant) right).Value;
1188                                 else if (left is IntConstant)
1189                                         bool_res = ((IntConstant) left).Value >
1190                                                 ((IntConstant) right).Value;
1191                                 else
1192                                         return null;
1193
1194                                 return new BoolConstant (bool_res, left.Location);
1195
1196                         case Binary.Operator.GreaterThanOrEqual:
1197                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1198                                 if (left == null || right == null)
1199                                         return null;
1200
1201                                 bool_res = false;
1202                                 if (left is DoubleConstant)
1203                                         bool_res = ((DoubleConstant) left).Value >=
1204                                                 ((DoubleConstant) right).Value;
1205                                 else if (left is FloatConstant)
1206                                         bool_res = ((FloatConstant) left).Value >=
1207                                                 ((FloatConstant) right).Value;
1208                                 else if (left is ULongConstant)
1209                                         bool_res = ((ULongConstant) left).Value >=
1210                                                 ((ULongConstant) right).Value;
1211                                 else if (left is LongConstant)
1212                                         bool_res = ((LongConstant) left).Value >=
1213                                                 ((LongConstant) right).Value;
1214                                 else if (left is UIntConstant)
1215                                         bool_res = ((UIntConstant) left).Value >=
1216                                                 ((UIntConstant) right).Value;
1217                                 else if (left is IntConstant)
1218                                         bool_res = ((IntConstant) left).Value >=
1219                                                 ((IntConstant) right).Value;
1220                                 else
1221                                         return null;
1222
1223                                 return new BoolConstant (bool_res, left.Location);
1224
1225                         case Binary.Operator.LessThanOrEqual:
1226                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1227                                 if (left == null || right == null)
1228                                         return null;
1229
1230                                 bool_res = false;
1231                                 if (left is DoubleConstant)
1232                                         bool_res = ((DoubleConstant) left).Value <=
1233                                                 ((DoubleConstant) right).Value;
1234                                 else if (left is FloatConstant)
1235                                         bool_res = ((FloatConstant) left).Value <=
1236                                                 ((FloatConstant) right).Value;
1237                                 else if (left is ULongConstant)
1238                                         bool_res = ((ULongConstant) left).Value <=
1239                                                 ((ULongConstant) right).Value;
1240                                 else if (left is LongConstant)
1241                                         bool_res = ((LongConstant) left).Value <=
1242                                                 ((LongConstant) right).Value;
1243                                 else if (left is UIntConstant)
1244                                         bool_res = ((UIntConstant) left).Value <=
1245                                                 ((UIntConstant) right).Value;
1246                                 else if (left is IntConstant)
1247                                         bool_res = ((IntConstant) left).Value <=
1248                                                 ((IntConstant) right).Value;
1249                                 else
1250                                         return null;
1251
1252                                 return new BoolConstant (bool_res, left.Location);
1253                         }
1254                                         
1255                         return null;
1256                 }
1257         }
1258 }