5be0f68a67e47a3de22f89ffb3bf693cadf32c44
[mono.git] / mcs / mcs / lambda.cs
1 //
2 // lambda.cs: support for lambda expressions
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 //          Marek Safar (marek.safar@gmail.com)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2007-2008 Novell, Inc
10 //
11
12 using System;
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
16
17 namespace Mono.CSharp {
18         public class LambdaExpression : AnonymousMethodExpression
19         {
20                 //
21                 // The parameters can either be:
22                 //    A list of Parameters (explicitly typed parameters)
23                 //    An ImplicitLambdaParameter
24                 //
25                 public LambdaExpression (Location loc)
26                         : base (loc)
27                 {
28                 }
29
30                 protected override Expression CreateExpressionTree (ResolveContext ec, Type delegate_type)
31                 {
32                         if (ec.IsInProbingMode)
33                                 return this;
34
35                         BlockContext bc = new BlockContext (ec.MemberContext, ec.CurrentBlock.Explicit, TypeManager.void_type);
36                         Expression args = Parameters.CreateExpressionTree (bc, loc);
37                         Expression expr = Block.CreateExpressionTree (ec);
38                         if (expr == null)
39                                 return null;
40
41                         Arguments arguments = new Arguments (2);
42                         arguments.Add (new Argument (expr));
43                         arguments.Add (new Argument (args));
44                         return CreateExpressionFactoryCall ("Lambda",
45                                 new TypeArguments (new TypeExpression (delegate_type, loc)),
46                                 arguments);
47                 }
48
49                 public override bool HasExplicitParameters {
50                         get {
51                                 return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
52                         }
53                 }
54
55                 protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, Type delegateType)
56                 {
57                         if (!TypeManager.IsDelegateType (delegateType))
58                                 return null;
59
60                         AParametersCollection d_params = TypeManager.GetDelegateParameters (delegateType);
61
62                         if (HasExplicitParameters) {
63                                 if (!VerifyExplicitParameters (delegateType, d_params, ec.IsInProbingMode))
64                                         return null;
65
66                                 return Parameters;
67                         }
68
69                         //
70                         // If L has an implicitly typed parameter list we make implicit parameters explicit
71                         // Set each parameter of L is given the type of the corresponding parameter in D
72                         //
73                         if (!VerifyParameterCompatibility (delegateType, d_params, ec.IsInProbingMode))
74                                 return null;
75
76                         Type [] ptypes = new Type [Parameters.Count];
77                         for (int i = 0; i < d_params.Count; i++) {
78                                 // D has no ref or out parameters
79                                 if ((d_params.FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) != 0)
80                                         return null;
81
82                                 Type d_param = d_params.Types [i];
83
84 #if MS_COMPATIBLE
85                                 // Blablabla, because reflection does not work with dynamic types
86                                 if (d_param.IsGenericParameter)
87                                         d_param = delegateType.GetGenericArguments () [d_param.GenericParameterPosition];
88 #endif
89                                 //
90                                 // When type inference context exists try to apply inferred type arguments
91                                 //
92                                 if (tic != null) {
93                                         d_param = tic.InflateGenericArgument (d_param);
94                                 }
95
96                                 ptypes [i] = d_param;
97                                 ((ImplicitLambdaParameter) Parameters.FixedParameters [i]).Type = d_param;
98                         }
99
100                         Parameters.Types = ptypes;
101                         return Parameters;
102                 }
103
104                 public override Expression DoResolve (ResolveContext ec)
105                 {
106                         //
107                         // Only explicit parameters can be resolved at this point
108                         //
109                         if (HasExplicitParameters) {
110                                 if (!Parameters.Resolve (ec))
111                                         return null;
112                         }
113
114                         eclass = ExprClass.Value;
115                         type = InternalType.AnonymousMethod;
116                         return this;
117                 }
118
119                 protected override AnonymousMethodBody CompatibleMethodFactory (Type returnType, Type delegateType, ParametersCompiled p, ToplevelBlock b)
120                 {
121                         return new LambdaMethod (p, b, returnType, delegateType, loc);
122                 }
123
124                 public override string GetSignatureForError ()
125                 {
126                         return "lambda expression";
127                 }
128         }
129
130         public class LambdaMethod : AnonymousMethodBody
131         {
132                 public LambdaMethod (ParametersCompiled parameters,
133                                         ToplevelBlock block, Type return_type, Type delegate_type,
134                                         Location loc)
135                         : base (parameters, block, return_type, delegate_type, loc)
136                 {
137                 }
138
139                 protected override void CloneTo (CloneContext clonectx, Expression target)
140                 {
141                         // TODO: nothing ??
142                 }
143
144                 public override string ContainerType {
145                         get {
146                                 return "lambda expression";
147                         }
148                 }
149
150                 public override Expression CreateExpressionTree (ResolveContext ec)
151                 {
152                         BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
153                         Expression args = parameters.CreateExpressionTree (bc, loc);
154                         Expression expr = Block.CreateExpressionTree (ec);
155                         if (expr == null)
156                                 return null;
157
158                         Arguments arguments = new Arguments (2);
159                         arguments.Add (new Argument (expr));
160                         arguments.Add (new Argument (args));
161                         return CreateExpressionFactoryCall ("Lambda",
162                                 new TypeArguments (new TypeExpression (type, loc)),
163                                 arguments);
164                 }
165         }
166
167         //
168         // This is a return statement that is prepended lambda expression bodies that happen
169         // to be expressions.  Depending on the return type of the delegate this will behave
170         // as either { expr (); return (); } or { return expr (); }
171         //
172         public class ContextualReturn : Return
173         {
174                 ExpressionStatement statement;
175
176                 public ContextualReturn (Expression expr)
177                         : base (expr, expr.Location)
178                 {
179                 }
180
181                 public override Expression CreateExpressionTree (ResolveContext ec)
182                 {
183                         return Expr.CreateExpressionTree (ec);
184                 }
185
186                 public override void Emit (EmitContext ec)
187                 {
188                         if (statement != null) {
189                                 statement.EmitStatement (ec);
190                                 ec.ig.Emit (OpCodes.Ret);
191                                 return;
192                         }
193
194                         base.Emit (ec);
195                 }
196
197                 protected override bool DoResolve (BlockContext ec)
198                 {
199                         //
200                         // When delegate returns void, only expression statements can be used
201                         //
202                         if (ec.ReturnType == TypeManager.void_type) {
203                                 Expr = Expr.Resolve (ec);
204                                 if (Expr == null)
205                                         return false;
206
207                                 statement = Expr as ExpressionStatement;
208                                 if (statement == null)
209                                         Expr.Error_InvalidExpressionStatement ();
210
211                                 return true;
212                         }
213
214                         return base.DoResolve (ec);
215                 }
216         }
217 }