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