PageRenderTime 127ms CodeModel.GetById 39ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 3ms

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

http://github.com/icsharpcode/ILSpy
C# | 11921 lines | 8883 code | 2037 blank | 1001 comment | 2460 complexity | 24d900a0fd8e2b864aaeb0244c899382 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1//
   2// expression.cs: Expression representation for the IL tree.
   3//
   4// Author:
   5//   Miguel de Icaza (miguel@ximian.com)
   6//   Marek Safar (marek.safar@gmail.com)
   7//
   8// Copyright 2001, 2002, 2003 Ximian, Inc.
   9// Copyright 2003-2008 Novell, Inc.
  10// Copyright 2011 Xamarin Inc.
  11//
  12
  13using System;
  14using System.Collections.Generic;
  15using System.Linq;
  16using SLE = System.Linq.Expressions;
  17
  18#if STATIC
  19using MetaType = IKVM.Reflection.Type;
  20using IKVM.Reflection;
  21using IKVM.Reflection.Emit;
  22#else
  23using MetaType = System.Type;
  24using System.Reflection;
  25using System.Reflection.Emit;
  26#endif
  27
  28namespace Mono.CSharp
  29{
  30	//
  31	// This is an user operator expression, automatically created during
  32	// resolve phase
  33	//
  34	public class UserOperatorCall : Expression {
  35		protected readonly Arguments arguments;
  36		protected readonly MethodSpec oper;
  37		readonly Func<ResolveContext, Expression, Expression> expr_tree;
  38
  39		public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
  40		{
  41			this.oper = oper;
  42			this.arguments = args;
  43			this.expr_tree = expr_tree;
  44
  45			type = oper.ReturnType;
  46			eclass = ExprClass.Value;
  47			this.loc = loc;
  48		}
  49
  50		public override bool ContainsEmitWithAwait ()
  51		{
  52			return arguments.ContainsEmitWithAwait ();
  53		}
  54
  55		public override Expression CreateExpressionTree (ResolveContext ec)
  56		{
  57			if (expr_tree != null)
  58				return expr_tree (ec, new TypeOfMethod (oper, loc));
  59
  60			Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
  61				new NullLiteral (loc),
  62				new TypeOfMethod (oper, loc));
  63
  64			return CreateExpressionFactoryCall (ec, "Call", args);
  65		}
  66
  67		protected override void CloneTo (CloneContext context, Expression target)
  68		{
  69			// Nothing to clone
  70		}
  71		
  72		protected override Expression DoResolve (ResolveContext ec)
  73		{
  74			//
  75			// We are born fully resolved
  76			//
  77			return this;
  78		}
  79
  80		public override void Emit (EmitContext ec)
  81		{
  82			var call = new CallEmitter ();
  83			call.Emit (ec, oper, arguments, loc);
  84		}
  85
  86		public override void FlowAnalysis (FlowAnalysisContext fc)
  87		{
  88			arguments.FlowAnalysis (fc);
  89		}
  90
  91		public override SLE.Expression MakeExpression (BuilderContext ctx)
  92		{
  93#if STATIC
  94			return base.MakeExpression (ctx);
  95#else
  96			return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
  97#endif
  98		}
  99	}
 100
 101	public class ParenthesizedExpression : ShimExpression
 102	{
 103		public ParenthesizedExpression (Expression expr, Location loc)
 104			: base (expr)
 105		{
 106			this.loc = loc;
 107		}
 108
 109		protected override Expression DoResolve (ResolveContext ec)
 110		{
 111			var res = expr.Resolve (ec);
 112			var constant = res as Constant;
 113			if (constant != null && constant.IsLiteral)
 114				return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
 115
 116			return res;
 117		}
 118
 119		public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
 120		{
 121			return expr.DoResolveLValue (ec, right_side);
 122		}
 123		
 124		public override object Accept (StructuralVisitor visitor)
 125		{
 126			return visitor.Visit (this);
 127		}
 128	}
 129	
 130	//
 131	//   Unary implements unary expressions.
 132	//
 133	public class Unary : Expression
 134	{
 135		public enum Operator : byte {
 136			UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
 137			AddressOf,  TOP
 138		}
 139
 140		public readonly Operator Oper;
 141		public Expression Expr;
 142		ConvCast.Mode enum_conversion;
 143
 144		public Unary (Operator op, Expression expr, Location loc)
 145		{
 146			Oper = op;
 147			Expr = expr;
 148			this.loc = loc;
 149		}
 150
 151		// <summary>
 152		//   This routine will attempt to simplify the unary expression when the
 153		//   argument is a constant.
 154		// </summary>
 155		Constant TryReduceConstant (ResolveContext ec, Constant constant)
 156		{
 157			var e = constant;
 158
 159			while (e is EmptyConstantCast)
 160				e = ((EmptyConstantCast) e).child;
 161			
 162			if (e is SideEffectConstant) {
 163				Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
 164				return r == null ? null : new SideEffectConstant (r, e, r.Location);
 165			}
 166
 167			TypeSpec expr_type = e.Type;
 168			
 169			switch (Oper){
 170			case Operator.UnaryPlus:
 171				// Unary numeric promotions
 172				switch (expr_type.BuiltinType) {
 173				case BuiltinTypeSpec.Type.Byte:
 174					return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
 175				case BuiltinTypeSpec.Type.SByte:
 176					return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
 177				case BuiltinTypeSpec.Type.Short:
 178					return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
 179				case BuiltinTypeSpec.Type.UShort:
 180					return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
 181				case BuiltinTypeSpec.Type.Char:
 182					return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
 183				
 184				// Predefined operators
 185				case BuiltinTypeSpec.Type.Int:
 186				case BuiltinTypeSpec.Type.UInt:
 187				case BuiltinTypeSpec.Type.Long:
 188				case BuiltinTypeSpec.Type.ULong:
 189				case BuiltinTypeSpec.Type.Float:
 190				case BuiltinTypeSpec.Type.Double:
 191				case BuiltinTypeSpec.Type.Decimal:
 192					return e;
 193				}
 194				
 195				return null;
 196				
 197			case Operator.UnaryNegation:
 198				// Unary numeric promotions
 199				switch (expr_type.BuiltinType) {
 200				case BuiltinTypeSpec.Type.Byte:
 201					return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
 202				case BuiltinTypeSpec.Type.SByte:
 203					return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
 204				case BuiltinTypeSpec.Type.Short:
 205					return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
 206				case BuiltinTypeSpec.Type.UShort:
 207					return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
 208				case BuiltinTypeSpec.Type.Char:
 209					return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
 210
 211				// Predefined operators
 212				case BuiltinTypeSpec.Type.Int:
 213					int ivalue = ((IntConstant) e).Value;
 214					if (ivalue == int.MinValue) {
 215						if (ec.ConstantCheckState) {
 216							ConstantFold.Error_CompileTimeOverflow (ec, loc);
 217							return null;
 218						}
 219						return e;
 220					}
 221					return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
 222
 223				case BuiltinTypeSpec.Type.Long:
 224					long lvalue = ((LongConstant) e).Value;
 225					if (lvalue == long.MinValue) {
 226						if (ec.ConstantCheckState) {
 227							ConstantFold.Error_CompileTimeOverflow (ec, loc);
 228							return null;
 229						}
 230						return e;
 231					}
 232					return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
 233
 234				case BuiltinTypeSpec.Type.UInt:
 235					UIntLiteral uil = constant as UIntLiteral;
 236					if (uil != null) {
 237						if (uil.Value == int.MaxValue + (uint) 1)
 238							return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
 239						return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
 240					}
 241					return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
 242
 243
 244				case BuiltinTypeSpec.Type.ULong:
 245					ULongLiteral ull = constant as ULongLiteral;
 246					if (ull != null && ull.Value == 9223372036854775808)
 247						return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
 248					return null;
 249
 250				case BuiltinTypeSpec.Type.Float:
 251					FloatLiteral fl = constant as FloatLiteral;
 252					// For better error reporting
 253					if (fl != null)
 254						return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
 255
 256					return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
 257
 258				case BuiltinTypeSpec.Type.Double:
 259					DoubleLiteral dl = constant as DoubleLiteral;
 260					// For better error reporting
 261					if (dl != null)
 262						return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
 263
 264					return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
 265
 266				case BuiltinTypeSpec.Type.Decimal:
 267					return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
 268				}
 269
 270				return null;
 271				
 272			case Operator.LogicalNot:
 273				if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
 274					return null;
 275				
 276				bool b = (bool)e.GetValue ();
 277				return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
 278				
 279			case Operator.OnesComplement:
 280				// Unary numeric promotions
 281				switch (expr_type.BuiltinType) {
 282				case BuiltinTypeSpec.Type.Byte:
 283					return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
 284				case BuiltinTypeSpec.Type.SByte:
 285					return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
 286				case BuiltinTypeSpec.Type.Short:
 287					return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
 288				case BuiltinTypeSpec.Type.UShort:
 289					return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
 290				case BuiltinTypeSpec.Type.Char:
 291					return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
 292				
 293				// Predefined operators
 294				case BuiltinTypeSpec.Type.Int:
 295					return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
 296				case BuiltinTypeSpec.Type.UInt:
 297					return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
 298				case BuiltinTypeSpec.Type.Long:
 299					return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
 300				case BuiltinTypeSpec.Type.ULong:
 301					return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
 302				}
 303				if (e is EnumConstant) {
 304					var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
 305					if (res != null) {
 306						//
 307						// Numeric promotion upgraded types to int but for enum constant
 308						// original underlying constant type is needed
 309						//
 310						if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
 311							int v = ((IntConstant) res).Value;
 312							switch (((EnumConstant) e).Child.Type.BuiltinType) {
 313								case BuiltinTypeSpec.Type.UShort:
 314								res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
 315								break;
 316								case BuiltinTypeSpec.Type.Short:
 317								res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
 318								break;
 319								case BuiltinTypeSpec.Type.Byte:
 320								res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
 321								break;
 322								case BuiltinTypeSpec.Type.SByte:
 323								res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
 324								break;
 325							}
 326						}
 327
 328						res = new EnumConstant (res, expr_type);
 329					}
 330					return res;
 331				}
 332				return null;
 333			}
 334			throw new Exception ("Can not constant fold: " + Oper.ToString());
 335		}
 336		
 337		protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
 338		{
 339			eclass = ExprClass.Value;
 340
 341			TypeSpec expr_type = expr.Type;
 342			Expression best_expr;
 343
 344			TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
 345
 346			//
 347			// Primitive types first
 348			//
 349			if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
 350				best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
 351				if (best_expr == null)
 352					return null;
 353
 354				type = best_expr.Type;
 355				Expr = best_expr;
 356				return this;
 357			}
 358
 359			//
 360			// E operator ~(E x);
 361			//
 362			if (Oper == Operator.OnesComplement && expr_type.IsEnum)
 363				return ResolveEnumOperator (ec, expr, predefined);
 364
 365			return ResolveUserType (ec, expr, predefined);
 366		}
 367
 368		protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
 369		{
 370			TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
 371			Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
 372			if (best_expr == null)
 373				return null;
 374
 375			Expr = best_expr;
 376			enum_conversion = Binary.GetEnumResultCast (underlying_type);
 377			type = expr.Type;
 378			return EmptyCast.Create (this, type);
 379		}
 380
 381		public override bool ContainsEmitWithAwait ()
 382		{
 383			return Expr.ContainsEmitWithAwait ();
 384		}
 385
 386		public override Expression CreateExpressionTree (ResolveContext ec)
 387		{
 388			return CreateExpressionTree (ec, null);
 389		}
 390
 391		Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
 392		{
 393			string method_name;
 394			switch (Oper) {
 395			case Operator.AddressOf:
 396				Error_PointerInsideExpressionTree (ec);
 397				return null;
 398			case Operator.UnaryNegation:
 399				if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
 400					method_name = "NegateChecked";
 401				else
 402					method_name = "Negate";
 403				break;
 404			case Operator.OnesComplement:
 405			case Operator.LogicalNot:
 406				method_name = "Not";
 407				break;
 408			case Operator.UnaryPlus:
 409				method_name = "UnaryPlus";
 410				break;
 411			default:
 412				throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
 413			}
 414
 415			Arguments args = new Arguments (2);
 416			args.Add (new Argument (Expr.CreateExpressionTree (ec)));
 417			if (user_op != null)
 418				args.Add (new Argument (user_op));
 419
 420			return CreateExpressionFactoryCall (ec, method_name, args);
 421		}
 422
 423		public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
 424		{
 425			var predefined_operators = new TypeSpec[(int) Operator.TOP][];
 426
 427			//
 428			// 7.6.1 Unary plus operator
 429			//
 430			predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
 431				types.Int, types.UInt,
 432				types.Long, types.ULong,
 433				types.Float, types.Double,
 434				types.Decimal
 435			};
 436
 437			//
 438			// 7.6.2 Unary minus operator
 439			//
 440			predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
 441				types.Int,  types.Long,
 442				types.Float, types.Double,
 443				types.Decimal
 444			};
 445
 446			//
 447			// 7.6.3 Logical negation operator
 448			//
 449			predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
 450				types.Bool
 451			};
 452
 453			//
 454			// 7.6.4 Bitwise complement operator
 455			//
 456			predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
 457				types.Int, types.UInt,
 458				types.Long, types.ULong
 459			};
 460
 461			return predefined_operators;
 462		}
 463
 464		//
 465		// Unary numeric promotions
 466		//
 467		static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
 468		{
 469			TypeSpec expr_type = expr.Type;
 470			if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
 471				switch (expr_type.BuiltinType) {
 472				case BuiltinTypeSpec.Type.Byte:
 473				case BuiltinTypeSpec.Type.SByte:
 474				case BuiltinTypeSpec.Type.Short:
 475				case BuiltinTypeSpec.Type.UShort:
 476				case BuiltinTypeSpec.Type.Char:
 477					return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
 478				}
 479			}
 480
 481			if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
 482				return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
 483
 484			return expr;
 485		}
 486
 487		protected override Expression DoResolve (ResolveContext ec)
 488		{
 489			if (Oper == Operator.AddressOf) {
 490				return ResolveAddressOf (ec);
 491			}
 492
 493			Expr = Expr.Resolve (ec);
 494			if (Expr == null)
 495				return null;
 496
 497			if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
 498				Arguments args = new Arguments (1);
 499				args.Add (new Argument (Expr));
 500				return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
 501			}
 502
 503			if (Expr.Type.IsNullableType)
 504				return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
 505
 506			//
 507			// Attempt to use a constant folding operation.
 508			//
 509			Constant cexpr = Expr as Constant;
 510			if (cexpr != null) {
 511				cexpr = TryReduceConstant (ec, cexpr);
 512				if (cexpr != null)
 513					return cexpr;
 514			}
 515
 516			Expression expr = ResolveOperator (ec, Expr);
 517			if (expr == null)
 518				Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
 519			
 520			//
 521			// Reduce unary operator on predefined types
 522			//
 523			if (expr == this && Oper == Operator.UnaryPlus)
 524				return Expr;
 525
 526			return expr;
 527		}
 528
 529		public override Expression DoResolveLValue (ResolveContext ec, Expression right)
 530		{
 531			return null;
 532		}
 533
 534		public override void Emit (EmitContext ec)
 535		{
 536			EmitOperator (ec, type);
 537		}
 538
 539		protected void EmitOperator (EmitContext ec, TypeSpec type)
 540		{
 541			switch (Oper) {
 542			case Operator.UnaryPlus:
 543				Expr.Emit (ec);
 544				break;
 545				
 546			case Operator.UnaryNegation:
 547				if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
 548					if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
 549						Expr = Expr.EmitToField (ec);
 550
 551					ec.EmitInt (0);
 552					if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
 553						ec.Emit (OpCodes.Conv_U8);
 554					Expr.Emit (ec);
 555					ec.Emit (OpCodes.Sub_Ovf);
 556				} else {
 557					Expr.Emit (ec);
 558					ec.Emit (OpCodes.Neg);
 559				}
 560				
 561				break;
 562				
 563			case Operator.LogicalNot:
 564				Expr.Emit (ec);
 565				ec.EmitInt (0);
 566				ec.Emit (OpCodes.Ceq);
 567				break;
 568				
 569			case Operator.OnesComplement:
 570				Expr.Emit (ec);
 571				ec.Emit (OpCodes.Not);
 572				break;
 573				
 574			case Operator.AddressOf:
 575				((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
 576				break;
 577				
 578			default:
 579				throw new Exception ("This should not happen: Operator = "
 580						     + Oper.ToString ());
 581			}
 582
 583			//
 584			// Same trick as in Binary expression
 585			//
 586			if (enum_conversion != 0) {
 587				using (ec.With (BuilderContext.Options.CheckedScope, false)) {
 588					ConvCast.Emit (ec, enum_conversion);
 589				}
 590			}
 591		}
 592
 593		public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
 594		{
 595			if (Oper == Operator.LogicalNot)
 596				Expr.EmitBranchable (ec, target, !on_true);
 597			else
 598				base.EmitBranchable (ec, target, on_true);
 599		}
 600
 601		public override void EmitSideEffect (EmitContext ec)
 602		{
 603			Expr.EmitSideEffect (ec);
 604		}
 605
 606		public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
 607		{
 608			rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
 609				oper, type.GetSignatureForError ());
 610		}
 611
 612		public override void FlowAnalysis (FlowAnalysisContext fc)
 613		{
 614			FlowAnalysis (fc, false);
 615		}
 616
 617		public override void FlowAnalysisConditional (FlowAnalysisContext fc)
 618		{
 619			FlowAnalysis (fc, true);
 620		}
 621
 622		void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
 623		{
 624			if (Oper == Operator.AddressOf) {
 625				var vr = Expr as VariableReference;
 626				if (vr != null && vr.VariableInfo != null)
 627					fc.SetVariableAssigned (vr.VariableInfo);
 628
 629				return;
 630			}
 631
 632			if (Oper == Operator.LogicalNot && conditional) {
 633				Expr.FlowAnalysisConditional (fc);
 634
 635				var temp = fc.DefiniteAssignmentOnTrue;
 636				fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
 637				fc.DefiniteAssignmentOnFalse = temp;
 638			} else {
 639				Expr.FlowAnalysis (fc);
 640			}
 641		}
 642
 643		//
 644		// Converts operator to System.Linq.Expressions.ExpressionType enum name
 645		//
 646		string GetOperatorExpressionTypeName ()
 647		{
 648			switch (Oper) {
 649			case Operator.OnesComplement:
 650				return "OnesComplement";
 651			case Operator.LogicalNot:
 652				return "Not";
 653			case Operator.UnaryNegation:
 654				return "Negate";
 655			case Operator.UnaryPlus:
 656				return "UnaryPlus";
 657			default:
 658				throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
 659			}
 660		}
 661
 662		static bool IsFloat (TypeSpec t)
 663		{
 664			return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
 665		}
 666
 667		//
 668		// Returns a stringified representation of the Operator
 669		//
 670		public static string OperName (Operator oper)
 671		{
 672			switch (oper) {
 673			case Operator.UnaryPlus:
 674				return "+";
 675			case Operator.UnaryNegation:
 676				return "-";
 677			case Operator.LogicalNot:
 678				return "!";
 679			case Operator.OnesComplement:
 680				return "~";
 681			case Operator.AddressOf:
 682				return "&";
 683			}
 684
 685			throw new NotImplementedException (oper.ToString ());
 686		}
 687
 688		public override SLE.Expression MakeExpression (BuilderContext ctx)
 689		{
 690			var expr = Expr.MakeExpression (ctx);
 691			bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
 692
 693			switch (Oper) {
 694			case Operator.UnaryNegation:
 695				return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
 696			case Operator.LogicalNot:
 697				return SLE.Expression.Not (expr);
 698#if NET_4_0 || MOBILE_DYNAMIC
 699			case Operator.OnesComplement:
 700				return SLE.Expression.OnesComplement (expr);
 701#endif
 702			default:
 703				throw new NotImplementedException (Oper.ToString ());
 704			}
 705		}
 706
 707		Expression ResolveAddressOf (ResolveContext ec)
 708		{
 709			if (!ec.IsUnsafe)
 710				UnsafeError (ec, loc);
 711
 712			Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
 713			if (Expr == null || Expr.eclass != ExprClass.Variable) {
 714				ec.Report.Error (211, loc, "Cannot take the address of the given expression");
 715				return null;
 716			}
 717
 718			if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
 719				return null;
 720			}
 721
 722			IVariableReference vr = Expr as IVariableReference;
 723			bool is_fixed;
 724			if (vr != null) {
 725				is_fixed = vr.IsFixed;
 726				vr.SetHasAddressTaken ();
 727
 728				if (vr.IsHoisted) {
 729					AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
 730				}
 731			} else {
 732				IFixedExpression fe = Expr as IFixedExpression;
 733				is_fixed = fe != null && fe.IsFixed;
 734			}
 735
 736			if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
 737				ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
 738			}
 739
 740			type = PointerContainer.MakeType (ec.Module, Expr.Type);
 741			eclass = ExprClass.Value;
 742			return this;
 743		}
 744
 745		Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
 746		{
 747			expr = DoNumericPromotion (rc, Oper, expr);
 748			TypeSpec expr_type = expr.Type;
 749			foreach (TypeSpec t in predefined) {
 750				if (t == expr_type)
 751					return expr;
 752			}
 753			return null;
 754		}
 755
 756		//
 757		// Perform user-operator overload resolution
 758		//
 759		protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
 760		{
 761			CSharp.Operator.OpType op_type;
 762			switch (Oper) {
 763			case Operator.LogicalNot:
 764				op_type = CSharp.Operator.OpType.LogicalNot; break;
 765			case Operator.OnesComplement:
 766				op_type = CSharp.Operator.OpType.OnesComplement; break;
 767			case Operator.UnaryNegation:
 768				op_type = CSharp.Operator.OpType.UnaryNegation; break;
 769			case Operator.UnaryPlus:
 770				op_type = CSharp.Operator.OpType.UnaryPlus; break;
 771			default:
 772				throw new InternalErrorException (Oper.ToString ());
 773			}
 774
 775			var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
 776			if (methods == null)
 777				return null;
 778
 779			Arguments args = new Arguments (1);
 780			args.Add (new Argument (expr));
 781
 782			var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
 783			var oper = res.ResolveOperator (ec, ref args);
 784
 785			if (oper == null)
 786				return null;
 787
 788			Expr = args [0].Expr;
 789			return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
 790		}
 791
 792		//
 793		// Unary user type overload resolution
 794		//
 795		Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
 796		{
 797			Expression best_expr = ResolveUserOperator (ec, expr);
 798			if (best_expr != null)
 799				return best_expr;
 800
 801			foreach (TypeSpec t in predefined) {
 802				Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
 803				if (oper_expr == null)
 804					continue;
 805
 806				if (oper_expr == ErrorExpression.Instance)
 807					return oper_expr;
 808
 809				//
 810				// decimal type is predefined but has user-operators
 811				//
 812				if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
 813					oper_expr = ResolveUserType (ec, oper_expr, predefined);
 814				else
 815					oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
 816
 817				if (oper_expr == null)
 818					continue;
 819
 820				if (best_expr == null) {
 821					best_expr = oper_expr;
 822					continue;
 823				}
 824
 825				int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
 826				if (result == 0) {
 827					if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
 828						Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
 829					} else {
 830						Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
 831					}
 832
 833					break;
 834				}
 835
 836				if (result == 2)
 837					best_expr = oper_expr;
 838			}
 839			
 840			if (best_expr == null)
 841				return null;
 842			
 843			//
 844			// HACK: Decimal user-operator is included in standard operators
 845			//
 846			if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
 847				return best_expr;
 848
 849			Expr = best_expr;
 850			type = best_expr.Type;
 851			return this;			
 852		}
 853
 854		protected override void CloneTo (CloneContext clonectx, Expression t)
 855		{
 856			Unary target = (Unary) t;
 857
 858			target.Expr = Expr.Clone (clonectx);
 859		}
 860		
 861		public override object Accept (StructuralVisitor visitor)
 862		{
 863			return visitor.Visit (this);
 864		}
 865
 866	}
 867
 868	//
 869	// Unary operators are turned into Indirection expressions
 870	// after semantic analysis (this is so we can take the address
 871	// of an indirection).
 872	//
 873	public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
 874		Expression expr;
 875		LocalTemporary temporary;
 876		bool prepared;
 877		
 878		public Indirection (Expression expr, Location l)
 879		{
 880			this.expr = expr;
 881			loc = l;
 882		}
 883
 884		public Expression Expr {
 885			get {
 886				return expr;
 887			}
 888		}
 889
 890		public bool IsFixed {
 891			get { return true; }
 892		}
 893
 894		public override Location StartLocation {
 895			get {
 896				return expr.StartLocation;
 897			}
 898		}
 899
 900		protected override void CloneTo (CloneContext clonectx, Expression t)
 901		{
 902			Indirection target = (Indirection) t;
 903			target.expr = expr.Clone (clonectx);
 904		}
 905
 906		public override bool ContainsEmitWithAwait ()
 907		{
 908			throw new NotImplementedException ();
 909		}
 910
 911		public override Expression CreateExpressionTree (ResolveContext ec)
 912		{
 913			Error_PointerInsideExpressionTree (ec);
 914			return null;
 915		}
 916		
 917		public override void Emit (EmitContext ec)
 918		{
 919			if (!prepared)
 920				expr.Emit (ec);
 921			
 922			ec.EmitLoadFromPtr (Type);
 923		}
 924
 925		public void Emit (EmitContext ec, bool leave_copy)
 926		{
 927			Emit (ec);
 928			if (leave_copy) {
 929				ec.Emit (OpCodes.Dup);
 930				temporary = new LocalTemporary (expr.Type);
 931				temporary.Store (ec);
 932			}
 933		}
 934		
 935		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
 936		{
 937			prepared = isCompound;
 938			
 939			expr.Emit (ec);
 940
 941			if (isCompound)
 942				ec.Emit (OpCodes.Dup);
 943			
 944			source.Emit (ec);
 945			if (leave_copy) {
 946				ec.Emit (OpCodes.Dup);
 947				temporary = new LocalTemporary (source.Type);
 948				temporary.Store (ec);
 949			}
 950			
 951			ec.EmitStoreFromPtr (type);
 952			
 953			if (temporary != null) {
 954				temporary.Emit (ec);
 955				temporary.Release (ec);
 956			}
 957		}
 958		
 959		public void AddressOf (EmitContext ec, AddressOp Mode)
 960		{
 961			expr.Emit (ec);
 962		}
 963
 964		public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
 965		{
 966			return DoResolve (ec);
 967		}
 968
 969		protected override Expression DoResolve (ResolveContext ec)
 970		{
 971			expr = expr.Resolve (ec);
 972			if (expr == null)
 973				return null;
 974
 975			if (!ec.IsUnsafe)
 976				UnsafeError (ec, loc);
 977
 978			var pc = expr.Type as PointerContainer;
 979
 980			if (pc == null) {
 981				ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
 982				return null;
 983			}
 984
 985			type = pc.Element;
 986
 987			if (type.Kind == MemberKind.Void) {
 988				Error_VoidPointerOperation (ec);
 989				return null;
 990			}
 991
 992			eclass = ExprClass.Variable;
 993			return this;
 994		}
 995
 996		public override object Accept (StructuralVisitor visitor)
 997		{
 998			return visitor.Visit (this);
 999		}
