示例#1
0
        public void ExpressionTupletizer_IsTuple()
        {
            AssertEx.ThrowsException <ArgumentNullException>(() => ExpressionTupletizer.IsTuple(type: null), ex => Assert.AreEqual("type", ex.ParamName));

            foreach (var t in new[] {
                typeof(Tuple <int>),
                typeof(Tuple <int, int>),
                typeof(Tuple <int, int, int>),
                typeof(Tuple <int, int, int, int>),
                typeof(Tuple <int, int, int, int, int>),
                typeof(Tuple <int, int, int, int, int, int>),
                typeof(Tuple <int, int, int, int, int, int, int>),
                typeof(Tuple <int, int, int, int, int, int, int, Tuple <int> >),
                typeof(Tuple <int, int, int, int, int, int, int, Tuple <int, int> >),
                typeof(Tuple <int, int, int, int, int, int, int, Tuple <int, int, int, int, int, int, int, Tuple <int, int, int> > >),
            })
            {
                Assert.IsTrue(IsTuple(t));
            }

            foreach (var t in new[] {
                typeof(int),
                typeof(List <int>),
                typeof(Tuple <>),
                typeof(Tuple <,>),
                typeof(Tuple <int, int, int, int, int, int, int, /*TRest*/ int>),
            })
            {
                Assert.IsFalse(IsTuple(t));
            }
        }
示例#2
0
        public void ExpressionTupletizer_PackAndUnpack_Lambda_NoVoid()
        {
#if USE_SLIM
            var packs = new Func <LambdaExpression, LambdaExpression>[]
            {
                f => (LambdaExpression)ExpressionSlimTupletizer.Pack((LambdaExpressionSlim)f.ToExpressionSlim()).ToExpression(),
                f => { var s = (LambdaExpressionSlim)f.ToExpressionSlim(); return((LambdaExpression)ExpressionSlimTupletizer.Pack(s.Body, s.Parameters).ToExpression()); },
            };
#else
            var packs = new Func <LambdaExpression, LambdaExpression>[]
            {
                f => ExpressionTupletizer.Pack(f),
                f => ExpressionTupletizer.Pack(f.Body, f.Parameters),
            };
#endif

            foreach (var f in new LambdaExpression[] {
#pragma warning disable IDE0004 // Remove Unnecessary Cast. (Only unnecessary on C# 10 or later.)
                (Expression <Func <int> >)(() => 42),
#pragma warning restore IDE0004 // Remove Unnecessary Cast
                (Expression <Func <string, int> >)(s => s.Length),
                (Expression <Func <string, int, int> >)((s, i) => s.Length + i),
                (Expression <Func <int, int, int, int> >)((a, b, c) => a * b + c),
                (Expression <Func <int, int, int, int, int> >)((a, b, c, d) => a * b + c - d),
                (Expression <Func <int, int, int, int, int, int> >)((a, b, c, d, e) => a * b + c - d / e),
                (Expression <Func <int, int, int, int, int, int, int> >)((a, b, c, d, e, f) => a * b + c - d / e + f),
                (Expression <Func <int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g) => a * b + c - d / e + f * g),
                (Expression <Func <int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h) => a * b + c - d / e + f * g / h),
                (Expression <Func <int, int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h, i) => a * b + c - d / e + f * g / h + i),
                (Expression <Func <int, int, int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h, i, j) => a * b + c - d / e + f * g / h + i - j),
                (Expression <Func <int, int, int, int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h, i, j, k) => a * b + c - d / e + f * g / h + i - j * k),
                (Expression <Func <int, int, int, int, int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h, i, j, k, l) => a * b + c - d / e + f * g / h + i - j * k / l),
                (Expression <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h, i, j, k, l, m) => a * b + c - d / e + f * g / h + i - j * k / l + m),
                (Expression <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h, i, j, k, l, m, n) => a * b + c - d / e + f * g / h + i - j * k / l + m % n),
                (Expression <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >)((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) => a * b + c - d / e + f * g / h + i - j * k / l + m % n + o),
                (Expression <Func <string, Uri, int, double, DateTime, float, byte, TimeSpan, long, short, Guid, char, uint, AppDomain, decimal[], List <int>, bool> >)((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) => (a + b.ToString() + new string(l, 10) + n.FriendlyName).Length + i * d - e.Year % j + f * g / h.Days + k.ToByteArray().Length + m * p[c] > 0 && o[c] < 12.45m),
            })
            {
                foreach (var pack in packs)
                {
                    var g = pack(f);

                    var n = g.Parameters.Count;
                    Assert.IsTrue(n is 0 or 1, "Parameter count: " + f.ToString());

                    if (n == 1)
                    {
                        Assert.IsTrue(g.Parameters[0].Type.FullName.StartsWith("System.Tuple`"), "Parameter type: " + f.ToString());
                    }

                    var h = ExpressionTupletizer.Unpack(g);

                    var res = new ExpressionEqualityComparer().Equals(f, h);
                    Assert.IsTrue(res, "Equality: " + f.ToString());
                }
            }
        }
