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-2011, Novell, Inc.
10 //
11 using System;
12 
13 namespace Mono.CSharp {
14 
15 	public static class ConstantFold
16 	{
CreateBinaryPromotionsTypes(BuiltinTypes types)17 		public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes 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 		//
DoBinaryNumericPromotions(ResolveContext rc, ref Constant left, ref Constant right)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.BuiltinTypes.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.BuiltinTypes.Int);
49 			right = right.ConvertImplicitly (rc.BuiltinTypes.Int);
50 			return left != null && right != null;
51 		}
52 
ConvertPromotion(ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)53 		static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
54 		{
55 			Constant c = prim.ConvertImplicitly (type);
56 			if (c != null) {
57 				prim = c;
58 				return true;
59 			}
60 
61 			if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
62 				type = rc.BuiltinTypes.Long;
63 				prim = prim.ConvertImplicitly (type);
64 				second = second.ConvertImplicitly (type);
65 				return prim != null && second != null;
66 			}
67 
68 			return false;
69 		}
70 
Error_CompileTimeOverflow(ResolveContext rc, Location loc)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>
BinaryFold(ResolveContext ec, Binary.Operator oper, Constant left, Constant right, Location loc)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.BuiltinType == BuiltinTypeSpec.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 (ec.BuiltinTypes, lv && rv, left.Location);
117 				case Binary.Operator.BitwiseOr:
118 				case Binary.Operator.LogicalOr:
119 					return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location);
120 				case Binary.Operator.ExclusiveOr:
121 					return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location);
122 				case Binary.Operator.Equality:
123 					return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location);
124 				case Binary.Operator.Inequality:
125 					return new BoolConstant (ec.BuiltinTypes, 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.Reduce (ec, lt);
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.Reduce (ec, EnumSpec.GetUnderlyingType (lt));
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.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
189 					(rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
190 					var b = new Binary (oper, left, right).ResolveOperator (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 (ec.BuiltinTypes, true, loc), 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 (ec.BuiltinTypes, res, left.Location);
209 				}
210 				if (left is UIntConstant){
211 					uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
212 
213 					return new UIntConstant (ec.BuiltinTypes, res, left.Location);
214 				}
215 				if (left is LongConstant){
216 					long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
217 
218 					return new LongConstant (ec.BuiltinTypes, res, left.Location);
219 				}
220 				if (left is ULongConstant){
221 					ulong res = ((ULongConstant)left).Value |
222 						((ULongConstant)right).Value;
223 
224 					return new ULongConstant (ec.BuiltinTypes, res, left.Location);
225 				}
226 				break;
227 
228 			case Binary.Operator.BitwiseAnd:
229 				//
230 				// bool? operator &(bool? x, bool? y);
231 				//
232 				if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
233 					(rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
234 					var b = new Binary (oper, left, right).ResolveOperator (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 (ec.BuiltinTypes, false, loc), 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 (ec.BuiltinTypes, res, left.Location);
258 				}
259 				if (left is UIntConstant){
260 					uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
261 					return new UIntConstant (ec.BuiltinTypes, res, left.Location);
262 				}
263 				if (left is LongConstant){
264 					long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
265 					return new LongConstant (ec.BuiltinTypes, res, left.Location);
266 				}
267 				if (left is ULongConstant){
268 					ulong res = ((ULongConstant)left).Value &
269 						((ULongConstant)right).Value;
270 
271 					return new ULongConstant (ec.BuiltinTypes, 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 (ec.BuiltinTypes, res, left.Location);
282 				}
283 				if (left is UIntConstant){
284 					uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
285 
286 					return new UIntConstant (ec.BuiltinTypes, res, left.Location);
287 				}
288 				if (left is LongConstant){
289 					long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
290 
291 					return new LongConstant (ec.BuiltinTypes, res, left.Location);
292 				}
293 				if (left is ULongConstant){
294 					ulong res = ((ULongConstant)left).Value ^
295 						((ULongConstant)right).Value;
296 
297 					return new ULongConstant (ec.BuiltinTypes, res, left.Location);
298 				}
299 				break;
300 
301 			case Binary.Operator.Addition:
302 				//
303 				// If both sides are strings, then concatenate
304 				//
305 				// string operator + (string x, string y)
306 				//
307 				if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
308 					if (lt == rt)
309 						return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
310 							left.Location);
311 
312 					if (lt == InternalType.NullLiteral || left.IsNull)
313 						return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
314 
315 					if (rt == InternalType.NullLiteral || right.IsNull)
316 						return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location);
317 
318 					return null;
319 				}
320 
321 				//
322 				// string operator + (string x, object y)
323 				//
324 				if (lt == InternalType.NullLiteral) {
325 					if (rt.BuiltinType == BuiltinTypeSpec.Type.Object)
326 						return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
327 
328 					if (lt == rt) {
329 						ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
330 							"+", lt.GetSignatureForError (), rt.GetSignatureForError ());
331 						return null;
332 					}
333 
334 					return right;
335 				}
336 
337 				//
338 				// string operator + (object x, string y)
339 				//
340 				if (rt == InternalType.NullLiteral) {
341 					if (lt.BuiltinType == BuiltinTypeSpec.Type.Object)
342 						return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location);
343 
344 					return left;
345 				}
346 
347 				//
348 				// handle "E operator + (E x, U y)"
349 				// handle "E operator + (Y y, E x)"
350 				//
351 				EnumConstant lc = left as EnumConstant;
352 				EnumConstant rc = right as EnumConstant;
353 				if (lc != null || rc != null){
354 					if (lc == null) {
355 						lc = rc;
356 						lt = lc.Type;
357 						right = left;
358 					}
359 
360 					// U has to be implicitly convetible to E.base
361 					right = right.ConvertImplicitly (lc.Child.Type);
362 					if (right == null)
363 						return null;
364 
365 					result = BinaryFold (ec, oper, lc.Child, right, loc);
366 					if (result == null)
367 						return null;
368 
369 					result = result.Reduce (ec, lt);
370 					if (result == null || lt.IsEnum)
371 						return result;
372 
373 					return new EnumConstant (result, lt);
374 				}
375 
376 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
377 					return null;
378 
379 				try {
380 					if (left is DoubleConstant){
381 						double res;
382 
383 						if (ec.ConstantCheckState)
384 							res = checked (((DoubleConstant) left).Value +
385 								       ((DoubleConstant) right).Value);
386 						else
387 							res = unchecked (((DoubleConstant) left).Value +
388 									 ((DoubleConstant) right).Value);
389 
390 						return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
391 					}
392 					if (left is FloatConstant){
393 						double a, b, res;
394 						a = ((FloatConstant) left).DoubleValue;
395 						b = ((FloatConstant) right).DoubleValue;
396 
397 						if (ec.ConstantCheckState)
398 							res = checked (a + b);
399 						else
400 							res = unchecked (a + b);
401 
402 						result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
403 					} else if (left is ULongConstant){
404 						ulong res;
405 
406 						if (ec.ConstantCheckState)
407 							res = checked (((ULongConstant) left).Value +
408 								       ((ULongConstant) right).Value);
409 						else
410 							res = unchecked (((ULongConstant) left).Value +
411 									 ((ULongConstant) right).Value);
412 
413 						result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
414 					} else if (left is LongConstant){
415 						long res;
416 
417 						if (ec.ConstantCheckState)
418 							res = checked (((LongConstant) left).Value +
419 								       ((LongConstant) right).Value);
420 						else
421 							res = unchecked (((LongConstant) left).Value +
422 									 ((LongConstant) right).Value);
423 
424 						result = new LongConstant (ec.BuiltinTypes, res, left.Location);
425 					} else if (left is UIntConstant){
426 						uint res;
427 
428 						if (ec.ConstantCheckState)
429 							res = checked (((UIntConstant) left).Value +
430 								       ((UIntConstant) right).Value);
431 						else
432 							res = unchecked (((UIntConstant) left).Value +
433 									 ((UIntConstant) right).Value);
434 
435 						result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
436 					} else if (left is IntConstant){
437 						int res;
438 
439 						if (ec.ConstantCheckState)
440 							res = checked (((IntConstant) left).Value +
441 								       ((IntConstant) right).Value);
442 						else
443 							res = unchecked (((IntConstant) left).Value +
444 									 ((IntConstant) right).Value);
445 
446 						result = new IntConstant (ec.BuiltinTypes, res, left.Location);
447 					} else if (left is DecimalConstant) {
448 						decimal res;
449 
450 						if (ec.ConstantCheckState)
451 							res = checked (((DecimalConstant) left).Value +
452 								((DecimalConstant) right).Value);
453 						else
454 							res = unchecked (((DecimalConstant) left).Value +
455 								((DecimalConstant) right).Value);
456 
457 						result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
458 					}
459 				} catch (OverflowException){
460 					Error_CompileTimeOverflow (ec, loc);
461 				}
462 
463 				return result;
464 
465 			case Binary.Operator.Subtraction:
466 				//
467 				// handle "E operator - (E x, U y)"
468 				// handle "E operator - (Y y, E x)"
469 				//
470 				lc = left as EnumConstant;
471 				rc = right as EnumConstant;
472 				if (lc != null || rc != null) {
473 					TypeSpec res_type;
474 					if (lc == null) {
475 						res_type = right.Type;
476 
477 						// Y has to be implicitly convertible to E.base
478 						left = left.ConvertImplicitly (rc.Child.Type);
479 						if (left == null)
480 							return null;
481 
482 						right = rc.Child;
483 					} else {
484 						res_type = left.Type;
485 
486 						// U has to be implicitly convertible to E.base
487 						right = right.ConvertImplicitly (lc.Child.Type);
488 						if (right == null)
489 							return null;
490 
491 						left = lc.Child;
492 					}
493 
494 					result = BinaryFold (ec, oper, left, right, loc);
495 					if (result == null)
496 						return null;
497 
498 					result = result.Reduce (ec, res_type);
499 					if (result == null)
500 						return null;
501 
502 					return new EnumConstant (result, res_type);
503 				}
504 
505 				if (left is NullLiteral && right is NullLiteral) {
506 					var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
507 					lifted_int.ResolveAsType (ec);
508 					return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
509 				}
510 
511 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
512 					return null;
513 
514 				try {
515 					if (left is DoubleConstant){
516 						double res;
517 
518 						if (ec.ConstantCheckState)
519 							res = checked (((DoubleConstant) left).Value -
520 								       ((DoubleConstant) right).Value);
521 						else
522 							res = unchecked (((DoubleConstant) left).Value -
523 									 ((DoubleConstant) right).Value);
524 
525 						result = new DoubleConstant (ec.BuiltinTypes, res, left.Location);
526 					} else if (left is FloatConstant){
527 						double a, b, res;
528 						a = ((FloatConstant) left).DoubleValue;
529 						b = ((FloatConstant) right).DoubleValue;
530 
531 						if (ec.ConstantCheckState)
532 							res = checked (a - b);
533 						else
534 							res = unchecked (a - b);
535 
536 						result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
537 					} else if (left is ULongConstant){
538 						ulong res;
539 
540 						if (ec.ConstantCheckState)
541 							res = checked (((ULongConstant) left).Value -
542 								       ((ULongConstant) right).Value);
543 						else
544 							res = unchecked (((ULongConstant) left).Value -
545 									 ((ULongConstant) right).Value);
546 
547 						result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
548 					} else if (left is LongConstant){
549 						long res;
550 
551 						if (ec.ConstantCheckState)
552 							res = checked (((LongConstant) left).Value -
553 								       ((LongConstant) right).Value);
554 						else
555 							res = unchecked (((LongConstant) left).Value -
556 									 ((LongConstant) right).Value);
557 
558 						result = new LongConstant (ec.BuiltinTypes, res, left.Location);
559 					} else if (left is UIntConstant){
560 						uint res;
561 
562 						if (ec.ConstantCheckState)
563 							res = checked (((UIntConstant) left).Value -
564 								       ((UIntConstant) right).Value);
565 						else
566 							res = unchecked (((UIntConstant) left).Value -
567 									 ((UIntConstant) right).Value);
568 
569 						result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
570 					} else if (left is IntConstant){
571 						int res;
572 
573 						if (ec.ConstantCheckState)
574 							res = checked (((IntConstant) left).Value -
575 								       ((IntConstant) right).Value);
576 						else
577 							res = unchecked (((IntConstant) left).Value -
578 									 ((IntConstant) right).Value);
579 
580 						result = new IntConstant (ec.BuiltinTypes, res, left.Location);
581 					} else if (left is DecimalConstant) {
582 						decimal res;
583 
584 						if (ec.ConstantCheckState)
585 							res = checked (((DecimalConstant) left).Value -
586 								((DecimalConstant) right).Value);
587 						else
588 							res = unchecked (((DecimalConstant) left).Value -
589 								((DecimalConstant) right).Value);
590 
591 						return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
592 					} else {
593 						throw new Exception ( "Unexepected subtraction input: " + left);
594 					}
595 				} catch (OverflowException){
596 					Error_CompileTimeOverflow (ec, loc);
597 				}
598 
599 				return result;
600 
601 			case Binary.Operator.Multiply:
602 				if (left is NullLiteral && right is NullLiteral) {
603 					var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
604 					lifted_int.ResolveAsType (ec);
605 					return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
606 				}
607 
608 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
609 					return null;
610 
611 				try {
612 					if (left is DoubleConstant){
613 						double res;
614 
615 						if (ec.ConstantCheckState)
616 							res = checked (((DoubleConstant) left).Value *
617 								((DoubleConstant) right).Value);
618 						else
619 							res = unchecked (((DoubleConstant) left).Value *
620 								((DoubleConstant) right).Value);
621 
622 						return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
623 					} else if (left is FloatConstant){
624 						double a, b, res;
625 						a = ((FloatConstant) left).DoubleValue;
626 						b = ((FloatConstant) right).DoubleValue;
627 
628 						if (ec.ConstantCheckState)
629 							res = checked (a * b);
630 						else
631 							res = unchecked (a * b);
632 
633 						return new FloatConstant (ec.BuiltinTypes, res, left.Location);
634 					} else if (left is ULongConstant){
635 						ulong res;
636 
637 						if (ec.ConstantCheckState)
638 							res = checked (((ULongConstant) left).Value *
639 								((ULongConstant) right).Value);
640 						else
641 							res = unchecked (((ULongConstant) left).Value *
642 								((ULongConstant) right).Value);
643 
644 						return new ULongConstant (ec.BuiltinTypes, res, left.Location);
645 					} else if (left is LongConstant){
646 						long res;
647 
648 						if (ec.ConstantCheckState)
649 							res = checked (((LongConstant) left).Value *
650 								((LongConstant) right).Value);
651 						else
652 							res = unchecked (((LongConstant) left).Value *
653 								((LongConstant) right).Value);
654 
655 						return new LongConstant (ec.BuiltinTypes, res, left.Location);
656 					} else if (left is UIntConstant){
657 						uint res;
658 
659 						if (ec.ConstantCheckState)
660 							res = checked (((UIntConstant) left).Value *
661 								((UIntConstant) right).Value);
662 						else
663 							res = unchecked (((UIntConstant) left).Value *
664 								((UIntConstant) right).Value);
665 
666 						return new UIntConstant (ec.BuiltinTypes, res, left.Location);
667 					} else if (left is IntConstant){
668 						int res;
669 
670 						if (ec.ConstantCheckState)
671 							res = checked (((IntConstant) left).Value *
672 								((IntConstant) right).Value);
673 						else
674 							res = unchecked (((IntConstant) left).Value *
675 								((IntConstant) right).Value);
676 
677 						return new IntConstant (ec.BuiltinTypes, res, left.Location);
678 					} else if (left is DecimalConstant) {
679 						decimal res;
680 
681 						if (ec.ConstantCheckState)
682 							res = checked (((DecimalConstant) left).Value *
683 								((DecimalConstant) right).Value);
684 						else
685 							res = unchecked (((DecimalConstant) left).Value *
686 								((DecimalConstant) right).Value);
687 
688 						return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
689 					} else {
690 						throw new Exception ( "Unexepected multiply input: " + left);
691 					}
692 				} catch (OverflowException){
693 					Error_CompileTimeOverflow (ec, loc);
694 				}
695 				break;
696 
697 			case Binary.Operator.Division:
698 				if (left is NullLiteral && right is NullLiteral) {
699 					var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
700 					lifted_int.ResolveAsType (ec);
701 					return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
702 				}
703 
704 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
705 					return null;
706 
707 				try {
708 					if (left is DoubleConstant){
709 						double res;
710 
711 						if (ec.ConstantCheckState)
712 							res = checked (((DoubleConstant) left).Value /
713 								((DoubleConstant) right).Value);
714 						else
715 							res = unchecked (((DoubleConstant) left).Value /
716 								((DoubleConstant) right).Value);
717 
718 						return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
719 					} else if (left is FloatConstant){
720 						double a, b, res;
721 						a = ((FloatConstant) left).DoubleValue;
722 						b = ((FloatConstant) right).DoubleValue;
723 
724 						if (ec.ConstantCheckState)
725 							res = checked (a / b);
726 						else
727 							res = unchecked (a / b);
728 
729 						return new FloatConstant (ec.BuiltinTypes, res, left.Location);
730 					} else if (left is ULongConstant){
731 						ulong res;
732 
733 						if (ec.ConstantCheckState)
734 							res = checked (((ULongConstant) left).Value /
735 								((ULongConstant) right).Value);
736 						else
737 							res = unchecked (((ULongConstant) left).Value /
738 								((ULongConstant) right).Value);
739 
740 						return new ULongConstant (ec.BuiltinTypes, res, left.Location);
741 					} else if (left is LongConstant){
742 						long res;
743 
744 						if (ec.ConstantCheckState)
745 							res = checked (((LongConstant) left).Value /
746 								((LongConstant) right).Value);
747 						else
748 							res = unchecked (((LongConstant) left).Value /
749 								((LongConstant) right).Value);
750 
751 						return new LongConstant (ec.BuiltinTypes, res, left.Location);
752 					} else if (left is UIntConstant){
753 						uint res;
754 
755 						if (ec.ConstantCheckState)
756 							res = checked (((UIntConstant) left).Value /
757 								((UIntConstant) right).Value);
758 						else
759 							res = unchecked (((UIntConstant) left).Value /
760 								((UIntConstant) right).Value);
761 
762 						return new UIntConstant (ec.BuiltinTypes, res, left.Location);
763 					} else if (left is IntConstant){
764 						int res;
765 
766 						if (ec.ConstantCheckState)
767 							res = checked (((IntConstant) left).Value /
768 								((IntConstant) right).Value);
769 						else
770 							res = unchecked (((IntConstant) left).Value /
771 								((IntConstant) right).Value);
772 
773 						return new IntConstant (ec.BuiltinTypes, res, left.Location);
774 					} else if (left is DecimalConstant) {
775 						decimal res;
776 
777 						if (ec.ConstantCheckState)
778 							res = checked (((DecimalConstant) left).Value /
779 								((DecimalConstant) right).Value);
780 						else
781 							res = unchecked (((DecimalConstant) left).Value /
782 								((DecimalConstant) right).Value);
783 
784 						return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
785 					} else {
786 						throw new Exception ( "Unexepected division input: " + left);
787 					}
788 				} catch (OverflowException){
789 					Error_CompileTimeOverflow (ec, loc);
790 
791 				} catch (DivideByZeroException) {
792 					ec.Report.Error (20, loc, "Division by constant zero");
793 				}
794 
795 				break;
796 
797 			case Binary.Operator.Modulus:
798 				if (left is NullLiteral && right is NullLiteral) {
799 					var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
800 					lifted_int.ResolveAsType (ec);
801 					return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
802 				}
803 
804 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
805 					return null;
806 
807 				try {
808 					if (left is DoubleConstant){
809 						double res;
810 
811 						if (ec.ConstantCheckState)
812 							res = checked (((DoubleConstant) left).Value %
813 								       ((DoubleConstant) right).Value);
814 						else
815 							res = unchecked (((DoubleConstant) left).Value %
816 									 ((DoubleConstant) right).Value);
817 
818 						return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
819 					} else if (left is FloatConstant){
820 						double a, b, res;
821 						a = ((FloatConstant) left).DoubleValue;
822 						b = ((FloatConstant) right).DoubleValue;
823 
824 						if (ec.ConstantCheckState)
825 							res = checked (a % b);
826 						else
827 							res = unchecked (a % b);
828 
829 						return new FloatConstant (ec.BuiltinTypes, res, left.Location);
830 					} else if (left is ULongConstant){
831 						ulong res;
832 
833 						if (ec.ConstantCheckState)
834 							res = checked (((ULongConstant) left).Value %
835 								       ((ULongConstant) right).Value);
836 						else
837 							res = unchecked (((ULongConstant) left).Value %
838 									 ((ULongConstant) right).Value);
839 
840 						return new ULongConstant (ec.BuiltinTypes, res, left.Location);
841 					} else if (left is LongConstant){
842 						long res;
843 
844 						if (ec.ConstantCheckState)
845 							res = checked (((LongConstant) left).Value %
846 								       ((LongConstant) right).Value);
847 						else
848 							res = unchecked (((LongConstant) left).Value %
849 									 ((LongConstant) right).Value);
850 
851 						return new LongConstant (ec.BuiltinTypes, res, left.Location);
852 					} else if (left is UIntConstant){
853 						uint res;
854 
855 						if (ec.ConstantCheckState)
856 							res = checked (((UIntConstant) left).Value %
857 								       ((UIntConstant) right).Value);
858 						else
859 							res = unchecked (((UIntConstant) left).Value %
860 									 ((UIntConstant) right).Value);
861 
862 						return new UIntConstant (ec.BuiltinTypes, res, left.Location);
863 					} else if (left is IntConstant){
864 						int res;
865 
866 						if (ec.ConstantCheckState)
867 							res = checked (((IntConstant) left).Value %
868 								       ((IntConstant) right).Value);
869 						else
870 							res = unchecked (((IntConstant) left).Value %
871 									 ((IntConstant) right).Value);
872 
873 						return new IntConstant (ec.BuiltinTypes, res, left.Location);
874 					}
875 
876 					if (left is DecimalConstant) {
877 						decimal res;
878 
879 						if (ec.ConstantCheckState)
880 							res = checked (((DecimalConstant) left).Value %
881 								((DecimalConstant) right).Value);
882 						else
883 							res = unchecked (((DecimalConstant) left).Value %
884 								((DecimalConstant) right).Value);
885 
886 						return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
887 					}
888 
889 					throw new Exception ( "Unexepected modulus input: " + left);
890 				} catch (DivideByZeroException){
891 					ec.Report.Error (20, loc, "Division by constant zero");
892 				} catch (OverflowException){
893 					Error_CompileTimeOverflow (ec, loc);
894 				}
895 				break;
896 
897 				//
898 				// There is no overflow checking on left shift
899 				//
900 			case Binary.Operator.LeftShift:
901 				if (left is NullLiteral && right is NullLiteral) {
902 					var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
903 					lifted_int.ResolveAsType (ec);
904 					return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
905 				}
906 
907 				IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
908 				if (ic == null){
909 					return null;
910 				}
911 
912 				int lshift_val = ic.Value;
913 				switch (left.Type.BuiltinType) {
914 				case BuiltinTypeSpec.Type.ULong:
915 					return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location);
916 				case BuiltinTypeSpec.Type.Long:
917 					return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location);
918 				case BuiltinTypeSpec.Type.UInt:
919 					return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location);
920 				}
921 
922 				// null << value => null
923 				if (left is NullLiteral)
924 					return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
925 
926 				left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
927 				if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
928 					return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location);
929 
930 				return null;
931 
932 				//
933 				// There is no overflow checking on right shift
934 				//
935 			case Binary.Operator.RightShift:
936 				if (left is NullLiteral && right is NullLiteral) {
937 					var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
938 					lifted_int.ResolveAsType (ec);
939 					return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
940 				}
941 
942 				IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
943 				if (sic == null){
944 					return null;
945 				}
946 				int rshift_val = sic.Value;
947 				switch (left.Type.BuiltinType) {
948 				case BuiltinTypeSpec.Type.ULong:
949 					return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location);
950 				case BuiltinTypeSpec.Type.Long:
951 					return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location);
952 				case BuiltinTypeSpec.Type.UInt:
953 					return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location);
954 				}
955 
956 				// null >> value => null
957 				if (left is NullLiteral)
958 					return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
959 
960 				left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
961 				if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
962 					return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location);
963 
964 				return null;
965 
966 			case Binary.Operator.Equality:
967 				if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
968 					(left is Nullable.LiftedNull && right.IsNull) ||
969 					(right is Nullable.LiftedNull && left.IsNull)) {
970 					if (left.IsNull || right.IsNull) {
971 						return ReducedExpression.Create (
972 							new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
973 							new Binary (oper, left, right));
974 					}
975 
976 					if (left is StringConstant && right is StringConstant)
977 						return new BoolConstant (ec.BuiltinTypes,
978 							((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
979 
980 					return null;
981 				}
982 
983 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
984 					return null;
985 
986 				bool_res = false;
987 				if (left is DoubleConstant)
988 					bool_res = ((DoubleConstant) left).Value ==
989 						((DoubleConstant) right).Value;
990 				else if (left is FloatConstant)
991 					bool_res = ((FloatConstant) left).DoubleValue ==
992 						((FloatConstant) right).DoubleValue;
993 				else if (left is ULongConstant)
994 					bool_res = ((ULongConstant) left).Value ==
995 						((ULongConstant) right).Value;
996 				else if (left is LongConstant)
997 					bool_res = ((LongConstant) left).Value ==
998 						((LongConstant) right).Value;
999 				else if (left is UIntConstant)
1000 					bool_res = ((UIntConstant) left).Value ==
1001 						((UIntConstant) right).Value;
1002 				else if (left is IntConstant)
1003 					bool_res = ((IntConstant) left).Value ==
1004 						((IntConstant) right).Value;
1005 				else
1006 					return null;
1007 
1008 				return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1009 
1010 			case Binary.Operator.Inequality:
1011 				if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
1012 					(left is Nullable.LiftedNull && right.IsNull) ||
1013 					(right is Nullable.LiftedNull && left.IsNull)) {
1014 					if (left.IsNull || right.IsNull) {
1015 						return ReducedExpression.Create (
1016 							new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
1017 							new Binary (oper, left, right));
1018 					}
1019 
1020 					if (left is StringConstant && right is StringConstant)
1021 						return new BoolConstant (ec.BuiltinTypes,
1022 							((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
1023 
1024 					return null;
1025 				}
1026 
1027 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1028 					return null;
1029 
1030 				bool_res = false;
1031 				if (left is DoubleConstant)
1032 					bool_res = ((DoubleConstant) left).Value !=
1033 						((DoubleConstant) right).Value;
1034 				else if (left is FloatConstant)
1035 					bool_res = ((FloatConstant) left).DoubleValue !=
1036 						((FloatConstant) right).DoubleValue;
1037 				else if (left is ULongConstant)
1038 					bool_res = ((ULongConstant) left).Value !=
1039 						((ULongConstant) right).Value;
1040 				else if (left is LongConstant)
1041 					bool_res = ((LongConstant) left).Value !=
1042 						((LongConstant) right).Value;
1043 				else if (left is UIntConstant)
1044 					bool_res = ((UIntConstant) left).Value !=
1045 						((UIntConstant) right).Value;
1046 				else if (left is IntConstant)
1047 					bool_res = ((IntConstant) left).Value !=
1048 						((IntConstant) right).Value;
1049 				else
1050 					return null;
1051 
1052 				return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1053 
1054 			case Binary.Operator.LessThan:
1055 				if (right is NullLiteral) {
1056 					if (left is NullLiteral) {
1057 						var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1058 						lifted_int.ResolveAsType (ec);
1059 						return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1060 					}
1061 				}
1062 
1063 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1064 					return null;
1065 
1066 				bool_res = false;
1067 				if (left is DoubleConstant)
1068 					bool_res = ((DoubleConstant) left).Value <
1069 						((DoubleConstant) right).Value;
1070 				else if (left is FloatConstant)
1071 					bool_res = ((FloatConstant) left).DoubleValue <
1072 						((FloatConstant) right).DoubleValue;
1073 				else if (left is ULongConstant)
1074 					bool_res = ((ULongConstant) left).Value <
1075 						((ULongConstant) right).Value;
1076 				else if (left is LongConstant)
1077 					bool_res = ((LongConstant) left).Value <
1078 						((LongConstant) right).Value;
1079 				else if (left is UIntConstant)
1080 					bool_res = ((UIntConstant) left).Value <
1081 						((UIntConstant) right).Value;
1082 				else if (left is IntConstant)
1083 					bool_res = ((IntConstant) left).Value <
1084 						((IntConstant) right).Value;
1085 				else
1086 					return null;
1087 
1088 				return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1089 
1090 			case Binary.Operator.GreaterThan:
1091 				if (right is NullLiteral) {
1092 					if (left is NullLiteral) {
1093 						var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1094 						lifted_int.ResolveAsType (ec);
1095 						return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1096 					}
1097 				}
1098 
1099 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1100 					return null;
1101 
1102 				bool_res = false;
1103 				if (left is DoubleConstant)
1104 					bool_res = ((DoubleConstant) left).Value >
1105 						((DoubleConstant) right).Value;
1106 				else if (left is FloatConstant)
1107 					bool_res = ((FloatConstant) left).DoubleValue >
1108 						((FloatConstant) right).DoubleValue;
1109 				else if (left is ULongConstant)
1110 					bool_res = ((ULongConstant) left).Value >
1111 						((ULongConstant) right).Value;
1112 				else if (left is LongConstant)
1113 					bool_res = ((LongConstant) left).Value >
1114 						((LongConstant) right).Value;
1115 				else if (left is UIntConstant)
1116 					bool_res = ((UIntConstant) left).Value >
1117 						((UIntConstant) right).Value;
1118 				else if (left is IntConstant)
1119 					bool_res = ((IntConstant) left).Value >
1120 						((IntConstant) right).Value;
1121 				else
1122 					return null;
1123 
1124 				return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1125 
1126 			case Binary.Operator.GreaterThanOrEqual:
1127 				if (right is NullLiteral) {
1128 					if (left is NullLiteral) {
1129 						var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1130 						lifted_int.ResolveAsType (ec);
1131 						return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1132 					}
1133 				}
1134 
1135 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1136 					return null;
1137 
1138 				bool_res = false;
1139 				if (left is DoubleConstant)
1140 					bool_res = ((DoubleConstant) left).Value >=
1141 						((DoubleConstant) right).Value;
1142 				else if (left is FloatConstant)
1143 					bool_res = ((FloatConstant) left).DoubleValue >=
1144 						((FloatConstant) right).DoubleValue;
1145 				else if (left is ULongConstant)
1146 					bool_res = ((ULongConstant) left).Value >=
1147 						((ULongConstant) right).Value;
1148 				else if (left is LongConstant)
1149 					bool_res = ((LongConstant) left).Value >=
1150 						((LongConstant) right).Value;
1151 				else if (left is UIntConstant)
1152 					bool_res = ((UIntConstant) left).Value >=
1153 						((UIntConstant) right).Value;
1154 				else if (left is IntConstant)
1155 					bool_res = ((IntConstant) left).Value >=
1156 						((IntConstant) right).Value;
1157 				else
1158 					return null;
1159 
1160 				return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1161 
1162 			case Binary.Operator.LessThanOrEqual:
1163 				if (right is NullLiteral) {
1164 					if (left is NullLiteral) {
1165 						var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
1166 						lifted_int.ResolveAsType (ec);
1167 						return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
1168 					}
1169 				}
1170 
1171 				if (!DoBinaryNumericPromotions (ec, ref left, ref right))
1172 					return null;
1173 
1174 				bool_res = false;
1175 				if (left is DoubleConstant)
1176 					bool_res = ((DoubleConstant) left).Value <=
1177 						((DoubleConstant) right).Value;
1178 				else if (left is FloatConstant)
1179 					bool_res = ((FloatConstant) left).DoubleValue <=
1180 						((FloatConstant) right).DoubleValue;
1181 				else if (left is ULongConstant)
1182 					bool_res = ((ULongConstant) left).Value <=
1183 						((ULongConstant) right).Value;
1184 				else if (left is LongConstant)
1185 					bool_res = ((LongConstant) left).Value <=
1186 						((LongConstant) right).Value;
1187 				else if (left is UIntConstant)
1188 					bool_res = ((UIntConstant) left).Value <=
1189 						((UIntConstant) right).Value;
1190 				else if (left is IntConstant)
1191 					bool_res = ((IntConstant) left).Value <=
1192 						((IntConstant) right).Value;
1193 				else
1194 					return null;
1195 
1196 				return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
1197 			}
1198 
1199 			return null;
1200 		}
1201 	}
1202 }
1203