Questions on Lambda.CompileToMethod

Jan 28, 2010 at 2:13 PM
Edited Jan 28, 2010 at 2:13 PM

I've been playing around with moving IronJS to CompileToMethod() instead of the current Compile(), I seem to be on the right track - but as soon as I try to compile a constant into the Lambda it fails with a InvalidOperationException saying "CompileToMethod cannot compile constant '1' because it is a non-trivial value, such as a live object. Instead, create an expression tree that can construct this value.". The example code I'm using is this:

using System;
using System.Reflection;
using System.Reflection.Emit;
using Et = System.Linq.Expressions.Expression;
using EtParam = System.Linq.Expressions.ParameterExpression;

namespace MethodBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            var target = Et.Lambda(
                Et.Block(
                    new EtParam[] {  },
                    Et.Call(
                        typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }),
                        Et.Constant(1.0, typeof(object))
                    )
                ),
                new EtParam[] { }
            );

            var domain = AppDomain.CurrentDomain;

            // Create dynamic assembly
            var asmName = new AssemblyName("dynamicAssembly");
            var dynAsm = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);

            // Create a dynamic module and type
            var dynMod = dynAsm.DefineDynamicModule("dynamicModule", "dynamicModule.dll");
            var typeBuilder = dynMod.DefineType("dynamicType");

            // Create our method builder for this type builder
            var methodBuilder = typeBuilder.DefineMethod(
                "dynamicMethod", MethodAttributes.Public | MethodAttributes.Static
            );

            // 
            target.CompileToMethod(methodBuilder);
        }
    }
}

The exception gets thrown on the target.CompileToMethod(methodBuilder); call. I have inspected the IronPython sources and saw that it uses a MethodBuilder in several places, so this has to be possible at least? 

Jan 28, 2010 at 2:21 PM

You can emit typed primitives like "int" and "float" in that fashion, but you're actually asking for an arbitrary type because you specify that that the type of the Constant is "object". The following does work:

Et.Call(
    typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }),
    Et.Convert(Et.Constant(1.0, typeof(double)), typeof(object))
)