Don't crash on liften null left/right shift
[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, EnumSpec.GetUnderlyingType (lt), 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                                 //
197                                 // bool? operator &(bool? x, bool? y);
198                                 //
199                                 if ((lt == TypeManager.bool_type && right is NullLiteral) ||
200                                         (rt == TypeManager.bool_type && left is NullLiteral)) {
201                                         var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
202
203                                         // false | null => null
204                                         // null | false => null
205                                         if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
206                                                 return Nullable.LiftedNull.CreateFromExpression (ec, b);
207
208                                         // true | null => true
209                                         // null | true => true
210                                         return ReducedExpression.Create (new BoolConstant (true, loc).Resolve (ec), b);                                 
211                                 }
212
213                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
214                                         return null;
215
216                                 if (left is IntConstant){
217                                         int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
218                                         
219                                         return new IntConstant (res, left.Location);
220                                 }
221                                 if (left is UIntConstant){
222                                         uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
223                                         
224                                         return new UIntConstant (res, left.Location);
225                                 }
226                                 if (left is LongConstant){
227                                         long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
228                                         
229                                         return new LongConstant (res, left.Location);
230                                 }
231                                 if (left is ULongConstant){
232                                         ulong res = ((ULongConstant)left).Value |
233                                                 ((ULongConstant)right).Value;
234                                         
235                                         return new ULongConstant (res, left.Location);
236                                 }
237                                 break;
238                                 
239                         case Binary.Operator.BitwiseAnd:
240                                 //
241                                 // bool? operator &(bool? x, bool? y);
242                                 //
243                                 if ((lt == TypeManager.bool_type && right is NullLiteral) ||
244                                         (rt == TypeManager.bool_type && left is NullLiteral)) {
245                                         var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
246
247                                         // false & null => false
248                                         // null & false => false
249                                         if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
250                                                 return ReducedExpression.Create (new BoolConstant (false, loc).Resolve (ec), b);
251
252                                         // true & null => null
253                                         // null & true => null
254                                         return Nullable.LiftedNull.CreateFromExpression (ec, b);
255                                 }
256
257                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
258                                         return null;
259                                 
260                                 ///
261                                 /// int operator &(int x, int y);
262                                 /// uint operator &(uint x, uint y);
263                                 /// long operator &(long x, long y);
264                                 /// ulong operator &(ulong x, ulong y);
265                                 ///
266                                 if (left is IntConstant){
267                                         int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
268                                         return new IntConstant (res, left.Location);
269                                 }
270                                 if (left is UIntConstant){
271                                         uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
272                                         return new UIntConstant (res, left.Location);
273                                 }
274                                 if (left is LongConstant){
275                                         long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
276                                         return new LongConstant (res, left.Location);
277                                 }
278                                 if (left is ULongConstant){
279                                         ulong res = ((ULongConstant)left).Value &
280                                                 ((ULongConstant)right).Value;
281                                         
282                                         return new ULongConstant (res, left.Location);
283                                 }
284                                 break;
285
286                         case Binary.Operator.ExclusiveOr:
287                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
288                                         return null;
289                                 
290                                 if (left is IntConstant){
291                                         int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
292                                         return new IntConstant (res, left.Location);
293                                 }
294                                 if (left is UIntConstant){
295                                         uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
296                                         
297                                         return  new UIntConstant (res, left.Location);
298                                 }
299                                 if (left is LongConstant){
300                                         long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
301                                         
302                                         return new LongConstant (res, left.Location);
303                                 }
304                                 if (left is ULongConstant){
305                                         ulong res = ((ULongConstant)left).Value ^
306                                                 ((ULongConstant)right).Value;
307                                         
308                                         return new ULongConstant (res, left.Location);
309                                 }
310                                 break;
311
312                         case Binary.Operator.Addition:
313                                 if (lt == InternalType.Null)
314                                         return right;
315
316                                 if (rt == InternalType.Null)
317                                         return left;
318
319                                 //
320                                 // If both sides are strings, then concatenate, if
321                                 // one is a string, and the other is not, then defer
322                                 // to runtime concatenation
323                                 //
324                                 if (lt == TypeManager.string_type || rt == TypeManager.string_type){
325                                         if (lt == rt)
326                                                 return new StringConstant ((string)left.GetValue () + (string)right.GetValue (),
327                                                         left.Location);
328                                         
329                                         return null;
330                                 }
331
332                                 //
333                                 // handle "E operator + (E x, U y)"
334                                 // handle "E operator + (Y y, E x)"
335                                 //
336                                 EnumConstant lc = left as EnumConstant;
337                                 EnumConstant rc = right as EnumConstant;
338                                 if (lc != null || rc != null){
339                                         if (lc == null) {
340                                                 lc = rc;
341                                                 lt = lc.Type;
342                                                 right = left;
343                                         }
344
345                                         // U has to be implicitly convetible to E.base
346                                         right = right.ConvertImplicitly (ec, lc.Child.Type);
347                                         if (right == null)
348                                                 return null;
349
350                                         result = BinaryFold (ec, oper, lc.Child, right, loc);
351                                         if (result == null)
352                                                 return null;
353
354                                         result = result.Resolve (ec).TryReduce (ec, lt, loc);
355                                         if (result == null)
356                                                 return null;
357
358                                         return new EnumConstant (result, lt);
359                                 }
360
361                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
362                                         return null;
363
364                                 try {
365                                         if (left is DoubleConstant){
366                                                 double res;
367                                                 
368                                                 if (ec.ConstantCheckState)
369                                                         res = checked (((DoubleConstant) left).Value +
370                                                                        ((DoubleConstant) right).Value);
371                                                 else
372                                                         res = unchecked (((DoubleConstant) left).Value +
373                                                                          ((DoubleConstant) right).Value);
374                                                 
375                                                 return new DoubleConstant (res, left.Location);
376                                         }
377                                         if (left is FloatConstant){
378                                                 float res;
379                                                 
380                                                 if (ec.ConstantCheckState)
381                                                         res = checked (((FloatConstant) left).Value +
382                                                                        ((FloatConstant) right).Value);
383                                                 else
384                                                         res = unchecked (((FloatConstant) left).Value +
385                                                                          ((FloatConstant) right).Value);
386                                                 
387                                                 result = new FloatConstant (res, left.Location);
388                                         } else if (left is ULongConstant){
389                                                 ulong res;
390                                                 
391                                                 if (ec.ConstantCheckState)
392                                                         res = checked (((ULongConstant) left).Value +
393                                                                        ((ULongConstant) right).Value);
394                                                 else
395                                                         res = unchecked (((ULongConstant) left).Value +
396                                                                          ((ULongConstant) right).Value);
397
398                                                 result = new ULongConstant (res, left.Location);
399                                         } else if (left is LongConstant){
400                                                 long res;
401                                                 
402                                                 if (ec.ConstantCheckState)
403                                                         res = checked (((LongConstant) left).Value +
404                                                                        ((LongConstant) right).Value);
405                                                 else
406                                                         res = unchecked (((LongConstant) left).Value +
407                                                                          ((LongConstant) right).Value);
408                                                 
409                                                 result = new LongConstant (res, left.Location);
410                                         } else if (left is UIntConstant){
411                                                 uint res;
412                                                 
413                                                 if (ec.ConstantCheckState)
414                                                         res = checked (((UIntConstant) left).Value +
415                                                                        ((UIntConstant) right).Value);
416                                                 else
417                                                         res = unchecked (((UIntConstant) left).Value +
418                                                                          ((UIntConstant) right).Value);
419                                                 
420                                                 result = new UIntConstant (res, left.Location);
421                                         } else if (left is IntConstant){
422                                                 int res;
423
424                                                 if (ec.ConstantCheckState)
425                                                         res = checked (((IntConstant) left).Value +
426                                                                        ((IntConstant) right).Value);
427                                                 else
428                                                         res = unchecked (((IntConstant) left).Value +
429                                                                          ((IntConstant) right).Value);
430
431                                                 result = new IntConstant (res, left.Location);
432                                         } else if (left is DecimalConstant) {
433                                                 decimal res;
434
435                                                 if (ec.ConstantCheckState)
436                                                         res = checked (((DecimalConstant) left).Value +
437                                                                 ((DecimalConstant) right).Value);
438                                                 else
439                                                         res = unchecked (((DecimalConstant) left).Value +
440                                                                 ((DecimalConstant) right).Value);
441
442                                                 result = new DecimalConstant (res, left.Location);
443                                         }
444                                 } catch (OverflowException){
445                                         Error_CompileTimeOverflow (ec, loc);
446                                 }
447
448                                 return result;
449
450                         case Binary.Operator.Subtraction:
451                                 //
452                                 // handle "E operator - (E x, U y)"
453                                 // handle "E operator - (Y y, E x)"
454                                 //
455                                 lc = left as EnumConstant;
456                                 rc = right as EnumConstant;
457                                 if (lc != null || rc != null){
458                                         if (lc == null) {
459                                                 lc = rc;
460                                                 lt = lc.Type;
461                                                 right = left;
462                                         }
463
464                                         // U has to be implicitly convetible to E.base
465                                         right = right.ConvertImplicitly (ec, lc.Child.Type);
466                                         if (right == null)
467                                                 return null;
468
469                                         result = BinaryFold (ec, oper, lc.Child, right, loc);
470                                         if (result == null)
471                                                 return null;
472
473                                         result = result.Resolve (ec).TryReduce (ec, lt, loc);
474                                         if (result == null)
475                                                 return null;
476
477                                         return new EnumConstant (result, lt);
478                                 }
479
480                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
481                                         return null;
482
483                                 try {
484                                         if (left is DoubleConstant){
485                                                 double res;
486                                                 
487                                                 if (ec.ConstantCheckState)
488                                                         res = checked (((DoubleConstant) left).Value -
489                                                                        ((DoubleConstant) right).Value);
490                                                 else
491                                                         res = unchecked (((DoubleConstant) left).Value -
492                                                                          ((DoubleConstant) right).Value);
493                                                 
494                                                 result = new DoubleConstant (res, left.Location);
495                                         } else if (left is FloatConstant){
496                                                 float res;
497                                                 
498                                                 if (ec.ConstantCheckState)
499                                                         res = checked (((FloatConstant) left).Value -
500                                                                        ((FloatConstant) right).Value);
501                                                 else
502                                                         res = unchecked (((FloatConstant) left).Value -
503                                                                          ((FloatConstant) right).Value);
504                                                 
505                                                 result = new FloatConstant (res, left.Location);
506                                         } else if (left is ULongConstant){
507                                                 ulong res;
508                                                 
509                                                 if (ec.ConstantCheckState)
510                                                         res = checked (((ULongConstant) left).Value -
511                                                                        ((ULongConstant) right).Value);
512                                                 else
513                                                         res = unchecked (((ULongConstant) left).Value -
514                                                                          ((ULongConstant) right).Value);
515                                                 
516                                                 result = new ULongConstant (res, left.Location);
517                                         } else if (left is LongConstant){
518                                                 long res;
519                                                 
520                                                 if (ec.ConstantCheckState)
521                                                         res = checked (((LongConstant) left).Value -
522                                                                        ((LongConstant) right).Value);
523                                                 else
524                                                         res = unchecked (((LongConstant) left).Value -
525                                                                          ((LongConstant) right).Value);
526                                                 
527                                                 result = new LongConstant (res, left.Location);
528                                         } else if (left is UIntConstant){
529                                                 uint res;
530                                                 
531                                                 if (ec.ConstantCheckState)
532                                                         res = checked (((UIntConstant) left).Value -
533                                                                        ((UIntConstant) right).Value);
534                                                 else
535                                                         res = unchecked (((UIntConstant) left).Value -
536                                                                          ((UIntConstant) right).Value);
537                                                 
538                                                 result = new UIntConstant (res, left.Location);
539                                         } else if (left is IntConstant){
540                                                 int res;
541
542                                                 if (ec.ConstantCheckState)
543                                                         res = checked (((IntConstant) left).Value -
544                                                                        ((IntConstant) right).Value);
545                                                 else
546                                                         res = unchecked (((IntConstant) left).Value -
547                                                                          ((IntConstant) right).Value);
548
549                                                 result = new IntConstant (res, left.Location);
550                                         } else if (left is DecimalConstant) {
551                                                 decimal res;
552
553                                                 if (ec.ConstantCheckState)
554                                                         res = checked (((DecimalConstant) left).Value -
555                                                                 ((DecimalConstant) right).Value);
556                                                 else
557                                                         res = unchecked (((DecimalConstant) left).Value -
558                                                                 ((DecimalConstant) right).Value);
559
560                                                 return new DecimalConstant (res, left.Location);
561                                         } else {
562                                                 throw new Exception ( "Unexepected subtraction input: " + left);
563                                         }
564                                 } catch (OverflowException){
565                                         Error_CompileTimeOverflow (ec, loc);
566                                 }
567
568                                 return result;
569                                 
570                         case Binary.Operator.Multiply:
571                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
572                                         return null;
573
574                                 try {
575                                         if (left is DoubleConstant){
576                                                 double res;
577                                                 
578                                                 if (ec.ConstantCheckState)
579                                                         res = checked (((DoubleConstant) left).Value *
580                                                                 ((DoubleConstant) right).Value);
581                                                 else
582                                                         res = unchecked (((DoubleConstant) left).Value *
583                                                                 ((DoubleConstant) right).Value);
584                                                 
585                                                 return new DoubleConstant (res, left.Location);
586                                         } else if (left is FloatConstant){
587                                                 float res;
588                                                 
589                                                 if (ec.ConstantCheckState)
590                                                         res = checked (((FloatConstant) left).Value *
591                                                                 ((FloatConstant) right).Value);
592                                                 else
593                                                         res = unchecked (((FloatConstant) left).Value *
594                                                                 ((FloatConstant) right).Value);
595                                                 
596                                                 return new FloatConstant (res, left.Location);
597                                         } else if (left is ULongConstant){
598                                                 ulong res;
599                                                 
600                                                 if (ec.ConstantCheckState)
601                                                         res = checked (((ULongConstant) left).Value *
602                                                                 ((ULongConstant) right).Value);
603                                                 else
604                                                         res = unchecked (((ULongConstant) left).Value *
605                                                                 ((ULongConstant) right).Value);
606                                                 
607                                                 return new ULongConstant (res, left.Location);
608                                         } else if (left is LongConstant){
609                                                 long res;
610                                                 
611                                                 if (ec.ConstantCheckState)
612                                                         res = checked (((LongConstant) left).Value *
613                                                                 ((LongConstant) right).Value);
614                                                 else
615                                                         res = unchecked (((LongConstant) left).Value *
616                                                                 ((LongConstant) right).Value);
617                                                 
618                                                 return new LongConstant (res, left.Location);
619                                         } else if (left is UIntConstant){
620                                                 uint res;
621                                                 
622                                                 if (ec.ConstantCheckState)
623                                                         res = checked (((UIntConstant) left).Value *
624                                                                 ((UIntConstant) right).Value);
625                                                 else
626                                                         res = unchecked (((UIntConstant) left).Value *
627                                                                 ((UIntConstant) right).Value);
628                                                 
629                                                 return new UIntConstant (res, left.Location);
630                                         } else if (left is IntConstant){
631                                                 int res;
632
633                                                 if (ec.ConstantCheckState)
634                                                         res = checked (((IntConstant) left).Value *
635                                                                 ((IntConstant) right).Value);
636                                                 else
637                                                         res = unchecked (((IntConstant) left).Value *
638                                                                 ((IntConstant) right).Value);
639
640                                                 return new IntConstant (res, left.Location);
641                                         } else if (left is DecimalConstant) {
642                                                 decimal res;
643
644                                                 if (ec.ConstantCheckState)
645                                                         res = checked (((DecimalConstant) left).Value *
646                                                                 ((DecimalConstant) right).Value);
647                                                 else
648                                                         res = unchecked (((DecimalConstant) left).Value *
649                                                                 ((DecimalConstant) right).Value);
650
651                                                 return new DecimalConstant (res, left.Location);
652                                         } else {
653                                                 throw new Exception ( "Unexepected multiply input: " + left);
654                                         }
655                                 } catch (OverflowException){
656                                         Error_CompileTimeOverflow (ec, loc);
657                                 }
658                                 break;
659
660                         case Binary.Operator.Division:
661                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
662                                         return null;
663
664                                 try {
665                                         if (left is DoubleConstant){
666                                                 double res;
667                                                 
668                                                 if (ec.ConstantCheckState)
669                                                         res = checked (((DoubleConstant) left).Value /
670                                                                 ((DoubleConstant) right).Value);
671                                                 else
672                                                         res = unchecked (((DoubleConstant) left).Value /
673                                                                 ((DoubleConstant) right).Value);
674                                                 
675                                                 return new DoubleConstant (res, left.Location);
676                                         } else if (left is FloatConstant){
677                                                 float res;
678                                                 
679                                                 if (ec.ConstantCheckState)
680                                                         res = checked (((FloatConstant) left).Value /
681                                                                 ((FloatConstant) right).Value);
682                                                 else
683                                                         res = unchecked (((FloatConstant) left).Value /
684                                                                 ((FloatConstant) right).Value);
685                                                 
686                                                 return new FloatConstant (res, left.Location);
687                                         } else if (left is ULongConstant){
688                                                 ulong res;
689                                                 
690                                                 if (ec.ConstantCheckState)
691                                                         res = checked (((ULongConstant) left).Value /
692                                                                 ((ULongConstant) right).Value);
693                                                 else
694                                                         res = unchecked (((ULongConstant) left).Value /
695                                                                 ((ULongConstant) right).Value);
696                                                 
697                                                 return new ULongConstant (res, left.Location);
698                                         } else if (left is LongConstant){
699                                                 long res;
700                                                 
701                                                 if (ec.ConstantCheckState)
702                                                         res = checked (((LongConstant) left).Value /
703                                                                 ((LongConstant) right).Value);
704                                                 else
705                                                         res = unchecked (((LongConstant) left).Value /
706                                                                 ((LongConstant) right).Value);
707                                                 
708                                                 return new LongConstant (res, left.Location);
709                                         } else if (left is UIntConstant){
710                                                 uint res;
711                                                 
712                                                 if (ec.ConstantCheckState)
713                                                         res = checked (((UIntConstant) left).Value /
714                                                                 ((UIntConstant) right).Value);
715                                                 else
716                                                         res = unchecked (((UIntConstant) left).Value /
717                                                                 ((UIntConstant) right).Value);
718                                                 
719                                                 return new UIntConstant (res, left.Location);
720                                         } else if (left is IntConstant){
721                                                 int res;
722
723                                                 if (ec.ConstantCheckState)
724                                                         res = checked (((IntConstant) left).Value /
725                                                                 ((IntConstant) right).Value);
726                                                 else
727                                                         res = unchecked (((IntConstant) left).Value /
728                                                                 ((IntConstant) right).Value);
729
730                                                 return new IntConstant (res, left.Location);
731                                         } else if (left is DecimalConstant) {
732                                                 decimal res;
733
734                                                 if (ec.ConstantCheckState)
735                                                         res = checked (((DecimalConstant) left).Value /
736                                                                 ((DecimalConstant) right).Value);
737                                                 else
738                                                         res = unchecked (((DecimalConstant) left).Value /
739                                                                 ((DecimalConstant) right).Value);
740
741                                                 return new DecimalConstant (res, left.Location);
742                                         } else {
743                                                 throw new Exception ( "Unexepected division input: " + left);
744                                         }
745                                 } catch (OverflowException){
746                                         Error_CompileTimeOverflow (ec, loc);
747
748                                 } catch (DivideByZeroException) {
749                                         ec.Report.Error (20, loc, "Division by constant zero");
750                                 }
751                                 
752                                 break;
753                                 
754                         case Binary.Operator.Modulus:
755                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
756                                         return null;
757
758                                 try {
759                                         if (left is DoubleConstant){
760                                                 double res;
761                                                 
762                                                 if (ec.ConstantCheckState)
763                                                         res = checked (((DoubleConstant) left).Value %
764                                                                        ((DoubleConstant) right).Value);
765                                                 else
766                                                         res = unchecked (((DoubleConstant) left).Value %
767                                                                          ((DoubleConstant) right).Value);
768                                                 
769                                                 return new DoubleConstant (res, left.Location);
770                                         } else if (left is FloatConstant){
771                                                 float res;
772                                                 
773                                                 if (ec.ConstantCheckState)
774                                                         res = checked (((FloatConstant) left).Value %
775                                                                        ((FloatConstant) right).Value);
776                                                 else
777                                                         res = unchecked (((FloatConstant) left).Value %
778                                                                          ((FloatConstant) right).Value);
779                                                 
780                                                 return new FloatConstant (res, left.Location);
781                                         } else if (left is ULongConstant){
782                                                 ulong res;
783                                                 
784                                                 if (ec.ConstantCheckState)
785                                                         res = checked (((ULongConstant) left).Value %
786                                                                        ((ULongConstant) right).Value);
787                                                 else
788                                                         res = unchecked (((ULongConstant) left).Value %
789                                                                          ((ULongConstant) right).Value);
790                                                 
791                                                 return new ULongConstant (res, left.Location);
792                                         } else if (left is LongConstant){
793                                                 long res;
794                                                 
795                                                 if (ec.ConstantCheckState)
796                                                         res = checked (((LongConstant) left).Value %
797                                                                        ((LongConstant) right).Value);
798                                                 else
799                                                         res = unchecked (((LongConstant) left).Value %
800                                                                          ((LongConstant) right).Value);
801                                                 
802                                                 return new LongConstant (res, left.Location);
803                                         } else if (left is UIntConstant){
804                                                 uint res;
805                                                 
806                                                 if (ec.ConstantCheckState)
807                                                         res = checked (((UIntConstant) left).Value %
808                                                                        ((UIntConstant) right).Value);
809                                                 else
810                                                         res = unchecked (((UIntConstant) left).Value %
811                                                                          ((UIntConstant) right).Value);
812                                                 
813                                                 return new UIntConstant (res, left.Location);
814                                         } else if (left is IntConstant){
815                                                 int res;
816
817                                                 if (ec.ConstantCheckState)
818                                                         res = checked (((IntConstant) left).Value %
819                                                                        ((IntConstant) right).Value);
820                                                 else
821                                                         res = unchecked (((IntConstant) left).Value %
822                                                                          ((IntConstant) right).Value);
823
824                                                 return new IntConstant (res, left.Location);
825                                         } else {
826                                                 throw new Exception ( "Unexepected modulus input: " + left);
827                                         }
828                                 } catch (DivideByZeroException){
829                                         ec.Report.Error (20, loc, "Division by constant zero");
830                                 } catch (OverflowException){
831                                         Error_CompileTimeOverflow (ec, loc);
832                                 }
833                                 break;
834
835                                 //
836                                 // There is no overflow checking on left shift
837                                 //
838                         case Binary.Operator.LeftShift:
839                                 IntConstant ic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
840                                 if (ic == null){
841                                         Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
842                                         return null;
843                                 }
844
845                                 int lshift_val = ic.Value;
846                                 if (left.Type == TypeManager.uint64_type)
847                                         return new ULongConstant (((ULongConstant)left).Value << lshift_val, left.Location);
848                                 if (left.Type == TypeManager.int64_type)
849                                         return new LongConstant (((LongConstant)left).Value << lshift_val, left.Location);
850                                 if (left.Type == TypeManager.uint32_type)
851                                         return new UIntConstant (((UIntConstant)left).Value << lshift_val, left.Location);
852
853                                 // null << value => null
854                                 if (left is NullLiteral)
855                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
856
857                                 left = left.ConvertImplicitly (ec, TypeManager.int32_type);
858                                 if (left.Type == TypeManager.int32_type)
859                                         return new IntConstant (((IntConstant)left).Value << lshift_val, left.Location);
860
861                                 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
862                                 break;
863
864                                 //
865                                 // There is no overflow checking on right shift
866                                 //
867                         case Binary.Operator.RightShift:
868                                 IntConstant sic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
869                                 if (sic == null){
870                                         Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
871                                         return null;
872                                 }
873                                 int rshift_val = sic.Value;
874                                 if (left.Type == TypeManager.uint64_type)
875                                         return new ULongConstant (((ULongConstant)left).Value >> rshift_val, left.Location);
876                                 if (left.Type == TypeManager.int64_type)
877                                         return new LongConstant (((LongConstant)left).Value >> rshift_val, left.Location);
878                                 if (left.Type == TypeManager.uint32_type)
879                                         return new UIntConstant (((UIntConstant)left).Value >> rshift_val, left.Location);
880
881                                 // null >> value => null
882                                 if (left is NullLiteral)
883                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
884
885                                 left = left.ConvertImplicitly (ec, TypeManager.int32_type);
886                                 if (left.Type == TypeManager.int32_type)
887                                         return new IntConstant (((IntConstant)left).Value >> rshift_val, left.Location);
888
889                                 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
890                                 break;
891
892                         case Binary.Operator.Equality:
893                                 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
894                                         (left is Nullable.LiftedNull && right.IsNull) ||
895                                         (right is Nullable.LiftedNull && left.IsNull)) {
896                                         if (left.IsNull || right.IsNull) {
897                                                 return ReducedExpression.Create (
898                                                         new BoolConstant (left.IsNull == right.IsNull, left.Location).Resolve (ec),
899                                                         new Binary (oper, left, right, loc));
900                                         }
901
902                                         if (left is StringConstant && right is StringConstant)
903                                                 return new BoolConstant (
904                                                         ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
905
906                                         return null;
907                                 }
908
909                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
910                                         return null;
911
912                                 bool_res = false;
913                                 if (left is DoubleConstant)
914                                         bool_res = ((DoubleConstant) left).Value ==
915                                                 ((DoubleConstant) right).Value;
916                                 else if (left is FloatConstant)
917                                         bool_res = ((FloatConstant) left).Value ==
918                                                 ((FloatConstant) right).Value;
919                                 else if (left is ULongConstant)
920                                         bool_res = ((ULongConstant) left).Value ==
921                                                 ((ULongConstant) right).Value;
922                                 else if (left is LongConstant)
923                                         bool_res = ((LongConstant) left).Value ==
924                                                 ((LongConstant) right).Value;
925                                 else if (left is UIntConstant)
926                                         bool_res = ((UIntConstant) left).Value ==
927                                                 ((UIntConstant) right).Value;
928                                 else if (left is IntConstant)
929                                         bool_res = ((IntConstant) left).Value ==
930                                                 ((IntConstant) right).Value;
931                                 else
932                                         return null;
933
934                                 return new BoolConstant (bool_res, left.Location);
935
936                         case Binary.Operator.Inequality:
937                                 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
938                                         (left is Nullable.LiftedNull && right.IsNull) ||
939                                         (right is Nullable.LiftedNull && left.IsNull)) {
940                                         if (left.IsNull || right.IsNull) {
941                                                 return ReducedExpression.Create (
942                                                         new BoolConstant (left.IsNull != right.IsNull, left.Location).Resolve (ec),
943                                                         new Binary (oper, left, right, loc));
944                                         }
945
946                                         if (left is StringConstant && right is StringConstant)
947                                                 return new BoolConstant (
948                                                         ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
949
950                                         return null;
951                                 }
952
953                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
954                                         return null;
955
956                                 bool_res = false;
957                                 if (left is DoubleConstant)
958                                         bool_res = ((DoubleConstant) left).Value !=
959                                                 ((DoubleConstant) right).Value;
960                                 else if (left is FloatConstant)
961                                         bool_res = ((FloatConstant) left).Value !=
962                                                 ((FloatConstant) right).Value;
963                                 else if (left is ULongConstant)
964                                         bool_res = ((ULongConstant) left).Value !=
965                                                 ((ULongConstant) right).Value;
966                                 else if (left is LongConstant)
967                                         bool_res = ((LongConstant) left).Value !=
968                                                 ((LongConstant) right).Value;
969                                 else if (left is UIntConstant)
970                                         bool_res = ((UIntConstant) left).Value !=
971                                                 ((UIntConstant) right).Value;
972                                 else if (left is IntConstant)
973                                         bool_res = ((IntConstant) left).Value !=
974                                                 ((IntConstant) right).Value;
975                                 else
976                                         return null;
977
978                                 return new BoolConstant (bool_res, left.Location);
979
980                         case Binary.Operator.LessThan:
981                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
982                                         return null;
983
984                                 bool_res = false;
985                                 if (left is DoubleConstant)
986                                         bool_res = ((DoubleConstant) left).Value <
987                                                 ((DoubleConstant) right).Value;
988                                 else if (left is FloatConstant)
989                                         bool_res = ((FloatConstant) left).Value <
990                                                 ((FloatConstant) right).Value;
991                                 else if (left is ULongConstant)
992                                         bool_res = ((ULongConstant) left).Value <
993                                                 ((ULongConstant) right).Value;
994                                 else if (left is LongConstant)
995                                         bool_res = ((LongConstant) left).Value <
996                                                 ((LongConstant) right).Value;
997                                 else if (left is UIntConstant)
998                                         bool_res = ((UIntConstant) left).Value <
999                                                 ((UIntConstant) right).Value;
1000                                 else if (left is IntConstant)
1001                                         bool_res = ((IntConstant) left).Value <
1002                                                 ((IntConstant) right).Value;
1003                                 else
1004                                         return null;
1005
1006                                 return new BoolConstant (bool_res, left.Location);
1007                                 
1008                         case Binary.Operator.GreaterThan:
1009                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1010                                         return null;
1011
1012                                 bool_res = false;
1013                                 if (left is DoubleConstant)
1014                                         bool_res = ((DoubleConstant) left).Value >
1015                                                 ((DoubleConstant) right).Value;
1016                                 else if (left is FloatConstant)
1017                                         bool_res = ((FloatConstant) left).Value >
1018                                                 ((FloatConstant) right).Value;
1019                                 else if (left is ULongConstant)
1020                                         bool_res = ((ULongConstant) left).Value >
1021                                                 ((ULongConstant) right).Value;
1022                                 else if (left is LongConstant)
1023                                         bool_res = ((LongConstant) left).Value >
1024                                                 ((LongConstant) right).Value;
1025                                 else if (left is UIntConstant)
1026                                         bool_res = ((UIntConstant) left).Value >
1027                                                 ((UIntConstant) right).Value;
1028                                 else if (left is IntConstant)
1029                                         bool_res = ((IntConstant) left).Value >
1030                                                 ((IntConstant) right).Value;
1031                                 else
1032                                         return null;
1033
1034                                 return new BoolConstant (bool_res, left.Location);
1035
1036                         case Binary.Operator.GreaterThanOrEqual:
1037                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1038                                         return null;
1039
1040                                 bool_res = false;
1041                                 if (left is DoubleConstant)
1042                                         bool_res = ((DoubleConstant) left).Value >=
1043                                                 ((DoubleConstant) right).Value;
1044                                 else if (left is FloatConstant)
1045                                         bool_res = ((FloatConstant) left).Value >=
1046                                                 ((FloatConstant) right).Value;
1047                                 else if (left is ULongConstant)
1048                                         bool_res = ((ULongConstant) left).Value >=
1049                                                 ((ULongConstant) right).Value;
1050                                 else if (left is LongConstant)
1051                                         bool_res = ((LongConstant) left).Value >=
1052                                                 ((LongConstant) right).Value;
1053                                 else if (left is UIntConstant)
1054                                         bool_res = ((UIntConstant) left).Value >=
1055                                                 ((UIntConstant) right).Value;
1056                                 else if (left is IntConstant)
1057                                         bool_res = ((IntConstant) left).Value >=
1058                                                 ((IntConstant) right).Value;
1059                                 else
1060                                         return null;
1061
1062                                 return new BoolConstant (bool_res, left.Location);
1063
1064                         case Binary.Operator.LessThanOrEqual:
1065                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1066                                         return null;
1067
1068                                 bool_res = false;
1069                                 if (left is DoubleConstant)
1070                                         bool_res = ((DoubleConstant) left).Value <=
1071                                                 ((DoubleConstant) right).Value;
1072                                 else if (left is FloatConstant)
1073                                         bool_res = ((FloatConstant) left).Value <=
1074                                                 ((FloatConstant) right).Value;
1075                                 else if (left is ULongConstant)
1076                                         bool_res = ((ULongConstant) left).Value <=
1077                                                 ((ULongConstant) right).Value;
1078                                 else if (left is LongConstant)
1079                                         bool_res = ((LongConstant) left).Value <=
1080                                                 ((LongConstant) right).Value;
1081                                 else if (left is UIntConstant)
1082                                         bool_res = ((UIntConstant) left).Value <=
1083                                                 ((UIntConstant) right).Value;
1084                                 else if (left is IntConstant)
1085                                         bool_res = ((IntConstant) left).Value <=
1086                                                 ((IntConstant) right).Value;
1087                                 else
1088                                         return null;
1089
1090                                 return new BoolConstant (bool_res, left.Location);
1091                         }
1092                                         
1093                         return null;
1094                 }
1095         }
1096 }