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 (Location loc)
31 protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
33 if (ec.IsInProbingMode)
36 BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, TypeManager.void_type) {
37 CurrentAnonymousMethod = ec.CurrentAnonymousMethod
40 Expression args = Parameters.CreateExpressionTree (bc, loc);
41 Expression expr = Block.CreateExpressionTree (ec);
45 Arguments arguments = new Arguments (2);
46 arguments.Add (new Argument (expr));
47 arguments.Add (new Argument (args));
48 return CreateExpressionFactoryCall (ec, "Lambda",
49 new TypeArguments (new TypeExpression (delegate_type, loc)),
53 public override bool HasExplicitParameters {
55 return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
59 protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
61 if (!delegateType.IsDelegate)
64 AParametersCollection d_params = Delegate.GetParameters (ec.Compiler, delegateType);
66 if (HasExplicitParameters) {
67 if (!VerifyExplicitParameters (ec, delegateType, d_params))
74 // If L has an implicitly typed parameter list we make implicit parameters explicit
75 // Set each parameter of L is given the type of the corresponding parameter in D
77 if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
80 TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
81 for (int i = 0; i < d_params.Count; i++) {
82 // D has no ref or out parameters
83 if ((d_params.FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) != 0)
86 TypeSpec d_param = d_params.Types [i];
89 // When type inference context exists try to apply inferred type arguments
92 d_param = tic.InflateGenericArgument (d_param);
96 ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
97 ilp.SetParameterType (d_param);
98 ilp.Resolve (null, i);
101 Parameters.Types = ptypes;
105 protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
107 return new LambdaMethod (p, b, returnType, delegateType, loc);
110 protected override bool DoResolveParameters (ResolveContext rc)
113 // Only explicit parameters can be resolved at this point
115 if (HasExplicitParameters) {
116 return Parameters.Resolve (rc);
122 public override string GetSignatureForError ()
124 return "lambda expression";
128 class LambdaMethod : AnonymousMethodBody
130 public LambdaMethod (ParametersCompiled parameters,
131 ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
133 : base (parameters, block, return_type, delegate_type, loc)
139 public override string ContainerType {
141 return "lambda expression";
147 protected override void CloneTo (CloneContext clonectx, Expression target)
152 public override Expression CreateExpressionTree (ResolveContext ec)
154 BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
155 Expression args = parameters.CreateExpressionTree (bc, loc);
156 Expression expr = Block.CreateExpressionTree (ec);
160 Arguments arguments = new Arguments (2);
161 arguments.Add (new Argument (expr));
162 arguments.Add (new Argument (args));
163 return CreateExpressionFactoryCall (ec, "Lambda",
164 new TypeArguments (new TypeExpression (type, loc)),
170 // This is a return statement that is prepended lambda expression bodies that happen
171 // to be expressions. Depending on the return type of the delegate this will behave
172 // as either { expr (); return (); } or { return expr (); }
174 public class ContextualReturn : Return
176 ExpressionStatement statement;
178 public ContextualReturn (Expression expr)
179 : base (expr, expr.Location)
183 public override Expression CreateExpressionTree (ResolveContext ec)
185 return Expr.CreateExpressionTree (ec);
188 public override void Emit (EmitContext ec)
190 if (statement != null) {
191 statement.EmitStatement (ec);
192 ec.Emit (OpCodes.Ret);
199 protected override bool DoResolve (BlockContext ec)
202 // When delegate returns void, only expression statements can be used
204 if (ec.ReturnType == TypeManager.void_type) {
205 Expr = Expr.Resolve (ec);
209 statement = Expr as ExpressionStatement;
210 if (statement == null)
211 Expr.Error_InvalidExpressionStatement (ec);
216 return base.DoResolve (ec);