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