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