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;
14 using System.Reflection.Emit;
16 namespace Mono.CSharp {
17 public class LambdaExpression : AnonymousMethodExpression
20 // The parameters can either be:
21 // A list of Parameters (explicitly typed parameters)
22 // An ImplicitLambdaParameter
24 public LambdaExpression (Location loc)
29 protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
31 if (ec.IsInProbingMode)
34 BlockContext bc = new BlockContext (ec.MemberContext, ec.CurrentBlock.Explicit, TypeManager.void_type) {
35 CurrentAnonymousMethod = ec.CurrentAnonymousMethod
38 Expression args = Parameters.CreateExpressionTree (bc, loc);
39 Expression expr = Block.CreateExpressionTree (ec);
43 Arguments arguments = new Arguments (2);
44 arguments.Add (new Argument (expr));
45 arguments.Add (new Argument (args));
46 return CreateExpressionFactoryCall (ec, "Lambda",
47 new TypeArguments (new TypeExpression (delegate_type, loc)),
51 public override bool HasExplicitParameters {
53 return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
57 protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
59 if (!delegateType.IsDelegate)
62 AParametersCollection d_params = Delegate.GetParameters (ec.Compiler, delegateType);
64 if (HasExplicitParameters) {
65 if (!VerifyExplicitParameters (ec, delegateType, d_params))
72 // If L has an implicitly typed parameter list we make implicit parameters explicit
73 // Set each parameter of L is given the type of the corresponding parameter in D
75 if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
78 TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
79 for (int i = 0; i < d_params.Count; i++) {
80 // D has no ref or out parameters
81 if ((d_params.FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) != 0)
84 TypeSpec d_param = d_params.Types [i];
87 // When type inference context exists try to apply inferred type arguments
90 d_param = tic.InflateGenericArgument (d_param);
94 ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
96 ilp.Resolve (null, i);
99 Parameters.Types = ptypes;
103 protected override Expression DoResolve (ResolveContext ec)
106 // Only explicit parameters can be resolved at this point
108 if (HasExplicitParameters) {
109 if (!Parameters.Resolve (ec))
113 eclass = ExprClass.Value;
114 type = InternalType.AnonymousMethod;
118 protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ToplevelBlock b)
120 return new LambdaMethod (p, b, returnType, delegateType, loc);
123 public override string GetSignatureForError ()
125 return "lambda expression";
129 public class LambdaMethod : AnonymousMethodBody
131 public LambdaMethod (ParametersCompiled parameters,
132 ToplevelBlock block, TypeSpec return_type, TypeSpec delegate_type,
134 : base (parameters, block, return_type, delegate_type, loc)
138 protected override void CloneTo (CloneContext clonectx, Expression target)
143 public override string ContainerType {
145 return "lambda expression";
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);