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 System.Reflection.Emit;
15 namespace Mono.CSharp {
16 public class LambdaExpression : AnonymousMethodExpression
19 // The parameters can either be:
20 // A list of Parameters (explicitly typed parameters)
21 // An ImplicitLambdaParameter
23 public LambdaExpression (Location loc)
28 protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
30 if (ec.IsInProbingMode)
33 BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, TypeManager.void_type) {
34 CurrentAnonymousMethod = ec.CurrentAnonymousMethod
37 Expression args = Parameters.CreateExpressionTree (bc, loc);
38 Expression expr = Block.CreateExpressionTree (ec);
42 Arguments arguments = new Arguments (2);
43 arguments.Add (new Argument (expr));
44 arguments.Add (new Argument (args));
45 return CreateExpressionFactoryCall (ec, "Lambda",
46 new TypeArguments (new TypeExpression (delegate_type, loc)),
50 public override bool HasExplicitParameters {
52 return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
56 protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
58 if (!delegateType.IsDelegate)
61 AParametersCollection d_params = Delegate.GetParameters (ec.Compiler, delegateType);
63 if (HasExplicitParameters) {
64 if (!VerifyExplicitParameters (ec, delegateType, d_params))
71 // If L has an implicitly typed parameter list we make implicit parameters explicit
72 // Set each parameter of L is given the type of the corresponding parameter in D
74 if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
77 TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
78 for (int i = 0; i < d_params.Count; i++) {
79 // D has no ref or out parameters
80 if ((d_params.FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) != 0)
83 TypeSpec d_param = d_params.Types [i];
86 // When type inference context exists try to apply inferred type arguments
89 d_param = tic.InflateGenericArgument (d_param);
93 ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
94 ilp.SetParameterType (d_param);
95 ilp.Resolve (null, i);
98 Parameters.Types = ptypes;
102 protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
104 return new LambdaMethod (p, b, returnType, delegateType, loc);
107 protected override bool DoResolveParameters (ResolveContext rc)
110 // Only explicit parameters can be resolved at this point
112 if (HasExplicitParameters) {
113 return Parameters.Resolve (rc);
119 public override string GetSignatureForError ()
121 return "lambda expression";
125 class LambdaMethod : AnonymousMethodBody
127 public LambdaMethod (ParametersCompiled parameters,
128 ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
130 : base (parameters, block, return_type, delegate_type, loc)
136 public override string ContainerType {
138 return "lambda expression";
144 protected override void CloneTo (CloneContext clonectx, Expression target)
149 public override Expression CreateExpressionTree (ResolveContext ec)
151 BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
152 Expression args = parameters.CreateExpressionTree (bc, loc);
153 Expression expr = Block.CreateExpressionTree (ec);
157 Arguments arguments = new Arguments (2);
158 arguments.Add (new Argument (expr));
159 arguments.Add (new Argument (args));
160 return CreateExpressionFactoryCall (ec, "Lambda",
161 new TypeArguments (new TypeExpression (type, loc)),
167 // This is a return statement that is prepended lambda expression bodies that happen
168 // to be expressions. Depending on the return type of the delegate this will behave
169 // as either { expr (); return (); } or { return expr (); }
171 public class ContextualReturn : Return
173 ExpressionStatement statement;
175 public ContextualReturn (Expression expr)
176 : base (expr, expr.Location)
180 public override Expression CreateExpressionTree (ResolveContext ec)
182 return Expr.CreateExpressionTree (ec);
185 public override void Emit (EmitContext ec)
187 if (statement != null) {
188 statement.EmitStatement (ec);
189 ec.Emit (OpCodes.Ret);
196 protected override bool DoResolve (BlockContext ec)
199 // When delegate returns void, only expression statements can be used
201 if (ec.ReturnType == TypeManager.void_type) {
202 Expr = Expr.Resolve (ec);
206 statement = Expr as ExpressionStatement;
207 if (statement == null)
208 Expr.Error_InvalidExpressionStatement (ec);
213 return base.DoResolve (ec);