From: Miguel de Icaza Date: Sat, 28 Apr 2007 01:47:05 +0000 (-0000) Subject: 2007-04-27 Miguel de Icaza X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=8bd7683a097d947390a824930cbd5b9615ee7f61;p=mono.git 2007-04-27 Miguel de Icaza * statement.cs (If.CloneTo): Only clone the FalseStatement if it exists. * lambda.cs (ContextualReturn.Resolve): An expression is valid inside the ContextualReturn, it does not have to be an ExpressionStatement. 2007-04-27 Miguel de Icaza * generic.cs (TypeManager.LambdaInfer): now this routine will make only one inference from the list of lambda expression that have not participated in inferring a type. (TypeManager.InferTypeArguments): The logic that drives the type inference in lambda expressions is now driven here. svn path=/trunk/mcs/; revision=76423 --- diff --git a/mcs/gmcs/ChangeLog b/mcs/gmcs/ChangeLog index 5ebaff71eff..71d2816bf0f 100644 --- a/mcs/gmcs/ChangeLog +++ b/mcs/gmcs/ChangeLog @@ -1,3 +1,12 @@ +2007-04-27 Miguel de Icaza + + * generic.cs (TypeManager.LambdaInfer): now this routine will + make only one inference from the list of lambda expression that + have not participated in inferring a type. + + (TypeManager.InferTypeArguments): The logic that drives the type + inference in lambda expressions is now driven here. + 2007-04-23 Miguel de Icaza * generic.cs: Large update to LambdaInfer, this is merely an diff --git a/mcs/gmcs/generic.cs b/mcs/gmcs/generic.cs index eb692dcafd1..bd2f6e7df2f 100644 --- a/mcs/gmcs/generic.cs +++ b/mcs/gmcs/generic.cs @@ -2418,12 +2418,16 @@ namespace Mono.CSharp { } // - // Infers the remaining inferred_types from lambda expressions contained in the - // invocation call. + // Infers the type of a single LambdaExpression in the invocation call and + // stores the infered type in the inferred_types array. + // + // The index of the arguments that contain lambdas is passed in + // + // @lambdas. Merely to avoid rescanning the list. // // The method being called: // @method_generic_args: The generic type arguments for the method being called - // @method_pd: The ParameterData for the method being called. + // @method_pd: The ParameterData for the method being called. // // The call site: // @arguments: Arraylist of Argument()s. The arguments being passed. @@ -2431,37 +2435,29 @@ namespace Mono.CSharp { // Returns: // @inferred_types: the array that is populated with our results. // - // true on success + // true if the code was able to do one inference. // static bool LambdaInfer (EmitContext ec, Type [] method_generic_args, ParameterData method_pd, ArrayList arguments, - Type[] inferred_types) + Type[] inferred_types, + ArrayList lambdas) { - int arg_count = method_pd.Count; + int last_count = lambdas.Count; + + for (int i = 0; i < last_count; i++){ + int argn = (int) lambdas [i]; - // - // TODO: track the lambads that have resulted in a type inference - // and skip over those - // - // TODO: loop until there are no lambdas left to infer values (or - // one of the conditions is not satisfied) - // - for (int argn = 0; argn < arg_count; argn++){ Argument a = (Argument) arguments [argn]; LambdaExpression le = a.Expr as LambdaExpression; - - if (a == null) - continue; - - // - // TODO: "The argument is a lambda expression, in - // the following called L, from which no inferences - // have yet been made." - // - + + if (le == null) + throw new Exception ( + String.Format ("Internal Compiler error: argument {0} should be a Lambda Expression", + argn)); + // // "The corresponding parameter’s type, in the // following called P, is a delegate type with a @@ -2470,7 +2466,7 @@ namespace Mono.CSharp { // // if (!TypeManager.IsDelegateType (method_pd.ParameterType (argn))) - continue; + goto useless_lambda; Type p_type = method_pd.ParameterType (argn); MethodGroupExpr method_group = Expression.MemberLookup ( @@ -2479,17 +2475,17 @@ namespace Mono.CSharp { if (method_group == null){ // This we report elsewhere as -200, but here we can ignore - continue; + goto useless_lambda; } MethodInfo p_delegate_method = method_group.Methods [0] as MethodInfo; if (p_delegate_method == null){ // This should not happen. - continue; + goto useless_lambda; } Type p_return_type = p_delegate_method.ReturnType; if (!p_return_type.IsGenericParameter) - continue; + goto useless_lambda; // // P and L have the same number of parameters, and @@ -2500,18 +2496,18 @@ namespace Mono.CSharp { ParameterData p_delegate_parameters = TypeManager.GetParameterData (p_delegate_method); int p_delegate_parameter_count = p_delegate_parameters.Count; if (p_delegate_parameter_count != le.Parameters.Count) - continue; + goto useless_lambda; if (le.HasExplicitParameters){ for (int j = 0; j < p_delegate_parameter_count; j++){ if (p_delegate_parameters.ParameterModifier (j) != le.Parameters.ParameterModifier (j)) - goto do_continue; + goto useless_lambda; } } else { for (int j = 0; j < p_delegate_parameter_count; j++) if (le.Parameters.ParameterModifier (j) != Parameter.Modifier.NONE) - goto do_continue; + goto useless_lambda; } // @@ -2576,19 +2572,25 @@ namespace Mono.CSharp { // If it results in a valid expression or statement block // Type lambda_inferred_type = le.TryBuild (ec, types); - //Console.WriteLine ("TryBuild: {0}", lambda_inferred_type); + if (lambda_inferred_type != null){ - //Console.WriteLine ("Able to build"); + // // Success, set the proper inferred_type value to the new type. - + // return true + // for (int k = 0; k < method_generic_args.Length; k++){ if (method_generic_args [k] == p_return_type){ inferred_types [k] = lambda_inferred_type; - break; + + lambdas.RemoveAt (i); + return true; } } } } + + useless_lambda: + lambdas.RemoveAt (i); do_continue: ; @@ -2602,7 +2604,9 @@ namespace Mono.CSharp { return false; } #endif - return true; + + // No inference was made in any of the elements. + return false; } /// @@ -2647,8 +2651,8 @@ namespace Mono.CSharp { Type[] param_types = new Type [pd.Count]; Type[] arg_types = new Type [pd.Count]; - - int lambdas = 0; + ArrayList lambdas = null; + for (int i = 0; i < arg_count; i++) { param_types [i] = pd.ParameterType (i); @@ -2656,8 +2660,11 @@ namespace Mono.CSharp { if (a.Expr is NullLiteral || a.Expr is MethodGroupExpr) continue; - if (a.Expr is LambdaExpression) - lambdas++; + if (a.Expr is LambdaExpression){ + if (lambdas == null) + lambdas = new ArrayList (); + lambdas.Add (i); + } else if (a.Expr is AnonymousMethodExpression) { if (RootContext.Version != LanguageVersion.LINQ) continue; @@ -2681,11 +2688,18 @@ namespace Mono.CSharp { if (!InferTypeArguments (param_types, arg_types, inferred_types)){ //Console.WriteLine ("InferTypeArgument found {0} lambdas ", lambdas); - if (lambdas == 0) + if (lambdas == null) return false; - if (!LambdaInfer (ec, method_generic_args, pd, arguments, inferred_types)) - return false; + // + // While the lambda expressions lead to a valid inference + // + int lambda_count; + do { + lambda_count = lambdas.Count; + if (!LambdaInfer (ec, method_generic_args, pd, arguments, inferred_types, lambdas)) + return false; + } while (lambdas.Count != 0 && lambdas.Count != lambda_count); } method = ((MethodInfo)method).MakeGenericMethod (inferred_types); diff --git a/mcs/mcs/ChangeLog b/mcs/mcs/ChangeLog index c9985edec64..8f09bc2a75b 100644 --- a/mcs/mcs/ChangeLog +++ b/mcs/mcs/ChangeLog @@ -1,3 +1,12 @@ +2007-04-27 Miguel de Icaza + + * statement.cs (If.CloneTo): Only clone the FalseStatement if it + exists. + + * lambda.cs (ContextualReturn.Resolve): An expression is valid + inside the ContextualReturn, it does not have to be an + ExpressionStatement. + 2007-04-24 Miguel de Icaza * lambda.cs (ContextualReturn.Resolve): if the return type is not diff --git a/mcs/mcs/lambda.cs b/mcs/mcs/lambda.cs index 0750dd92b30..4280da89934 100644 --- a/mcs/mcs/lambda.cs +++ b/mcs/mcs/lambda.cs @@ -234,10 +234,6 @@ namespace Mono.CSharp { return false; if (ec.ReturnType == null){ - if (!(Expr is ExpressionStatement)){ - Expression.Error_InvalidExpressionStatement (Expr.Location); - return false; - } ec.ReturnType = Expr.Type; } else { if (Expr.Type != ec.ReturnType) { diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index da5b4b10dc8..7aa6aaf5a8e 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -325,7 +325,8 @@ namespace Mono.CSharp { target.expr = expr.Clone (clonectx); target.TrueStatement = TrueStatement.Clone (clonectx); - target.FalseStatement = FalseStatement.Clone (clonectx); + if (FalseStatement != null) + target.FalseStatement = FalseStatement.Clone (clonectx); } } diff --git a/mcs/tests/ltest-3.cs b/mcs/tests/ltest-3.cs index b13b7697409..86e0fa2b269 100644 --- a/mcs/tests/ltest-3.cs +++ b/mcs/tests/ltest-3.cs @@ -1,3 +1,5 @@ +// Compiler options: -langversion:linq + using System; public delegate TResult Func (TArg0 arg0); class Demo { diff --git a/mcs/tests/ltest-4.cs b/mcs/tests/ltest-4.cs new file mode 100644 index 00000000000..d7715297cfc --- /dev/null +++ b/mcs/tests/ltest-4.cs @@ -0,0 +1,30 @@ +// Compiler options: -langversion:linq +// +// This test is used to test the type information flow between arguments +// in a generic method invocation, where: +// +// 1. We first infer the type of X from the first argument to F +// +// 2. We use this information to infer from the type of f1 and Func +// that X is a TimeSpan. +// +// 3. Use the X=String and Y=TimeSpan to infer the value for Z +// which is double +// + +using System; +public delegate TResult Func (TArg0 arg0); + +class Demo { + static Z F(X value, Func f1, Func f2) + { + return f2 (f1(value)); + } + static int Main () + { + double d = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds); + if (d < 4529 || d > 4531) + return 1; + return 0; + } +}