X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Flambda.cs;h=42a096dab1289e619b4676f6619331d48366684e;hb=cc39d7ebf1bfa8fafd6adc3a9fda354672579d1c;hp=283f3bdbd0c319477a1c723a8abf9e543d437fc6;hpb=6f733d05c2435bec596fbc357fd4c62219d57622;p=mono.git diff --git a/mcs/mcs/lambda.cs b/mcs/mcs/lambda.cs index 283f3bdbd0c..42a096dab12 100644 --- a/mcs/mcs/lambda.cs +++ b/mcs/mcs/lambda.cs @@ -2,143 +2,165 @@ // 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; -using System.Collections; using System.Reflection; using System.Reflection.Emit; namespace Mono.CSharp { - public class LambdaExpression : AnonymousMethodExpression { - 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. - // - Expression lambda_expr; - + public class LambdaExpression : AnonymousMethodExpression + { // - // The parameter list can either be: - // null: no parameters - // arraylist of Parameter (explicitly typed parameters) - // arraylist of strings (implicitly typed parameters) + // The parameters can either be: + // A list of Parameters (explicitly typed parameters) + // An ImplicitLambdaParameter // - public LambdaExpression (AnonymousMethodExpression parent, - GenericMethod generic, TypeContainer host, - Parameters parameters, Block container, - Location loc) - : base (parent, generic, host, parameters, container, loc) + public LambdaExpression (Location loc) + : base (loc) { - explicit_parameters = (parameters != null && parameters.Count > 0 && parameters [0].TypeName != null); - if (parameters == null) - Parameters = new Parameters (new Parameter [0]); } - public void SetExpression (Expression expr) + protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type) { - lambda_expr = expr; + if (ec.IsInProbingMode) + return this; + + BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, TypeManager.void_type) { + CurrentAnonymousMethod = ec.CurrentAnonymousMethod + }; + + Expression args = Parameters.CreateExpressionTree (bc, loc); + Expression expr = Block.CreateExpressionTree (ec); + if (expr == null) + return null; + + Arguments arguments = new Arguments (2); + arguments.Add (new Argument (expr)); + arguments.Add (new Argument (args)); + return CreateExpressionFactoryCall (ec, "Lambda", + new TypeArguments (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 Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter); } - - // We will resolve parameters later, we do not - // have information at this point. - - return this; } - public override void Emit (EmitContext ec) + protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType) { - base.Emit (ec); - } + if (!delegateType.IsDelegate) + 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; + AParametersCollection d_params = Delegate.GetParameters (ec.Compiler, delegateType); - if (CompatibleChecks (ec, delegate_type) == null) - return null; + if (HasExplicitParameters) { + if (!VerifyExplicitParameters (ec, delegateType, d_params)) + 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 (ec, 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)) + TypeSpec [] ptypes = new TypeSpec [Parameters.Count]; + for (int i = 0; i < d_params.Count; i++) { + // D has no ref or out parameters + if ((d_params.FixedParameters [i].ModFlags & 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. + TypeSpec d_param = d_params.Types [i]; // - // each parameter of L is given the type of the corresponding parameter in D + // When type inference context exists try to apply inferred type arguments // + if (tic != null) { + d_param = tic.InflateGenericArgument (d_param); + } - for (int i = 0; i < invoke_pd.Count; i++) - parameters_copy [i].TypeName = new TypeExpression ( - invoke_pd.ParameterType (i), - parameters_copy [i].Location); + ptypes [i] = d_param; + ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i]; + ilp.SetParameterType (d_param); + ilp.Resolve (null, i); } + Parameters.Types = ptypes; + return Parameters; + } + + protected override AnonymousMethodBody CompatibleMethodFactory (TypeSpec returnType, TypeSpec delegateType, ParametersCompiled p, ParametersBlock b) + { + return new LambdaMethod (p, b, returnType, delegateType, loc); + } + + protected override bool DoResolveParameters (ResolveContext rc) + { // - // 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 (HasExplicitParameters) { + return Parameters.Resolve (rc); + } - anonymous = new AnonymousMethod ( - Parent != null ? Parent.AnonymousMethod : null, RootScope, Host, - GenericMethod, parameters_copy, Container, Block, invoke_mb.ReturnType, - delegate_type, loc); + return true; + } + + public override string GetSignatureForError () + { + return "lambda expression"; + } + } + + class LambdaMethod : AnonymousMethodBody + { + public LambdaMethod (ParametersCompiled parameters, + ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type, + Location loc) + : base (parameters, block, return_type, delegate_type, loc) + { + } + + #region Properties - if (!anonymous.Resolve (ec)) + public override string ContainerType { + get { + return "lambda expression"; + } + } + + #endregion + + protected override void CloneTo (CloneContext clonectx, Expression target) + { + // TODO: nothing ?? + } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + BlockContext bc = new BlockContext (ec.MemberContext, Block, ReturnType); + Expression args = parameters.CreateExpressionTree (bc, loc); + Expression expr = Block.CreateExpressionTree (ec); + if (expr == null) return null; - return anonymous.AnonymousDelegate; + Arguments arguments = new Arguments (2); + arguments.Add (new Argument (expr)); + arguments.Add (new Argument (args)); + return CreateExpressionFactoryCall (ec, "Lambda", + new TypeArguments (new TypeExpression (type, loc)), + arguments); } } @@ -147,62 +169,49 @@ 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 + { + ExpressionStatement statement; + + public ContextualReturn (Expression expr) + : base (expr, expr.Location) { - Expr = e; - loc = Expr.Location; } - bool unwind_protect; + public override Expression CreateExpressionTree (ResolveContext 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 (statement != null) { + statement.EmitStatement (ec); + ec.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 (BlockContext 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; - } - } - 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); + statement = Expr as ExpressionStatement; + if (statement == null) + Expr.Error_InvalidExpressionStatement (ec); + + return true; + } - 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); } - } }