Few mcs property accessors tweaks
[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 (left is NullLiteral && right is NullLiteral) {
481                                         var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
482                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
483                                 }
484
485                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
486                                         return null;
487
488                                 try {
489                                         if (left is DoubleConstant){
490                                                 double res;
491                                                 
492                                                 if (ec.ConstantCheckState)
493                                                         res = checked (((DoubleConstant) left).Value -
494                                                                        ((DoubleConstant) right).Value);
495                                                 else
496                                                         res = unchecked (((DoubleConstant) left).Value -
497                                                                          ((DoubleConstant) right).Value);
498                                                 
499                                                 result = new DoubleConstant (res, left.Location);
500                                         } else if (left is FloatConstant){
501                                                 float res;
502                                                 
503                                                 if (ec.ConstantCheckState)
504                                                         res = checked (((FloatConstant) left).Value -
505                                                                        ((FloatConstant) right).Value);
506                                                 else
507                                                         res = unchecked (((FloatConstant) left).Value -
508                                                                          ((FloatConstant) right).Value);
509                                                 
510                                                 result = new FloatConstant (res, left.Location);
511                                         } else if (left is ULongConstant){
512                                                 ulong res;
513                                                 
514                                                 if (ec.ConstantCheckState)
515                                                         res = checked (((ULongConstant) left).Value -
516                                                                        ((ULongConstant) right).Value);
517                                                 else
518                                                         res = unchecked (((ULongConstant) left).Value -
519                                                                          ((ULongConstant) right).Value);
520                                                 
521                                                 result = new ULongConstant (res, left.Location);
522                                         } else if (left is LongConstant){
523                                                 long res;
524                                                 
525                                                 if (ec.ConstantCheckState)
526                                                         res = checked (((LongConstant) left).Value -
527                                                                        ((LongConstant) right).Value);
528                                                 else
529                                                         res = unchecked (((LongConstant) left).Value -
530                                                                          ((LongConstant) right).Value);
531                                                 
532                                                 result = new LongConstant (res, left.Location);
533                                         } else if (left is UIntConstant){
534                                                 uint res;
535                                                 
536                                                 if (ec.ConstantCheckState)
537                                                         res = checked (((UIntConstant) left).Value -
538                                                                        ((UIntConstant) right).Value);
539                                                 else
540                                                         res = unchecked (((UIntConstant) left).Value -
541                                                                          ((UIntConstant) right).Value);
542                                                 
543                                                 result = new UIntConstant (res, left.Location);
544                                         } else if (left is IntConstant){
545                                                 int res;
546
547                                                 if (ec.ConstantCheckState)
548                                                         res = checked (((IntConstant) left).Value -
549                                                                        ((IntConstant) right).Value);
550                                                 else
551                                                         res = unchecked (((IntConstant) left).Value -
552                                                                          ((IntConstant) right).Value);
553
554                                                 result = new IntConstant (res, left.Location);
555                                         } else if (left is DecimalConstant) {
556                                                 decimal res;
557
558                                                 if (ec.ConstantCheckState)
559                                                         res = checked (((DecimalConstant) left).Value -
560                                                                 ((DecimalConstant) right).Value);
561                                                 else
562                                                         res = unchecked (((DecimalConstant) left).Value -
563                                                                 ((DecimalConstant) right).Value);
564
565                                                 return new DecimalConstant (res, left.Location);
566                                         } else {
567                                                 throw new Exception ( "Unexepected subtraction input: " + left);
568                                         }
569                                 } catch (OverflowException){
570                                         Error_CompileTimeOverflow (ec, loc);
571                                 }
572
573                                 return result;
574                                 
575                         case Binary.Operator.Multiply:
576                                 if (left is NullLiteral && right is NullLiteral) {
577                                         var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
578                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
579                                 }
580
581                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
582                                         return null;
583
584                                 try {
585                                         if (left is DoubleConstant){
586                                                 double res;
587                                                 
588                                                 if (ec.ConstantCheckState)
589                                                         res = checked (((DoubleConstant) left).Value *
590                                                                 ((DoubleConstant) right).Value);
591                                                 else
592                                                         res = unchecked (((DoubleConstant) left).Value *
593                                                                 ((DoubleConstant) right).Value);
594                                                 
595                                                 return new DoubleConstant (res, left.Location);
596                                         } else if (left is FloatConstant){
597                                                 float res;
598                                                 
599                                                 if (ec.ConstantCheckState)
600                                                         res = checked (((FloatConstant) left).Value *
601                                                                 ((FloatConstant) right).Value);
602                                                 else
603                                                         res = unchecked (((FloatConstant) left).Value *
604                                                                 ((FloatConstant) right).Value);
605                                                 
606                                                 return new FloatConstant (res, left.Location);
607                                         } else if (left is ULongConstant){
608                                                 ulong res;
609                                                 
610                                                 if (ec.ConstantCheckState)
611                                                         res = checked (((ULongConstant) left).Value *
612                                                                 ((ULongConstant) right).Value);
613                                                 else
614                                                         res = unchecked (((ULongConstant) left).Value *
615                                                                 ((ULongConstant) right).Value);
616                                                 
617                                                 return new ULongConstant (res, left.Location);
618                                         } else if (left is LongConstant){
619                                                 long res;
620                                                 
621                                                 if (ec.ConstantCheckState)
622                                                         res = checked (((LongConstant) left).Value *
623                                                                 ((LongConstant) right).Value);
624                                                 else
625                                                         res = unchecked (((LongConstant) left).Value *
626                                                                 ((LongConstant) right).Value);
627                                                 
628                                                 return new LongConstant (res, left.Location);
629                                         } else if (left is UIntConstant){
630                                                 uint res;
631                                                 
632                                                 if (ec.ConstantCheckState)
633                                                         res = checked (((UIntConstant) left).Value *
634                                                                 ((UIntConstant) right).Value);
635                                                 else
636                                                         res = unchecked (((UIntConstant) left).Value *
637                                                                 ((UIntConstant) right).Value);
638                                                 
639                                                 return new UIntConstant (res, left.Location);
640                                         } else if (left is IntConstant){
641                                                 int res;
642
643                                                 if (ec.ConstantCheckState)
644                                                         res = checked (((IntConstant) left).Value *
645                                                                 ((IntConstant) right).Value);
646                                                 else
647                                                         res = unchecked (((IntConstant) left).Value *
648                                                                 ((IntConstant) right).Value);
649
650                                                 return new IntConstant (res, left.Location);
651                                         } else if (left is DecimalConstant) {
652                                                 decimal res;
653
654                                                 if (ec.ConstantCheckState)
655                                                         res = checked (((DecimalConstant) left).Value *
656                                                                 ((DecimalConstant) right).Value);
657                                                 else
658                                                         res = unchecked (((DecimalConstant) left).Value *
659                                                                 ((DecimalConstant) right).Value);
660
661                                                 return new DecimalConstant (res, left.Location);
662                                         } else {
663                                                 throw new Exception ( "Unexepected multiply input: " + left);
664                                         }
665                                 } catch (OverflowException){
666                                         Error_CompileTimeOverflow (ec, loc);
667                                 }
668                                 break;
669
670                         case Binary.Operator.Division:
671                                 if (left is NullLiteral && right is NullLiteral) {
672                                         var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
673                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
674                                 }
675
676                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
677                                         return null;
678
679                                 try {
680                                         if (left is DoubleConstant){
681                                                 double res;
682                                                 
683                                                 if (ec.ConstantCheckState)
684                                                         res = checked (((DoubleConstant) left).Value /
685                                                                 ((DoubleConstant) right).Value);
686                                                 else
687                                                         res = unchecked (((DoubleConstant) left).Value /
688                                                                 ((DoubleConstant) right).Value);
689                                                 
690                                                 return new DoubleConstant (res, left.Location);
691                                         } else if (left is FloatConstant){
692                                                 float res;
693                                                 
694                                                 if (ec.ConstantCheckState)
695                                                         res = checked (((FloatConstant) left).Value /
696                                                                 ((FloatConstant) right).Value);
697                                                 else
698                                                         res = unchecked (((FloatConstant) left).Value /
699                                                                 ((FloatConstant) right).Value);
700                                                 
701                                                 return new FloatConstant (res, left.Location);
702                                         } else if (left is ULongConstant){
703                                                 ulong res;
704                                                 
705                                                 if (ec.ConstantCheckState)
706                                                         res = checked (((ULongConstant) left).Value /
707                                                                 ((ULongConstant) right).Value);
708                                                 else
709                                                         res = unchecked (((ULongConstant) left).Value /
710                                                                 ((ULongConstant) right).Value);
711                                                 
712                                                 return new ULongConstant (res, left.Location);
713                                         } else if (left is LongConstant){
714                                                 long res;
715                                                 
716                                                 if (ec.ConstantCheckState)
717                                                         res = checked (((LongConstant) left).Value /
718                                                                 ((LongConstant) right).Value);
719                                                 else
720                                                         res = unchecked (((LongConstant) left).Value /
721                                                                 ((LongConstant) right).Value);
722                                                 
723                                                 return new LongConstant (res, left.Location);
724                                         } else if (left is UIntConstant){
725                                                 uint res;
726                                                 
727                                                 if (ec.ConstantCheckState)
728                                                         res = checked (((UIntConstant) left).Value /
729                                                                 ((UIntConstant) right).Value);
730                                                 else
731                                                         res = unchecked (((UIntConstant) left).Value /
732                                                                 ((UIntConstant) right).Value);
733                                                 
734                                                 return new UIntConstant (res, left.Location);
735                                         } else if (left is IntConstant){
736                                                 int res;
737
738                                                 if (ec.ConstantCheckState)
739                                                         res = checked (((IntConstant) left).Value /
740                                                                 ((IntConstant) right).Value);
741                                                 else
742                                                         res = unchecked (((IntConstant) left).Value /
743                                                                 ((IntConstant) right).Value);
744
745                                                 return new IntConstant (res, left.Location);
746                                         } else if (left is DecimalConstant) {
747                                                 decimal res;
748
749                                                 if (ec.ConstantCheckState)
750                                                         res = checked (((DecimalConstant) left).Value /
751                                                                 ((DecimalConstant) right).Value);
752                                                 else
753                                                         res = unchecked (((DecimalConstant) left).Value /
754                                                                 ((DecimalConstant) right).Value);
755
756                                                 return new DecimalConstant (res, left.Location);
757                                         } else {
758                                                 throw new Exception ( "Unexepected division input: " + left);
759                                         }
760                                 } catch (OverflowException){
761                                         Error_CompileTimeOverflow (ec, loc);
762
763                                 } catch (DivideByZeroException) {
764                                         ec.Report.Error (20, loc, "Division by constant zero");
765                                 }
766                                 
767                                 break;
768                                 
769                         case Binary.Operator.Modulus:
770                                 if (left is NullLiteral && right is NullLiteral) {
771                                         var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
772                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
773                                 }
774
775                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
776                                         return null;
777
778                                 try {
779                                         if (left is DoubleConstant){
780                                                 double res;
781                                                 
782                                                 if (ec.ConstantCheckState)
783                                                         res = checked (((DoubleConstant) left).Value %
784                                                                        ((DoubleConstant) right).Value);
785                                                 else
786                                                         res = unchecked (((DoubleConstant) left).Value %
787                                                                          ((DoubleConstant) right).Value);
788                                                 
789                                                 return new DoubleConstant (res, left.Location);
790                                         } else if (left is FloatConstant){
791                                                 float res;
792                                                 
793                                                 if (ec.ConstantCheckState)
794                                                         res = checked (((FloatConstant) left).Value %
795                                                                        ((FloatConstant) right).Value);
796                                                 else
797                                                         res = unchecked (((FloatConstant) left).Value %
798                                                                          ((FloatConstant) right).Value);
799                                                 
800                                                 return new FloatConstant (res, left.Location);
801                                         } else if (left is ULongConstant){
802                                                 ulong res;
803                                                 
804                                                 if (ec.ConstantCheckState)
805                                                         res = checked (((ULongConstant) left).Value %
806                                                                        ((ULongConstant) right).Value);
807                                                 else
808                                                         res = unchecked (((ULongConstant) left).Value %
809                                                                          ((ULongConstant) right).Value);
810                                                 
811                                                 return new ULongConstant (res, left.Location);
812                                         } else if (left is LongConstant){
813                                                 long res;
814                                                 
815                                                 if (ec.ConstantCheckState)
816                                                         res = checked (((LongConstant) left).Value %
817                                                                        ((LongConstant) right).Value);
818                                                 else
819                                                         res = unchecked (((LongConstant) left).Value %
820                                                                          ((LongConstant) right).Value);
821                                                 
822                                                 return new LongConstant (res, left.Location);
823                                         } else if (left is UIntConstant){
824                                                 uint res;
825                                                 
826                                                 if (ec.ConstantCheckState)
827                                                         res = checked (((UIntConstant) left).Value %
828                                                                        ((UIntConstant) right).Value);
829                                                 else
830                                                         res = unchecked (((UIntConstant) left).Value %
831                                                                          ((UIntConstant) right).Value);
832                                                 
833                                                 return new UIntConstant (res, left.Location);
834                                         } else if (left is IntConstant){
835                                                 int res;
836
837                                                 if (ec.ConstantCheckState)
838                                                         res = checked (((IntConstant) left).Value %
839                                                                        ((IntConstant) right).Value);
840                                                 else
841                                                         res = unchecked (((IntConstant) left).Value %
842                                                                          ((IntConstant) right).Value);
843
844                                                 return new IntConstant (res, left.Location);
845                                         } else {
846                                                 throw new Exception ( "Unexepected modulus input: " + left);
847                                         }
848                                 } catch (DivideByZeroException){
849                                         ec.Report.Error (20, loc, "Division by constant zero");
850                                 } catch (OverflowException){
851                                         Error_CompileTimeOverflow (ec, loc);
852                                 }
853                                 break;
854
855                                 //
856                                 // There is no overflow checking on left shift
857                                 //
858                         case Binary.Operator.LeftShift:
859                                 if (left is NullLiteral && right is NullLiteral) {
860                                         var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
861                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
862                                 }
863
864                                 IntConstant ic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
865                                 if (ic == null){
866                                         Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
867                                         return null;
868                                 }
869
870                                 int lshift_val = ic.Value;
871                                 if (left.Type == TypeManager.uint64_type)
872                                         return new ULongConstant (((ULongConstant)left).Value << lshift_val, left.Location);
873                                 if (left.Type == TypeManager.int64_type)
874                                         return new LongConstant (((LongConstant)left).Value << lshift_val, left.Location);
875                                 if (left.Type == TypeManager.uint32_type)
876                                         return new UIntConstant (((UIntConstant)left).Value << lshift_val, left.Location);
877
878                                 // null << value => null
879                                 if (left is NullLiteral)
880                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
881
882                                 left = left.ConvertImplicitly (ec, TypeManager.int32_type);
883                                 if (left.Type == TypeManager.int32_type)
884                                         return new IntConstant (((IntConstant)left).Value << lshift_val, left.Location);
885
886                                 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
887                                 break;
888
889                                 //
890                                 // There is no overflow checking on right shift
891                                 //
892                         case Binary.Operator.RightShift:
893                                 if (left is NullLiteral && right is NullLiteral) {
894                                         var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
895                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
896                                 }
897
898                                 IntConstant sic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
899                                 if (sic == null){
900                                         Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
901                                         return null;
902                                 }
903                                 int rshift_val = sic.Value;
904                                 if (left.Type == TypeManager.uint64_type)
905                                         return new ULongConstant (((ULongConstant)left).Value >> rshift_val, left.Location);
906                                 if (left.Type == TypeManager.int64_type)
907                                         return new LongConstant (((LongConstant)left).Value >> rshift_val, left.Location);
908                                 if (left.Type == TypeManager.uint32_type)
909                                         return new UIntConstant (((UIntConstant)left).Value >> rshift_val, left.Location);
910
911                                 // null >> value => null
912                                 if (left is NullLiteral)
913                                         return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
914
915                                 left = left.ConvertImplicitly (ec, TypeManager.int32_type);
916                                 if (left.Type == TypeManager.int32_type)
917                                         return new IntConstant (((IntConstant)left).Value >> rshift_val, left.Location);
918
919                                 Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
920                                 break;
921
922                         case Binary.Operator.Equality:
923                                 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
924                                         (left is Nullable.LiftedNull && right.IsNull) ||
925                                         (right is Nullable.LiftedNull && left.IsNull)) {
926                                         if (left.IsNull || right.IsNull) {
927                                                 return ReducedExpression.Create (
928                                                         new BoolConstant (left.IsNull == right.IsNull, left.Location).Resolve (ec),
929                                                         new Binary (oper, left, right, loc));
930                                         }
931
932                                         if (left is StringConstant && right is StringConstant)
933                                                 return new BoolConstant (
934                                                         ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
935
936                                         return null;
937                                 }
938
939                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
940                                         return null;
941
942                                 bool_res = false;
943                                 if (left is DoubleConstant)
944                                         bool_res = ((DoubleConstant) left).Value ==
945                                                 ((DoubleConstant) right).Value;
946                                 else if (left is FloatConstant)
947                                         bool_res = ((FloatConstant) left).Value ==
948                                                 ((FloatConstant) right).Value;
949                                 else if (left is ULongConstant)
950                                         bool_res = ((ULongConstant) left).Value ==
951                                                 ((ULongConstant) right).Value;
952                                 else if (left is LongConstant)
953                                         bool_res = ((LongConstant) left).Value ==
954                                                 ((LongConstant) right).Value;
955                                 else if (left is UIntConstant)
956                                         bool_res = ((UIntConstant) left).Value ==
957                                                 ((UIntConstant) right).Value;
958                                 else if (left is IntConstant)
959                                         bool_res = ((IntConstant) left).Value ==
960                                                 ((IntConstant) right).Value;
961                                 else
962                                         return null;
963
964                                 return new BoolConstant (bool_res, left.Location);
965
966                         case Binary.Operator.Inequality:
967                                 if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (rt) ||
968                                         (left is Nullable.LiftedNull && right.IsNull) ||
969                                         (right is Nullable.LiftedNull && left.IsNull)) {
970                                         if (left.IsNull || right.IsNull) {
971                                                 return ReducedExpression.Create (
972                                                         new BoolConstant (left.IsNull != right.IsNull, left.Location).Resolve (ec),
973                                                         new Binary (oper, left, right, loc));
974                                         }
975
976                                         if (left is StringConstant && right is StringConstant)
977                                                 return new BoolConstant (
978                                                         ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
979
980                                         return null;
981                                 }
982
983                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
984                                         return null;
985
986                                 bool_res = false;
987                                 if (left is DoubleConstant)
988                                         bool_res = ((DoubleConstant) left).Value !=
989                                                 ((DoubleConstant) right).Value;
990                                 else if (left is FloatConstant)
991                                         bool_res = ((FloatConstant) left).Value !=
992                                                 ((FloatConstant) right).Value;
993                                 else if (left is ULongConstant)
994                                         bool_res = ((ULongConstant) left).Value !=
995                                                 ((ULongConstant) right).Value;
996                                 else if (left is LongConstant)
997                                         bool_res = ((LongConstant) left).Value !=
998                                                 ((LongConstant) right).Value;
999                                 else if (left is UIntConstant)
1000                                         bool_res = ((UIntConstant) left).Value !=
1001                                                 ((UIntConstant) right).Value;
1002                                 else if (left is IntConstant)
1003                                         bool_res = ((IntConstant) left).Value !=
1004                                                 ((IntConstant) right).Value;
1005                                 else
1006                                         return null;
1007
1008                                 return new BoolConstant (bool_res, left.Location);
1009
1010                         case Binary.Operator.LessThan:
1011                                 if (right is NullLiteral) {
1012                                         if (left is NullLiteral) {
1013                                                 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
1014                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1015                                         }
1016
1017                                         if (left is Nullable.LiftedNull) {
1018                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1019                                         }
1020                                 }
1021
1022                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1023                                         return null;
1024
1025                                 bool_res = false;
1026                                 if (left is DoubleConstant)
1027                                         bool_res = ((DoubleConstant) left).Value <
1028                                                 ((DoubleConstant) right).Value;
1029                                 else if (left is FloatConstant)
1030                                         bool_res = ((FloatConstant) left).Value <
1031                                                 ((FloatConstant) right).Value;
1032                                 else if (left is ULongConstant)
1033                                         bool_res = ((ULongConstant) left).Value <
1034                                                 ((ULongConstant) right).Value;
1035                                 else if (left is LongConstant)
1036                                         bool_res = ((LongConstant) left).Value <
1037                                                 ((LongConstant) right).Value;
1038                                 else if (left is UIntConstant)
1039                                         bool_res = ((UIntConstant) left).Value <
1040                                                 ((UIntConstant) right).Value;
1041                                 else if (left is IntConstant)
1042                                         bool_res = ((IntConstant) left).Value <
1043                                                 ((IntConstant) right).Value;
1044                                 else
1045                                         return null;
1046
1047                                 return new BoolConstant (bool_res, left.Location);
1048                                 
1049                         case Binary.Operator.GreaterThan:
1050                                 if (right is NullLiteral) {
1051                                         if (left is NullLiteral) {
1052                                                 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
1053                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1054                                         }
1055
1056                                         if (left is Nullable.LiftedNull) {
1057                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1058                                         }
1059                                 }
1060
1061                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1062                                         return null;
1063
1064                                 bool_res = false;
1065                                 if (left is DoubleConstant)
1066                                         bool_res = ((DoubleConstant) left).Value >
1067                                                 ((DoubleConstant) right).Value;
1068                                 else if (left is FloatConstant)
1069                                         bool_res = ((FloatConstant) left).Value >
1070                                                 ((FloatConstant) right).Value;
1071                                 else if (left is ULongConstant)
1072                                         bool_res = ((ULongConstant) left).Value >
1073                                                 ((ULongConstant) right).Value;
1074                                 else if (left is LongConstant)
1075                                         bool_res = ((LongConstant) left).Value >
1076                                                 ((LongConstant) right).Value;
1077                                 else if (left is UIntConstant)
1078                                         bool_res = ((UIntConstant) left).Value >
1079                                                 ((UIntConstant) right).Value;
1080                                 else if (left is IntConstant)
1081                                         bool_res = ((IntConstant) left).Value >
1082                                                 ((IntConstant) right).Value;
1083                                 else
1084                                         return null;
1085
1086                                 return new BoolConstant (bool_res, left.Location);
1087
1088                         case Binary.Operator.GreaterThanOrEqual:
1089                                 if (right is NullLiteral) {
1090                                         if (left is NullLiteral) {
1091                                                 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
1092                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1093                                         }
1094
1095                                         if (left is Nullable.LiftedNull) {
1096                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1097                                         }
1098                                 }
1099
1100                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1101                                         return null;
1102
1103                                 bool_res = false;
1104                                 if (left is DoubleConstant)
1105                                         bool_res = ((DoubleConstant) left).Value >=
1106                                                 ((DoubleConstant) right).Value;
1107                                 else if (left is FloatConstant)
1108                                         bool_res = ((FloatConstant) left).Value >=
1109                                                 ((FloatConstant) right).Value;
1110                                 else if (left is ULongConstant)
1111                                         bool_res = ((ULongConstant) left).Value >=
1112                                                 ((ULongConstant) right).Value;
1113                                 else if (left is LongConstant)
1114                                         bool_res = ((LongConstant) left).Value >=
1115                                                 ((LongConstant) right).Value;
1116                                 else if (left is UIntConstant)
1117                                         bool_res = ((UIntConstant) left).Value >=
1118                                                 ((UIntConstant) right).Value;
1119                                 else if (left is IntConstant)
1120                                         bool_res = ((IntConstant) left).Value >=
1121                                                 ((IntConstant) right).Value;
1122                                 else
1123                                         return null;
1124
1125                                 return new BoolConstant (bool_res, left.Location);
1126
1127                         case Binary.Operator.LessThanOrEqual:
1128                                 if (right is NullLiteral) {
1129                                         if (left is NullLiteral) {
1130                                                 var lifted_int = new Nullable.NullableType (TypeManager.int32_type, loc).ResolveAsTypeTerminal (ec, false);
1131                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
1132                                         }
1133
1134                                         if (left is Nullable.LiftedNull) {
1135                                                 return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
1136                                         }
1137                                 }
1138
1139                                 if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1140                                         return null;
1141
1142                                 bool_res = false;
1143                                 if (left is DoubleConstant)
1144                                         bool_res = ((DoubleConstant) left).Value <=
1145                                                 ((DoubleConstant) right).Value;
1146                                 else if (left is FloatConstant)
1147                                         bool_res = ((FloatConstant) left).Value <=
1148                                                 ((FloatConstant) right).Value;
1149                                 else if (left is ULongConstant)
1150                                         bool_res = ((ULongConstant) left).Value <=
1151                                                 ((ULongConstant) right).Value;
1152                                 else if (left is LongConstant)
1153                                         bool_res = ((LongConstant) left).Value <=
1154                                                 ((LongConstant) right).Value;
1155                                 else if (left is UIntConstant)
1156                                         bool_res = ((UIntConstant) left).Value <=
1157                                                 ((UIntConstant) right).Value;
1158                                 else if (left is IntConstant)
1159                                         bool_res = ((IntConstant) left).Value <=
1160                                                 ((IntConstant) right).Value;
1161                                 else
1162                                         return null;
1163
1164                                 return new BoolConstant (bool_res, left.Location);
1165                         }
1166                                         
1167                         return null;
1168                 }
1169         }
1170 }