PageRenderTime 105ms CodeModel.GetById 31ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/cfold.cs

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