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