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