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