2 // lambda.cs: support for lambda expressions
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@gmail.com)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2007 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";
155 // This is a return statement that is prepended lambda expression bodies that happen
156 // to be expressions. Depending on the return type of the delegate this will behave
157 // as either { expr (); return (); } or { return expr (); }
159 public class ContextualReturn : Return
161 public ContextualReturn (Expression expr)
162 : base (expr, expr.Location)
166 public override Expression CreateExpressionTree (EmitContext ec)
168 return Expr.CreateExpressionTree (ec);
171 public override void Emit (EmitContext ec)
173 if (ec.ReturnType == TypeManager.void_type)
174 ((ExpressionStatement) Expr).EmitStatement (ec);
179 public override bool Resolve (EmitContext ec)
182 // When delegate returns void, only expression statements can be used
184 if (ec.ReturnType == TypeManager.void_type) {
185 Expr = Expr.Resolve (ec);
189 if (Expr is ExpressionStatement && (Expr is Assign || TypeManager.IsEqual (Expr.Type, ec.ReturnType)))
192 Expr.Error_InvalidExpressionStatement ();
196 return base.Resolve (ec);