merge from trunk at 97714
[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 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2007 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                 readonly bool explicit_parameters;
21
22                 //
23                 // The parameters can either be:
24                 //    A list of Parameters (explicitly typed parameters)
25                 //    An ImplicitLambdaParameter
26                 //
27                 public LambdaExpression (AnonymousMethodExpression parent,
28                                          GenericMethod generic, TypeContainer host,
29                                          Parameters parameters, Block container,
30                                          Location loc)
31                         : base (parent, generic, host, parameters, container, loc)
32                 {
33                         if (parameters.Count > 0)
34                                 explicit_parameters = !(parameters.FixedParameters [0] is ImplicitLambdaParameter);
35                 }
36
37                 protected override Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
38                 {
39                         if (ec.IsInProbingMode)
40                                 return this;
41                         
42                         Expression args = Parameters.CreateExpressionTree (ec, loc);
43                         Expression expr = Block.CreateExpressionTree (ec);
44                         if (expr == null)
45                                 return null;
46
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)),
52                                 arguments);
53                 }
54
55                 public override bool HasExplicitParameters {
56                         get {
57                                 return explicit_parameters;
58                         }
59                 }
60
61                 protected override Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegateType)
62                 {
63                         if (!TypeManager.IsDelegateType (delegateType))
64                                 return null;
65
66                         ParameterData d_params = TypeManager.GetDelegateParameters (delegateType);
67
68                         if (explicit_parameters) {
69                                 if (!VerifyExplicitParameters (delegateType, d_params, ec.IsInProbingMode))
70                                         return null;
71
72                                 return Parameters;
73                         }
74
75                         //
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
78                         //
79                         if (!VerifyParameterCompatibility (delegateType, d_params, ec.IsInProbingMode))
80                                 return null;
81
82                         if (Parameters.Types == null)
83                                 Parameters.Types = new Type [Parameters.Count];
84
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)
88                                         return null;
89
90                                 Type d_param = d_params.Types [i];
91
92 #if MS_COMPATIBLE
93                                 // Blablabla, because reflection does not work with dynamic types
94                                 if (d_param.IsGenericParameter)
95                                         d_param = delegateType.GetGenericArguments () [d_param.GenericParameterPosition];
96 #endif
97                                 // When inferred context exists all generics parameters have type replacements
98                                 if (tic != null) {
99                                         d_param = tic.InflateGenericArgument (d_param);
100                                 }
101
102                                 Parameters.Types [i] = Parameters.FixedParameters[i].ParameterType = d_param;
103                         }
104                         return Parameters;
105                 }
106
107                 public override Expression DoResolve (EmitContext ec)
108                 {
109                         //
110                         // Only explicit parameters can be resolved at this point
111                         //
112                         if (explicit_parameters) {
113                                 if (!Parameters.Resolve (ec))
114                                         return null;
115                         }
116
117                         eclass = ExprClass.Value;
118                         type = TypeManager.anonymous_method_type;                                               
119                         return this;
120                 }
121
122                 protected override AnonymousMethod CompatibleMethodFactory (Type returnType, Type delegateType, Parameters p, ToplevelBlock b)
123                 {
124                         return new LambdaMethod (RootScope, Host,
125                                 GenericMethod, p, Container, b, returnType,
126                                 delegateType, loc);
127                 }
128
129                 public override string GetSignatureForError ()
130                 {
131                         return "lambda expression";
132                 }
133         }
134
135         public class LambdaMethod : AnonymousMethod
136         {
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,
141                                         Location loc)
142                         : base (root_scope, host, generic, parameters, container, block,
143                                 return_type, delegate_type, loc)
144                 {
145                 }
146
147                 public override string ContainerType {
148                         get {
149                                 return "lambda expression";
150                         }
151                 }
152         }
153
154         //
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 (); }
158         //
159         public class ContextualReturn : Return
160         {
161                 public ContextualReturn (Expression expr)
162                         : base (expr, expr.Location)
163                 {
164                 }
165
166                 public override Expression CreateExpressionTree (EmitContext ec)
167                 {
168                         return Expr.CreateExpressionTree (ec);
169                 }
170
171                 public override void Emit (EmitContext ec)
172                 {
173                         if (ec.ReturnType == TypeManager.void_type)
174                                 ((ExpressionStatement) Expr).EmitStatement (ec);
175                         else
176                                 base.Emit (ec);
177                 }
178
179                 public override bool Resolve (EmitContext ec)
180                 {       
181                         //
182                         // When delegate returns void, only expression statements can be used
183                         //
184                         if (ec.ReturnType == TypeManager.void_type) {
185                                 Expr = Expr.Resolve (ec);
186                                 if (Expr == null)
187                                         return false;
188                                 
189                                 if (Expr is ExpressionStatement) {
190                                         if (Expr is Invocation)
191                                                 return TypeManager.IsEqual (Expr.Type, TypeManager.void_type);
192                                         return true;
193                                 }
194                                 
195                                 Expr.Error_InvalidExpressionStatement ();
196                                 return false;
197                         }
198
199                         return base.Resolve (ec);
200                 }
201         }
202 }