Author: miguel
Date: 2008-01-22 02:01:58 -0500 (Tue, 22 Jan 2008)
New Revision: 93480
Added:
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Coalesce.cs
Modified:
trunk/mcs/class/System.Core/System.Core_test.dll.sources
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_And.cs
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Or.cs
Log:
2008-01-22 Miguel de Icaza <[EMAIL PROTECTED]>
* BinaryExpression.cs (EmitCoalesce): Add support for emitting
code for Coalesce.
TODO: this does not use the "Conversion" Lambda, which am not sure
who generates this or what it is used for.
(EmitLogical): Fix a couple of bugs in AndAlso, OrElse.
* Expression.cs: Add support for Coalesce.
(BinaryCoreCheck): Move more checking here, instead of the helper
routines, will remove them next.
* LambdaExpression.cs (Compile): Create the delegate last, so we
manage to save the assembly while debugging in case of error
Modified: trunk/mcs/class/System.Core/System.Core_test.dll.sources
===================================================================
--- trunk/mcs/class/System.Core/System.Core_test.dll.sources 2008-01-22
06:50:55 UTC (rev 93479)
+++ trunk/mcs/class/System.Core/System.Core_test.dll.sources 2008-01-22
07:01:58 UTC (rev 93480)
@@ -10,6 +10,7 @@
System.Linq.Expressions/ExpressionTest_ArrayIndex.cs
System.Linq.Expressions/ExpressionTest_ArrayLength.cs
System.Linq.Expressions/ExpressionTest_CallWithExpression.cs
+System.Linq.Expressions/ExpressionTest_Coalesce.cs
System.Linq.Expressions/ExpressionTest_Condition.cs
System.Linq.Expressions/ExpressionTest_Constant.cs
System.Linq.Expressions/ExpressionTest_Divide.cs
Modified:
trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs
2008-01-22 06:50:55 UTC (rev 93479)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/BinaryExpression.cs
2008-01-22 07:01:58 UTC (rev 93480)
@@ -176,9 +176,13 @@
ig.Emit (OpCodes.Ldloca, vright);
ig.Emit (OpCodes.Call, has_value);
ig.Emit (OpCodes.Brfalse, both_are_null);
+ ig.Emit (OpCodes.Ldloca, vright);
ig.Emit (OpCodes.Call, get_value);
ig.Emit (OpCodes.Dup);
ig.Emit (and ? OpCodes.Brfalse :
OpCodes.Brtrue, create);
+
+ // right_is_null:
+ ig.MarkLabel (right_is_null);
ig.Emit (OpCodes.Pop);
// both_are_null:
@@ -201,6 +205,53 @@
}
}
+
+ void EmitCoalesce (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ LocalBuilder vleft;
+ LocalBuilder vright;
+
+ MethodInfo has_value = left.Type.GetMethod
("get_HasValue");
+
+ Label exit = ig.DefineLabel ();
+ Label try_right = ig.DefineLabel ();
+ Label setup_null = ig.DefineLabel ();
+
+ vleft = EmitStored (ec, left);
+ if (IsNullable (left.Type)){
+ ig.Emit (OpCodes.Ldloca, vleft);
+ ig.Emit (OpCodes.Call, has_value);
+ } else
+ ig.Emit (OpCodes.Ldloc, vleft);
+
+ ig.Emit (OpCodes.Brfalse, try_right);
+ ig.Emit (OpCodes.Ldloc, vleft);
+ ig.Emit (OpCodes.Br, exit);
+
+ // try_right;
+ ig.MarkLabel (try_right);
+ vright = EmitStored (ec, right);
+ if (IsNullable (right.Type)){
+ ig.Emit (OpCodes.Ldloca, vright);
+ ig.Emit (OpCodes.Call, has_value);
+ } else
+ ig.Emit (OpCodes.Ldloc, vright);
+
+ ig.Emit (OpCodes.Brfalse, setup_null);
+ ig.Emit (OpCodes.Ldloc, vright);
+ ig.Emit (OpCodes.Br, exit);
+
+ // setup_null:
+ ig.MarkLabel (setup_null);
+ LocalBuilder ret = ig.DeclareLocal (Type);
+ ig.Emit (OpCodes.Ldloca, ret);
+ ig.Emit (OpCodes.Initobj, Type);
+
+ // exit:
+ ig.MarkLabel (exit);
+ }
internal override void Emit (EmitContext ec)
{
@@ -230,6 +281,10 @@
Console.WriteLine ("LINQ/BinaryExpression:
OrElse code path not yet reviewed");
EmitLogical (ec, false, true);
return;
+
+ case ExpressionType.Coalesce:
+ EmitCoalesce (ec);
+ return;
}
Label? empty_value = null;
Modified: trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog
2008-01-22 06:50:55 UTC (rev 93479)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/ChangeLog
2008-01-22 07:01:58 UTC (rev 93480)
@@ -1,3 +1,20 @@
+2008-01-22 Miguel de Icaza <[EMAIL PROTECTED]>
+
+ * BinaryExpression.cs (EmitCoalesce): Add support for emitting
+ code for Coalesce.
+
+ TODO: this does not use the "Conversion" Lambda, which am not sure
+ who generates this or what it is used for.
+
+ (EmitLogical): Fix a couple of bugs in AndAlso, OrElse.
+
+ * Expression.cs: Add support for Coalesce.
+ (BinaryCoreCheck): Move more checking here, instead of the helper
+ routines, will remove them next.
+
+ * LambdaExpression.cs (Compile): Create the delegate last, so we
+ manage to save the assembly while debugging in case of error
+
2008-01-21 Miguel de Icaza <[EMAIL PROTECTED]>
* Expression.cs (BinaryCoreCheck): Add checking for a few
Modified: trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs
2008-01-22 06:50:55 UTC (rev 93479)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/Expression.cs
2008-01-22 07:01:58 UTC (rev 93480)
@@ -215,6 +215,13 @@
if (IsNullable (rtype))
urtype = GetNullableOf (rtype);
+ if (oper_name == "op_BitwiseOr" || oper_name ==
"op_BitwiseAnd"){
+ if (ultype == typeof (bool)){
+ if (ultype == urtype && ltype
== rtype)
+ return null;
+ }
+ }
+
if (oper_name == "op_LogicalAnd" || oper_name
== "op_LogicalOr"){
if (ultype == typeof (bool)){
if (ultype == urtype && ltype
== rtype)
@@ -271,7 +278,6 @@
// avoid reflection shortcut and catches
Ints/bools before we check Numbers in general
if (left.Type == right.Type && (left.Type ==
typeof (bool) || IsInt (left.Type)))
return method;
-
}
method = BinaryCoreCheck (oper_name, left, right,
method);
@@ -280,7 +286,8 @@
// The check in BinaryCoreCheck allows a bit
more than we do
// (floats and doubles). Catch this here
//
- throw new InvalidOperationException ("Types not
supported");
+ if (left.Type == typeof(double) || left.Type ==
typeof(float))
+ throw new InvalidOperationException
("Types not supported");
}
return method;
}
@@ -704,12 +711,44 @@
return Coalesce (left, right, null);
}
- [MonoTODO]
public static BinaryExpression Coalesce (Expression left,
Expression right, LambdaExpression conversion)
{
- BinaryCoreCheck (null, left, right, null);
+ if (left == null)
+ throw new ArgumentNullException ("left");
+ if (right == null)
+ throw new ArgumentNullException ("right");
- throw new NotImplementedException ();
+ //
+ // First arg must ne nullable (either Nullable<T> or a
reference type
+ //
+ if (left.Type.IsValueType && !IsNullable (left.Type))
+ throw new InvalidOperationException ("Left
expression can never be null");
+
+ Type result = null;
+
+ if (IsNullable (left.Type)){
+ Type lbase = GetNullableOf (left.Type);
+
+ if (!IsNullable (right.Type) &&
lbase.IsAssignableFrom (right.Type))
+ result = lbase;
+ }
+
+ if (result == null && left.Type.IsAssignableFrom
(right.Type))
+ result = left.Type;
+
+ if (result == null){
+ if (IsNullable (left.Type) &&
right.Type.IsAssignableFrom (GetNullableOf (left.Type))){
+ result = right.Type;
+ }
+ }
+
+ if (result == null)
+ throw new ArgumentException ("Incompatible
argument types");
+
+ //
+ // FIXME: What do we do with "conversion"?
+ //
+ return new BinaryExpression (ExpressionType.Coalesce,
result, left, right, false, false, null, conversion);
}
//
@@ -1390,12 +1429,12 @@
return MakeSimpleUnary (ExpressionType.UnaryPlus,
expression, method);
}
- static bool IsNullable (Type type)
+ internal static bool IsNullable (Type type)
{
return type.IsGenericType &&
type.GetGenericTypeDefinition () == typeof (Nullable<>);
}
- protected static bool IsUnsigned (Type t)
+ internal static bool IsUnsigned (Type t)
{
if (t.IsPointer)
return IsUnsigned (t.GetElementType ());
@@ -1406,7 +1445,7 @@
//
// returns the T in a a Nullable<T> type.
//
- static Type GetNullableOf (Type type)
+ internal static Type GetNullableOf (Type type)
{
return type.GetGenericArguments () [0];
}
Modified:
trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs
===================================================================
--- trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs
2008-01-22 06:50:55 UTC (rev 93479)
+++ trunk/mcs/class/System.Core/System.Linq.Expressions/LambdaExpression.cs
2008-01-22 07:01:58 UTC (rev 93480)
@@ -171,8 +171,6 @@
body.Emit (ec);
ec.ig.Emit (OpCodes.Ret);
- lambda_delegate = ec.CreateDelegate ();
-
if (Environment.GetEnvironmentVariable
("LINQ_DBG") != null){
string fname = "linq" +
(EmitContext.method_count-1) + ".dll";
AssemblyBuilder ab = Thread.GetDomain
().DefineDynamicAssembly (
@@ -189,6 +187,8 @@
tb.CreateType ();
ab.Save (fname);
}
+
+ lambda_delegate = ec.CreateDelegate ();
}
return lambda_delegate;
}
Modified:
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_And.cs
===================================================================
---
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_And.cs
2008-01-22 06:50:55 UTC (rev 93479)
+++
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_And.cs
2008-01-22 07:01:58 UTC (rev 93480)
@@ -100,5 +100,38 @@
Assert.AreEqual
("(value(MonoTests.System.Linq.Expressions.OpClass) &
value(MonoTests.System.Linq.Expressions.OpClass))",
expr.ToString(), "And#13");
}
+
+ [Test]
+ public void AndTest ()
+ {
+ Expression<Func<bool, bool, bool>> e = (bool a, bool b)
=> a & b;
+
+ Func<bool,bool,bool> c = e.Compile ();
+
+ Assert.AreEqual (true, c (true, true), "t1");
+ Assert.AreEqual (false, c (true, false), "t2");
+ Assert.AreEqual (false, c (false, true), "t3");
+ Assert.AreEqual (false, c (false, false), "t4");
+ }
+
+ [Test]
+ public void AndNullableTest ()
+ {
+ Expression<Func<bool?, bool?, bool?>> e = (bool? a,
bool? b) => a & b;
+
+ Func<bool?,bool?,bool?> c = e.Compile ();
+
+
+ Assert.AreEqual (true, c (true, true), "a1");
+ Assert.AreEqual (false, c (true, false), "a2");
+ Assert.AreEqual (false, c (false, true), "a3");
+ Assert.AreEqual (false, c (false, false), "a4");
+
+ Assert.AreEqual (null, c (true, null), "a5");
+ Assert.AreEqual (false, c (false, null), "a6");
+ Assert.AreEqual (false, c (null, false), "a7");
+ Assert.AreEqual (null, c (true, null), "a8");
+ Assert.AreEqual (null, c (null, null), "a9");
+ }
}
}
Added:
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Coalesce.cs
===================================================================
---
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Coalesce.cs
2008-01-22 06:50:55 UTC (rev 93479)
+++
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Coalesce.cs
2008-01-22 07:01:58 UTC (rev 93480)
@@ -0,0 +1,80 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+//
+// Authors:
+// Federico Di Gregorio <[EMAIL PROTECTED]>
+
+using System;
+using System.Reflection;
+using System.Linq;
+using System.Linq.Expressions;
+using NUnit.Framework;
+
+namespace MonoTests.System.Linq.Expressions
+{
+ [TestFixture]
+ public class ExpressionTest_Coalesce
+ {
+ [Test]
+ [ExpectedException (typeof (ArgumentNullException))]
+ public void Arg1Null ()
+ {
+ Expression.Coalesce (null, Expression.Constant (1));
+ }
+
+ [Test]
+ [ExpectedException (typeof (ArgumentNullException))]
+ public void Arg2Null ()
+ {
+ Expression.Coalesce (Expression.Constant (1), null);
+ }
+
+ [Test]
+ [ExpectedException (typeof (InvalidOperationException))]
+ public void NonNullLeftParameter ()
+ {
+ // This throws because they are both doubles, which are
never
+ Expression.Coalesce (Expression.Constant (1.0),
Expression.Constant (2.0));
+ }
+
+ [Test]
+ [ExpectedException (typeof (ArgumentException))]
+ public void Incompatible_Arguments ()
+ {
+ // The artuments are not compatible
+ Expression.Coalesce (Expression.Parameter (typeof
(int?), "a"),
+ Expression.Parameter (typeof
(bool), "b"));
+ }
+
+ [Test]
+ public void Coalesce_1 ()
+ {
+ // Build the expression by hand for now:
+ ParameterExpression pa = Expression.Parameter (typeof
(int?), "a");
+ ParameterExpression pb = Expression.Parameter (typeof
(int?), "b");
+ BinaryExpression c = Expression.Coalesce (pa, pb);
+
+ Expression<Func<int?, int?, int?>> e =
Expression.Lambda<Func<int?,int?,int?>>(
+ c, new ParameterExpression [] { pa, pb });
+
+ Func<int?,int?,int?> comp = e.Compile ();
+
+ Assert.AreEqual (10, comp (10, 20));
+ }
+ }
+}
Property changes on:
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Coalesce.cs
___________________________________________________________________
Name: svn:eol-style
+ native
Modified:
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Or.cs
===================================================================
---
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Or.cs
2008-01-22 06:50:55 UTC (rev 93479)
+++
trunk/mcs/class/System.Core/Test/System.Linq.Expressions/ExpressionTest_Or.cs
2008-01-22 07:01:58 UTC (rev 93480)
@@ -100,5 +100,38 @@
Assert.AreEqual
("(value(MonoTests.System.Linq.Expressions.OpClass) |
value(MonoTests.System.Linq.Expressions.OpClass))",
expr.ToString(), "Or#13");
}
+
+ [Test]
+ public void OrTest ()
+ {
+ Expression<Func<bool, bool, bool>> e = (bool a, bool b)
=> a | b;
+
+ Func<bool,bool,bool> c = e.Compile ();
+
+ Assert.AreEqual (true, c (true, true), "o1");
+ Assert.AreEqual (true, c (true, false), "o2");
+ Assert.AreEqual (true, c (false, true), "o3");
+ Assert.AreEqual (false, c (false, false), "o4");
+ }
+
+ [Test]
+ public void OrNullableTest ()
+ {
+ Expression<Func<bool?, bool?, bool?>> e = (bool? a,
bool? b) => a | b;
+
+ Func<bool?,bool?,bool?> c = e.Compile ();
+
+ Assert.AreEqual (true, c (true, true), "o1");
+ Assert.AreEqual (true, c (true, false), "o2");
+ Assert.AreEqual (true, c (false, true), "o3");
+ Assert.AreEqual (false, c (false, false), "o4");
+
+ Assert.AreEqual (true, c (true, null), "o5");
+ Assert.AreEqual (null, c (false, null), "o6");
+ Assert.AreEqual (null, c (null, false), "o7");
+ Assert.AreEqual (true, c (true, null), "o8");
+ Assert.AreEqual (null, c (null, null), "o9");
+ }
+
}
}
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches