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