2007-07-18 Miguel de Icaza <miguel@novell.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 using System.Reflection.Emit;
15
16 namespace Mono.CSharp {
17         public class LambdaExpression : AnonymousMethodExpression {
18                 bool explicit_parameters;
19
20                 //
21                 // The parameters can either be:
22                 //    A list of Parameters (explicitly typed parameters)
23                 //    An ImplicitLambdaParameter
24                 //
25                 public LambdaExpression (AnonymousMethodExpression parent,
26                                          GenericMethod generic, TypeContainer host,
27                                          Parameters parameters, Block container,
28                                          Location loc)
29                         : base (parent, generic, host, parameters, container, loc)
30                 {
31                         if (parameters.FixedParameters.Length > 0)
32                                 explicit_parameters = parameters.FixedParameters [0].TypeName != null;
33                 }
34
35                 public override bool HasExplicitParameters {
36                         get {
37                                 return explicit_parameters;
38                         }
39                 }
40
41                 protected override Parameters CreateParameters (EmitContext ec, Type delegateType, ParameterData delegateParameters)
42                 {
43                         Parameters p = base.CreateParameters (ec, delegateType, delegateParameters);
44                         if (explicit_parameters)
45                                 return p;
46
47                         //
48                         // If L has an implicitly typed parameter list
49                         //
50                         for (int i = 0; i < delegateParameters.Count; i++) {
51                                 // D has no ref or out parameters
52                                 //if ((invoke_pd.ParameterModifier (i) & Parameter.Modifier.ISBYREF) != 0)
53                                 //      return null;
54
55                                 //
56                                 // Makes implicit parameters explicit
57                                 // Set each parameter of L is given the type of the corresponding parameter in D
58                                 //
59                                 p[i].ParameterType = delegateParameters.Types[i];
60                         }
61                         return p;
62                 }
63
64                 public override Expression DoResolve (EmitContext ec)
65                 {
66                         //
67                         // Only explicit parameters can be resolved at this point
68                         //
69                         if (explicit_parameters) {
70                                 if (!Parameters.Resolve (ec))
71                                         return null;
72                         }
73
74                         eclass = ExprClass.Value;
75                         type = TypeManager.anonymous_method_type;                                               
76                         return this;
77                 }
78
79                 //
80                 // Returns true if the body of lambda expression can be implicitly
81                 // converted to the delegate of type `delegate_type'
82                 //
83                 public override bool ImplicitStandardConversionExists (Type delegate_type)
84                 {
85                         EmitContext ec = EmitContext.TempEc;
86
87                         using (ec.Set (EmitContext.Flags.ProbingMode)) {
88                                 bool r = Compatible (ec, delegate_type) != null;
89
90                                 // Ignore the result
91                                 anonymous = null;
92
93                                 return r;
94                         }
95                 }
96
97                 //
98                 // Resolves a body of lambda expression.
99                 //
100                 protected override Expression ResolveMethod (EmitContext ec, Parameters parameters, Type returnType, Type delegateType)
101                 {
102                         ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
103
104                         anonymous = new LambdaMethod (
105                                 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
106                                 GenericMethod, Parameters, Container, b, returnType,
107                                 delegateType, loc);
108
109                         bool r;
110                         if (ec.IsInProbingMode)
111                                 r = anonymous.ResolveNoDefine (ec);
112                         else
113                                 r = anonymous.Resolve (ec);
114
115                         // Resolution failed.
116                         if (!r)
117                                 return null;
118
119                         return anonymous.AnonymousDelegate;
120                 }
121                 
122                 public override string GetSignatureForError ()
123                 {
124                         return "lambda expression";
125                 }
126
127                 //
128                 // TryBuild: tries to compile this LambdaExpression with the given
129                 // types as the lambda expression parameter types.   
130                 //
131                 // If the lambda expression successfully builds with those types, the
132                 // return value will be the inferred type for the lambda expression,
133                 // otherwise the result will be null.
134                 //
135                 public Type TryBuild (EmitContext ec, Type [] types)
136                 {
137                         for (int i = 0; i < types.Length; i++)
138                                 Parameters [i].TypeName = new TypeExpression (types [i], Parameters [i].Location);
139
140                         // TODO: temporary hack
141                         ec.InferReturnType = true;
142                         
143                         Expression e;
144                         using (ec.Set (EmitContext.Flags.ProbingMode)) {
145                                 e = ResolveMethod (ec, Parameters, typeof (LambdaExpression), null);
146                         }
147                         
148                         if (e == null)
149                                 return null;
150                         
151                         return e.Type;
152                 }
153         }
154
155         //
156         // This is a return statement that is prepended lambda expression bodies that happen
157         // to be expressions.  Depending on the return type of the delegate this will behave
158         // as either { expr (); return (); } or { return expr (); }
159
160         public class ContextualReturn : Return
161         {
162                 public ContextualReturn (Expression expr)
163                         : base (expr, expr.Location)
164                 {
165                 }
166         }
167 }