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
12 using System.Reflection.Emit;
14 namespace Mono.CSharp {
15 public class LambdaExpression : AnonymousMethodExpression
18 // The parameters can either be:
19 // A list of Parameters (explicitly typed parameters)
20 // An ImplicitLambdaParameter
22 public LambdaExpression (Location loc)
27 protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
29 if (ec.IsInProbingMode)
32 BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, TypeManager.void_type) {
33 CurrentAnonymousMethod = ec.CurrentAnonymousMethod
36 Expression args = Parameters.CreateExpressionTree (bc, loc);
37 Expression expr = Block.CreateExpressionTree (ec);
41 Arguments arguments = new Arguments (2);
42 arguments.Add (new Argument (expr));
43 arguments.Add (new Argument (args));
44 return CreateExpressionFactoryCall (ec, "Lambda",
45 new TypeArguments (new TypeExpression (delegate_type, loc)),
49 public override bool HasExplicitParameters {
51 return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
55 protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
57 if (!delegateType.IsDelegate)
60 AParametersCollection d_params = Delegate.GetParameters (ec.Compiler, delegateType);
62 if (HasExplicitParameters) {
63 if (!VerifyExplicitParameters (ec, delegateType, d_params))
70 // If L has an implicitly typed parameter list we make implicit parameters explicit
71 // Set each parameter of L is given the type of the corresponding parameter in D
73 if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
76 TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
77 for (int i = 0; i < d_params.Count; i++) {
78 // D has no ref or out parameters
79 if ((d_params.FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) != 0)
82 TypeSpec d_param = d_params.Types [i];
85 // When type inference context exists try to apply inferred type arguments
88 d_param = tic.InflateGenericArgument (d_param);
92 ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
93 ilp.SetParameterType (d_param);
94 ilp.Resolve (null, i);
97 Parameters.Types = ptypes;
101 protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
103 return new LambdaMethod (p, b, returnType, delegateType, loc);
106 protected override bool DoResolveParameters (ResolveContext rc)
109 // Only explicit parameters can be resolved at this point
111 if (HasExplicitParameters) {
112 return Parameters.Resolve (rc);
118 public override string GetSignatureForError ()
120 return "lambda expression";
124 class LambdaMethod : AnonymousMethodBody
126 public LambdaMethod (ParametersCompiled parameters,
127 ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
129 : base (parameters, block, return_type, delegate_type, loc)
135 public override string ContainerType {
137 return "lambda expression";
143 protected override void CloneTo (CloneContext clonectx, Expression target)
148 public override Expression CreateExpressionTree (ResolveContext ec)
150 BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
151 Expression args = parameters.CreateExpressionTree (bc, loc);
152 Expression expr = Block.CreateExpressionTree (ec);
156 Arguments arguments = new Arguments (2);
157 arguments.Add (new Argument (expr));
158 arguments.Add (new Argument (args));
159 return CreateExpressionFactoryCall (ec, "Lambda",
160 new TypeArguments (new TypeExpression (type, loc)),
166 // This is a return statement that is prepended lambda expression bodies that happen
167 // to be expressions. Depending on the return type of the delegate this will behave
168 // as either { expr (); return (); } or { return expr (); }
170 public class ContextualReturn : Return
172 ExpressionStatement statement;
174 public ContextualReturn (Expression expr)
175 : base (expr, expr.Location)
179 public override Expression CreateExpressionTree (ResolveContext ec)
181 return Expr.CreateExpressionTree (ec);
184 public override void Emit (EmitContext ec)
186 if (statement != null) {
187 statement.EmitStatement (ec);
188 ec.Emit (OpCodes.Ret);
195 protected override bool DoResolve (BlockContext ec)
198 // When delegate returns void, only expression statements can be used
200 if (ec.ReturnType == TypeManager.void_type) {
201 Expr = Expr.Resolve (ec);
205 statement = Expr as ExpressionStatement;
206 if (statement == null)
207 Expr.Error_InvalidExpressionStatement (ec);
212 return base.DoResolve (ec);