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