1000	}
1001	
1002	/// <summary>
1003	///   Unary Mutator expressions (pre and post ++ and --)
1004	/// </summary>
1005	///
1006	/// <remarks>
1007	///   UnaryMutator implements ++ and -- expressions.   It derives from
1008	///   ExpressionStatement becuase the pre/post increment/decrement
1009	///   operators can be used in a statement context.
1010	///
1011	/// FIXME: Idea, we could split this up in two classes, one simpler
1012	/// for the common case, and one with the extra fields for more complex
1013	/// classes (indexers require temporary access;  overloaded require method)
1014	///
1015	/// </remarks>
1016	public class UnaryMutator : ExpressionStatement
1017	{
1018		class DynamicPostMutator : Expression, IAssignMethod
1019		{
1020			LocalTemporary temp;
1021			Expression expr;
1022
1023			public DynamicPostMutator (Expression expr)
1024			{
1025				this.expr = expr;
1026				this.type = expr.Type;
1027				this.loc = expr.Location;
1028			}
1029
1030			public override Expression CreateExpressionTree (ResolveContext ec)
1031			{
1032				throw new NotImplementedException ("ET");
1033			}
1034
1035			protected override Expression DoResolve (ResolveContext rc)
1036			{
1037				eclass = expr.eclass;
1038				return this;
1039			}
1040
1041			public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1042			{
1043				expr.DoResolveLValue (ec, right_side);
1044				return DoResolve (ec);
1045			}
1046
1047			public override void Emit (EmitContext ec)
1048			{
1049				temp.Emit (ec);
1050			}
1051
1052			public void Emit (EmitContext ec, bool leave_copy)
1053			{
1054				throw new NotImplementedException ();
1055			}
1056
1057			//
1058			// Emits target assignment using unmodified source value
1059			//
1060			public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1061			{
1062				//
1063				// Allocate temporary variable to keep original value before it's modified
1064				//
1065				temp = new LocalTemporary (type);
1066				expr.Emit (ec);
1067				temp.Store (ec);
1068
1069				((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1070
1071				if (leave_copy)
1072					Emit (ec);
1073
1074				temp.Release (ec);
1075				temp = null;
1076			}
1077		}
1078
1079		[Flags]
1080		public enum Mode : byte {
1081			IsIncrement    = 0,
1082			IsDecrement    = 1,
1083			IsPre          = 0,
1084			IsPost         = 2,
1085			
1086			PreIncrement   = 0,
1087			PreDecrement   = IsDecrement,
1088			PostIncrement  = IsPost,
1089			PostDecrement  = IsPost | IsDecrement
1090		}
1091
1092		Mode mode;
1093		bool is_expr, recurse;
1094
1095		protected Expression expr;
1096
1097		// Holds the real operation
1098		Expression operation;
1099		
1100		public UnaryMutator (Mode m, Expression e, Location loc)
1101		{
1102			mode = m;
1103			this.loc = loc;
1104			expr = e;
1105		}
1106
1107		public Mode UnaryMutatorMode {
1108			get {
1109				return mode;
1110			}
1111		}
1112		
1113		public Expression Expr {
1114			get {
1115				return expr;
1116			}
1117		}
1118
1119		public override Location StartLocation {
1120			get {
1121				return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1122			}
1123		}
1124
1125		public override bool ContainsEmitWithAwait ()
1126		{
1127			return expr.ContainsEmitWithAwait ();
1128		}
1129
1130		public override Expression CreateExpressionTree (ResolveContext ec)
1131		{
1132			return new SimpleAssign (this, this).CreateExpressionTree (ec);
1133		}
1134
1135		public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1136		{
1137			//
1138			// Predefined ++ and -- operators exist for the following types: 
1139			// sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1140			//
1141			return new TypeSpec[] {
1142				types.Int,
1143				types.Long,
1144
1145				types.SByte,
1146				types.Byte,
1147				types.Short,
1148				types.UInt,
1149				types.ULong,
1150				types.Char,
1151				types.Float,
1152				types.Double,
1153				types.Decimal
1154			};
1155		}
1156
1157		protected override Expression DoResolve (ResolveContext ec)
1158		{
1159			expr = expr.Resolve (ec);
1160			
1161			if (expr == null || expr.Type == InternalType.ErrorType)
1162				return null;
1163
1164			if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1165				//
1166				// Handle postfix unary operators using local
1167				// temporary variable
1168				//
1169				if ((mode & Mode.IsPost) != 0)
1170					expr = new DynamicPostMutator (expr);
1171
1172				Arguments args = new Arguments (1);
1173				args.Add (new Argument (expr));
1174				return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1175			}
1176
1177			if (expr.Type.IsNullableType)
1178				return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1179
1180			return DoResolveOperation (ec);
1181		}
1182
1183		protected Expression DoResolveOperation (ResolveContext ec)
1184		{
1185			eclass = ExprClass.Value;
1186			type = expr.Type;
1187
1188			if (expr is RuntimeValueExpression) {
1189				operation = expr;
1190			} else {
1191				// Use itself at the top of the stack
1192				operation = new EmptyExpression (type);
1193			}
1194
1195			//
1196			// The operand of the prefix/postfix increment decrement operators
1197			// should be an expression that is classified as a variable,
1198			// a property access or an indexer access
1199			//
1200			// TODO: Move to parser, expr is ATypeNameExpression
1201			if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1202				expr = expr.ResolveLValue (ec, expr);
1203			} else {
1204				ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1205			}
1206
1207			//
1208			// Step 1: Try to find a user operator, it has priority over predefined ones
1209			//
1210			var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1211			var methods = MemberCache.GetUserOperator (type, user_op, false);
1212
1213			if (methods != null) {
1214				Arguments args = new Arguments (1);
1215				args.Add (new Argument (expr));
1216
1217				var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1218				var method = res.ResolveOperator (ec, ref args);
1219				if (method == null)
1220					return null;
1221
1222				args[0].Expr = operation;
1223				operation = new UserOperatorCall (method, args, null, loc);
1224				operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1225				return this;
1226			}
1227
1228			//
1229			// Step 2: Try predefined types
1230			//
1231
1232			Expression source = null;
1233			bool primitive_type;
1234
1235			//
1236			// Predefined without user conversion first for speed-up
1237			//
1238			// Predefined ++ and -- operators exist for the following types: 
1239			// sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1240			//
1241			switch (type.BuiltinType) {
1242			case BuiltinTypeSpec.Type.Byte:
1243			case BuiltinTypeSpec.Type.SByte:
1244			case BuiltinTypeSpec.Type.Short:
1245			case BuiltinTypeSpec.Type.UShort:
1246			case BuiltinTypeSpec.Type.Int:
1247			case BuiltinTypeSpec.Type.UInt:
1248			case BuiltinTypeSpec.Type.Long:
1249			case BuiltinTypeSpec.Type.ULong:
1250			case BuiltinTypeSpec.Type.Char:
1251			case BuiltinTypeSpec.Type.Float:
1252			case BuiltinTypeSpec.Type.Double:
1253			case BuiltinTypeSpec.Type.Decimal:
1254				source = operation;
1255				primitive_type = true;
1256				break;
1257			default:
1258				primitive_type = false;
1259
1260				// ++/-- on pointer variables of all types except void*
1261				if (type.IsPointer) {
1262					if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1263						Error_VoidPointerOperation (ec);
1264						return null;
1265					}
1266
1267					source = operation;
1268				} else {
1269					Expression best_source = null;
1270					foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1271						source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1272
1273						// LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1274						if (source == null)
1275							continue;
1276
1277						if (best_source == null) {
1278							best_source = source;
1279							continue;
1280						}
1281
1282						var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1283						if (better == 1)
1284							continue;
1285
1286						if (better == 2) {
1287							best_source = source;
1288							continue;
1289						}
1290
1291						Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1292						break;
1293					}
1294
1295					source = best_source;
1296				}
1297
1298				// ++/-- on enum types
1299				if (source == null && type.IsEnum)
1300					source = operation;
1301
1302				if (source == null) {
1303					expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1304					return null;
1305				}
1306
1307				break;
1308			}
1309
1310			var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1311			var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1312			operation = new Binary (op, source, one);
1313			operation = operation.Resolve (ec);
1314			if (operation == null)
1315				throw new NotImplementedException ("should not be reached");
1316
1317			if (operation.Type != type) {
1318				if (primitive_type)
1319					operation = Convert.ExplicitNumericConversion (ec, operation, type);
1320				else
1321					operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1322			}
1323
1324			return this;
1325		}
1326
1327		void EmitCode (EmitContext ec, bool is_expr)
1328		{
1329			recurse = true;
1330			this.is_expr = is_expr;
1331			((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1332		}
1333
1334		public override void Emit (EmitContext ec)
1335		{
1336			//
1337			// We use recurse to allow ourselfs to be the source
1338			// of an assignment. This little hack prevents us from
1339			// having to allocate another expression
1340			//
1341			if (recurse) {
1342				((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1343
1344				EmitOperation (ec);
1345
1346				recurse = false;
1347				return;
1348			}
1349
1350			EmitCode (ec, true);
1351		}
1352
1353		protected virtual void EmitOperation (EmitContext ec)
1354		{
1355			operation.Emit (ec);
1356		}
1357
1358		public override void EmitStatement (EmitContext ec)
1359		{
1360			EmitCode (ec, false);
1361		}
1362
1363		public override void FlowAnalysis (FlowAnalysisContext fc)
1364		{
1365			expr.FlowAnalysis (fc);
1366		}
1367
1368		//
1369		// Converts operator to System.Linq.Expressions.ExpressionType enum name
1370		//
1371		string GetOperatorExpressionTypeName ()
1372		{
1373			return IsDecrement ? "Decrement" : "Increment";
1374		}
1375
1376		bool IsDecrement {
1377			get { return (mode & Mode.IsDecrement) != 0; }
1378		}
1379
1380
1381#if NET_4_0 || MOBILE_DYNAMIC
1382		public override SLE.Expression MakeExpression (BuilderContext ctx)
1383		{
1384			var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1385			var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1386			return SLE.Expression.Assign (target, source);
1387		}
1388#endif
1389
1390		public static string OperName (Mode oper)
1391		{
1392			return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1393		}
1394
1395		protected override void CloneTo (CloneContext clonectx, Expression t)
1396		{
1397			UnaryMutator target = (UnaryMutator) t;
1398
1399			target.expr = expr.Clone (clonectx);
1400		}
1401
1402		public override object Accept (StructuralVisitor visitor)
1403		{
1404			return visitor.Visit (this);
1405		}
1406
1407	}
1408
1409	//
1410	// Base class for the `is' and `as' operators
1411	//
1412	public abstract class Probe : Expression
1413	{
1414		public Expression ProbeType;
1415		protected Expression expr;
1416		protected TypeSpec probe_type_expr;
1417		
1418		protected Probe (Expression expr, Expression probe_type, Location l)
1419		{
1420			ProbeType = probe_type;
1421			loc = l;
1422			this.expr = expr;
1423		}
1424
1425		public Expression Expr {
1426			get {
1427				return expr;
1428			}
1429		}
1430
1431		public override bool ContainsEmitWithAwait ()
1432		{
1433			return expr.ContainsEmitWithAwait ();
1434		}
1435
1436		protected Expression ResolveCommon (ResolveContext rc)
1437		{
1438			expr = expr.Resolve (rc);
1439			if (expr == null)
1440				return null;
1441
1442			ResolveProbeType (rc);
1443			if (probe_type_expr == null)
1444				return this;
1445
1446			if (probe_type_expr.IsStatic) {
1447				rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1448					probe_type_expr.GetSignatureForError ());
1449				return null;
1450			}
1451			
1452			if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1453				rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1454					OperatorName);
1455				return null;
1456			}
1457
1458			if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1459				rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1460					OperatorName);
1461				return null;
1462			}
1463
1464			return this;
1465		}
1466
1467		protected virtual void ResolveProbeType (ResolveContext rc)
1468		{
1469			probe_type_expr = ProbeType.ResolveAsType (rc);
1470		}
1471
1472		public override void EmitSideEffect (EmitContext ec)
1473		{
1474			expr.EmitSideEffect (ec);
1475		}
1476
1477		public override void FlowAnalysis (FlowAnalysisContext fc)
1478		{
1479			expr.FlowAnalysis (fc);
1480		}
1481
1482		protected abstract string OperatorName { get; }
1483
1484		protected override void CloneTo (CloneContext clonectx, Expression t)
1485		{
1486			Probe target = (Probe) t;
1487
1488			target.expr = expr.Clone (clonectx);
1489			target.ProbeType = ProbeType.Clone (clonectx);
1490		}
1491
1492	}
1493
1494	/// <summary>
1495	///   Implementation of the `is' operator.
1496	/// </summary>
1497	public class Is : Probe
1498	{
1499		Nullable.Unwrap expr_unwrap;
1500		MethodSpec number_mg;
1501		Arguments number_args;
1502
1503		public Is (Expression expr, Expression probe_type, Location l)
1504			: base (expr, probe_type, l)
1505		{
1506		}
1507
1508		protected override string OperatorName {
1509			get { return "is"; }
1510		}
1511
1512		public LocalVariable Variable { get; set; }
1513
1514		public override Expression CreateExpressionTree (ResolveContext ec)
1515		{
1516			if (Variable != null)
1517				throw new NotSupportedException ();
1518
1519			Arguments args = Arguments.CreateForExpressionTree (ec, null,
1520				expr.CreateExpressionTree (ec),
1521				new TypeOf (probe_type_expr, loc));
1522
1523			return CreateExpressionFactoryCall (ec, "TypeIs", args);
1524		}
1525
1526		Expression CreateConstantResult (ResolveContext rc, bool result)
1527		{
1528			if (result)
1529				rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1530					probe_type_expr.GetSignatureForError ());
1531			else
1532				rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1533					probe_type_expr.GetSignatureForError ());
1534
1535			var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1536			return expr.IsSideEffectFree ?
1537				ReducedExpression.Create (c, this) :
1538				new SideEffectConstant (c, this, loc);
1539		}
1540
1541		public override void Emit (EmitContext ec)
1542		{
1543			if (probe_type_expr == null) {
1544				EmitConstantMatch (ec);
1545				return;
1546			}
1547
1548			EmitLoad (ec);
1549
1550			if (expr_unwrap == null) {
1551				ec.EmitNull ();
1552				ec.Emit (OpCodes.Cgt_Un);
1553			}
1554		}
1555
1556		public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1557		{
1558			if (probe_type_expr == null) {
1559				EmitConstantMatch (ec);
1560			} else {
1561				EmitLoad (ec);
1562			}
1563
1564			ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1565		}
1566
1567		void EmitConstantMatch (EmitContext ec)
1568		{
1569			var no_match = ec.DefineLabel ();
1570			var end = ec.DefineLabel ();
1571
1572			if (expr_unwrap != null) {
1573				expr_unwrap.EmitCheck (ec);
1574
1575				if (ProbeType.IsNull) {
1576					ec.EmitInt (0);
1577					ec.Emit (OpCodes.Ceq);
1578					return;
1579				}
1580
1581				ec.Emit (OpCodes.Brfalse_S, no_match);
1582				expr_unwrap.Emit (ec);
1583				ProbeType.Emit (ec);
1584				ec.Emit (OpCodes.Ceq);
1585				ec.Emit (OpCodes.Br_S, end);
1586				ec.MarkLabel (no_match);
1587				ec.EmitInt (0);
1588				ec.MarkLabel (end);
1589				return;
1590			}
1591
1592			if (number_args != null && number_args.Count == 3) {
1593				var ce = new CallEmitter ();
1594				ce.Emit (ec, number_mg, number_args, loc);
1595				return;
1596			}
1597
1598			Expr.Emit (ec);
1599			ec.Emit (OpCodes.Isinst, ProbeType.Type);
1600			ec.Emit (OpCodes.Dup);
1601			ec.Emit (OpCodes.Brfalse, no_match);
1602
1603			if (number_mg != null) {
1604				var ce = new CallEmitter ();
1605				ce.Emit (ec, number_mg, number_args, loc);
1606			} else {
1607				ProbeType.Emit (ec);
1608				ec.Emit (OpCodes.Ceq);
1609			}
1610			ec.Emit (OpCodes.Br_S, end);
1611			ec.MarkLabel (no_match);
1612
1613			ec.Emit (OpCodes.Pop);
1614			ec.EmitInt (0);
1615			ec.MarkLabel (end);
1616		}
1617
1618		void EmitLoad (EmitContext ec)
1619		{
1620			Label no_value_label = new Label ();
1621
1622			if (expr_unwrap != null) {
1623				expr_unwrap.EmitCheck (ec);
1624
1625				if (Variable == null)
1626					return;
1627
1628				ec.Emit (OpCodes.Dup);
1629				no_value_label = ec.DefineLabel ();
1630				ec.Emit (OpCodes.Brfalse_S, no_value_label);
1631				expr_unwrap.Emit (ec);
1632			} else {
1633				expr.Emit (ec);
1634
1635				// Only to make verifier happy
1636				if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1637					ec.Emit (OpCodes.Box, expr.Type);
1638
1639				ec.Emit (OpCodes.Isinst, probe_type_expr);
1640			}
1641
1642			if (Variable != null) {
1643				bool value_on_stack;
1644				if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1645					ec.Emit (OpCodes.Dup);
1646					ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1647					value_on_stack = true;
1648				} else {
1649					value_on_stack = false;
1650				}
1651
1652				Variable.CreateBuilder (ec);
1653				Variable.EmitAssign (ec);
1654
1655				if (expr_unwrap != null) {
1656					ec.MarkLabel (no_value_label);
1657				} else if (!value_on_stack) {
1658					Variable.Emit (ec);
1659				}
1660			}
1661		}
1662
1663		protected override Expression DoResolve (ResolveContext rc)
1664		{
1665			if (ResolveCommon (rc) == null)
1666				return null;
1667
1668			type = rc.BuiltinTypes.Bool;
1669			eclass = ExprClass.Value;
1670
1671			if (probe_type_expr == null)
1672				return ResolveMatchingExpression (rc);
1673
1674			var res = ResolveResultExpression (rc);
1675			if (Variable != null) {
1676				if (res is Constant)
1677					throw new NotImplementedException ("constant in type pattern matching");
1678
1679				Variable.Type = probe_type_expr;
1680				var bc = rc as BlockContext;
1681				if (bc != null)
1682					Variable.PrepareAssignmentAnalysis (bc);
1683			}
1684
1685			return res;
1686		}
1687
1688		public override void FlowAnalysis (FlowAnalysisContext fc)
1689		{
1690			base.FlowAnalysis (fc);
1691
1692			if (Variable != null)
1693				fc.SetVariableAssigned (Variable.VariableInfo, true);
1694		}
1695
1696		protected override void ResolveProbeType (ResolveContext rc)
1697		{
1698			if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1699				ProbeType = ProbeType.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
1700				if (ProbeType == null)
1701					return;
1702
1703				if (ProbeType.eclass == ExprClass.Type) {
1704					probe_type_expr = ProbeType.Type;
1705				}
1706
1707				return;
1708			}
1709
1710			base.ResolveProbeType (rc);
1711		}
1712
1713		Expression ResolveMatchingExpression (ResolveContext rc)
1714		{
1715			var mc = ProbeType as Constant;
1716			if (mc != null) {
1717				if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1718					ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1719					return null;
1720				}
1721
1722				if (mc.IsNull)
1723					return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1724
1725				var c = Expr as Constant;
1726				if (c != null) {
1727					c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1728					if (c != null)
1729						return c;
1730				}
1731
1732				if (Expr.Type.IsNullableType) {
1733					expr_unwrap = new Nullable.Unwrap (Expr);
1734					expr_unwrap.Resolve (rc);
1735				} else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1736					var helper = rc.Module.CreatePatterMatchingHelper ();
1737					number_mg = helper.NumberMatcher.Spec;
1738
1739					//
1740					// There are actually 3 arguments but the first one is already on the stack
1741					//
1742					number_args = new Arguments (3);
1743					if (!ProbeType.Type.IsEnum)
1744						number_args.Add (new Argument (Expr));
1745
1746					number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1747					number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1748				}
1749
1750				return this;
1751			}
1752
1753			throw new NotImplementedException ();
1754		}
1755
1756		Expression ResolveResultExpression (ResolveContext ec)
1757		{
1758			TypeSpec d = expr.Type;
1759			bool d_is_nullable = false;
1760
1761			//
1762			// If E is a method group or the null literal, or if the type of E is a reference
1763			// type or a nullable type and the value of E is null, the result is false
1764			//
1765			if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1766				return CreateConstantResult (ec, false);
1767
1768			if (d.IsNullableType) {
1769				var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1770				if (!ut.IsGenericParameter) {
1771					d = ut;
1772					d_is_nullable = true;
1773				}
1774			}
1775				
1776			TypeSpec t = probe_type_expr;
1777			bool t_is_nullable = false;
1778			if (t.IsNullableType) {
1779				var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1780				if (!ut.IsGenericParameter) {
1781					t = ut;
1782					t_is_nullable = true;
1783				}
1784			}
1785
1786			if (t.IsStruct) {
1787				if (d == t) {
1788					//
1789					// D and T are the same value types but D can be null
1790					//
1791					if (d_is_nullable && !t_is_nullable) {
1792						expr_unwrap = Nullable.Unwrap.Create (expr, true);
1793						return this;
1794					}
1795					
1796					//
1797					// The result is true if D and T are the same value types
1798					//
1799					return CreateConstantResult (ec, true);
1800				}
1801
1802				var tp = d as TypeParameterSpec;
1803				if (tp != null)
1804					return ResolveGenericParameter (ec, t, tp);
1805
1806				//
1807				// An unboxing conversion exists
1808				//
1809				if (Convert.ExplicitReferenceConversionExists (d, t))
1810					return this;
1811
1812				//
1813				// open generic type
1814				//
1815				if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1816					return this;
1817			} else {
1818				var tps = t as TypeParameterSpec;
1819				if (tps != null)
1820					return ResolveGenericParameter (ec, d, tps);
1821
1822				if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1823					ec.Report.Warning (1981, 3, loc,
1824						"Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1825						OperatorName, t.GetSignatureForError ());
1826				}
1827
1828				if (TypeManager.IsGenericParameter (d))
1829					return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1830
1831				if (TypeSpec.IsValueType (d)) {
1832					if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1833						if (d_is_nullable && !t_is_nullable) {
1834							expr_unwrap = Nullable.Unwrap.Create (expr, false);
1835							return this;
1836						}
1837
1838						return CreateConstantResult (ec, true);
1839					}
1840				} else {
1841					if (Convert.ImplicitReferenceConversionExists (d, t)) {
1842						var c = expr as Constant;
1843						if (c != null)
1844							return CreateConstantResult (ec, !c.IsNull);
1845
1846						//
1847						// Do not optimize for imported type or dynamic type
1848						//
1849						if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1850							d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1851							return this;
1852						}
1853
1854						if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1855							return this;
1856						
1857						//
1858						// Turn is check into simple null check for implicitly convertible reference types
1859						//
1860						return ReducedExpression.Create (
1861							new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1862							this).Resolve (ec);
1863					}
1864
1865					if (Convert.ExplicitReferenceConversionExists (d, t))
1866						return this;
1867
1868					//
1869					// open generic type
1870					//
1871					if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1872						return this;
1873				}
1874			}
1875
1876			return CreateConstantResult (ec, false);
1877		}
1878
1879		Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1880		{
1881			if (t.IsReferenceType) {
1882				if (d.IsStruct)
1883					return CreateConstantR

Large files files are truncated, but you can click here to view the full file