示例#3
0
            public override Expression Normalize(Expression expression)
            {
                var normalized = base.Normalize(expression);
                var tupletized = new InvocationTupletizer().Visit(normalized);

                if (tupletized is LambdaExpression lambda)
                {
                    tupletized = ExpressionTupletizer.Pack(lambda);
                }

                return(tupletized);
            }
            public static Expression Detupletize(Expression expression)
            {
                var detupletized = new InvocationDetupletizer().Visit(expression);

                // TODO: Check if the lambda parameter is tuple.
                if (detupletized is LambdaExpression lambda)
                {
                    detupletized = ExpressionTupletizer.Unpack(lambda);
                }

                return(detupletized);
            }
示例#5
0
            private static Expression Tupletize(Expression expression)
            {
                var inv    = new InvocationTupletizer();
                var result = inv.Visit(expression);

                if (result is LambdaExpression lambda)
                {
                    result = ExpressionTupletizer.Pack(lambda);
                }

                return(result);
            }
                private static bool IsTuple(Expression expression)
                {
                    if (expression.NodeType == ExpressionType.New)
                    {
                        // TODO: All of this code really should move up, closer to where we know we're using tuples.

                        if (ExpressionTupletizer.IsTuple(expression.Type))
                        {
                            return(true);
                        }
                    }

                    return(false);
                }
示例#7
0
            public override Expression Normalize(Expression expression)
            {
                var normalized = base.Normalize(expression);
                var tupletized = new InvocationTupletizer().Visit(normalized);

                if (tupletized is LambdaExpression lambda)
                {
                    tupletized = ExpressionTupletizer.Pack(lambda);
                }

                var sync = new AsyncToSyncRewriter(new Dictionary <Type, Type>()).Rewrite(tupletized);

                return(sync);
            }
                protected override Expression VisitInvocation(InvocationExpression node)
                {
                    if (node.Expression is ParameterExpression function && IsUnboundParameter(function) && node.Arguments.Count == 1 && IsTuple(node.Arguments[0]))
                    {
                        var args = ExpressionTupletizer.Unpack(Visit(node.Arguments[0]));

                        var newFunctionType = Expression.GetDelegateType(args.Select(a => a.Type).Concat(new[] { node.Type }).ToArray());

                        var newFunction = Expression.Parameter(newFunctionType, function.Name);

                        return(Expression.Invoke(newFunction, args));
                    }

                    return(base.VisitInvocation(node));
                }
示例#9
0
        public void ExpressionTupletizer_Pack_TheWorks()
        {
            for (int i = 1; i < 18; i++)
            {
                var t = Enumerable.Range(1, i).Select(x => Expression.Constant(x));
                var e = ExpressionTupletizer.Pack(t);

                var n = 0;
                var u = e;
                while (u != null)
                {
                    var c = u.Type.GetGenericArguments().Length;
                    n += c;

                    var f = (NewExpression)u;

                    if (u.Type.GetGenericTypeDefinition() == typeof(Tuple <, , , , , , ,>))
                    {
                        u = f.Arguments.Last();
                        Assert.IsTrue(u.Type.Name.StartsWith("Tuple"));

                        Assert.IsTrue(f.Members.Take(7).Select(m => m.Name).SequenceEqual(Enumerable.Range(1, 7).Select(j => "Item" + j)));
                        Assert.IsTrue(f.Members.Last().Name == "Rest");
                        n--;
                    }
                    else
                    {
                        Assert.IsTrue(f.Members.Select(m => m.Name).SequenceEqual(Enumerable.Range(1, c).Select(j => "Item" + j)));
                        u = null;
                    }
                }

                Assert.AreEqual(i, n);

                var s = e.Evaluate();

                var z = "(" + string.Join(", ", t.Select(c => c.Value)) + ")";
                Assert.AreEqual(z, s.ToString());
            }
        }
