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
10
// Copyright 2011 Xamarin Inc
14
using IKVM.Reflection.Emit;
16
using System.Reflection.Emit;
19
namespace Mono.CSharp {
20
public class LambdaExpression : AnonymousMethodExpression
23
// The parameters can either be:
24
// A list of Parameters (explicitly typed parameters)
25
// An ImplicitLambdaParameter
27
public LambdaExpression (Location loc)
32
protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
34
if (ec.IsInProbingMode)
37
BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, ec.BuiltinTypes.Void) {
38
CurrentAnonymousMethod = ec.CurrentAnonymousMethod
41
Expression args = Parameters.CreateExpressionTree (bc, loc);
42
Expression expr = Block.CreateExpressionTree (ec);
46
Arguments arguments = new Arguments (2);
47
arguments.Add (new Argument (expr));
48
arguments.Add (new Argument (args));
49
return CreateExpressionFactoryCall (ec, "Lambda",
50
new TypeArguments (new TypeExpression (delegate_type, loc)),
54
public override bool HasExplicitParameters {
56
return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
60
protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
62
if (!delegateType.IsDelegate)
65
AParametersCollection d_params = Delegate.GetParameters (delegateType);
67
if (HasExplicitParameters) {
68
if (!VerifyExplicitParameters (ec, delegateType, d_params))
75
// If L has an implicitly typed parameter list we make implicit parameters explicit
76
// Set each parameter of L is given the type of the corresponding parameter in D
78
if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
81
TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
82
for (int i = 0; i < d_params.Count; i++) {
83
// D has no ref or out parameters
84
if ((d_params.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
87
TypeSpec d_param = d_params.Types [i];
90
// When type inference context exists try to apply inferred type arguments
93
d_param = tic.InflateGenericArgument (ec, d_param);
97
ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
98
ilp.SetParameterType (d_param);
99
ilp.Resolve (null, i);
102
Parameters.Types = ptypes;
106
protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
108
return new LambdaMethod (p, b, returnType, delegateType, loc);
111
protected override bool DoResolveParameters (ResolveContext rc)
114
// Only explicit parameters can be resolved at this point
116
if (HasExplicitParameters) {
117
return Parameters.Resolve (rc);
123
public override string GetSignatureForError ()
125
return "lambda expression";
128
public override object Accept (StructuralVisitor visitor)
130
return visitor.Visit (this);
134
class LambdaMethod : AnonymousMethodBody
136
public LambdaMethod (ParametersCompiled parameters,
137
ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
139
: base (parameters, block, return_type, delegate_type, loc)
145
public override string ContainerType {
147
return "lambda expression";
153
protected override void CloneTo (CloneContext clonectx, Expression target)
158
public override Expression CreateExpressionTree (ResolveContext ec)
160
BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
161
Expression args = parameters.CreateExpressionTree (bc, loc);
162
Expression expr = Block.CreateExpressionTree (ec);
166
Arguments arguments = new Arguments (2);
167
arguments.Add (new Argument (expr));
168
arguments.Add (new Argument (args));
169
return CreateExpressionFactoryCall (ec, "Lambda",
170
new TypeArguments (new TypeExpression (type, loc)),
176
// This is a return statement that is prepended lambda expression bodies that happen
177
// to be expressions. Depending on the return type of the delegate this will behave
178
// as either { expr (); return (); } or { return expr (); }
180
public class ContextualReturn : Return
182
ExpressionStatement statement;
184
public ContextualReturn (Expression expr)
185
: base (expr, expr.Location)
189
public override Expression CreateExpressionTree (ResolveContext ec)
191
return Expr.CreateExpressionTree (ec);
194
protected override void DoEmit (EmitContext ec)
196
if (statement != null) {
197
statement.EmitStatement (ec);
199
ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
201
ec.Emit (OpCodes.Ret);
209
protected override bool DoResolve (BlockContext ec)
212
// When delegate returns void, only expression statements can be used
214
if (ec.ReturnType.Kind == MemberKind.Void) {
215
Expr = Expr.Resolve (ec);
219
statement = Expr as ExpressionStatement;
220
if (statement == null)
221
Expr.Error_InvalidExpressionStatement (ec);
226
return base.DoResolve (ec);