X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Flambda.cs;h=42a096dab1289e619b4676f6619331d48366684e;hb=cc39d7ebf1bfa8fafd6adc3a9fda354672579d1c;hp=78affab548a7b5bc630d72521a3ef22139195b6f;hpb=6a48e162a191a2086057193b507056a59e595308;p=mono.git diff --git a/mcs/mcs/lambda.cs b/mcs/mcs/lambda.cs index 78affab548a..42a096dab12 100644 --- a/mcs/mcs/lambda.cs +++ b/mcs/mcs/lambda.cs @@ -2,195 +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; - + public class LambdaExpression : AnonymousMethodExpression + { // // 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.FixedParameters [0].TypeName != null; } - public bool HasExplicitParameters { - get { - return explicit_parameters; - } - } - - public override Expression DoResolve (EmitContext ec) + protected override Expression CreateExpressionTree (ResolveContext ec, TypeSpec delegate_type) { - // - // Only explicit parameters can be resolved at this point - // - if (explicit_parameters) { - if (!Parameters.Resolve (ec)) - return null; - } + if (ec.IsInProbingMode) + return this; - eclass = ExprClass.Value; - type = TypeManager.anonymous_method_type; - return this; - } + BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, TypeManager.void_type) { + CurrentAnonymousMethod = ec.CurrentAnonymousMethod + }; - public override bool ImplicitStandardConversionExists (Type delegate_type) - { - EmitContext ec = EmitContext.TempEc; + Expression args = Parameters.CreateExpressionTree (bc, loc); + Expression expr = Block.CreateExpressionTree (ec); + if (expr == null) + return null; - bool result; + 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); + } - try { - Report.DisableErrors (); - result = DoCompatibleTest (ec, delegate_type, true) != null; - } finally { - Report.EnableErrors (); + public override bool HasExplicitParameters { + get { + return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter); } - - // Ignore the result - anonymous = null; - - return result; - } - - // - // 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) - { - return DoCompatibleTest (ec, delegate_type, false); } - Expression DoCompatibleTest (EmitContext ec, Type delegate_type, bool clone) + protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType) { - if (anonymous != null) - return anonymous.AnonymousDelegate; - - if (CompatibleChecks (ec, delegate_type) == null) + if (!delegateType.IsDelegate) 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); + AParametersCollection d_params = Delegate.GetParameters (ec.Compiler, delegateType); - // - // The lambda expression is compatible with the delegate type, - // provided that: - // + if (HasExplicitParameters) { + if (!VerifyExplicitParameters (ec, delegateType, d_params)) + return null; + + return Parameters; + } // - // D and L have the same number of arguments. - if (Parameters.Count != invoke_pd.Count) + // 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 + // + if (!VerifyParameterCompatibility (ec, delegateType, d_params, ec.IsInProbingMode)) return null; - 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, false)) + 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; - } 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 [i].TypeName = new TypeExpression ( - invoke_pd.ParameterType (i), - Parameters [i].Location); + ptypes [i] = d_param; + ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i]; + ilp.SetParameterType (d_param); + ilp.Resolve (null, i); } - return CoreCompatibilityTest (ec, clone, invoke_mb.ReturnType, delegate_type); + 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); } - Expression CoreCompatibilityTest (EmitContext ec, bool clone, Type return_type, Type delegate_type) + 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); + } - ToplevelBlock b = clone ? (ToplevelBlock) Block.PerformClone () : Block; - - anonymous = new AnonymousMethod ( - Parent != null ? Parent.AnonymousMethod : null, RootScope, Host, - GenericMethod, Parameters, Container, b, return_type, - delegate_type, loc); - - bool r; - if (clone) - r = anonymous.ResolveNoDefine (ec); - else - r = anonymous.Resolve (ec); - - // Resolution failed. - if (!r) - return null; - - return anonymous.AnonymousDelegate; + return true; } - + public override string GetSignatureForError () { return "lambda expression"; } + } - // - // TryBuild: tries to compile this LambdaExpression with the given - // types as the lambda expression parameter types. - // - // If the lambda expression successfully builds with those types, the - // return value will be the inferred type for the lambda expression, - // otherwise the result will be null. - // - public Type TryBuild (EmitContext ec, Type [] types) + 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) { - for (int i = 0; i < types.Length; i++) - Parameters [i].TypeName = new TypeExpression (types [i], Parameters [i].Location); - - Expression e; - try { - Report.DisableErrors (); - e = CoreCompatibilityTest (ec, true, null, null); - } finally { - Report.EnableErrors (); + } + + #region Properties + + public override string ContainerType { + get { + return "lambda expression"; } - - if (e == null) + } + + #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 e.Type; + + 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); } } @@ -199,70 +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 bool Resolve (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext 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; - } + return Expr.CreateExpressionTree (ec); + } - Expr = Expr.Resolve (ec); - if (Expr == null) - return false; - - if (ec.ReturnType == null){ - ec.ReturnType = Expr.Type; - } else { - if (Expr.Type != ec.ReturnType) { - Expression nExpr = Convert.ImplicitConversionRequired ( - ec, Expr, ec.ReturnType, loc); - if (nExpr == null){ - Report.Error (1662, loc, "Could not implicitly convert from {0} to {1}", - TypeManager.CSharpName (Expr.Type), - TypeManager.CSharpName (ec.ReturnType)); - return false; - } - Expr = nExpr; - } + public override void Emit (EmitContext ec) + { + if (statement != null) { + statement.EmitStatement (ec); + ec.Emit (OpCodes.Ret); + return; } - int errors = Report.Errors; - unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc); - if (unwind_protect) - ec.NeedReturnLabel (); - ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + base.Emit (ec); } - - protected override void DoEmit (EmitContext ec) + + protected override bool DoResolve (BlockContext ec) { - Expr.Emit (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; - if (unwind_protect){ - ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ()); - ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel); - } - ec.ig.Emit (OpCodes.Ret); - } + statement = Expr as ExpressionStatement; + if (statement == null) + Expr.Error_InvalidExpressionStatement (ec); - protected override void CloneTo (CloneContext clonectx, Statement t) - { - ContextualReturn cr = (ContextualReturn) t; + return true; + } - cr.Expr = Expr.Clone (clonectx); + return base.DoResolve (ec); } } }