context: //
  // lambda.cs: support for lambda expressions
  //
  // Authors: Miguel de Icaza (miguel@gnu.org)
  //          Marek Safar (marek.safar@gmail.com)
  //
  // Dual licensed under the terms of the MIT X11 or GNU GPL
  //
  // Copyright 2007-2008 Novell, Inc
  // Copyright 2011 Xamarin Inc
  //
  
  #if STATIC
  using IKVM.Reflection.Emit;
  #else
  using System.Reflection.Emit;
  #endif
  
  namespace ICSharpCode.NRefactory.MonoCSharp {
  	public class LambdaExpression : AnonymousMethodExpression
  	{
  		//
  		// The parameters can either be:
  		//    A list of Parameters (explicitly typed parameters)
  		//    An ImplicitLambdaParameter
  		//
  		public LambdaExpression (Location loc)
  			: base (loc)
  		{
  		}
  
  		protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
  		{
  			if (ec.IsInProbingMode)
  				return this;
  
  			BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, ec.BuiltinTypes.Void) {
  				CurrentAnonymousMethod = ec.CurrentAnonymousMethod
  			};
  
  			Expression args = Parameters.CreateExpressionTree (bc, loc);
  			Expression expr = Block.CreateExpressionTree (ec);
  			if (expr == null)
  				return null;
  
  			Arguments arguments = new Arguments (2);
  			arguments.Add (new Argument (expr));
  			arguments.Add (new Argument (args));
  			return CreateExpressionFactoryCall (ec, "Lambda",
  				new TypeArguments (new TypeExpression (delegate_type, loc)),
  				arguments);
  		}
  
  		public override bool HasExplicitParameters {
  			get {
  				return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
  			}
  		}
  
  		protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
  		{
  			if (!delegateType.IsDelegate)
  				return null;
  
  			AParametersCollection d_params = Delegate.GetParameters (delegateType);
  
  			if (HasExplicitParameters) {
  				if (!VerifyExplicitParameters (ec, tic, delegateType, d_params))
  					return null;
  
  				return Parameters;
  			}
  
  			//
  			// If L has an implicitly typed parameter list we make implicit parameters explicit
  			// Set each parameter of L is given the type of the corresponding parameter in D
  			//
  			if (!VerifyParameterCompatibility (ec, tic, delegateType, d_params, ec.IsInProbingMode))
  				return null;
  
  			TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
  			for (int i = 0; i < d_params.Count; i++) {
  				// D has no ref or out parameters
  				if ((d_params.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
  					return null;
  
  				TypeSpec d_param = d_params.Types [i];
  
  				//
  				// When type inference context exists try to apply inferred type arguments
  				//
  				if (tic != null) {
  					d_param = tic.InflateGenericArgument (ec, d_param);
  				}
  
  				ptypes [i] = d_param;
  				ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
  				ilp.SetParameterType (d_param);
  				ilp.Resolve (null, i);
  			}
  
  			Parameters.Types = ptypes;
  			return Parameters;
  		}
  
  		protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
  		{
  			return new LambdaMethod (p, b, returnType, delegateType, loc);
  		}
  
  		protected override bool DoResolveParameters (ResolveContext rc)
  		{
  			//
  			// Only explicit parameters can be resolved at this point
  			//
  			if (HasExplicitParameters) {
  				return Parameters.Resolve (rc);
  			}
  
  			return true;
  		}
  
  		public override string GetSignatureForError ()
  		{
  			return "lambda expression";
  		}
  		
  		public override object Accept (StructuralVisitor visitor)
  		{
  			return visitor.Visit (this);
  		}
  	}
  
  	class LambdaMethod : AnonymousMethodBody
  	{
  		public LambdaMethod (ParametersCompiled parameters,
  					ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
  					Location loc)
  			: base (parameters, block, return_type, delegate_type, loc)
  		{
  		}
  
  		#region Properties
  
  		public override string ContainerType {
  			get {
  				return "lambda expression";
  			}
  		}
  
  		#endregion
  
  		protected override void CloneTo (CloneContext clonectx, Expression target)
  		{
  			// TODO: nothing ??
  		}
  
  		public override Expression CreateExpressionTree (ResolveContext ec)
  		{
  			BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
  			Expression args = parameters.CreateExpressionTree (bc, loc);
  			Expression expr = Block.CreateExpressionTree (ec);
  			if (expr == null)
  				return null;
  
  			Arguments arguments = new Arguments (2);
  			arguments.Add (new Argument (expr));
  			arguments.Add (new Argument (args));
  			return CreateExpressionFactoryCall (ec, "Lambda",
  				new TypeArguments (new TypeExpression (type, loc)),
  				arguments);
  		}
  	}
  
  	//
  	// This is a return statement that is prepended lambda expression bodies that happen
  	// to be expressions.  Depending on the return type of the delegate this will behave
  	// as either { expr (); return (); } or { return expr (); }
  	//
  	public class ContextualReturn : Return
  	{
  		ExpressionStatement statement;
  
  		public ContextualReturn (Expression expr)
  			: base (expr, expr.StartLocation)
  		{
  		}
  
  		public override Expression CreateExpressionTree (ResolveContext ec)
  		{
  			return Expr.CreateExpressionTree (ec);
  		}
  
  		protected override void DoEmit (EmitContext ec)
  		{
  			if (statement != null) {
  				statement.EmitStatement (ec);
  				if (unwind_protect)
  					ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
  				else {
  					ec.Emit (OpCodes.Ret);
  				}
  				return;
  			}
  
  			base.DoEmit (ec);
  		}
  
  		protected override bool DoResolve (BlockContext ec)
  		{
  			//
  			// When delegate returns void, only expression statements can be used
  			//
  			if (ec.ReturnType.Kind == MemberKind.Void) {
  				Expr = Expr.Resolve (ec);
  				if (Expr == null)
  					return false;
  
  				statement = Expr as ExpressionStatement;
  				if (statement == null)
  					Expr.Error_InvalidExpressionStatement (ec);
  
  				return true;
  			}
  
  
gt: 			return base.DoResolve (ec);