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