2 // lambda.cs: support for lambda expressions
4 // Authors: Miguel de Icaza (miguel@gnu.org)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2007 Novell, Inc
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
16 namespace Mono.CSharp {
17 public class LambdaExpression : AnonymousMethodExpression {
18 bool explicit_parameters;
21 // The parameters can either be:
22 // A list of Parameters (explicitly typed parameters)
23 // An ImplicitLambdaParameter
25 public LambdaExpression (AnonymousMethodExpression parent,
26 GenericMethod generic, TypeContainer host,
27 Parameters parameters, Block container,
29 : base (parent, generic, host, parameters, container, loc)
31 explicit_parameters = parameters.FixedParameters [0].TypeName != null;
34 public bool HasExplicitParameters {
36 return explicit_parameters;
40 public override Expression DoResolve (EmitContext ec)
43 // Only explicit parameters can be resolved at this point
45 if (explicit_parameters) {
46 if (!Parameters.Resolve (ec))
50 eclass = ExprClass.Value;
51 type = TypeManager.anonymous_method_type;
56 // Returns true if the body of lambda expression can be implicitly
57 // converted to the delegate of type `delegate_type'
59 public override bool ImplicitStandardConversionExists (Type delegate_type)
61 EmitContext ec = EmitContext.TempEc;
63 using (ec.Set (EmitContext.Flags.ProbingMode)) {
64 bool r = DoImplicitStandardConversion (ec, delegate_type) != null;
74 // Returns true if this anonymous method can be implicitly
75 // converted to the delegate type `delegate_type'
77 public override Expression Compatible (EmitContext ec, Type delegate_type)
79 if (anonymous != null)
80 return anonymous.AnonymousDelegate;
82 return DoImplicitStandardConversion (ec, delegate_type);
85 Expression DoImplicitStandardConversion (EmitContext ec, Type delegate_type)
87 if (CompatibleChecks (ec, delegate_type) == null)
90 MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (
91 ec.ContainerType, delegate_type, loc);
92 MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0];
93 ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
96 // The lambda expression is compatible with the delegate type,
101 // D and L have the same number of arguments.
102 if (Parameters.Count != invoke_pd.Count)
105 if (explicit_parameters){
107 // If L has an explicitly typed parameter list, each parameter
108 // in D has the same type and modifiers as the corresponding
111 if (!VerifyExplicitParameterCompatibility (delegate_type, invoke_pd, false))
115 // If L has an implicitly typed parameter list
117 for (int i = 0; i < invoke_pd.Count; i++) {
118 // D has no ref or out parameters
119 if ((invoke_pd.ParameterModifier (i) & Parameter.Modifier.ISBYREF) != 0)
123 // Makes implicit parameters explicit
124 // Set each parameter of L is given the type of the corresponding parameter in D
126 Parameters[i].ParameterType = invoke_pd.Types[i];
131 return CoreCompatibilityTest (ec, invoke_mb.ReturnType, delegate_type);
134 Expression CoreCompatibilityTest (EmitContext ec, Type return_type, Type delegate_type)
137 // The return type of the delegate must be compatible with
138 // the anonymous type. Instead of doing a pass to examine the block
139 // we satisfy the rule by setting the return type on the EmitContext
140 // to be the delegate type return type.
143 ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
145 anonymous = new AnonymousMethod (
146 Parent != null ? Parent.AnonymousMethod : null, RootScope, Host,
147 GenericMethod, Parameters, Container, b, return_type,
151 if (ec.IsInProbingMode)
152 r = anonymous.ResolveNoDefine (ec);
154 r = anonymous.Resolve (ec);
156 // Resolution failed.
160 return anonymous.AnonymousDelegate;
163 public override string GetSignatureForError ()
165 return "lambda expression";
169 // TryBuild: tries to compile this LambdaExpression with the given
170 // types as the lambda expression parameter types.
172 // If the lambda expression successfully builds with those types, the
173 // return value will be the inferred type for the lambda expression,
174 // otherwise the result will be null.
176 public Type TryBuild (EmitContext ec, Type [] types)
178 for (int i = 0; i < types.Length; i++)
179 Parameters [i].TypeName = new TypeExpression (types [i], Parameters [i].Location);
181 // TODO: temporary hack
182 ec.InferReturnType = true;
185 using (ec.Set (EmitContext.Flags.ProbingMode)) {
186 e = CoreCompatibilityTest (ec, null, null);
197 // This is a return statement that is prepended lambda expression bodies that happen
198 // to be expressions. Depending on the return type of the delegate this will behave
199 // as either { expr (); return (); } or { return expr (); }
201 public class ContextualReturn : Return
203 public ContextualReturn (Expression expr)
204 : base (expr, expr.Location)