示例#10
0
        private void SerializeTemplateArgument(Expression argument)
        {
            var args = ExpressionTupletizer.Unpack(argument);

            foreach (Expression arg in args)
            {
                _serializer.Serialize((int)arg.NodeType, _stream);
                switch (arg.NodeType)
                {
                case ExpressionType.Constant:
                    _serializer.Serialize(((ConstantExpression)arg).Value, arg.Type, _stream);
                    break;

                case ExpressionType.Parameter:
                    _serializer.Serialize(((ParameterExpression)arg).Name, _stream);
                    break;

                default:
                    throw new InvalidOperationException("Only constant and parameter expressions are supported.");
                }
            }
        }
示例#11
0
            public override Expression Visit(Expression node)
            {
                if (node != null && node.IsTemplatized(out ParameterExpression parameter, out Expression argument))
                {
                    var template = _bindings[parameter];

                    if (argument != null)
                    {
                        var unpackedTemplate = ExpressionTupletizer.Unpack((LambdaExpression)template);
                        var unpackedArgument = ExpressionTupletizer.Unpack(argument);

                        // Note that beta reduction is not required here as the caller to the
                        // `Inline` method will reduce the result of the inlining step.
                        return(Expression.Invoke(unpackedTemplate, unpackedArgument));
                    }
                    else
                    {
                        return(Expression.Invoke((LambdaExpression)template));
                    }
                }

                return(base.Visit(node));
            }
            /// <summary>
            /// Visits the children of the <see cref="System.Linq.Expressions.InvocationExpression" />.
            /// </summary>
            /// <param name="node">The expression to visit.</param>
            /// <returns>
            /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
            /// </returns>
            protected override Expression VisitInvocation(InvocationExpression node)
            {
                var expr = Visit(node.Expression);
                var args = Visit(node.Arguments);

                if (expr.NodeType == ExpressionType.Parameter)
                {
                    var parameter = (ParameterExpression)expr;

                    // Turns f(x, y, z) into f((x, y, z)) when f is an unbound parameter, i.e. representing a known resource.
                    if (IsUnboundParameter(parameter))
                    {
                        if (args.Count > 0)
                        {
                            var tuple    = ExpressionTupletizer.Pack(args);
                            var funcType = Expression.GetDelegateType(tuple.Type, node.Type);
                            var function = Expression.Parameter(funcType, parameter.Name);
                            return(Expression.Invoke(function, tuple));
                        }
                    }
                }

                return(node.Update(expr, args));
            }
                public bool TryConstruct(out NewExpression rewritten)
                {
                    var results = new List <MapEntry>();

                    if (TryConstruct(_expression, new List <MemberInfo>(), results))
                    {
                        rewritten = (NewExpression)ExpressionTupletizer.Pack(results.Select(x => x.ConstructorArgument));

                        var nestedTypes = Array.Empty <MemberInfo>();
                        var currentType = rewritten.Type;
                        for (int resultIdx = 0, tupleIdx = 0, count = results.Count; resultIdx < count; resultIdx++, tupleIdx++)
                        {
                            if (tupleIdx == s_tupleItems.Length - 1)
                            {
                                var temp = new MemberInfo[nestedTypes.Length + 1];
                                Array.Copy(nestedTypes, temp, nestedTypes.Length);
                                temp[nestedTypes.Length] = currentType.GetMember(s_tupleItems[tupleIdx]).Single();
                                nestedTypes = temp;
                                tupleIdx    = 0;
                                currentType = currentType.GetGenericArguments()[s_tupleItems.Length - 1];
                            }

                            var members = new MemberInfo[nestedTypes.Length + 1];
                            Array.Copy(nestedTypes, members, nestedTypes.Length);

                            members[nestedTypes.Length] = currentType.GetMember(s_tupleItems[tupleIdx]).Single();

                            _mapper.Add(results[resultIdx].MemberChain, members);
                        }

                        return(true);
                    }

                    rewritten = null;
                    return(false);
                }
 /// <summary>
 /// Unpacks the template lambda.
 /// </summary>
 /// <param name="lambda">The template lambda.</param>
 /// <param name="body">The unpacked template lambda body.</param>
 /// <param name="parameters">The unpacked template lambda parameters.</param>
 protected virtual void UnpackTemplateLambda(LambdaExpression lambda, out Expression body, out IEnumerable <ParameterExpression> parameters)
 {
     ExpressionTupletizer.Unpack(lambda, out body, out parameters);
 }
 /// <summary>
 /// Unpacks the template arguments.
 /// </summary>
 /// <param name="argument">The packed template argument.</param>
 /// <returns>The unpacked arguments.</returns>
 protected virtual IEnumerable <Expression> UnpackTemplateArguments(Expression argument)
 {
     return(ExpressionTupletizer.Unpack(argument));
 }
