X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Flambda.cs;h=42a096dab1289e619b4676f6619331d48366684e;hb=cc39d7ebf1bfa8fafd6adc3a9fda354672579d1c;hp=b79065d449ac809122d0743f114ed1929c12d46e;hpb=fe397c8c424f449af8f286f5259791b54e1a152f;p=mono.git diff --git a/mcs/mcs/lambda.cs b/mcs/mcs/lambda.cs index b79065d449a..42a096dab12 100644 --- a/mcs/mcs/lambda.cs +++ b/mcs/mcs/lambda.cs @@ -2,194 +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; - } - - eclass = ExprClass.Value; - type = TypeManager.anonymous_method_type; - return this; - } - - // - // Returns true if the body of lambda expression can be implicitly - // converted to the delegate of type `delegate_type' - // - public override bool ImplicitStandardConversionExists (Type delegate_type) - { - EmitContext ec = EmitContext.TempEc; + if (ec.IsInProbingMode) + return this; - using (ec.Set (EmitContext.Flags.ProbingMode)) { - bool r = DoImplicitStandardConversion (ec, delegate_type) != null; + BlockContext bc = new BlockContext (ec.MemberContext, ec.ConstructorBlock, TypeManager.void_type) { + CurrentAnonymousMethod = ec.CurrentAnonymousMethod + }; - // Ignore the result - anonymous = null; + Expression args = Parameters.CreateExpressionTree (bc, loc); + Expression expr = Block.CreateExpressionTree (ec); + if (expr == null) + return null; - return r; - } + 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); } - - // - // 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; - return DoImplicitStandardConversion (ec, delegate_type); + public override bool HasExplicitParameters { + get { + return Parameters.Count > 0 && !(Parameters.FixedParameters [0] is ImplicitLambdaParameter); + } } - Expression DoImplicitStandardConversion (EmitContext ec, Type delegate_type) + protected override ParametersCompiled ResolveParameters (ResolveContext ec, TypeInferenceContext tic, TypeSpec delegateType) { - 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 { + + TypeSpec d_param = d_params.Types [i]; + // - // If L has an implicitly typed parameter list + // When type inference context exists try to apply inferred type arguments // - for (int i = 0; i < invoke_pd.Count; i++) { - // D has no ref or out parameters - if ((invoke_pd.ParameterModifier (i) & Parameter.Modifier.ISBYREF) != 0) - return null; - - // - // Makes implicit parameters explicit - // Set each parameter of L is given the type of the corresponding parameter in D - // - Parameters[i].ParameterType = invoke_pd.Types[i]; - + if (tic != null) { + d_param = tic.InflateGenericArgument (d_param); } + + ptypes [i] = d_param; + ImplicitLambdaParameter ilp = (ImplicitLambdaParameter) Parameters.FixedParameters [i]; + ilp.SetParameterType (d_param); + ilp.Resolve (null, i); } - return CoreCompatibilityTest (ec, 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, 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 = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block; + return true; + } - anonymous = new AnonymousMethod ( - Parent != null ? Parent.AnonymousMethod : null, RootScope, Host, - GenericMethod, Parameters, Container, b, return_type, - delegate_type, loc); + public override string GetSignatureForError () + { + return "lambda expression"; + } + } - bool r; - if (ec.IsInProbingMode) - r = anonymous.ResolveNoDefine (ec); - else - r = anonymous.Resolve (ec); + 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) + { + } - // Resolution failed. - if (!r) - return null; + #region Properties - return anonymous.AnonymousDelegate; + public override string ContainerType { + get { + return "lambda expression"; + } } - - public override string GetSignatureForError () + + #endregion + + protected override void CloneTo (CloneContext clonectx, Expression target) { - return "lambda expression"; + // TODO: nothing ?? } - // - // 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) + public override Expression CreateExpressionTree (ResolveContext ec) { - for (int i = 0; i < types.Length; i++) - Parameters [i].TypeName = new TypeExpression (types [i], Parameters [i].Location); - - // TODO: temporary hack - ec.InferReturnType = true; - - Expression e; - using (ec.Set (EmitContext.Flags.ProbingMode)) { - e = CoreCompatibilityTest (ec, null, null); - } - - if (e == null) + 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); } } @@ -197,12 +168,50 @@ namespace Mono.CSharp { // This is a return statement that is prepended lambda expression bodies that happen // to be expressions. Depending on the return type of the delegate this will behave // as either { expr (); return (); } or { return expr (); } - + // public class ContextualReturn : Return { + ExpressionStatement statement; + public ContextualReturn (Expression expr) : base (expr, expr.Location) { } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + return Expr.CreateExpressionTree (ec); + } + + public override void Emit (EmitContext ec) + { + if (statement != null) { + statement.EmitStatement (ec); + ec.Emit (OpCodes.Ret); + return; + } + + base.Emit (ec); + } + + 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; + + statement = Expr as ExpressionStatement; + if (statement == null) + Expr.Error_InvalidExpressionStatement (ec); + + return true; + } + + return base.DoResolve (ec); + } } }