Author: miguel
Date: 2008-01-21 01:05:28 -0500 (Mon, 21 Jan 2008)
New Revision: 93369

Modified:
   trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs
   trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog
   trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs
   trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs
   
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Add.cs
   
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Lambda.cs
Log:
2008-01-21  Miguel de Icaza  <[EMAIL PROTECTED]>

        * Start code generation for nullables, currently this generates
        incorrect code for things like:
        
        Expression<Func<int?, int?, int?>> e2 = (a, b) => a + b;
        e2.Compile ().Invoke (null, 3))

        This should return null, but returns something else.

        * Introduce LINQ_DBG env variable, which generates a linq file in
        /tmp;   It currently does not work as well as it should, as the
        Func<> parameters do not mwatch the generated method.
        Investigate. 



Modified: 
trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs     
2008-01-21 00:45:16 UTC (rev 93368)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs     
2008-01-21 06:05:28 UTC (rev 93369)
@@ -105,14 +105,71 @@
                        return t == typeof (ushort) || t == typeof (uint) || t 
== typeof (ulong) || t == typeof (byte);
                }
 
+               static void EmitMethod ()
+               {
+                       throw new NotImplementedException ("Support for 
MethodInfo-based BinaryExpressions not yet supported");
+               }
+
+               static MethodInfo GetMethodNoPar (Type t, string name)
+               {
+                       MethodInfo [] methods = t.GetMethods ();
+                       foreach (MethodInfo m in methods){
+                               if (m.Name != name)
+                                       continue;
+                               if (m.GetParameters ().Length == 0)
+                                       return m;
+                       }
+                       throw new Exception (String.Format ("Internal error: 
method {0} with no parameters not found on {1}",
+                                                           name, t));
+               }
+               
                internal override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        OpCode opcode;
 
-                       left.Emit (ec);
-                       right.Emit (ec);
+                       if (method != null){
+                               EmitMethod ();
+                               return;
+                       }
 
+                       Label? empty_value = null;
+                       LocalBuilder ret = null;
+
+                       if (IsLifted){
+                               LocalBuilder vleft, vright;
+
+                               empty_value = ig.DefineLabel ();
+                               ret = ig.DeclareLocal (Type);
+                               
+                               vleft = ig.DeclareLocal (left.Type);
+                               left.Emit (ec);
+                               ig.Emit (OpCodes.Stloc, vleft);
+
+                               vright = ig.DeclareLocal (right.Type);
+                               right.Emit (ec);
+                               ig.Emit (OpCodes.Stloc, vright);
+
+                               MethodInfo has_value = left.Type.GetMethod 
("get_HasValue");
+                               
+                               ig.Emit (OpCodes.Ldloca, vleft);
+                               ig.Emit (OpCodes.Call, has_value);
+                               ig.Emit (OpCodes.Brfalse, empty_value.Value);
+                               ig.Emit (OpCodes.Ldloca, vright);
+                               ig.Emit (OpCodes.Call, has_value);
+                               ig.Emit (OpCodes.Brfalse, empty_value.Value);
+
+                               MethodInfo get_value_or_default = 
GetMethodNoPar (left.Type, "GetValueOrDefault");
+                               
+                               ig.Emit (OpCodes.Ldloca, vleft);
+                               ig.Emit (OpCodes.Call, get_value_or_default);
+                               ig.Emit (OpCodes.Ldloca, vright);
+                               ig.Emit (OpCodes.Call, get_value_or_default);
+                       } else {
+                               left.Emit (ec);
+                               right.Emit (ec);
+                       }
+
                        bool is_unsigned = IsUnsigned (left.Type);
 
                        switch (NodeType){
@@ -208,6 +265,20 @@
                                throw new Exception (String.Format ("Internal 
error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
                        }
                        ig.Emit (opcode);
+
+                       if (IsLifted){
+                               Label skip = ig.DefineLabel ();
+                               ig.Emit (OpCodes.Br, skip);
+                               ig.MarkLabel (empty_value.Value);
+                               ig.Emit (OpCodes.Ldloc, ret);
+                               ig.Emit (OpCodes.Initobj, Type);
+                               Label end = ig.DefineLabel ();
+                               ig.Emit (OpCodes.Br, end);
+                               
+                               ig.MarkLabel (skip);
+                               ig.Emit (OpCodes.Newobj, 
left.Type.GetConstructors ()[0]);
+                               ig.MarkLabel (end);
+                       }
                }
        }
 }

Modified: trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog       
2008-01-21 00:45:16 UTC (rev 93368)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog       
2008-01-21 06:05:28 UTC (rev 93369)
@@ -1,3 +1,19 @@
+2008-01-21  Miguel de Icaza  <[EMAIL PROTECTED]>
+
+       * Start code generation for nullables, currently this generates
+       incorrect code for things like:
+       
+       Expression<Func<int?, int?, int?>> e2 = (a, b) => a + b;
+       e2.Compile ().Invoke (null, 3))
+
+       This should return null, but returns something else.
+
+       * Introduce LINQ_DBG env variable, which generates a linq file in
+       /tmp;   It currently does not work as well as it should, as the
+       Func<> parameters do not mwatch the generated method.
+       Investigate. 
+       
+
 2008-01-20  Miguel de Icaza  <[EMAIL PROTECTED]>
 
        Introduce support for Nullable arguments, no code is generated for

