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