示例#16
0
 private static Expression Pack(Expression expression, IEnumerable <ParameterExpression> parameters, Type voidType)
 {
     return(ExpressionTupletizer.Pack(expression, parameters, voidType));
 }
示例#17
0
 private static Expression Pack(Expression expression, params ParameterExpression[] parameters)
 {
     return(ExpressionTupletizer.Pack(expression, parameters));
 }
示例#18
0
 private static bool IsTuple(Type type)
 {
     return(ExpressionTupletizer.IsTuple(type));
 }
示例#19
0
 private static void Unpack(LambdaExpression expression, Type voidType, out Expression body, out IEnumerable <ParameterExpression> parameters)
 {
     ExpressionTupletizer.Unpack(expression, voidType, out body, out parameters);
 }
示例#20
0
 private static IEnumerable <Expression> Unpack(Expression expression)
 {
     return(ExpressionTupletizer.Unpack(expression));
 }
示例#21
0
 private static LambdaExpression Unpack(LambdaExpression expression, Type voidType)
 {
     return(ExpressionTupletizer.Unpack(expression, voidType));
 }
示例#22
0
 private static LambdaExpression Unpack(LambdaExpression expression)
 {
     return(ExpressionTupletizer.Unpack(expression));
 }
            public static ExpressionTemplate Templatize(Expression e, IConstantHoister hoister)
            {
                var env = hoister.Hoist(e);

                var bindings = env.Bindings;
                var n        = bindings.Count;

                var res = new ExpressionTemplate();

                if (n == 0)
                {
                    res.Template = Expression.Lambda(e);
                }
                else
                {
                    var parameters = new ParameterExpression[n];
                    var arguments  = new Expression[n];

                    for (var i = 0; i < n; i++)
                    {
                        var c = bindings[i];
                        parameters[i] = c.Parameter;
                        arguments[i]  = c.Value;
                    }

                    //
                    // In case you wonder why we're not building a LambdaExpression from the parameters
                    // and the visited body, there are two reasons.
                    //
                    //
                    // The first reason is due to the way the LambdaCompiler generates code for closures,
                    // which can be illustrated with this example:
                    //
                    //   (c1, c2, c3) => (arg1, arg2) => f(arg1, c1, arg2, c2, c3)
                    //
                    // In here, the outermost lambda contains the hoisted constants, and the innermost
                    // lambda matches the original lambda's signature. When we compile this higher-order
                    // expression and then invoke the outer delegate to re-supply the constants, we end
                    // up with a delegate whose target is a System.Runtime.CompilerServices.Closure which
                    // contains two fields:
                    //
                    //   object[] Constants;
                    //   object[] Locals;
                    //
                    // Due to constant hoisting, the first array is empty. The second array will hold
                    // the variables that are closed over, in the form of StrongBox<T> objects, so we
                    // end up with the Locals containing:
                    //
                    //   new object[]
                    //   {
                    //       new StrongBox<T1> { Value = c1 },
                    //       new StrongBox<T2> { Value = c2 },
                    //       new StrongBox<T3> { Value = c3 },
                    //   }
                    //
                    // Uses of c1, c2, and c3 inside the inner lambda will effectively become accesses
                    // to the closure using a field traversal like this:
                    //
                    //   ((StrongBox<T1>)closure.Locals[0]).Value
                    //
                    // For N constants we have N allocations of a StrongBox<T>. If instead we use a
                    // single tuple to hold all of the constants, we reduce this cost slightly, at the
                    // expense of requiring one more property lookup to access the constant at runtime.
                    //
                    // NB: We could consider using a ValueTuple in the future (which was added to .NET
                    //     much later than the original implementation of this library) to avoid the
                    //     cost of accessing properties, though we should have a hard look at code gen
                    //     to a) make sure that the JITted code does not already elide the call, and
                    //     more importantly b) that no copies of ValueTuple values are made, and c) that
                    //     we don't end up just boxing the ValueTuple and thus undo the potential gains.
                    //
                    //
                    // The second (and original) reason is quite subtle. For lambda expressions with an
                    // arity of 17 and beyond the Expression.Lambda factory method will use lightweight
                    // code generation to create a delegate type. The code for this can be found in:
                    //
                    //  %DDROOT%\sources\ndp\fx\src\Core\Microsoft\Scripting\Compiler\AssemblyGen.cs
                    //
                    // The dynamic assembly used to host those delegate types is generated with the Run
                    // option rather than RunAndCollect. If we end up creating a lambda expression that
                    // uses LCG-generated types that are marked as RunAndCollect, an exception occurs:
                    //
                    //  System.NotSupportedException: A non-collectible assembly may not reference a collectible assembly.
                    //    at System.Reflection.Emit.ModuleBuilder.GetTypeRef(RuntimeModule module, String strFullName, RuntimeModule refedModule, String strRefedModuleFileName, Int32 tkResolution)
                    //    at System.Reflection.Emit.ModuleBuilder.GetTypeRefNested(Type type, Module refedModule, String strRefedModuleFileName)
                    //    at System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(Type type, Boolean getGenericDefinition)
                    //    at System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type, Boolean getGenericDefinition)
                    //    at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst)
                    //    at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst)
                    //    at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelper(Type clsArgument, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers)
                    //    at System.Reflection.Emit.SignatureHelper.AddArguments(Type[] arguments, Type[][] requiredCustomModifiers, Type[][] optionalCustomModifiers)
                    //    at System.Reflection.Emit.SignatureHelper.GetMethodSigHelper(Module scope, CallingConventions callingConvention, Int32 cGenericParam, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
                    //    at System.Reflection.Emit.MethodBuilder.GetMethodSignature()
                    //    at System.Reflection.Emit.MethodBuilder.GetTokenNoLock()
                    //    at System.Reflection.Emit.MethodBuilder.GetToken()
                    //    at System.Reflection.Emit.MethodBuilder.SetImplementationFlags(MethodImplAttributes attributes)
                    //    at System.Linq.Expressions.Compiler.DelegateHelpers.MakeNewCustomDelegate(Type[] types)
                    //    at System.Linq.Expressions.Compiler.DelegateHelpers.MakeDelegateType(Type[] types)
                    //    at System.Linq.Expressions.Expression.Lambda(Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
                    //    at System.Linq.Expressions.Expression.Lambda(Expression body, ParameterExpression[] parameters)
                    //
                    // To work around this limitation, we sidestep the creation of a lambda altogether
                    // and use a specialized overload to Pack that builds a tupletized lambda from the
                    // specified body and parameters collection.
                    //
                    res.Template = ExpressionTupletizer.Pack(env.Expression, parameters);
                    res.Argument = ExpressionTupletizer.Pack(arguments, setNewExpressionMembers: false);
                }

                return(res);
            }
