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