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