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);
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);
+ }
}
}
}
+2008-01-21 Miguel de Icaza <miguel@novell.com>
+
+ * 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 <miguel@novell.com>
Introduce support for Nullable arguments, no code is generated for
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)
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
+using System.Threading;
namespace System.Linq.Expressions {
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;
// 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);
}
body.Emit (ec);
ec.ig.Emit (OpCodes.Ret);
+
lambda_delegate = ec.CreateDelegate ();
}
return lambda_delegate;
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");
}
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);
+ }
}
}