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, tic, 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, tic, 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.StartLocation)
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);