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 (EmitContext ec
, Type delegate_type
)
32 if (ec
.IsInProbingMode
)
35 Expression args
= Parameters
.CreateExpressionTree (ec
, loc
);
36 Expression expr
= Block
.CreateExpressionTree (ec
);
40 Arguments arguments
= new Arguments (2);
41 arguments
.Add (new Argument (expr
));
42 arguments
.Add (new Argument (args
));
43 return CreateExpressionFactoryCall ("Lambda",
44 new TypeArguments (new TypeExpression (delegate_type
, loc
)),
48 public override bool HasExplicitParameters
{
50 return Parameters
.Count
> 0 && !(Parameters
.FixedParameters
[0] is ImplicitLambdaParameter
);
54 protected override ParametersCompiled
ResolveParameters (EmitContext ec
, TypeInferenceContext tic
, Type delegateType
)
56 if (!TypeManager
.IsDelegateType (delegateType
))
59 AParametersCollection d_params
= TypeManager
.GetDelegateParameters (delegateType
);
61 if (HasExplicitParameters
) {
62 if (!VerifyExplicitParameters (delegateType
, d_params
, ec
.IsInProbingMode
))
69 // If L has an implicitly typed parameter list we make implicit parameters explicit
70 // Set each parameter of L is given the type of the corresponding parameter in D
72 if (!VerifyParameterCompatibility (delegateType
, d_params
, ec
.IsInProbingMode
))
75 Type
[] ptypes
= new Type
[Parameters
.Count
];
76 for (int i
= 0; i
< d_params
.Count
; i
++) {
77 // D has no ref or out parameters
78 if ((d_params
.FixedParameters
[i
].ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0)
81 Type d_param
= d_params
.Types
[i
];
84 // Blablabla, because reflection does not work with dynamic types
85 if (d_param
.IsGenericParameter
)
86 d_param
= delegateType
.GetGenericArguments () [d_param
.GenericParameterPosition
];
89 // When type inference context exists try to apply inferred type arguments
92 d_param
= tic
.InflateGenericArgument (d_param
);
96 ((ImplicitLambdaParameter
) Parameters
.FixedParameters
[i
]).Type
= d_param
;
99 Parameters
.Types
= ptypes
;
103 public override Expression
DoResolve (EmitContext ec
)
106 // Only explicit parameters can be resolved at this point
108 if (HasExplicitParameters
) {
109 if (!Parameters
.Resolve (ec
))
113 eclass
= ExprClass
.Value
;
114 type
= InternalType
.AnonymousMethod
;
118 protected override AnonymousMethodBody
CompatibleMethodFactory (Type returnType
, Type delegateType
, ParametersCompiled p
, ToplevelBlock b
)
120 return new LambdaMethod (p
, b
, returnType
, delegateType
, loc
);
123 public override string GetSignatureForError ()
125 return "lambda expression";
129 public class LambdaMethod
: AnonymousMethodBody
131 public LambdaMethod (ParametersCompiled parameters
,
132 ToplevelBlock block
, Type return_type
, Type delegate_type
,
134 : base (parameters
, block
, return_type
, delegate_type
, loc
)
138 protected override void CloneTo (CloneContext clonectx
, Expression target
)
143 public override string ContainerType
{
145 return "lambda expression";
149 public override Expression
CreateExpressionTree (EmitContext ec
)
151 Expression args
= parameters
.CreateExpressionTree (ec
, loc
);
152 Expression expr
= Block
.CreateExpressionTree (ec
);
156 Arguments arguments
= new Arguments (2);
157 arguments
.Add (new Argument (expr
));
158 arguments
.Add (new Argument (args
));
159 return CreateExpressionFactoryCall ("Lambda",
160 new TypeArguments (new TypeExpression (type
, loc
)),
166 // This is a return statement that is prepended lambda expression bodies that happen
167 // to be expressions. Depending on the return type of the delegate this will behave
168 // as either { expr (); return (); } or { return expr (); }
170 public class ContextualReturn
: Return
172 public ContextualReturn (Expression expr
)
173 : base (expr
, expr
.Location
)
177 public override Expression
CreateExpressionTree (EmitContext ec
)
179 return Expr
.CreateExpressionTree (ec
);
182 public override void Emit (EmitContext ec
)
184 if (ec
.ReturnType
== TypeManager
.void_type
) {
185 ((ExpressionStatement
) Expr
).EmitStatement (ec
);
186 ec
.ig
.Emit (OpCodes
.Ret
);
193 protected override bool DoResolve (EmitContext ec
)
196 // When delegate returns void, only expression statements can be used
198 if (ec
.ReturnType
== TypeManager
.void_type
) {
199 Expr
= Expr
.Resolve (ec
);
203 if (Expr
is ExpressionStatement
)
206 Expr
.Error_InvalidExpressionStatement ();
210 return base.DoResolve (ec
);