context: //
  // assign.cs: Assignments.
  //
  // Author:
  //   Miguel de Icaza (miguel@ximian.com)
  //   Martin Baulig (martin@ximian.com)
  //   Marek Safar (marek.safar@gmail.com)	
  //
  // Dual licensed under the terms of the MIT X11 or GNU GPL
  //
  // Copyright 2001, 2002, 2003 Ximian, Inc.
  // Copyright 2004-2008 Novell, Inc
  // Copyright 2011 Xamarin Inc
  //
  using System;
  
  #if STATIC
  using IKVM.Reflection.Emit;
  #else
  using System.Reflection.Emit;
  #endif
  
  namespace Mono.CSharp {
  
  	/// <summary>
  	///   This interface is implemented by expressions that can be assigned to.
  	/// </summary>
  	/// <remarks>
  	///   This interface is implemented by Expressions whose values can not
  	///   store the result on the top of the stack.
  	///
  	///   Expressions implementing this (Properties, Indexers and Arrays) would
  	///   perform an assignment of the Expression "source" into its final
  	///   location.
  	///
  	///   No values on the top of the stack are expected to be left by
  	///   invoking this method.
  	/// </remarks>
  	public interface IAssignMethod {
  		//
  		// This is an extra version of Emit. If leave_copy is `true'
  		// A copy of the expression will be left on the stack at the
  		// end of the code generated for EmitAssign
  		//
  		void Emit (EmitContext ec, bool leave_copy);
  
  		//
  		// This method does the assignment
  		// `source' will be stored into the location specified by `this'
  		// if `leave_copy' is true, a copy of `source' will be left on the stack
  		// if `prepare_for_load' is true, when `source' is emitted, there will
  		// be data on the stack that it can use to compuatate its value. This is
  		// for expressions like a [f ()] ++, where you can't call `f ()' twice.
  		//
  		void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
  
  		/*
  		For simple assignments, this interface is very simple, EmitAssign is called with source
  		as the source expression and leave_copy and prepare_for_load false.
  
  		For compound assignments it gets complicated.
  
  		EmitAssign will be called as before, however, prepare_for_load will be
  		true. The @source expression will contain an expression
  		which calls Emit. So, the calls look like:
  
  		this.EmitAssign (ec, source, false, true) ->
  			source.Emit (ec); ->
  				[...] ->
  					this.Emit (ec, false); ->
  					end this.Emit (ec, false); ->
  				end [...]
  			end source.Emit (ec);
  		end this.EmitAssign (ec, source, false, true)
  
  
  		When prepare_for_load is true, EmitAssign emits a `token' on the stack that
  		Emit will use for its state.
  
  		Let's take FieldExpr as an example. assume we are emitting f ().y += 1;
  
  		Here is the call tree again. This time, each call is annotated with the IL
  		it produces:
  
  		this.EmitAssign (ec, source, false, true)
  			call f
  			dup
  
  			Binary.Emit ()
  				this.Emit (ec, false);
  				ldfld y
  				end this.Emit (ec, false);
  
  				IntConstant.Emit ()
  				ldc.i4.1
  				end IntConstant.Emit
  
  				add
  			end Binary.Emit ()
  
  			stfld
  		end this.EmitAssign (ec, source, false, true)
  
  		Observe two things:
  			1) EmitAssign left a token on the stack. It was the result of f ().
  			2) This token was used by Emit
  
  		leave_copy (in both EmitAssign and Emit) tells the compiler to leave a copy
  		of the expression at that point in evaluation. This is used for pre/post inc/dec
  		and for a = x += y. Let's do the above example with leave_copy true in EmitAssign
  
  		this.EmitAssign (ec, source, true, true)
  			call f
  			dup
  
  			Binary.Emit ()
  				this.Emit (ec, false);
  				ldfld y
  				end this.Emit (ec, false);
  
  				IntConstant.Emit ()
  				ldc.i4.1
  				end IntConstant.Emit
  
  				add
  			end Binary.Emit ()
  
  			dup
  			stloc temp
  			stfld
  			ldloc temp
  		end this.EmitAssign (ec, source, true, true)
  
  		And with it true in Emit
  
  		this.EmitAssign (ec, source, false, true)
  			call f
  			dup
  
  			Binary.Emit ()
  				this.Emit (ec, true);
  				ldfld y
  				dup
  				stloc temp
  				end this.Emit (ec, true);
  
  				IntConstant.Emit ()
  				ldc.i4.1
  				end IntConstant.Emit
  
  				add
  			end Binary.Emit ()
  
  			stfld
  			ldloc temp
  		end this.EmitAssign (ec, source, false, true)
  
  		Note that these two examples are what happens for ++x and x++, respectively.
  		*/
  	}
  
  	/// <summary>
  	///   An Expression to hold a temporary value.
  	/// </summary>
  	/// <remarks>
  	///   The LocalTemporary class is used to hold temporary values of a given
  	///   type to "simulate" the expression semantics. The local variable is
  	///   never captured.
  	///
  	///   The local temporary is used to alter the normal flow of code generation
  	///   basically it creates a local variable, and its emit instruction generates
  	///   code to access this value, return its address or save its value.
  	///
  	///   If `is_address' is true, then the value that we store is the address to the
  	///   real value, and not the value itself.
  	///
  	///   This is needed for a value type, because otherwise you just end up making a
  	///   copy of the value on the stack and modifying it. You really need a pointer
  	///   to the origional value so that you can modify it in that location. This
  	///   Does not happen with a class because a class is a pointer -- so you always
  	///   get the indirection.
  	///
  	/// </remarks>
  	public class LocalTemporary : Expression, IMemoryLocation, IAssignMethod {
  		LocalBuilder builder;
  
  		public LocalTemporary (TypeSpec t)
  		{
  			type = t;
  			eclass = ExprClass.Value;
  		}
  
  		public LocalTemporary (LocalBuilder b, TypeSpec t)
  			: this (t)
  		{
  			builder = b;
  		}
  
  		public void Release (EmitContext ec)
  		{
  			ec.FreeTemporaryLocal (builder, type);
  			builder = null;
  		}
  
  		public override bool ContainsEmitWithAwait ()
  		{
  			return false;
  		}
  
  		public override Expression CreateExpressionTree (ResolveContext ec)
  		{
  			Arguments args = new Arguments (1);
  			args.Add (new Argument (this));
  			return CreateExpressionFactoryCall (ec, "Constant", args);
  		}
  
  		protected override Expression DoResolve (ResolveContext ec)
  		{
  			return this;
  		}
  
  		public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  		{
  			return this;
  		}
  
  		public override void Emit (EmitContext ec)
  		{
  			if (builder == null)
  				throw new InternalErrorException ("Emit without Store, or after Release");
  
  			ec.Emit (OpCodes.Ldloc, builder);
  		}
  
  		#region IAssignMethod Members
  
  		public void Emit (EmitContext ec, bool leave_copy)
  		{
  			Emit (ec);
  
  			if (leave_copy)
  				Emit (ec);
  		}
  
  		public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  		{
  			if (isCompound)
  				throw new NotImplementedException ();
  
  			source.Emit (ec);
  
  			Store (ec);
  
  			if (leave_copy)
  				Emit (ec);
  		}
  
  		#endregion
  
  		public LocalBuilder Builder {
  			get { return builder; }
  		}
  
  		public void Store (EmitContext ec)
  		{
  			if (builder == null)
  				builder = ec.GetTemporaryLocal (type);
  
  			ec.Emit (OpCodes.Stloc, builder);
  		}
  
  		public void AddressOf (EmitContext ec, AddressOp mode)
  		{
  			if (builder == null)
  				builder = ec.GetTemporaryLocal (type);
  
  			if (builder.LocalType.IsByRef) {
  				//
  				// if is_address, than this is just the address anyways,
  				// so we just return this.
  				//
  				ec.Emit (OpCodes.Ldloc, builder);
  			} else {
  				ec.Emit (OpCodes.Ldloca, builder);
  			}
  		}
  	}
  
  	/// <summary>
  	///   The Assign node takes care of assigning the value of source into
  	///   the expression represented by target.
  	/// </summary>
  	public abstract class Assign : ExpressionStatement {
  		protected Expression target, source;
  
  		protected Assign (Expression target, Expression source, Location loc)
  		{
  			this.target = target;
  			this.source = source;
  			this.loc = loc;
  		}
  		
  		public Expression Target {
  			get { return target; }
  		}
  
  		public Expression Source {
  			get {
  				return source;
  			}
  		}
  
  		public override Location StartLocation {
  			get {
  				return target.StartLocation;
  			}
  		}
  
  		public override bool ContainsEmitWithAwait ()
  		{
  			return target.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ();
  		}
  
  		public override Expression CreateExpressionTree (ResolveContext ec)
  		{
  			ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
  			return null;
  		}
  
  		protected override Expression DoResolve (ResolveContext ec)
  		{
  			bool ok = true;
  			source = source.Resolve (ec);
  						
  			if (source == null) {
  				ok = false;
  				source = ErrorExpression.Instance;
  			}
  
  			target = target.ResolveLValue (ec, source);
  
  			if (target == null || !ok)
  				return null;
  
  			TypeSpec target_type = target.Type;
  			TypeSpec source_type = source.Type;
  
  			eclass = ExprClass.Value;
  			type = target_type;
  
  			if (!(target is IAssignMethod)) {
  				target.Error_ValueAssignment (ec, source);
  				return null;
  			}
  
  			if (target_type != source_type) {
  				Expression resolved = ResolveConversions (ec);
  
  				if (resolved != this)
  					return resolved;
  			}
  
  			return this;
  		}
  
  #if NET_4_0 || MOBILE_DYNAMIC
  		public override System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx)
  		{
  			var tassign = target as IDynamicAssign;
  
gt: 			if (tassign == null)