In-lining InvocationExpressions
I ended up using this code a few times, and recently was thinking through a scenario where the above will fail:

var iParam = Expression.Parameter(typeof(int));
var lParam = Expression.Parameter(typeof(int));

var original = Expression.Invoke(
    Expression.Lambda(
        Expression.Invoke(
                Expression.Lambda(
                    Expression.Add(iParam, lParam),
                    iParam),
                Expression.Constant(1)
        ),
        lParam),
    Expression.Constant(2)
);
var transformed = original.InlineInvokes();


The original can be visualized as:

Invoke(Param_0 =&gt; Invoke(Param_1 =&gt; (Param_1 + Param_0), 1), 2)


Here, the inner invocation is using a parameter from its parent. Since we're using a stack to represent the mappings between parameters, we're not taking into consideration Param_0. Here's the current output:

(1 + Param_0)


Here's the fixed code:

protected override Expression VisitInvocation(InvocationExpression e)
{
    var callingLambda = e.Expression as LambdaExpression;
    if (callingLambda == null)
        return base.VisitInvocation(e);
    var currentMapping = new Dictionary&lt;ParameterExpression, Expression&gt;();
    for (var i = 0; i &lt; e.Arguments.Count; i++)
    {
        var argument = Visit(e.Arguments[i]);
        var parameter = callingLambda.Parameters[i];
        if (parameter != argument)
            currentMapping.Add(parameter, argument);
    }
    if (_context.Count &gt; 0)
    {
        var existingContext = _context.Peek();
        foreach (var kvp in existingContext)
        {
            if (!currentMapping.ContainsKey(kvp.Key))
                currentMapping[kvp.Key] = kvp.Value;
        }
    }

    _context.Push(currentMapping);
    var result = Visit(callingLambda.Body);
    _context.Pop();
    return result;
}


Note that we only propagate the parameters if they don't already exist. This is required in situations as follows:

var iParam = Expression.Parameter(typeof(int));
var lParam = Expression.Parameter(typeof(int));

var original = Expression.Invoke(
    Expression.Lambda(
        Expression.Invoke(
                Expression.Lambda(
                    Expression.Add(iParam, lParam),
                    iParam, lParam),
                Expression.Constant(1), Expression.Constant(3)
        ),
        lParam),
    Expression.Constant(2)
);




Invoke(Param_0 =&gt; Invoke((Param_1, Param_0) =&gt; (Param_1 + Param_0), 1, 3), 2)


Here, the inner invoke is providing a value for Param_0 which takes precedence over what the outer invoke is providing. If we compile that expression (without inlining) - we see the result is 4.

Thus, we must ensure that we only add parameters from our parent context if we haven't already been provided them.