2 // lambda.cs: support for lambda expressions
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@gmail.com)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2007-2008 Novell, Inc
13 using System
.Collections
;
14 using System
.Reflection
;
15 using System
.Reflection
.Emit
;
17 namespace Mono
.CSharp
{
18 public class LambdaExpression
: AnonymousMethodExpression
21 // The parameters can either be:
22 // A list of Parameters (explicitly typed parameters)
23 // An ImplicitLambdaParameter
25 public LambdaExpression (Location loc
)
30 protected override Expression
CreateExpressionTree (ResolveContext ec
, Type delegate_type
)
32 if (ec
.IsInProbingMode
)
35 BlockContext bc
= new BlockContext (ec
.MemberContext
, ec
.CurrentBlock
.Explicit
, TypeManager
.void_type
);
36 Expression args
= Parameters
.CreateExpressionTree (bc
, loc
);
37 Expression expr
= Block
.CreateExpressionTree (ec
);
41 Arguments arguments
= new Arguments (2);
42 arguments
.Add (new Argument (expr
));
43 arguments
.Add (new Argument (args
));
44 return CreateExpressionFactoryCall (ec
, "Lambda",
45 new TypeArguments (new TypeExpression (delegate_type
, loc
)),
49 public override bool HasExplicitParameters
{
51 return Parameters
.Count
> 0 && !(Parameters
.FixedParameters
[0] is ImplicitLambdaParameter
);
55 protected override ParametersCompiled
ResolveParameters (ResolveContext ec
, TypeInferenceContext tic
, Type delegateType
)
57 if (!TypeManager
.IsDelegateType (delegateType
))
60 AParametersCollection d_params
= TypeManager
.GetDelegateParameters (ec
, delegateType
);
62 if (HasExplicitParameters
) {
63 if (!VerifyExplicitParameters (ec
, delegateType
, d_params
))
70 // If L has an implicitly typed parameter list we make implicit parameters explicit
71 // Set each parameter of L is given the type of the corresponding parameter in D
73 if (!VerifyParameterCompatibility (ec
, delegateType
, d_params
, ec
.IsInProbingMode
))
76 Type
[] ptypes
= new Type
[Parameters
.Count
];
77 for (int i
= 0; i
< d_params
.Count
; i
++) {
78 // D has no ref or out parameters
79 if ((d_params
.FixedParameters
[i
].ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0)
82 Type d_param
= d_params
.Types
[i
];
85 // Blablabla, because reflection does not work with dynamic types
86 if (d_param
.IsGenericParameter
)
87 d_param
= delegateType
.GetGenericArguments () [d_param
.GenericParameterPosition
];
90 // When type inference context exists try to apply inferred type arguments
93 d_param
= tic
.InflateGenericArgument (d_param
);
97 ((ImplicitLambdaParameter
) Parameters
.FixedParameters
[i
]).Type
= d_param
;
100 Parameters
.Types
= ptypes
;
104 public override Expression
DoResolve (ResolveContext ec
)
107 // Only explicit parameters can be resolved at this point
109 if (HasExplicitParameters
) {
110 if (!Parameters
.Resolve (ec
))
114 eclass
= ExprClass
.Value
;
115 type
= InternalType
.AnonymousMethod
;
119 protected override AnonymousMethodBody
CompatibleMethodFactory (Type returnType
, Type delegateType
, ParametersCompiled p
, ToplevelBlock b
)
121 return new LambdaMethod (p
, b
, returnType
, delegateType
, loc
);
124 public override string GetSignatureForError ()
126 return "lambda expression";
130 public class LambdaMethod
: AnonymousMethodBody
132 public LambdaMethod (ParametersCompiled parameters
,
133 ToplevelBlock block
, Type return_type
, Type delegate_type
,
135 : base (parameters
, block
, return_type
, delegate_type
, loc
)
139 protected override void CloneTo (CloneContext clonectx
, Expression target
)
144 public override string ContainerType
{
146 return "lambda expression";
150 public override Expression
CreateExpressionTree (ResolveContext ec
)
152 BlockContext bc
= new BlockContext (ec
.MemberContext
, Block
, ReturnType
);
153 Expression args
= parameters
.CreateExpressionTree (bc
, loc
);
154 Expression expr
= Block
.CreateExpressionTree (ec
);
158 Arguments arguments
= new Arguments (2);
159 arguments
.Add (new Argument (expr
));
160 arguments
.Add (new Argument (args
));
161 return CreateExpressionFactoryCall (ec
, "Lambda",
162 new TypeArguments (new TypeExpression (type
, loc
)),
168 // This is a return statement that is prepended lambda expression bodies that happen
169 // to be expressions. Depending on the return type of the delegate this will behave
170 // as either { expr (); return (); } or { return expr (); }
172 public class ContextualReturn
: Return
174 ExpressionStatement statement
;
176 public ContextualReturn (Expression expr
)
177 : base (expr
, expr
.Location
)
181 public override Expression
CreateExpressionTree (ResolveContext ec
)
183 return Expr
.CreateExpressionTree (ec
);
186 public override void Emit (EmitContext ec
)
188 if (statement
!= null) {
189 statement
.EmitStatement (ec
);
190 ec
.ig
.Emit (OpCodes
.Ret
);
197 protected override bool DoResolve (BlockContext ec
)
200 // When delegate returns void, only expression statements can be used
202 if (ec
.ReturnType
== TypeManager
.void_type
) {
203 Expr
= Expr
.Resolve (ec
);
207 statement
= Expr
as ExpressionStatement
;
208 if (statement
== null)
209 Expr
.Error_InvalidExpressionStatement (ec
);
214 return base.DoResolve (ec
);