Modified: trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs   
2008-01-21 00:45:16 UTC (rev 93368)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs   
2008-01-21 06:05:28 UTC (rev 93369)
@@ -277,8 +277,23 @@
                static BinaryExpression MakeSimpleBinary (ExpressionType et, 
Expression left, Expression right, MethodInfo method)
                {
                        Type result = method == null ? left.Type : 
method.ReturnType;
-
-                       return new BinaryExpression (et, result, left, right, 
method);
+                       bool is_lifted;
+                       
+                       if (method == null){
+                               if (IsNullable (left.Type)){
+                                       if (!IsNullable (right.Type))
+                                               throw new Exception 
("Assertion, internal error: left is nullable, requires right to be as well");
+                                       is_lifted = true;
+                               } else
+                                       is_lifted = false;
+                       } else {
+                               //
+                               // FIXME: implement
+                               //
+                               is_lifted = false;
+                       }
+                       
+                       return new BinaryExpression (et, result, left, right, 
false, is_lifted, method, null);
                }
 
                static UnaryExpression MakeSimpleUnary (ExpressionType et, 
Expression expression, MethodInfo method)

Modified: 
trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs     
2008-01-21 00:45:16 UTC (rev 93368)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs     
2008-01-21 06:05:28 UTC (rev 93369)
@@ -32,6 +32,7 @@
 using System.Collections.Generic;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Threading;
 
 namespace System.Linq.Expressions {
 
@@ -40,6 +41,11 @@
                internal Type [] ParamTypes;
                internal DynamicMethod Method;
                internal ILGenerator ig;
+
+               // When debugging:
+               internal AssemblyBuilder ab;
+               internal TypeBuilder tb;
+               internal MethodBuilder mb;
                
                static object mlock = new object ();
                static int method_count;
@@ -70,12 +76,39 @@
                        // FIXME: Need to force this to be verifiable, see:
                        // https://bugzilla.novell.com/show_bug.cgi?id=355005
                        //
-                       Method = new DynamicMethod (GenName (), Owner.Type, 
ParamTypes, owner_of_code);
-                       ig = Method.GetILGenerator ();
+                       string name = GenName ();
+                       if (Environment.GetEnvironmentVariable ("LINQ_DBG") != 
null){
+                               string fname = "linq" + (method_count-1) + 
".dll";
+                               ab = Thread.GetDomain ().DefineDynamicAssembly 
(new AssemblyName (fname),
+                                                                               
AssemblyBuilderAccess.RunAndSave, "/tmp");
+                               ModuleBuilder b = ab.DefineDynamicModule 
(fname, fname);
+                               tb = b.DefineType ("LINQ", 
TypeAttributes.Public);
+                               mb = tb.DefineMethod ("A", 
MethodAttributes.Static, Owner.Type, ParamTypes);
+                               ig = mb.GetILGenerator ();
+                       } else {
+                               Method = new DynamicMethod (name, Owner.Type, 
ParamTypes, owner_of_code);
+                       
+                               ig = Method.GetILGenerator ();
+                       }
                }
 
                internal Delegate CreateDelegate ()
                {
+                       if (ab != null){
+                               tb.CreateType ();
+                               ab.Save ("linq" + (method_count-1) + ".dll");
+
+                               // This does not work, need to figure out why, 
for now
+                               // makes debugging harder (only one linq file 
will work unless
+                               // you do not compile them
+                               Delegate d = Delegate.CreateDelegate 
(Owner.delegate_type, tb, mb, true);
+
+                               ab = null;
+                               tb = null;
+
+                               //Console.WriteLine ("got: {0}", d);
+                               return null;
+                       }
                        return Method.CreateDelegate (Owner.delegate_type);     
                
                }
 
@@ -167,6 +200,7 @@
                                body.Emit (ec);
 
                                ec.ig.Emit (OpCodes.Ret);
+
                                lambda_delegate = ec.CreateDelegate ();
                        }
                        return lambda_delegate;

Modified: 
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Add.cs
===================================================================
--- 
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Add.cs  
    2008-01-21 00:45:16 UTC (rev 93368)
+++ 
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Add.cs  
    2008-01-21 06:05:28 UTC (rev 93369)
@@ -81,9 +81,10 @@
                        int? a = 1;
                        int? b = 2;
 
-                       BinaryExpression expr = Expression.Add 
(Expression.Constant (a), Expression.Constant (b));
+                       BinaryExpression expr = Expression.Add 
(Expression.Constant (a,typeof(int?)),
+                                                               
Expression.Constant (b, typeof(int?)));
                        Assert.AreEqual (ExpressionType.Add, expr.NodeType, 
"Add#05");
-                       Assert.AreEqual (typeof (int), expr.Type, "Add#06");
+                       Assert.AreEqual (typeof (int?), expr.Type, "Add#06");
                        Assert.IsNull (expr.Method, "Add#07");
                        Assert.AreEqual ("(1 + 2)", expr.ToString(), "Add#08");
                }

Modified: 
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Lambda.cs
===================================================================
--- 
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Lambda.cs
   2008-01-21 00:45:16 UTC (rev 93368)
+++ 
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Lambda.cs
   2008-01-21 06:05:28 UTC (rev 93369)
@@ -141,5 +141,19 @@
                        Func<int> fi = l.Compile ();
                        fi ();
                }
+
+               [Test]
+               [ExpectedException(typeof(ArgumentException))]
+               public void ReturnValueCheck ()
+               {
+                       ParameterExpression p1 = 
Expression.Parameter(typeof(int?), "va");
+                       ParameterExpression p2 = 
Expression.Parameter(typeof(int?), "vb");
+                       Expression add = Expression.Add(p1, p2);
+                       
+
+                       // This should throw, since the add.Type is "int?" and 
the return
+                       // type we have here is int.
+                       Expression<Func<int?, int?, int>> efu = 
Expression.Lambda<Func<int?,int?,int>> (add, p1, p2);
+               }
        }
 }

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to