new tests + update
[mono.git] / mcs / mcs / cfold.cs
1 //
2 // cfold.cs: Constant Folding
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2002, 2003 Ximian, Inc.
8 //
9
10 using System;
11
12 namespace Mono.CSharp {
13
14         public class ConstantFold {
15
16                 //
17                 // Performs the numeric promotions on the left and right expresions
18                 // and desposits the results on `lc' and `rc'.
19                 //
20                 // On success, the types of `lc' and `rc' on output will always match,
21                 // and the pair will be one of:
22                 //
23                 //   (double, double)
24                 //   (float, float)
25                 //   (ulong, ulong)
26                 //   (long, long)
27                 //   (uint, uint)
28                 //   (int, int)
29                 //   (short, short)   (Happens with enumerations with underlying short type)
30                 //   (ushort, ushort) (Happens with enumerations with underlying short type)
31                 //
32                 static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper,
33                                                          ref Constant left, ref Constant right,
34                                                          Location loc)
35                 {
36                         if (left is DoubleConstant || right is DoubleConstant){
37                                 //
38                                 // If either side is a double, convert the other to a double
39                                 //
40                                 if (!(left is DoubleConstant))
41                                         left = left.ToDouble (loc);
42
43                                 if (!(right is DoubleConstant))
44                                         right = right.ToDouble (loc);
45                                 return;
46                         } else if (left is FloatConstant || right is FloatConstant) {
47                                 //
48                                 // If either side is a float, convert the other to a float
49                                 //
50                                 if (!(left is FloatConstant))
51                                         left = left.ToFloat (loc);
52
53                                 if (!(right is FloatConstant))
54                                         right = right.ToFloat (loc);
55 ;                               return;
56                         } else if (left is ULongConstant || right is ULongConstant){
57                                 //
58                                 // If either operand is of type ulong, the other operand is
59                                 // converted to type ulong.  or an error ocurrs if the other
60                                 // operand is of type sbyte, short, int or long
61                                 //
62 #if WRONG
63                                 Constant match, other;
64 #endif
65                                         
66                                 if (left is ULongConstant){
67 #if WRONG
68                                         other = right;
69                                         match = left;
70 #endif
71                                         if (!(right is ULongConstant))
72                                                 right = right.ToULong (loc);
73                                 } else {
74 #if WRONG
75                                         other = left;
76                                         match = right;
77 #endif
78                                         left = left.ToULong (loc);
79                                 }
80
81 #if WRONG
82                                 if (other is SByteConstant || other is ShortConstant ||
83                                     other is IntConstant || other is LongConstant){
84                                         Binary.Error_OperatorAmbiguous
85                                                 (loc, oper, other.Type, match.Type);
86                                         left = null;
87                                         right = null;
88                                 }
89 #endif
90                                 return;
91                         } else if (left is LongConstant || right is LongConstant){
92                                 //
93                                 // If either operand is of type long, the other operand is converted
94                                 // to type long.
95                                 //
96                                 if (!(left is LongConstant))
97                                         left = left.ToLong (loc);
98                                 else if (!(right is LongConstant))
99                                         right = right.ToLong (loc);
100                                 return;
101                         } else if (left is UIntConstant || right is UIntConstant){
102                                 //
103                                 // If either operand is of type uint, and the other
104                                 // operand is of type sbyte, short or int, the operands are
105                                 // converted to type long.
106                                 //
107                                 Constant other;
108                                 if (left is UIntConstant)
109                                         other = right;
110                                 else
111                                         other = left;
112
113                                 // Nothing to do.
114                                 if (other is UIntConstant)
115                                         return;
116
117                                 IntConstant ic = other as IntConstant;
118                                 if (ic != null){
119                                         if (ic.Value >= 0){
120                                                 if (left == other)
121                                                         left = new UIntConstant ((uint) ic.Value, ic.Location);
122                                                 else
123                                                         right = new UIntConstant ((uint) ic.Value, ic.Location);
124                                                 return;
125                                         }
126                                 }
127                                 
128                                 if (other is SByteConstant || other is ShortConstant || ic != null){
129                                         left = left.ToLong (loc);
130                                         right = right.ToLong (loc);
131                                 } else {
132                                         left = left.ToUInt (loc);
133                                         right = left.ToUInt (loc);
134                                 }
135
136                                 return;
137                         } else if (left is DecimalConstant || right is DecimalConstant) {
138                                 if (!(left is DecimalConstant))
139                                         left = left.ToDecimal (loc);
140                                 else if (!(right is DecimalConstant))
141                                         right = right.ToDecimal (loc);
142                                 return;
143                         } else if (left is EnumConstant || right is EnumConstant){
144                                 //
145                                 // If either operand is an enum constant, the other one must
146                                 // be implicitly convertable to that enum's underlying type.
147                                 //
148                                 EnumConstant match;
149                                 Constant other;
150                                 if (left is EnumConstant){
151                                         other = right;
152                                         match = (EnumConstant) left;
153                                 } else {
154                                         other = left;
155                                         match = (EnumConstant) right;
156                                 }
157
158                                 bool need_check = (other is EnumConstant) ||
159                                         !(oper == Binary.Operator.Addition || 
160                                           oper == Binary.Operator.Subtraction ||
161                                           (other.IsZeroInteger && other is IntConstant));
162
163                                 if (need_check &&
164                                     !Convert.ImplicitConversionExists (ec, match, other.Type)) {
165                                         Convert.Error_CannotImplicitConversion (loc, match.Type, other.Type);
166                                         left = null;
167                                         right = null;
168                                         return;
169                                 }
170
171                                 if (left is EnumConstant)
172                                         left = ((EnumConstant) left).Child;
173                                 if (right is EnumConstant)
174                                         right = ((EnumConstant) right).Child;
175
176                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
177                                 return;
178
179                         } else {
180                                 //
181                                 // Force conversions to int32
182                                 //
183                                 if (!(left is IntConstant))
184                                         left = left.ToInt (loc);
185                                 if (!(right is IntConstant))
186                                         right = right.ToInt (loc);
187                         }
188                         return;
189                 }
190
191                 static void Error_CompileTimeOverflow (Location loc)
192                 {
193                         Report.Error (220, loc, "The operation overflows at compile time in checked mode");
194                 }
195                 
196                 /// <summary>
197                 ///   Constant expression folder for binary operations.
198                 ///
199                 ///   Returns null if the expression can not be folded.
200                 /// </summary>
201                 static public Expression BinaryFold (EmitContext ec, Binary.Operator oper,
202                                                      Constant left, Constant right, Location loc)
203                 {
204                         Type lt = left.Type;
205                         Type rt = right.Type;
206                         Type result_type = null;
207                         bool bool_res;
208
209                         //
210                         // Enumerator folding
211                         //
212                         if (rt == lt && left is EnumConstant)
213                                 result_type = lt;
214
215                         //
216                         // During an enum evaluation, we need to unwrap enumerations
217                         //
218                         if (ec.InEnumContext){
219                                 if (left is EnumConstant)
220                                         left = ((EnumConstant) left).Child;
221                                 
222                                 if (right is EnumConstant)
223                                         right = ((EnumConstant) right).Child;
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, loc);
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, loc);
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                                         return new EnumConstant (result, wrap_as);
559                                 else
560                                         return result;
561
562                         case Binary.Operator.Subtraction:
563                                 //
564                                 // handle "E operator - (E x, U y)"
565                                 // handle "E operator - (Y y, E x)"
566                                 // handle "U operator - (E x, E y)"
567                                 //
568                                 wrap_as = null;
569                                 if (left is EnumConstant){
570                                         if (right is EnumConstant){
571                                                 if (left.Type != right.Type) {
572                                                         Binary.Error_OperatorCannotBeApplied (loc, "-", left.Type, right.Type);
573                                                         return null;
574                                                 }
575
576                                                 wrap_as = TypeManager.EnumToUnderlying (left.Type);
577                                                 right = ((EnumConstant) right).Child.ToType (wrap_as, loc);
578                                                 if (right == null)
579                                                         return null;
580
581                                                 left = ((EnumConstant) left).Child.ToType (wrap_as, loc);
582                                                 if (left == null)
583                                                         return null;
584                                         }
585                                         else {
586                                                 right = right.ToType (((EnumConstant) left).Child.Type, loc);
587                                                 if (right == null)
588                                                         return null;
589
590                                                 wrap_as = left.Type;
591                                         }
592                                 } else if (right is EnumConstant){
593                                         left = left.ToType (((EnumConstant) right).Child.Type, loc);
594                                         if (left == null)
595                                                 return null;
596
597                                         wrap_as = right.Type;
598                                 }
599
600                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
601                                 if (left == null || right == null)
602                                         return null;
603
604                                 try {
605                                         if (left is DoubleConstant){
606                                                 double res;
607                                                 
608                                                 if (ec.ConstantCheckState)
609                                                         res = checked (((DoubleConstant) left).Value -
610                                                                        ((DoubleConstant) right).Value);
611                                                 else
612                                                         res = unchecked (((DoubleConstant) left).Value -
613                                                                          ((DoubleConstant) right).Value);
614                                                 
615                                                 result = new DoubleConstant (res, left.Location);
616                                         } else if (left is FloatConstant){
617                                                 float res;
618                                                 
619                                                 if (ec.ConstantCheckState)
620                                                         res = checked (((FloatConstant) left).Value -
621                                                                        ((FloatConstant) right).Value);
622                                                 else
623                                                         res = unchecked (((FloatConstant) left).Value -
624                                                                          ((FloatConstant) right).Value);
625                                                 
626                                                 result = new FloatConstant (res, left.Location);
627                                         } else if (left is ULongConstant){
628                                                 ulong res;
629                                                 
630                                                 if (ec.ConstantCheckState)
631                                                         res = checked (((ULongConstant) left).Value -
632                                                                        ((ULongConstant) right).Value);
633                                                 else
634                                                         res = unchecked (((ULongConstant) left).Value -
635                                                                          ((ULongConstant) right).Value);
636                                                 
637                                                 result = new ULongConstant (res, left.Location);
638                                         } else if (left is LongConstant){
639                                                 long res;
640                                                 
641                                                 if (ec.ConstantCheckState)
642                                                         res = checked (((LongConstant) left).Value -
643                                                                        ((LongConstant) right).Value);
644                                                 else
645                                                         res = unchecked (((LongConstant) left).Value -
646                                                                          ((LongConstant) right).Value);
647                                                 
648                                                 result = new LongConstant (res, left.Location);
649                                         } else if (left is UIntConstant){
650                                                 uint res;
651                                                 
652                                                 if (ec.ConstantCheckState)
653                                                         res = checked (((UIntConstant) left).Value -
654                                                                        ((UIntConstant) right).Value);
655                                                 else
656                                                         res = unchecked (((UIntConstant) left).Value -
657                                                                          ((UIntConstant) right).Value);
658                                                 
659                                                 result = new UIntConstant (res, left.Location);
660                                         } else if (left is IntConstant){
661                                                 int res;
662
663                                                 if (ec.ConstantCheckState)
664                                                         res = checked (((IntConstant) left).Value -
665                                                                        ((IntConstant) right).Value);
666                                                 else
667                                                         res = unchecked (((IntConstant) left).Value -
668                                                                          ((IntConstant) right).Value);
669
670                                                 result = new IntConstant (res, left.Location);
671                                         } else if (left is DecimalConstant) {
672                                                 decimal res;
673
674                                                 if (ec.ConstantCheckState)
675                                                         res = checked (((DecimalConstant) left).Value -
676                                                                 ((DecimalConstant) right).Value);
677                                                 else
678                                                         res = unchecked (((DecimalConstant) left).Value -
679                                                                 ((DecimalConstant) right).Value);
680
681                                                 return new DecimalConstant (res, left.Location);
682                                         } else {
683                                                 throw new Exception ( "Unexepected subtraction input: " + left);
684                                         }
685                                 } catch (OverflowException){
686                                         Error_CompileTimeOverflow (loc);
687                                 }
688                                 if (wrap_as != null)
689                                         return new EnumConstant (result, wrap_as);
690                                 else
691                                         return result;
692                                 
693                         case Binary.Operator.Multiply:
694                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
695                                 if (left == null || right == null)
696                                         return null;
697
698                                 try {
699                                         if (left is DoubleConstant){
700                                                 double res;
701                                                 
702                                                 if (ec.ConstantCheckState)
703                                                         res = checked (((DoubleConstant) left).Value *
704                                                                 ((DoubleConstant) right).Value);
705                                                 else
706                                                         res = unchecked (((DoubleConstant) left).Value *
707                                                                 ((DoubleConstant) right).Value);
708                                                 
709                                                 return new DoubleConstant (res, left.Location);
710                                         } else if (left is FloatConstant){
711                                                 float res;
712                                                 
713                                                 if (ec.ConstantCheckState)
714                                                         res = checked (((FloatConstant) left).Value *
715                                                                 ((FloatConstant) right).Value);
716                                                 else
717                                                         res = unchecked (((FloatConstant) left).Value *
718                                                                 ((FloatConstant) right).Value);
719                                                 
720                                                 return new FloatConstant (res, left.Location);
721                                         } else if (left is ULongConstant){
722                                                 ulong res;
723                                                 
724                                                 if (ec.ConstantCheckState)
725                                                         res = checked (((ULongConstant) left).Value *
726                                                                 ((ULongConstant) right).Value);
727                                                 else
728                                                         res = unchecked (((ULongConstant) left).Value *
729                                                                 ((ULongConstant) right).Value);
730                                                 
731                                                 return new ULongConstant (res, left.Location);
732                                         } else if (left is LongConstant){
733                                                 long res;
734                                                 
735                                                 if (ec.ConstantCheckState)
736                                                         res = checked (((LongConstant) left).Value *
737                                                                 ((LongConstant) right).Value);
738                                                 else
739                                                         res = unchecked (((LongConstant) left).Value *
740                                                                 ((LongConstant) right).Value);
741                                                 
742                                                 return new LongConstant (res, left.Location);
743                                         } else if (left is UIntConstant){
744                                                 uint res;
745                                                 
746                                                 if (ec.ConstantCheckState)
747                                                         res = checked (((UIntConstant) left).Value *
748                                                                 ((UIntConstant) right).Value);
749                                                 else
750                                                         res = unchecked (((UIntConstant) left).Value *
751                                                                 ((UIntConstant) right).Value);
752                                                 
753                                                 return new UIntConstant (res, left.Location);
754                                         } else if (left is IntConstant){
755                                                 int res;
756
757                                                 if (ec.ConstantCheckState)
758                                                         res = checked (((IntConstant) left).Value *
759                                                                 ((IntConstant) right).Value);
760                                                 else
761                                                         res = unchecked (((IntConstant) left).Value *
762                                                                 ((IntConstant) right).Value);
763
764                                                 return new IntConstant (res, left.Location);
765                                         } else if (left is DecimalConstant) {
766                                                 decimal res;
767
768                                                 if (ec.ConstantCheckState)
769                                                         res = checked (((DecimalConstant) left).Value *
770                                                                 ((DecimalConstant) right).Value);
771                                                 else
772                                                         res = unchecked (((DecimalConstant) left).Value *
773                                                                 ((DecimalConstant) right).Value);
774
775                                                 return new DecimalConstant (res, left.Location);
776                                         } else {
777                                                 throw new Exception ( "Unexepected multiply input: " + left);
778                                         }
779                                 } catch (OverflowException){
780                                         Error_CompileTimeOverflow (loc);
781                                 }
782                                 break;
783
784                         case Binary.Operator.Division:
785                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
786                                 if (left == null || right == null)
787                                         return null;
788
789                                 try {
790                                         if (left is DoubleConstant){
791                                                 double res;
792                                                 
793                                                 if (ec.ConstantCheckState)
794                                                         res = checked (((DoubleConstant) left).Value /
795                                                                 ((DoubleConstant) right).Value);
796                                                 else
797                                                         res = unchecked (((DoubleConstant) left).Value /
798                                                                 ((DoubleConstant) right).Value);
799                                                 
800                                                 return new DoubleConstant (res, left.Location);
801                                         } else if (left is FloatConstant){
802                                                 float res;
803                                                 
804                                                 if (ec.ConstantCheckState)
805                                                         res = checked (((FloatConstant) left).Value /
806                                                                 ((FloatConstant) right).Value);
807                                                 else
808                                                         res = unchecked (((FloatConstant) left).Value /
809                                                                 ((FloatConstant) right).Value);
810                                                 
811                                                 return new FloatConstant (res, left.Location);
812                                         } else if (left is ULongConstant){
813                                                 ulong res;
814                                                 
815                                                 if (ec.ConstantCheckState)
816                                                         res = checked (((ULongConstant) left).Value /
817                                                                 ((ULongConstant) right).Value);
818                                                 else
819                                                         res = unchecked (((ULongConstant) left).Value /
820                                                                 ((ULongConstant) right).Value);
821                                                 
822                                                 return new ULongConstant (res, left.Location);
823                                         } else if (left is LongConstant){
824                                                 long res;
825                                                 
826                                                 if (ec.ConstantCheckState)
827                                                         res = checked (((LongConstant) left).Value /
828                                                                 ((LongConstant) right).Value);
829                                                 else
830                                                         res = unchecked (((LongConstant) left).Value /
831                                                                 ((LongConstant) right).Value);
832                                                 
833                                                 return new LongConstant (res, left.Location);
834                                         } else if (left is UIntConstant){
835                                                 uint res;
836                                                 
837                                                 if (ec.ConstantCheckState)
838                                                         res = checked (((UIntConstant) left).Value /
839                                                                 ((UIntConstant) right).Value);
840                                                 else
841                                                         res = unchecked (((UIntConstant) left).Value /
842                                                                 ((UIntConstant) right).Value);
843                                                 
844                                                 return new UIntConstant (res, left.Location);
845                                         } else if (left is IntConstant){
846                                                 int res;
847
848                                                 if (ec.ConstantCheckState)
849                                                         res = checked (((IntConstant) left).Value /
850                                                                 ((IntConstant) right).Value);
851                                                 else
852                                                         res = unchecked (((IntConstant) left).Value /
853                                                                 ((IntConstant) right).Value);
854
855                                                 return new IntConstant (res, left.Location);
856                                         } else if (left is DecimalConstant) {
857                                                 decimal res;
858
859                                                 if (ec.ConstantCheckState)
860                                                         res = checked (((DecimalConstant) left).Value /
861                                                                 ((DecimalConstant) right).Value);
862                                                 else
863                                                         res = unchecked (((DecimalConstant) left).Value /
864                                                                 ((DecimalConstant) right).Value);
865
866                                                 return new DecimalConstant (res, left.Location);
867                                         } else {
868                                                 throw new Exception ( "Unexepected division input: " + left);
869                                         }
870                                 } catch (OverflowException){
871                                         Error_CompileTimeOverflow (loc);
872
873                                 } catch (DivideByZeroException) {
874                                         Report.Error (020, loc, "Division by constant zero");
875                                 }
876                                 
877                                 break;
878                                 
879                         case Binary.Operator.Modulus:
880                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
881                                 if (left == null || right == null)
882                                         return null;
883
884                                 try {
885                                         if (left is DoubleConstant){
886                                                 double res;
887                                                 
888                                                 if (ec.ConstantCheckState)
889                                                         res = checked (((DoubleConstant) left).Value %
890                                                                        ((DoubleConstant) right).Value);
891                                                 else
892                                                         res = unchecked (((DoubleConstant) left).Value %
893                                                                          ((DoubleConstant) right).Value);
894                                                 
895                                                 return new DoubleConstant (res, left.Location);
896                                         } else if (left is FloatConstant){
897                                                 float res;
898                                                 
899                                                 if (ec.ConstantCheckState)
900                                                         res = checked (((FloatConstant) left).Value %
901                                                                        ((FloatConstant) right).Value);
902                                                 else
903                                                         res = unchecked (((FloatConstant) left).Value %
904                                                                          ((FloatConstant) right).Value);
905                                                 
906                                                 return new FloatConstant (res, left.Location);
907                                         } else if (left is ULongConstant){
908                                                 ulong res;
909                                                 
910                                                 if (ec.ConstantCheckState)
911                                                         res = checked (((ULongConstant) left).Value %
912                                                                        ((ULongConstant) right).Value);
913                                                 else
914                                                         res = unchecked (((ULongConstant) left).Value %
915                                                                          ((ULongConstant) right).Value);
916                                                 
917                                                 return new ULongConstant (res, left.Location);
918                                         } else if (left is LongConstant){
919                                                 long res;
920                                                 
921                                                 if (ec.ConstantCheckState)
922                                                         res = checked (((LongConstant) left).Value %
923                                                                        ((LongConstant) right).Value);
924                                                 else
925                                                         res = unchecked (((LongConstant) left).Value %
926                                                                          ((LongConstant) right).Value);
927                                                 
928                                                 return new LongConstant (res, left.Location);
929                                         } else if (left is UIntConstant){
930                                                 uint res;
931                                                 
932                                                 if (ec.ConstantCheckState)
933                                                         res = checked (((UIntConstant) left).Value %
934                                                                        ((UIntConstant) right).Value);
935                                                 else
936                                                         res = unchecked (((UIntConstant) left).Value %
937                                                                          ((UIntConstant) right).Value);
938                                                 
939                                                 return new UIntConstant (res, left.Location);
940                                         } else if (left is IntConstant){
941                                                 int res;
942
943                                                 if (ec.ConstantCheckState)
944                                                         res = checked (((IntConstant) left).Value %
945                                                                        ((IntConstant) right).Value);
946                                                 else
947                                                         res = unchecked (((IntConstant) left).Value %
948                                                                          ((IntConstant) right).Value);
949
950                                                 return new IntConstant (res, left.Location);
951                                         } else {
952                                                 throw new Exception ( "Unexepected modulus input: " + left);
953                                         }
954                                 } catch (DivideByZeroException){
955                                         Report.Error (020, loc, "Division by constant zero");
956                                 } catch (OverflowException){
957                                         Error_CompileTimeOverflow (loc);
958                                 }
959                                 break;
960
961                                 //
962                                 // There is no overflow checking on left shift
963                                 //
964                         case Binary.Operator.LeftShift:
965                                 IntConstant ic = right.ToInt (loc);
966                                 if (ic == null){
967                                         Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
968                                         return null;
969                                 }
970                                 int lshift_val = ic.Value;
971
972                                 IntConstant lic;
973                                 if ((lic = left.ConvertToInt ()) != null)
974                                         return new IntConstant (lic.Value << lshift_val, left.Location);
975
976                                 UIntConstant luic;
977                                 if ((luic = left.ConvertToUInt ()) != null)
978                                         return new UIntConstant (luic.Value << lshift_val, left.Location);
979
980                                 LongConstant llc;
981                                 if ((llc = left.ConvertToLong ()) != null)
982                                         return new LongConstant (llc.Value << lshift_val, left.Location);
983
984                                 ULongConstant lulc;
985                                 if ((lulc = left.ConvertToULong ()) != null)
986                                         return new ULongConstant (lulc.Value << lshift_val, left.Location);
987
988                                 Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
989                                 break;
990
991                                 //
992                                 // There is no overflow checking on right shift
993                                 //
994                         case Binary.Operator.RightShift:
995                                 IntConstant sic = right.ToInt (loc);
996                                 if (sic == null){
997                                         Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
998                                         return null;
999                                 }
1000                                 int rshift_val = sic.Value;
1001
1002                                 IntConstant ric;
1003                                 if ((ric = left.ConvertToInt ()) != null)
1004                                         return new IntConstant (ric.Value >> rshift_val, left.Location);
1005
1006                                 UIntConstant ruic;
1007                                 if ((ruic = left.ConvertToUInt ()) != null)
1008                                         return new UIntConstant (ruic.Value >> rshift_val, left.Location);
1009
1010                                 LongConstant rlc;
1011                                 if ((rlc = left.ConvertToLong ()) != null)
1012                                         return new LongConstant (rlc.Value >> rshift_val, left.Location);
1013
1014                                 ULongConstant rulc;
1015                                 if ((rulc = left.ConvertToULong ()) != null)
1016                                         return new ULongConstant (rulc.Value >> rshift_val, left.Location);
1017
1018                                 Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
1019                                 break;
1020
1021                         case Binary.Operator.LogicalAnd:
1022                                 if (left is BoolConstant && right is BoolConstant){
1023                                         return new BoolConstant (
1024                                                 ((BoolConstant) left).Value &&
1025                                                 ((BoolConstant) right).Value, left.Location);
1026                                 }
1027                                 break;
1028
1029                         case Binary.Operator.LogicalOr:
1030                                 if (left is BoolConstant && right is BoolConstant){
1031                                         return new BoolConstant (
1032                                                 ((BoolConstant) left).Value ||
1033                                                 ((BoolConstant) right).Value, left.Location);
1034                                 }
1035                                 break;
1036                                 
1037                         case Binary.Operator.Equality:
1038                                 if (left is BoolConstant && right is BoolConstant){
1039                                         return new BoolConstant (
1040                                                 ((BoolConstant) left).Value ==
1041                                                 ((BoolConstant) right).Value, left.Location);
1042                                 
1043                                 }
1044                                 if (left is NullLiteral){
1045                                         if (right is NullLiteral)
1046                                                 return new BoolConstant (true, left.Location);
1047                                         else if (right is StringConstant)
1048                                                 return new BoolConstant (
1049                                                         ((StringConstant) right).Value == null, left.Location);
1050                                 } else if (right is NullLiteral){
1051                                         if (left is NullLiteral)
1052                                                 return new BoolConstant (true, left.Location);
1053                                         else if (left is StringConstant)
1054                                                 return new BoolConstant (
1055                                                         ((StringConstant) left).Value == null, left.Location);
1056                                 }
1057                                 if (left is StringConstant && right is StringConstant){
1058                                         return new BoolConstant (
1059                                                 ((StringConstant) left).Value ==
1060                                                 ((StringConstant) right).Value, left.Location);
1061                                         
1062                                 }
1063
1064                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1065                                 if (left == null || right == null)
1066                                         return null;
1067
1068                                 bool_res = false;
1069                                 if (left is DoubleConstant)
1070                                         bool_res = ((DoubleConstant) left).Value ==
1071                                                 ((DoubleConstant) right).Value;
1072                                 else if (left is FloatConstant)
1073                                         bool_res = ((FloatConstant) left).Value ==
1074                                                 ((FloatConstant) right).Value;
1075                                 else if (left is ULongConstant)
1076                                         bool_res = ((ULongConstant) left).Value ==
1077                                                 ((ULongConstant) right).Value;
1078                                 else if (left is LongConstant)
1079                                         bool_res = ((LongConstant) left).Value ==
1080                                                 ((LongConstant) right).Value;
1081                                 else if (left is UIntConstant)
1082                                         bool_res = ((UIntConstant) left).Value ==
1083                                                 ((UIntConstant) right).Value;
1084                                 else if (left is IntConstant)
1085                                         bool_res = ((IntConstant) left).Value ==
1086                                                 ((IntConstant) right).Value;
1087                                 else
1088                                         return null;
1089
1090                                 return new BoolConstant (bool_res, left.Location);
1091
1092                         case Binary.Operator.Inequality:
1093                                 if (left is BoolConstant && right is BoolConstant){
1094                                         return new BoolConstant (
1095                                                 ((BoolConstant) left).Value !=
1096                                                 ((BoolConstant) right).Value, left.Location);
1097                                 }
1098                                 if (left is NullLiteral){
1099                                         if (right is NullLiteral)
1100                                                 return new BoolConstant (false, left.Location);
1101                                         else if (right is StringConstant)
1102                                                 return new BoolConstant (
1103                                                         ((StringConstant) right).Value != null, left.Location);
1104                                 } else if (right is NullLiteral){
1105                                         if (left is NullLiteral)
1106                                                 return new BoolConstant (false, left.Location);
1107                                         else if (left is StringConstant)
1108                                                 return new BoolConstant (
1109                                                         ((StringConstant) left).Value != null, left.Location);
1110                                 }
1111                                 if (left is StringConstant && right is StringConstant){
1112                                         return new BoolConstant (
1113                                                 ((StringConstant) left).Value !=
1114                                                 ((StringConstant) right).Value, left.Location);
1115                                         
1116                                 }
1117                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1118                                 if (left == null || right == null)
1119                                         return null;
1120
1121                                 bool_res = false;
1122                                 if (left is DoubleConstant)
1123                                         bool_res = ((DoubleConstant) left).Value !=
1124                                                 ((DoubleConstant) right).Value;
1125                                 else if (left is FloatConstant)
1126                                         bool_res = ((FloatConstant) left).Value !=
1127                                                 ((FloatConstant) right).Value;
1128                                 else if (left is ULongConstant)
1129                                         bool_res = ((ULongConstant) left).Value !=
1130                                                 ((ULongConstant) right).Value;
1131                                 else if (left is LongConstant)
1132                                         bool_res = ((LongConstant) left).Value !=
1133                                                 ((LongConstant) right).Value;
1134                                 else if (left is UIntConstant)
1135                                         bool_res = ((UIntConstant) left).Value !=
1136                                                 ((UIntConstant) right).Value;
1137                                 else if (left is IntConstant)
1138                                         bool_res = ((IntConstant) left).Value !=
1139                                                 ((IntConstant) right).Value;
1140                                 else
1141                                         return null;
1142
1143                                 return new BoolConstant (bool_res, left.Location);
1144
1145                         case Binary.Operator.LessThan:
1146                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1147                                 if (left == null || right == null)
1148                                         return null;
1149
1150                                 bool_res = false;
1151                                 if (left is DoubleConstant)
1152                                         bool_res = ((DoubleConstant) left).Value <
1153                                                 ((DoubleConstant) right).Value;
1154                                 else if (left is FloatConstant)
1155                                         bool_res = ((FloatConstant) left).Value <
1156                                                 ((FloatConstant) right).Value;
1157                                 else if (left is ULongConstant)
1158                                         bool_res = ((ULongConstant) left).Value <
1159                                                 ((ULongConstant) right).Value;
1160                                 else if (left is LongConstant)
1161                                         bool_res = ((LongConstant) left).Value <
1162                                                 ((LongConstant) right).Value;
1163                                 else if (left is UIntConstant)
1164                                         bool_res = ((UIntConstant) left).Value <
1165                                                 ((UIntConstant) right).Value;
1166                                 else if (left is IntConstant)
1167                                         bool_res = ((IntConstant) left).Value <
1168                                                 ((IntConstant) right).Value;
1169                                 else
1170                                         return null;
1171
1172                                 return new BoolConstant (bool_res, left.Location);
1173                                 
1174                         case Binary.Operator.GreaterThan:
1175                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1176                                 if (left == null || right == null)
1177                                         return null;
1178
1179                                 bool_res = false;
1180                                 if (left is DoubleConstant)
1181                                         bool_res = ((DoubleConstant) left).Value >
1182                                                 ((DoubleConstant) right).Value;
1183                                 else if (left is FloatConstant)
1184                                         bool_res = ((FloatConstant) left).Value >
1185                                                 ((FloatConstant) right).Value;
1186                                 else if (left is ULongConstant)
1187                                         bool_res = ((ULongConstant) left).Value >
1188                                                 ((ULongConstant) right).Value;
1189                                 else if (left is LongConstant)
1190                                         bool_res = ((LongConstant) left).Value >
1191                                                 ((LongConstant) right).Value;
1192                                 else if (left is UIntConstant)
1193                                         bool_res = ((UIntConstant) left).Value >
1194                                                 ((UIntConstant) right).Value;
1195                                 else if (left is IntConstant)
1196                                         bool_res = ((IntConstant) left).Value >
1197                                                 ((IntConstant) right).Value;
1198                                 else
1199                                         return null;
1200
1201                                 return new BoolConstant (bool_res, left.Location);
1202
1203                         case Binary.Operator.GreaterThanOrEqual:
1204                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1205                                 if (left == null || right == null)
1206                                         return null;
1207
1208                                 bool_res = false;
1209                                 if (left is DoubleConstant)
1210                                         bool_res = ((DoubleConstant) left).Value >=
1211                                                 ((DoubleConstant) right).Value;
1212                                 else if (left is FloatConstant)
1213                                         bool_res = ((FloatConstant) left).Value >=
1214                                                 ((FloatConstant) right).Value;
1215                                 else if (left is ULongConstant)
1216                                         bool_res = ((ULongConstant) left).Value >=
1217                                                 ((ULongConstant) right).Value;
1218                                 else if (left is LongConstant)
1219                                         bool_res = ((LongConstant) left).Value >=
1220                                                 ((LongConstant) right).Value;
1221                                 else if (left is UIntConstant)
1222                                         bool_res = ((UIntConstant) left).Value >=
1223                                                 ((UIntConstant) right).Value;
1224                                 else if (left is IntConstant)
1225                                         bool_res = ((IntConstant) left).Value >=
1226                                                 ((IntConstant) right).Value;
1227                                 else
1228                                         return null;
1229
1230                                 return new BoolConstant (bool_res, left.Location);
1231
1232                         case Binary.Operator.LessThanOrEqual:
1233                                 DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
1234                                 if (left == null || right == null)
1235                                         return null;
1236
1237                                 bool_res = false;
1238                                 if (left is DoubleConstant)
1239                                         bool_res = ((DoubleConstant) left).Value <=
1240                                                 ((DoubleConstant) right).Value;
1241                                 else if (left is FloatConstant)
1242                                         bool_res = ((FloatConstant) left).Value <=
1243                                                 ((FloatConstant) right).Value;
1244                                 else if (left is ULongConstant)
1245                                         bool_res = ((ULongConstant) left).Value <=
1246                                                 ((ULongConstant) right).Value;
1247                                 else if (left is LongConstant)
1248                                         bool_res = ((LongConstant) left).Value <=
1249                                                 ((LongConstant) right).Value;
1250                                 else if (left is UIntConstant)
1251                                         bool_res = ((UIntConstant) left).Value <=
1252                                                 ((UIntConstant) right).Value;
1253                                 else if (left is IntConstant)
1254                                         bool_res = ((IntConstant) left).Value <=
1255                                                 ((IntConstant) right).Value;
1256                                 else
1257                                         return null;
1258
1259                                 return new BoolConstant (bool_res, left.Location);
1260                         }
1261                                         
1262                         return null;
1263                 }
1264         }
1265 }