Merge branch 'bugfix'
[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 #if STATIC
13 using IKVM.Reflection.Emit;
14 #else
15 using System.Reflection.Emit;
16 #endif
17
18 namespace Mono.CSharp {
19         public class LambdaExpression : AnonymousMethodExpression
20         {
21                 //
22                 // The parameters can either be:
23                 //    A list of Parameters (explicitly typed parameters)
24                 //    An ImplicitLambdaParameter
25                 //
26                 public LambdaExpression (Location loc)
27                         : base (loc)
28                 {
29                 }
30
31                 protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type)
32                 {
33                         if (ec.IsInProbingMode)
34                                 return this;
35
36                         BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, ec.BuiltinTypes.Void) {
37                                 CurrentAnonymousMethod = ec.CurrentAnonymousMethod
38                         };
39
40                         Expression args = Parameters.CreateExpressionTree (bc, loc);
41                         Expression expr = Block.CreateExpressionTree (ec);
42                         if (expr == null)
43                                 return null;
44
45                         Arguments arguments = new Arguments (2);
46                         arguments.Add (new Argument (expr));
47                         arguments.Add (new Argument (args));
48                         return CreateExpressionFactoryCall (ec, "Lambda",
49                                 new TypeArguments (new TypeExpression (delegate_type, loc)),
50                                 arguments);
51                 }
52
53                 public override bool HasExplicitParameters {
54                         get {
55                                 return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter);
56                         }
57                 }
58
59                 protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType)
60                 {
61                         if (!delegateType.IsDelegate)
62                                 return null;
63
64                         AParametersCollection d_params = Delegate.GetParameters (delegateType);
65
66                         if (HasExplicitParameters) {
67                                 if (!VerifyExplicitParameters (ec, delegateType, d_params))
68                                         return null;
69
70                                 return Parameters;
71                         }
72
73                         //
74                         // If L has an implicitly typed parameter list we make implicit parameters explicit
75                         // Set each parameter of L is given the type of the corresponding parameter in D
76                         //
77                         if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode))
78                                 return null;
79
80                         TypeSpec [] ptypes = new TypeSpec [Parameters.Count];
81                         for (int i = 0; i < d_params.Count; i++) {
82                                 // D has no ref or out parameters
83                                 if ((d_params.FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) != 0)
84                                         return null;
85
86                                 TypeSpec d_param = d_params.Types [i];
87
88                                 //
89                                 // When type inference context exists try to apply inferred type arguments
90                                 //
91                                 if (tic != null) {
92                                         d_param = tic.InflateGenericArgument (ec, d_param);
93                                 }
94
95                                 ptypes [i] = d_param;
96                                 ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i];
97                                 ilp.SetParameterType (d_param);
98                                 ilp.Resolve (null, i);
99                         }
100
101                         Parameters.Types = ptypes;
102                         return Parameters;
103                 }
104
105                 protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b)
106                 {
107                         return new LambdaMethod (p, b, returnType, delegateType, loc);
108                 }
109
110                 protected override bool DoResolveParameters (ResolveContext rc)
111                 {
112                         //
113                         // Only explicit parameters can be resolved at this point
114                         //
115                         if (HasExplicitParameters) {
116                                 return Parameters.Resolve (rc);
117                         }
118
119                         return true;
120                 }
121
122                 public override string GetSignatureForError ()
123                 {
124                         return "lambda expression";
125                 }
126         }
127
128         class LambdaMethod : AnonymousMethodBody
129         {
130                 public LambdaMethod (ParametersCompiled parameters,
131                                         ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type,
132                                         Location loc)
133                         : base (parameters, block, return_type, delegate_type, loc)
134                 {
135                 }
136
137                 #region Properties
138
139                 public override string ContainerType {
140                         get {
141                                 return "lambda expression";
142                         }
143                 }
144
145                 #endregion
146
147                 protected override void CloneTo (CloneContext clonectx, Expression target)
148                 {
149                         // TODO: nothing ??
150                 }
151
152                 public override Expression CreateExpressionTree (ResolveContext ec)
153                 {
154                         BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType);
155                         Expression args = parameters.CreateExpressionTree (bc, loc);
156                         Expression expr = Block.CreateExpressionTree (ec);
157                         if (expr == null)
158                                 return null;
159
160                         Arguments arguments = new Arguments (2);
161                         arguments.Add (new Argument (expr));
162                         arguments.Add (new Argument (args));
163                         return CreateExpressionFactoryCall (ec, "Lambda",
164                                 new TypeArguments (new TypeExpression (type, loc)),
165                                 arguments);
166                 }
167         }
168
169         //
170         // This is a return statement that is prepended lambda expression bodies that happen
171         // to be expressions.  Depending on the return type of the delegate this will behave
172         // as either { expr (); return (); } or { return expr (); }
173         //
174         public class ContextualReturn : Return
175         {
176                 ExpressionStatement statement;
177
178                 public ContextualReturn (Expression expr)
179                         : base (expr, expr.Location)
180                 {
181                 }
182
183                 public override Expression CreateExpressionTree (ResolveContext ec)
184                 {
185                         return Expr.CreateExpressionTree (ec);
186                 }
187
188                 public override void Emit (EmitContext ec)
189                 {
190                         if (statement != null) {
191                                 statement.EmitStatement (ec);
192                                 ec.Emit (OpCodes.Ret);
193                                 return;
194                         }
195
196                         base.Emit (ec);
197                 }
198
199                 protected override bool DoResolve (BlockContext ec)
200                 {
201                         //
202                         // When delegate returns void, only expression statements can be used
203                         //
204                         if (ec.ReturnType.Kind == MemberKind.Void) {
205                                 Expr = Expr.Resolve (ec);
206                                 if (Expr == null)
207                                         return false;
208
209                                 statement = Expr as ExpressionStatement;
210                                 if (statement == null)
211                                         Expr.Error_InvalidExpressionStatement (ec);
212
213                                 return true;
214                         }
215
216                         return base.DoResolve (ec);
217                 }
218         }
219 }