示例#24
0
 private static Expression Pack(IEnumerable <Expression> expressions)
 {
     return(ExpressionTupletizer.Pack(expressions));
 }
示例#25
0
        /// <summary>
        /// Templatizes an expression.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <returns>The expression template.</returns>
        public static ExpressionTemplate Templatize(this Expression expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            ICollection <ParameterExpression> globals = ExpressionHelpers.FindFreeVariables(expression);

            IExpressionWithEnvironment hoisted = s_constantHoister.Hoist(expression);
            IReadOnlyList <System.Linq.CompilerServices.Binding> hoistedBindings = hoisted.Bindings;

            var hoistedBindingsCount = hoistedBindings.Count;

            var n = globals.Count + hoistedBindingsCount;

            var res = new ExpressionTemplate();

            if (n == 0)
            {
                res.Template = Expression.Lambda(expression);
            }
            else
            {
                var parameters = new ParameterExpression[n];
                var arguments  = new Expression[n];

                int i = 0;

                while (i < hoistedBindingsCount)
                {
                    var c = hoistedBindings[i];
                    parameters[i] = c.Parameter;
                    arguments[i]  = c.Value;

                    i++;
                }

                foreach (var p in globals)
                {
                    parameters[i] = p;
                    arguments[i]  = p;

                    i++;
                }

                Debug.Assert(i == n);

                //
                // In case you wonder why we're not building a LambdaExpression from the parameters
                // and the visited body, the reason is quite subtle. For lambda expressions with an
                // arity of 17 and beyond the Expression.Lambda factory method will use lightweight
                // code generation to create a delegate type. The code for this can be found in:
                //
                //  %DDROOT%\sources\ndp\fx\src\Core\Microsoft\Scripting\Compiler\AssemblyGen.cs
                //
                // The dynamic assembly used to host those delegate types is generated with the Run
                // option rather than RunAndCollect. If we end up creating a lambda expression that
                // uses LCG-generated types that are marked as RunAndCollect, an exception occurs:
                //
                //  System.NotSupportedException: A non-collectible assembly may not reference a collectible assembly.
                //    at System.Reflection.Emit.ModuleBuilder.GetTypeRef(RuntimeModule module, String strFullName, RuntimeModule refedModule, String strRefedModuleFileName, Int32 tkResolution)
                //    at System.Reflection.Emit.ModuleBuilder.GetTypeRefNested(Type type, Module refedModule, String strRefedModuleFileName)
                //    at System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(Type type, Boolean getGenericDefinition)
                //    at System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type, Boolean getGenericDefinition)
                //    at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst)
                //    at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst)
                //    at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelper(Type clsArgument, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers)
                //    at System.Reflection.Emit.SignatureHelper.AddArguments(Type[] arguments, Type[][] requiredCustomModifiers, Type[][] optionalCustomModifiers)
                //    at System.Reflection.Emit.SignatureHelper.GetMethodSigHelper(Module scope, CallingConventions callingConvention, Int32 cGenericParam, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
                //    at System.Reflection.Emit.MethodBuilder.GetMethodSignature()
                //    at System.Reflection.Emit.MethodBuilder.GetTokenNoLock()
                //    at System.Reflection.Emit.MethodBuilder.GetToken()
                //    at System.Reflection.Emit.MethodBuilder.SetImplementationFlags(MethodImplAttributes attributes)
                //    at System.Linq.Expressions.Compiler.DelegateHelpers.MakeNewCustomDelegate(Type[] types)
                //    at System.Linq.Expressions.Compiler.DelegateHelpers.MakeDelegateType(Type[] types)
                //    at System.Linq.Expressions.Expression.Lambda(Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
                //    at System.Linq.Expressions.Expression.Lambda(Expression body, ParameterExpression[] parameters)
                //
                // To work around this limitation, we sidestep the creation of a lambda altogether
                // and use a specialized overload to Pack that builds a tupletized lambda from the
                // specified body and parameters collection.
                //
                res.Template = ExpressionTupletizer.Pack(hoisted.Expression, parameters);
                res.Argument = ExpressionTupletizer.Pack(arguments);
            }

            return(res);
        }