2007-04-27 Miguel de Icaza <miguel@novell.com>
authorMiguel de Icaza <miguel@gnome.org>
Sat, 28 Apr 2007 01:47:05 +0000 (01:47 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Sat, 28 Apr 2007 01:47:05 +0000 (01:47 -0000)
* 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  <miguel@novell.com>

* 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

mcs/gmcs/ChangeLog
mcs/gmcs/generic.cs
mcs/mcs/ChangeLog
mcs/mcs/lambda.cs
mcs/mcs/statement.cs
mcs/tests/ltest-3.cs
mcs/tests/ltest-4.cs [new file with mode: 0644]

index 5ebaff71eff87161e76fa963ffb80ab132684947..71d2816bf0fe63775a61a7cae81d756f1045777b 100644 (file)
@@ -1,3 +1,12 @@
+2007-04-27  Miguel de Icaza  <miguel@novell.com>
+
+       * 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  <miguel@novell.com>
 
        * generic.cs: Large update to LambdaInfer, this is merely an
index eb692dcafd16a9b15a7ee99e03bb9a5bcc82b5b2..bd2f6e7df2f80bfd03180e8af017eba68f70fcb6 100644 (file)
@@ -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;
                }
        
                /// <summary>
@@ -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);
index c9985edec645e2b30628f48d1a8bb2198f018915..8f09bc2a75baa9ac6e859a05c8aeb93f4eaa0595 100644 (file)
@@ -1,3 +1,12 @@
+2007-04-27  Miguel de Icaza  <miguel@novell.com>
+
+       * 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  <miguel@novell.com>
 
        * lambda.cs (ContextualReturn.Resolve): if the return type is not
index 0750dd92b30ece98b807aa15852e9f83d7043fd3..4280da89934c94f8593882ee691b36f6388f4393 100644 (file)
@@ -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) {
index da5b4b10dc8bc2684563a0d1203e43742a0087b6..7aa6aaf5a8ee6de304d064432a716cc6d891af61 100644 (file)
@@ -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);
                }
        }
 
index b13b7697409bdf59886ebe57f1301db009cba55f..86e0fa2b269616e75a532cef7ebcede6444b0e56 100644 (file)
@@ -1,3 +1,5 @@
+// Compiler options: -langversion:linq
+
 using System;
 public delegate TResult Func<TArg0, TResult> (TArg0 arg0);
 class Demo {
diff --git a/mcs/tests/ltest-4.cs b/mcs/tests/ltest-4.cs
new file mode 100644 (file)
index 0000000..d771529
--- /dev/null
@@ -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, TResult> (TArg0 arg0);
+
+class Demo {
+       static Z F<X,Y,Z>(X value, Func<X,Y> f1, Func<Y,Z> 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;
+       }
+}