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