2007-02-06 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / lambda.cs
1 //
2 // lambda.cs: support for lambda expressions
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2007 Novell, Inc
9 //
10
11 using System;
12 using System.Collections;
13 using System.Reflection;
14
15 namespace Mono.CSharp {
16         public class LambdaExpression : AnonymousMethodExpression {
17                 bool explicit_parameters;
18
19                 //
20                 // If set, this was a lambda expression with an expression
21                 // argument.  And if so, we have a pointer to it, so we can
22                 // change it if needed.
23                 //
24                 Expression lambda_expr;
25                 
26                 //
27                 // The parameter list can either be:
28                 //    null: no parameters
29                 //    arraylist of Parameter (explicitly typed parameters)
30                 //    arraylist of strings (implicitly typed parameters)
31                 //
32                 public LambdaExpression (AnonymousMethodExpression parent,
33                                          GenericMethod generic, TypeContainer host,
34                                          Parameters parameters, Block container,
35                                          Location loc)
36                         : base (parent, generic, host, parameters, container, loc)
37                 {
38                         explicit_parameters = (parameters != null && parameters.Count > 0 && parameters [0].TypeName != null);
39                         if (parameters == null)
40                                 Parameters = new Parameters (new Parameter [0]);
41                 }
42
43                 public void SetExpression (Expression expr)
44                 {
45                         lambda_expr = expr;
46                 }
47                 
48                 public override Expression DoResolve (EmitContext ec)
49                 {
50                         eclass = ExprClass.Value;
51                         type = TypeManager.anonymous_method_type;
52
53                         if (explicit_parameters){
54                                 if (!Parameters.Resolve (ec))
55                                         return null;
56                         }
57                         
58                         // We will resolve parameters later, we do not
59                         // have information at this point.
60                         
61                         return this;
62                 }
63
64                 public override void Emit (EmitContext ec)
65                 {
66                         base.Emit (ec);
67                 }
68
69                 //
70                 // Returns true if this anonymous method can be implicitly
71                 // converted to the delegate type `delegate_type'
72                 //
73                 public override Expression Compatible (EmitContext ec, Type delegate_type)
74                 {
75                         if (anonymous != null)
76                                 return anonymous.AnonymousDelegate;
77
78                         if (CompatibleChecks (ec, delegate_type) == null)
79                                 return null;
80
81                         MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
82                                 ec.ContainerType, delegate_type, loc);
83                         MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
84                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
85
86                         //
87                         // The lambda expression is compatible with the delegate type,
88                         // provided that:
89                         //
90
91                         //
92                         // D and L have the same number of arguments.
93                         if (Parameters.Count != invoke_pd.Count)
94                                 return null;
95
96                         Parameters parameters_copy = Parameters.Clone ();
97                         if (explicit_parameters){
98                                 //
99                                 // If L has an explicitly typed parameter list, each parameter
100                                 // in D has the same type and modifiers as the corresponding
101                                 // parameter in L.
102                                 //
103                                 if (!VerifyExplicitParameterCompatibility (delegate_type, invoke_pd))
104                                         return null;
105
106                                 parameters_copy = Parameters.Clone ();
107                         } else {
108                                 //
109                                 // If L has an implicitly typed parameter list, D has no ref or
110                                 // out parameters
111                                 //
112                                 // Note: We currently do nothing, because the preview does not
113                                 // follow the above rule.
114
115                                 //
116                                 // each parameter of L is given the type of the corresponding parameter in D
117                                 //
118
119                                 for (int i = 0; i < invoke_pd.Count; i++)
120                                         parameters_copy [i].TypeName = new TypeExpression (
121                                                 invoke_pd.ParameterType (i),
122                                                 parameters_copy [i].Location);
123                         }
124                         
125                                 
126                         if (invoke_mb.ReturnType == TypeManager.void_type){
127                                 
128                         }
129                         
130                         if (lambda_expr == null){
131                         } else {
132                         }
133
134 #if false
135                         //
136                         // Second: the return type of the delegate must be compatible with 
137                         // the anonymous type.   Instead of doing a pass to examine the block
138                         // we satisfy the rule by setting the return type on the EmitContext
139                         // to be the delegate type return type.
140                         //
141
142                         //MethodBuilder builder = method_data.MethodBuilder;
143                         //ILGenerator ig = builder.GetILGenerator ();
144
145                         Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
146                                       Container, Block, invoke_mb.ReturnType, delegate_type,
147                                       TypeManager.IsGenericType (delegate_type), loc);
148
149                         anonymous = new AnonymousMethod (
150                                 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
151                                 GenericMethod, parameters, Container, Block, invoke_mb.ReturnType,
152                                 delegate_type, loc);
153
154                         if (!anonymous.Resolve (ec))
155                                 return null;
156
157                         return anonymous.AnonymousDelegate;
158 #endif
159                         return null;
160                 }
161         }
162 }