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 CurrentAnonymousMethod
= ec
.CurrentAnonymousMethod
39 Expression args
= Parameters
.CreateExpressionTree (bc
, loc
);
40 Expression expr
= Block
.CreateExpressionTree (ec
);
44 Arguments arguments
= new Arguments (2);
45 arguments
.Add (new Argument (expr
));
46 arguments
.Add (new Argument (args
));
47 return CreateExpressionFactoryCall (ec
, "Lambda",
48 new TypeArguments (new TypeExpression (delegate_type
, loc
)),
52 public override bool HasExplicitParameters
{
54 return Parameters
.Count
> 0 && !(Parameters
.FixedParameters
[0] is ImplicitLambdaParameter
);
58 protected override ParametersCompiled
ResolveParameters (ResolveContext ec
, TypeInferenceContext tic
, Type delegateType
)
60 if (!TypeManager
.IsDelegateType (delegateType
))
63 AParametersCollection d_params
= TypeManager
.GetDelegateParameters (ec
, delegateType
);
65 if (HasExplicitParameters
) {
66 if (!VerifyExplicitParameters (ec
, delegateType
, d_params
))
73 // If L has an implicitly typed parameter list we make implicit parameters explicit
74 // Set each parameter of L is given the type of the corresponding parameter in D
76 if (!VerifyParameterCompatibility (ec
, delegateType
, d_params
, ec
.IsInProbingMode
))
79 Type
[] ptypes
= new Type
[Parameters
.Count
];
80 for (int i
= 0; i
< d_params
.Count
; i
++) {
81 // D has no ref or out parameters
82 if ((d_params
.FixedParameters
[i
].ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0)
85 Type d_param
= d_params
.Types
[i
];
88 // Blablabla, because reflection does not work with dynamic types
89 if (d_param
.IsGenericParameter
)
90 d_param
= delegateType
.GetGenericArguments () [d_param
.GenericParameterPosition
];
93 // When type inference context exists try to apply inferred type arguments
96 d_param
= tic
.InflateGenericArgument (d_param
);
100 ((ImplicitLambdaParameter
) Parameters
.FixedParameters
[i
]).Type
= d_param
;
103 Parameters
.Types
= ptypes
;
107 protected override Expression
DoResolve (ResolveContext ec
)
110 // Only explicit parameters can be resolved at this point
112 if (HasExplicitParameters
) {
113 if (!Parameters
.Resolve (ec
))
117 eclass
= ExprClass
.Value
;
118 type
= InternalType
.AnonymousMethod
;
122 protected override AnonymousMethodBody
CompatibleMethodFactory (Type returnType
, Type delegateType
, ParametersCompiled p
, ToplevelBlock b
)
124 return new LambdaMethod (p
, b
, returnType
, delegateType
, loc
);
127 public override string GetSignatureForError ()
129 return "lambda expression";
133 public class LambdaMethod
: AnonymousMethodBody
135 public LambdaMethod (ParametersCompiled parameters
,
136 ToplevelBlock block
, Type return_type
, Type delegate_type
,
138 : base (parameters
, block
, return_type
, delegate_type
, loc
)
142 protected override void CloneTo (CloneContext clonectx
, Expression target
)
147 public override string ContainerType
{
149 return "lambda expression";
153 public override Expression
CreateExpressionTree (ResolveContext ec
)
155 BlockContext bc
= new BlockContext (ec
.MemberContext
, Block
, ReturnType
);
156 Expression args
= parameters
.CreateExpressionTree (bc
, loc
);
157 Expression expr
= Block
.CreateExpressionTree (ec
);
161 Arguments arguments
= new Arguments (2);
162 arguments
.Add (new Argument (expr
));
163 arguments
.Add (new Argument (args
));
164 return CreateExpressionFactoryCall (ec
, "Lambda",
165 new TypeArguments (new TypeExpression (type
, loc
)),
171 // This is a return statement that is prepended lambda expression bodies that happen
172 // to be expressions. Depending on the return type of the delegate this will behave
173 // as either { expr (); return (); } or { return expr (); }
175 public class ContextualReturn
: Return
177 ExpressionStatement statement
;
179 public ContextualReturn (Expression expr
)
180 : base (expr
, expr
.Location
)
184 public override Expression
CreateExpressionTree (ResolveContext ec
)
186 return Expr
.CreateExpressionTree (ec
);
189 public override void Emit (EmitContext ec
)
191 if (statement
!= null) {
192 statement
.EmitStatement (ec
);
193 ec
.ig
.Emit (OpCodes
.Ret
);
200 protected override bool DoResolve (BlockContext ec
)
203 // When delegate returns void, only expression statements can be used
205 if (ec
.ReturnType
== TypeManager
.void_type
) {
206 Expr
= Expr
.Resolve (ec
);
210 statement
= Expr
as ExpressionStatement
;
211 if (statement
== null)
212 Expr
.Error_InvalidExpressionStatement (ec
);
217 return base.DoResolve (ec
);