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.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
17 namespace Mono.CSharp {
18 public class LambdaExpression : AnonymousMethodExpression
20 readonly bool explicit_parameters;
23 // The parameters can either be:
24 // A list of Parameters (explicitly typed parameters)
25 // An ImplicitLambdaParameter
27 public LambdaExpression (AnonymousMethodExpression parent,
28 GenericMethod generic, TypeContainer host,
29 Parameters parameters, Block container,
31 : base (parent, generic, host, parameters, container, loc)
33 if (parameters.Count > 0)
34 explicit_parameters = !(parameters.FixedParameters [0] is ImplicitLambdaParameter);
37 protected override Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
39 if (ec.IsInProbingMode)
42 Expression args = Parameters.CreateExpressionTree (ec, loc);
43 Expression expr = Block.CreateExpressionTree (ec);
47 ArrayList arguments = new ArrayList (2);
48 arguments.Add (new Argument (expr));
49 arguments.Add (new Argument (args));
50 return CreateExpressionFactoryCall ("Lambda",
51 new TypeArguments (loc, new TypeExpression (delegate_type, loc)),
55 public override bool HasExplicitParameters {
57 return explicit_parameters;
61 protected override Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegateType)
63 if (!TypeManager.IsDelegateType (delegateType))
66 ParameterData d_params = TypeManager.GetDelegateParameters (delegateType);
68 if (explicit_parameters) {
69 if (!VerifyExplicitParameters (delegateType, d_params, ec.IsInProbingMode))
76 // If L has an implicitly typed parameter list we make implicit parameters explicit
77 // Set each parameter of L is given the type of the corresponding parameter in D
79 if (!VerifyParameterCompatibility (delegateType, d_params, ec.IsInProbingMode))
82 if (Parameters.Types == null)
83 Parameters.Types = new Type [Parameters.Count];
85 for (int i = 0; i < d_params.Count; i++) {
86 // D has no ref or out parameters
87 if ((d_params.ParameterModifier (i) & Parameter.Modifier.ISBYREF) != 0)
90 Type d_param = d_params.Types [i];
93 // Blablabla, because reflection does not work with dynamic types
94 if (d_param.IsGenericParameter)
95 d_param = delegateType.GetGenericArguments () [d_param.GenericParameterPosition];
97 // When inferred context exists all generics parameters have type replacements
99 d_param = tic.InflateGenericArgument (d_param);
102 Parameters.Types [i] = Parameters.FixedParameters[i].ParameterType = d_param;
107 public override Expression DoResolve (EmitContext ec)
110 // Only explicit parameters can be resolved at this point
112 if (explicit_parameters) {
113 if (!Parameters.Resolve (ec))
117 eclass = ExprClass.Value;
118 type = TypeManager.anonymous_method_type;
122 protected override AnonymousMethod CompatibleMethodFactory (Type returnType, Type delegateType, Parameters p, ToplevelBlock b)
124 return new LambdaMethod (RootScope, Host,
125 GenericMethod, p, Container, b, returnType,
129 public override string GetSignatureForError ()
131 return "lambda expression";
135 public class LambdaMethod : AnonymousMethod
137 public LambdaMethod (RootScopeInfo root_scope,
138 DeclSpace host, GenericMethod generic,
139 Parameters parameters, Block container,
140 ToplevelBlock block, Type return_type, Type delegate_type,
142 : base (root_scope, host, generic, parameters, container, block,
143 return_type, delegate_type, loc)
147 public override string ContainerType {
149 return "lambda expression";
153 public override Expression CreateExpressionTree (EmitContext ec)
155 return Block.CreateExpressionTree (ec);
160 // This is a return statement that is prepended lambda expression bodies that happen
161 // to be expressions. Depending on the return type of the delegate this will behave
162 // as either { expr (); return (); } or { return expr (); }
164 public class ContextualReturn : Return
166 public ContextualReturn (Expression expr)
167 : base (expr, expr.Location)
171 public override Expression CreateExpressionTree (EmitContext ec)
173 return Expr.CreateExpressionTree (ec);
176 public override void Emit (EmitContext ec)
178 if (ec.ReturnType == TypeManager.void_type)
179 ((ExpressionStatement) Expr).EmitStatement (ec);
184 protected override bool DoResolve (EmitContext ec)
187 // When delegate returns void, only expression statements can be used
189 if (ec.ReturnType == TypeManager.void_type) {
190 Expr = Expr.Resolve (ec);
194 if (Expr is ExpressionStatement) {
195 if (Expr is Invocation)
196 return TypeManager.IsEqual (Expr.Type, TypeManager.void_type);
200 Expr.Error_InvalidExpressionStatement ();
204 return base.DoResolve (ec);