2 // lambda.cs: support for lambda expressions
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@gmail.com)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2007-2008 Novell, Inc
13 using IKVM.Reflection.Emit;
15 using System.Reflection.Emit;
18 namespace Mono.CSharp {
19 public class LambdaExpression : AnonymousMethodExpression
22 // The parameters can either be:
23 // A list of Parameters (explicitly typed parameters)
24 // An ImplicitLambdaParameter
26 public LambdaExpression (bool isAsync, Location loc)
31 public LambdaExpression (Location loc)
36 protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
38 if (ec.IsInProbingMode)
41 BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, ec.BuiltinTypes.Void) {
42 CurrentAnonymousMethod = ec.CurrentAnonymousMethod
45 Expression args = Parameters.CreateExpressionTree (bc, loc);
46 Expression expr = Block.CreateExpressionTree (ec);
50 Arguments arguments = new Arguments (2);
51 arguments.Add (new Argument (expr));
52 arguments.Add (new Argument (args));
53 return CreateExpressionFactoryCall (ec, "Lambda",
54 new TypeArguments (new TypeExpression (delegate_type, loc)),
58 public override bool HasExplicitParameters {
60 return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
64 protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
66 if (!delegateType.IsDelegate)
69 AParametersCollection d_params = Delegate.GetParameters (delegateType);
71 if (HasExplicitParameters) {
72 if (!VerifyExplicitParameters (ec, delegateType, d_params))
79 // If L has an implicitly typed parameter list we make implicit parameters explicit
80 // Set each parameter of L is given the type of the corresponding parameter in D
82 if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
85 TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
86 for (int i = 0; i < d_params.Count; i++) {
87 // D has no ref or out parameters
88 if ((d_params.FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) != 0)
91 TypeSpec d_param = d_params.Types [i];
94 // When type inference context exists try to apply inferred type arguments
97 d_param = tic.InflateGenericArgument (ec, d_param);
100 ptypes [i] = d_param;
101 ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
102 ilp.SetParameterType (d_param);
103 ilp.Resolve (null, i);
106 Parameters.Types = ptypes;
110 protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
112 return new LambdaMethod (p, b, returnType, delegateType, loc);
115 protected override bool DoResolveParameters (ResolveContext rc)
118 // Only explicit parameters can be resolved at this point
120 if (HasExplicitParameters) {
121 return Parameters.Resolve (rc);
127 public override string GetSignatureForError ()
129 return "lambda expression";
133 class LambdaMethod : AnonymousMethodBody
135 public LambdaMethod (ParametersCompiled parameters,
136 ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
138 : base (parameters, block, return_type, delegate_type, loc)
144 public override string ContainerType {
146 return "lambda expression";
152 protected override void CloneTo (CloneContext clonectx, Expression target)
157 public override Expression CreateExpressionTree (ResolveContext ec)
159 BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
160 Expression args = parameters.CreateExpressionTree (bc, loc);
161 Expression expr = Block.CreateExpressionTree (ec);
165 Arguments arguments = new Arguments (2);
166 arguments.Add (new Argument (expr));
167 arguments.Add (new Argument (args));
168 return CreateExpressionFactoryCall (ec, "Lambda",
169 new TypeArguments (new TypeExpression (type, loc)),
175 // This is a return statement that is prepended lambda expression bodies that happen
176 // to be expressions. Depending on the return type of the delegate this will behave
177 // as either { expr (); return (); } or { return expr (); }
179 public class ContextualReturn : Return
181 ExpressionStatement statement;
183 public ContextualReturn (Expression expr)
184 : base (expr, expr.Location)
188 public override Expression CreateExpressionTree (ResolveContext ec)
190 return Expr.CreateExpressionTree (ec);
193 public override void Emit (EmitContext ec)
195 if (statement != null) {
196 statement.EmitStatement (ec);
198 ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
200 ec.Emit (OpCodes.Ret);
208 protected override bool DoResolve (BlockContext ec)
211 // When delegate returns void, only expression statements can be used
213 if (ec.ReturnType.Kind == MemberKind.Void) {
214 Expr = Expr.Resolve (ec);
218 statement = Expr as ExpressionStatement;
219 if (statement == null)
220 Expr.Error_InvalidExpressionStatement (ec);
225 return base.DoResolve (ec);