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