X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Flambda.cs;h=b11dc6000e254d2c8c6beec1f9ce9445c9891e56;hb=cdc4a8b84e0d6bd22f43e5e12243c68a0eb68658;hp=283f3bdbd0c319477a1c723a8abf9e543d437fc6;hpb=6f733d05c2435bec596fbc357fd4c62219d57622;p=mono.git diff --git a/mcs/mcs/lambda.cs b/mcs/mcs/lambda.cs index 283f3bdbd0c..b11dc6000e2 100644 --- a/mcs/mcs/lambda.cs +++ b/mcs/mcs/lambda.cs @@ -2,10 +2,11 @@ // lambda.cs: support for lambda expressions // // Authors: Miguel de Icaza (miguel@gnu.org) +// Marek Safar (marek.safar@gmail.com) // -// Licensed under the terms of the GNU GPL +// Dual licensed under the terms of the MIT X11 or GNU GPL // -// (C) 2007 Novell, Inc +// Copyright 2007-2008 Novell, Inc // using System; @@ -14,131 +15,153 @@ using System.Reflection; using System.Reflection.Emit; namespace Mono.CSharp { - public class LambdaExpression : AnonymousMethodExpression { - bool explicit_parameters; + public class LambdaExpression : AnonymousMethodExpression + { + readonly bool explicit_parameters; // - // If set, this was a lambda expression with an expression - // argument. And if so, we have a pointer to it, so we can - // change it if needed. + // The parameters can either be: + // A list of Parameters (explicitly typed parameters) + // An ImplicitLambdaParameter // - Expression lambda_expr; - - // - // The parameter list can either be: - // null: no parameters - // arraylist of Parameter (explicitly typed parameters) - // arraylist of strings (implicitly typed parameters) - // - public LambdaExpression (AnonymousMethodExpression parent, - GenericMethod generic, TypeContainer host, - Parameters parameters, Block container, - Location loc) - : base (parent, generic, host, parameters, container, loc) + public LambdaExpression (TypeContainer host, Parameters parameters, Location loc) + : base (host, parameters, loc) { - explicit_parameters = (parameters != null && parameters.Count > 0 && parameters [0].TypeName != null); - if (parameters == null) - Parameters = new Parameters (new Parameter [0]); + if (parameters.Count > 0) + explicit_parameters = !(parameters.FixedParameters [0] is ImplicitLambdaParameter); } - public void SetExpression (Expression expr) + protected override Expression CreateExpressionTree (EmitContext ec, Type delegate_type) { - lambda_expr = expr; + if (ec.IsInProbingMode) + return this; + + Expression args = Parameters.CreateExpressionTree (ec, loc); + Expression expr = Block.CreateExpressionTree (ec); + if (expr == null) + return null; + + ArrayList arguments = new ArrayList (2); + arguments.Add (new Argument (expr)); + arguments.Add (new Argument (args)); + return CreateExpressionFactoryCall ("Lambda", + new TypeArguments (loc, new TypeExpression (delegate_type, loc)), + arguments); } - - public override Expression DoResolve (EmitContext ec) - { - eclass = ExprClass.Value; - type = TypeManager.anonymous_method_type; - if (explicit_parameters){ - if (!Parameters.Resolve (ec)) - return null; + public override bool HasExplicitParameters { + get { + return explicit_parameters; } - - // We will resolve parameters later, we do not - // have information at this point. - - return this; } - public override void Emit (EmitContext ec) + protected override Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegateType) { - base.Emit (ec); - } + if (!TypeManager.IsDelegateType (delegateType)) + return null; - // - // Returns true if this anonymous method can be implicitly - // converted to the delegate type `delegate_type' - // - public override Expression Compatible (EmitContext ec, Type delegate_type) - { - if (anonymous != null) - return anonymous.AnonymousDelegate; + ParameterData d_params = TypeManager.GetDelegateParameters (delegateType); - if (CompatibleChecks (ec, delegate_type) == null) - return null; + if (explicit_parameters) { + if (!VerifyExplicitParameters (delegateType, d_params, ec.IsInProbingMode)) + return null; - MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod ( - ec.ContainerType, delegate_type, loc); - MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0]; - ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb); + return Parameters; + } // - // The lambda expression is compatible with the delegate type, - // provided that: + // If L has an implicitly typed parameter list we make implicit parameters explicit + // Set each parameter of L is given the type of the corresponding parameter in D // - - // - // D and L have the same number of arguments. - if (Parameters.Count != invoke_pd.Count) + if (!VerifyParameterCompatibility (delegateType, d_params, ec.IsInProbingMode)) return null; - Parameters parameters_copy = Parameters.Clone (); - if (explicit_parameters){ - // - // If L has an explicitly typed parameter list, each parameter - // in D has the same type and modifiers as the corresponding - // parameter in L. - // - if (!VerifyExplicitParameterCompatibility (delegate_type, invoke_pd)) + if (Parameters.Types == null) + Parameters.Types = new Type [Parameters.Count]; + + for (int i = 0; i < d_params.Count; i++) { + // D has no ref or out parameters + if ((d_params.ParameterModifier (i) & Parameter.Modifier.ISBYREF) != 0) return null; - parameters_copy = Parameters.Clone (); - } else { - // - // If L has an implicitly typed parameter list, D has no ref or - // out parameters - // - // Note: We currently do nothing, because the preview does not - // follow the above rule. - - // - // each parameter of L is given the type of the corresponding parameter in D - // - - for (int i = 0; i < invoke_pd.Count; i++) - parameters_copy [i].TypeName = new TypeExpression ( - invoke_pd.ParameterType (i), - parameters_copy [i].Location); + Type d_param = d_params.Types [i]; + +#if MS_COMPATIBLE + // Blablabla, because reflection does not work with dynamic types + if (d_param.IsGenericParameter) + d_param = delegateType.GetGenericArguments () [d_param.GenericParameterPosition]; +#endif + // When inferred context exists all generics parameters have type replacements + if (tic != null) { + d_param = tic.InflateGenericArgument (d_param); + } + + Parameters.Types [i] = Parameters.FixedParameters[i].ParameterType = d_param; } + return Parameters; + } + public override Expression DoResolve (EmitContext ec) + { // - // The return type of the delegate must be compatible with - // the anonymous type. Instead of doing a pass to examine the block - // we satisfy the rule by setting the return type on the EmitContext - // to be the delegate type return type. + // Only explicit parameters can be resolved at this point // + if (explicit_parameters) { + if (!Parameters.Resolve (ec)) + return null; + } - anonymous = new AnonymousMethod ( - Parent != null ? Parent.AnonymousMethod : null, RootScope, Host, - GenericMethod, parameters_copy, Container, Block, invoke_mb.ReturnType, - delegate_type, loc); + eclass = ExprClass.Value; + type = TypeManager.anonymous_method_type; + return this; + } + + protected override AnonymousMethodBody CompatibleMethodFactory (Type returnType, Type delegateType, Parameters p, ToplevelBlock b) + { + return new LambdaMethod (Host, + p, b, returnType, + delegateType, loc); + } + + public override string GetSignatureForError () + { + return "lambda expression"; + } + } - if (!anonymous.Resolve (ec)) + public class LambdaMethod : AnonymousMethodBody + { + public LambdaMethod (TypeContainer host, Parameters parameters, + ToplevelBlock block, Type return_type, Type delegate_type, + Location loc) + : base (host, parameters, block, return_type, delegate_type, loc) + { + } + + public override string ContainerType { + get { + return "lambda expression"; + } + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + // + // Remove IL method implementation when expression tree is requested + // + method.Parent.PartialContainer.RemoveMethod (method); + + Expression args = parameters.CreateExpressionTree (ec, loc); + Expression expr = Block.CreateExpressionTree (ec); + if (expr == null) return null; - return anonymous.AnonymousDelegate; + ArrayList arguments = new ArrayList (2); + arguments.Add (new Argument (expr)); + arguments.Add (new Argument (args)); + return CreateExpressionFactoryCall ("Lambda", + new TypeArguments (loc, new TypeExpression (type, loc)), + arguments); } } @@ -147,62 +170,47 @@ namespace Mono.CSharp { // to be expressions. Depending on the return type of the delegate this will behave // as either { expr (); return (); } or { return expr (); } // - public class ContextualReturn : Statement { - public Expression Expr; - - public ContextualReturn (Expression e) + public class ContextualReturn : Return + { + public ContextualReturn (Expression expr) + : base (expr, expr.Location) { - Expr = e; - loc = Expr.Location; } - bool unwind_protect; + public override Expression CreateExpressionTree (EmitContext ec) + { + return Expr.CreateExpressionTree (ec); + } - public override bool Resolve (EmitContext ec) + public override void Emit (EmitContext ec) { - AnonymousContainer am = ec.CurrentAnonymousMethod; - if ((am != null) && am.IsIterator && ec.InIterator) { - Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + - "statement to return a value, or yield break to end the iteration"); - return false; + if (ec.ReturnType == TypeManager.void_type) { + ((ExpressionStatement) Expr).EmitStatement (ec); + ec.ig.Emit (OpCodes.Ret); + return; } - Expr = Expr.Resolve (ec); - if (Expr == null) - return false; + base.Emit (ec); + } - if (ec.ReturnType == null){ - if (!(Expr is ExpressionStatement)){ - Expression.Error_InvalidExpressionStatement (Expr.Location); + protected override bool DoResolve (EmitContext ec) + { + // + // When delegate returns void, only expression statements can be used + // + if (ec.ReturnType == TypeManager.void_type) { + Expr = Expr.Resolve (ec); + if (Expr == null) return false; - } - } else { - if (Expr.Type != ec.ReturnType) { - Expr = Convert.ImplicitConversionRequired ( - ec, Expr, ec.ReturnType, loc); - if (Expr == null) - return false; - } + + if (Expr is ExpressionStatement) + return true; + + Expr.Error_InvalidExpressionStatement (); + return false; } - int errors = Report.Errors; - unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc); - if (unwind_protect) - ec.NeedReturnLabel (); - ec.CurrentBranching.CurrentUsageVector.Return (); - return errors == Report.Errors; - } - - protected override void DoEmit (EmitContext ec) - { - Expr.Emit (ec); - - if (unwind_protect){ - ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ()); - ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel); - } - ec.ig.Emit (OpCodes.Ret); + return base.DoResolve (ec); } - } }