Beispiel #1
0
        public void MethodCall_Compile_ByRef_Array3()
        {
            var method = MethodInfoOf((int x) => int.TryParse("", out x));

            var parameters = method.GetParameters();

            var parameterX = parameters[0];
            var parameterY = parameters[1];

            var valueX = Expression.Constant("42");
            var valueY = Expression.Parameter(typeof(int));

            var array    = Expression.Parameter(typeof(int[, ]));
            var newArray = Expression.Assign(array, Expression.NewArrayBounds(typeof(int), Expression.Constant(1), Expression.Constant(1)));
            var element  = Expression.ArrayIndex(array, Expression.Constant(0), Expression.Constant(0));

            AssertCompile <int>(log =>
                                Expression.Block(new[] { array },
                                                 newArray,
                                                 CSharpExpression.Call(method,
                                                                       CSharpExpression.Bind(parameterY, element),
                                                                       CSharpExpression.Bind(parameterX, log(valueX, "S"))
                                                                       ),
                                                 element
                                                 ),
                                new LogAndResult <int> {
                Value = 42, Log = { "S" }
            }
                                );
        }
Beispiel #2
0
        public void MethodCall_Update()
        {
            var substring = MethodInfoOf((string s) => s.Substring(default(int), default(int)));

            var parameters = substring.GetParameters();

            var startIndexParameter = parameters[0];
            var lengthParameter     = parameters[1];

            var obj        = Expression.Constant("bar");
            var startIndex = Expression.Constant(0);
            var length     = Expression.Constant(1);

            var arg0 = CSharpExpression.Bind(startIndexParameter, startIndex);
            var arg1 = CSharpExpression.Bind(lengthParameter, length);

            var res = CSharpExpression.Call(obj, substring, arg0, arg1);

            Assert.AreSame(res, res.Update(res.Object, res.Arguments));

            var obj1 = Expression.Constant("foo");
            var upd1 = res.Update(obj1, res.Arguments);

            Assert.AreNotSame(upd1, res);
            Assert.AreSame(res.Arguments, upd1.Arguments);
            Assert.AreSame(obj1, upd1.Object);

            var upd2 = res.Update(obj, new[] { arg1, arg0 });

            Assert.AreNotSame(upd2, res);
            Assert.AreSame(res.Object, upd2.Object);
            Assert.IsTrue(upd2.Arguments.SequenceEqual(new[] { arg1, arg0 }));
        }
Beispiel #3
0
        public void MethodCall_Compile_Instance()
        {
            var method = MethodInfoOf((string s) => s.Substring(default(int), default(int)));

            var parameters = method.GetParameters();

            var parameterStartIndex = parameters[0];
            var parameterLength     = parameters[1];

            var obj             = Expression.Constant("foobar");
            var valueStartIndex = Expression.Constant(1);
            var valueLength     = Expression.Constant(2);

            AssertCompile <string>(log =>
                                   CSharpExpression.Call(log(obj, "O"), method,
                                                         CSharpExpression.Bind(parameterStartIndex, log(valueStartIndex, "S")),
                                                         CSharpExpression.Bind(parameterLength, log(valueLength, "L"))
                                                         ),
                                   new LogAndResult <string> {
                Value = "foobar".Substring(1, 2), Log = { "O", "S", "L" }
            }
                                   );

            AssertCompile <string>(log =>
                                   CSharpExpression.Call(log(obj, "O"), method,
                                                         CSharpExpression.Bind(parameterLength, log(valueLength, "L")),
                                                         CSharpExpression.Bind(parameterStartIndex, log(valueStartIndex, "S"))
                                                         ),
                                   new LogAndResult <string> {
                Value = "foobar".Substring(1, 2), Log = { "O", "L", "S" }
            }
                                   );
        }
Beispiel #4
0
        public void MethodCall_Properties_Static()
        {
            var min = MethodInfoOf(() => Math.Min(default(int), default(int)));

            var parameters = min.GetParameters();

            var val1Parameter = parameters[0];
            var val2Parameter = parameters[1];

            var val1 = Expression.Constant(0);
            var val2 = Expression.Constant(1);

            var arg0 = CSharpExpression.Bind(val1Parameter, val1);
            var arg1 = CSharpExpression.Bind(val2Parameter, val2);

            {
                var res = CSharpExpression.Call(min, arg0, arg1);

                Assert.AreEqual(CSharpExpressionType.Call, res.CSharpNodeType);
                Assert.IsNull(res.Object);
                Assert.AreEqual(min, res.Method);
                Assert.AreEqual(typeof(int), res.Type);
                Assert.IsTrue(res.Arguments.SequenceEqual(new[] { arg0, arg1 }));
            }

            {
                var res = CSharpExpression.Call(min, new[] { arg0, arg1 }.AsEnumerable());

                Assert.AreEqual(CSharpExpressionType.Call, res.CSharpNodeType);
                Assert.IsNull(res.Object);
                Assert.AreEqual(min, res.Method);
                Assert.AreEqual(typeof(int), res.Type);
                Assert.IsTrue(res.Arguments.SequenceEqual(new[] { arg0, arg1 }));
            }
        }
Beispiel #5
0
        public void MethodCall_Compile_ByRef_Index()
        {
            var method = MethodInfoOf((int x) => int.TryParse("", out x));

            var parameters = method.GetParameters();

            var parameterX = parameters[0];
            var parameterY = parameters[1];

            var valueX = Expression.Constant("42");
            var valueY = Expression.Parameter(typeof(int));

            var list    = Expression.Parameter(typeof(List <int>));
            var newList = Expression.Assign(list, Expression.ListInit(Expression.New(typeof(List <int>)), Expression.Constant(1)));
            var element = Expression.MakeIndex(list, typeof(List <int>).GetProperty("Item"), new[] { Expression.Constant(0) });

            AssertCompile <int>(log =>
                                Expression.Block(new[] { list },
                                                 newList,
                                                 CSharpExpression.Call(method,
                                                                       CSharpExpression.Bind(parameterY, element),
                                                                       CSharpExpression.Bind(parameterX, log(valueX, "S"))
                                                                       ),
                                                 element
                                                 ),
                                new LogAndResult <int> {
                Value = 42, Log = { "S" }
            }
                                );
        }
Beispiel #6
0
        public void MethodCall_Compile_ByRef_Property()
        {
            var method = MethodInfoOf((int x) => int.TryParse("", out x));

            var parameters = method.GetParameters();

            var parameterX = parameters[0];
            var parameterY = parameters[1];

            var valueX = Expression.Constant("42");
            var valueY = Expression.Parameter(typeof(int));

            var box      = Expression.Parameter(typeof(MyBox <int>));
            var newBox   = Expression.Assign(box, Expression.New(box.Type));
            var boxValue = Expression.Property(box, "Value");

            AssertCompile <int>(log =>
                                Expression.Block(new[] { box },
                                                 newBox,
                                                 CSharpExpression.Call(method,
                                                                       CSharpExpression.Bind(parameterY, boxValue),
                                                                       CSharpExpression.Bind(parameterX, log(valueX, "S"))
                                                                       ),
                                                 boxValue
                                                 ),
                                new LogAndResult <int> {
                Value = 42, Log = { "S" }
            }
                                );
        }
Beispiel #7
0
        public void MethodCall_Compile_Static()
        {
            var method = MethodInfoOf(() => F(default(int), default(int), default(int)));

            var parameters = method.GetParameters();

            var parameterX = parameters[0];
            var parameterY = parameters[1];
            var parameterZ = parameters[2];

            var valueX = Expression.Constant(1);
            var valueY = Expression.Constant(2);
            var valueZ = Expression.Constant(3);

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterX, log(valueX, "X")),
                                                      CSharpExpression.Bind(parameterY, log(valueY, "Y"))
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2), Log = { "X", "Y" }
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterY, log(valueY, "Y")),
                                                      CSharpExpression.Bind(parameterX, log(valueX, "X"))
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2), Log = { "Y", "X" }
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterY, log(valueY, "Y")),
                                                      CSharpExpression.Bind(parameterX, log(valueX, "X")),
                                                      CSharpExpression.Bind(parameterZ, log(valueZ, "Z"))
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2, 3), Log = { "Y", "X", "Z" }
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterX, log(valueX, "X")),
                                                      CSharpExpression.Bind(parameterY, log(valueY, "Y")),
                                                      CSharpExpression.Bind(parameterZ, log(valueZ, "Z"))
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2, 3), Log = { "X", "Y", "Z" }
            }
                                );
        }
Beispiel #8
0
        public void MethodCall_Factory_Expression()
        {
            var method = MethodInfoOf(() => F(default(int), default(int), default(int)));

            var args = new[] { Expression.Constant(1), Expression.Constant(2) };

            foreach (var e in new[]
            {
                CSharpExpression.Call(method, args),
                CSharpExpression.Call(method, args.AsEnumerable()),
                CSharpExpression.Call(null, method, args),
                CSharpExpression.Call(null, method, args.AsEnumerable()),
            })
            {
                Assert.IsNull(e.Object);

                Assert.AreEqual(method, e.Method);

                Assert.AreEqual(2, e.Arguments.Count);

                Assert.AreEqual(method.GetParameters()[0], e.Arguments[0].Parameter);
                Assert.AreEqual(method.GetParameters()[1], e.Arguments[1].Parameter);

                Assert.AreSame(args[0], e.Arguments[0].Expression);
                Assert.AreSame(args[1], e.Arguments[1].Expression);
            }

            var tooLittle = args.Take(1);

            foreach (var f in new Func <MethodCallCSharpExpression>[]
            {
                () => CSharpExpression.Call(method, tooLittle),
                () => CSharpExpression.Call(method, tooLittle.AsEnumerable()),
                () => CSharpExpression.Call(null, method, tooLittle),
                () => CSharpExpression.Call(null, method, tooLittle.AsEnumerable()),
            })
            {
                AssertEx.Throws <ArgumentException>(() => f());
            }

            var tooMany = args.Concat(args).ToArray();

            foreach (var f in new Func <MethodCallCSharpExpression>[]
            {
                () => CSharpExpression.Call(method, tooMany),
                () => CSharpExpression.Call(method, tooMany.AsEnumerable()),
                () => CSharpExpression.Call(null, method, tooMany),
                () => CSharpExpression.Call(null, method, tooMany.AsEnumerable()),
            })
            {
                AssertEx.Throws <ArgumentException>(() => f());
            }
        }
Beispiel #9
0
        public void MethodCall_Visitor()
        {
            var cout           = MethodInfoOf(() => Console.WriteLine(default(int)));
            var valueParameter = cout.GetParameters()[0];
            var value          = Expression.Constant(42);
            var res            = CSharpExpression.Call(cout, CSharpExpression.Bind(valueParameter, value));

            var v = new V();

            Assert.AreSame(res, v.Visit(res));
            Assert.IsTrue(v.Visited);
        }
        public void ParameterAssignment_Visitor()
        {
            var method    = typeof(C).GetMethod("F");
            var parameter = method.GetParameters()[0];
            var expr      = Expression.Constant(42);

            var bind = CSharpExpression.Bind(parameter, expr);

            var res = CSharpExpression.Call(method, bind);

            var v = new V();

            Assert.AreSame(res, v.Visit(res));
            Assert.IsTrue(v.Visited);
        }
Beispiel #11
0
        public void ArrayAccess_ByRef_CSharpNodes_SystemIndex()
        {
            //
            // NB: Unlike the test case above, this works because we can reduce CSharpExpression variants of MethodCall, New, and Invoke
            //     while properly accounting for by-ref passing of ArrayAccess.
            //
            //     The corresponding changes to the Roslyn compiler account for by-ref passing of ArrayAccess nodes that involve an Index
            //     operand, causing calls to be made to CSharpExpression.* factories for Call, New, and Invoke.  E.g.
            //
            //        Interlocked.Exchange(ref xs[i])
            //
            //     where i is of type Index, becomes
            //
            //        CSharpExpression.Call(xchg, CSharpExpression.ArrayAccess(...))
            //
            //     rather than
            //
            //        Expression.Call(xchg, CSharpExpression.ArrayAccess(...))
            //
            //     This triggers custom reduction logic in the C# variants of Call, New, and Invoke nodes.
            //
            //     However, this does not fix the previous test case where one explicitly uses Expression.Call. For this to be fixed, we
            //     either need:
            //
            //       1. Guaranteed custom reduction at a higher node (e.g. lambda).
            //       2. Changes to ref semantics in System.Linq.Expressions, e.g. allowing to peek into a comma node.
            //       3. Changes to Reduce logic in System.Linq.Expressions, e.g. custom logic for lval reduciton versus rval reduction.
            //       4. Push down Index/Range support to IndexExpression and piggyback on its by-ref support.
            //

            var xs = Expression.Parameter(typeof(int[]));
            var i  = Expression.Parameter(typeof(Index));

            var inc = typeof(Interlocked).GetMethod(nameof(Interlocked.Increment), new[] { typeof(int).MakeByRefType() });

            MethodCallCSharpExpression mce = CSharpExpression.Call(inc, new Expression[] { CSharpExpression.ArrayAccess(xs, i) });

            var res = Expression.Lambda <Func <int[], Index, int> >(mce, xs, i);

            var f = res.Compile();

            var vals = new int[] { 41 };

            int val = f(vals, 0);

            Assert.AreEqual(42, val);
            Assert.AreEqual(42, vals[0]);
        }
Beispiel #12
0
        public void MethodCall_Compile_ByRef_MutableStruct2()
        {
            var y      = default(int);
            var method = MethodInfoOf((S s) => s.F(default(int), ref y));

            var parameters = method.GetParameters();

            var parameterX = parameters[0];
            var parameterY = parameters[1];

            var valueX = Expression.Constant(12);
            var valueY = Expression.Parameter(typeof(int));

            var value    = Expression.Parameter(typeof(StrongBox <S>));
            var prop     = Expression.Field(value, "Value");
            var newValue = Expression.Assign(value, Expression.New(typeof(StrongBox <S>)));
            var valueZ   = Expression.Field(prop, "Z");

            AssertCompile <int>(log =>
                                Expression.Block(new[] { value, valueY },
                                                 newValue,
                                                 Expression.Assign(valueY, Expression.Constant(30)),
                                                 CSharpExpression.Call(prop, method,
                                                                       CSharpExpression.Bind(parameterX, valueX),
                                                                       CSharpExpression.Bind(parameterY, valueY)
                                                                       ),
                                                 Expression.Subtract(valueZ, valueY)
                                                 ),
                                new LogAndResult <int> {
                Value = 0
            }
                                );

            AssertCompile <int>(log =>
                                Expression.Block(new[] { value, valueY },
                                                 newValue,
                                                 Expression.Assign(valueY, Expression.Constant(30)),
                                                 CSharpExpression.Call(prop, method,
                                                                       CSharpExpression.Bind(parameterY, valueY),
                                                                       CSharpExpression.Bind(parameterX, valueX)
                                                                       ),
                                                 Expression.Subtract(valueZ, valueY)
                                                 ),
                                new LogAndResult <int> {
                Value = 0
            }
                                );
        }
Beispiel #13
0
        public void MethodCall_Factory_ArgumentChecking()
        {
            // NB: A lot of checks are performed by LINQ helpers, so we omit tests for those cases.

            var substring = MethodInfoOf((string s) => s.Substring(default(int), default(int)));

            var parameters = substring.GetParameters();

            var startIndexParameter = parameters[0];
            var lengthParameter     = parameters[1];

            var obj        = Expression.Constant("bar");
            var startIndex = Expression.Constant(0);
            var length     = Expression.Constant(1);

            var argStartIndex = CSharpExpression.Bind(startIndexParameter, startIndex);
            var argLength     = CSharpExpression.Bind(lengthParameter, length);

            var cout = MethodInfoOf(() => Console.WriteLine(default(int)));

            var valueParameter = cout.GetParameters()[0];

            var value    = Expression.Constant(42);
            var argValue = CSharpExpression.Bind(valueParameter, value);

            // duplicate
            AssertEx.Throws <ArgumentException>(() => CSharpExpression.Call(obj, substring, argStartIndex, argStartIndex));

            // unbound
            AssertEx.Throws <ArgumentException>(() => CSharpExpression.Call(obj, substring, argStartIndex));

            // wrong member
            AssertEx.Throws <ArgumentException>(() => CSharpExpression.Call(obj, substring, argValue));

            // null
            var bindings = new[] { argStartIndex, argLength };

            AssertEx.Throws <ArgumentNullException>(() => CSharpExpression.Call(default(MethodInfo), bindings));
            AssertEx.Throws <ArgumentNullException>(() => CSharpExpression.Call(default(MethodInfo), bindings.AsEnumerable()));
            AssertEx.Throws <ArgumentNullException>(() => CSharpExpression.Call(obj, default(MethodInfo), bindings));
            AssertEx.Throws <ArgumentNullException>(() => CSharpExpression.Call(obj, default(MethodInfo), bindings.AsEnumerable()));
        }
Beispiel #14
0
        public void ArrayAccess_ByRef_CSharpNodes_Int()
        {
            var xs = Expression.Parameter(typeof(int[]));
            var i  = Expression.Parameter(typeof(int));

            var inc = typeof(Interlocked).GetMethod(nameof(Interlocked.Increment), new[] { typeof(int).MakeByRefType() });

            MethodCallCSharpExpression mce = CSharpExpression.Call(inc, new Expression[] { CSharpExpression.ArrayAccess(xs, i) });

            var res = Expression.Lambda <Func <int[], int, int> >(mce, xs, i);

            var f = res.Compile();

            var vals = new int[] { 41 };

            int val = f(vals, 0);

            Assert.AreEqual(42, val);
            Assert.AreEqual(42, vals[0]);
        }
Beispiel #15
0
        public void MethodCall_Compile_EvalOrder()
        {
            var a  = Expression.Parameter(typeof(int));
            var m  = MethodInfoOf(() => G(0, 0, 0));
            var ps = m.GetParameters();

            var a1 = CSharpExpression.Bind(ps[1], Expression.Assign(a, Expression.Constant(1)));
            var a2 = CSharpExpression.Bind(ps[0], a);
            var a3 = CSharpExpression.Bind(ps[2], Expression.Assign(a, Expression.Constant(2)));

            var e =
                Expression.Block(
                    new[] { a },
                    // G(y: a = 1, x: a, z: a = 2)
                    CSharpExpression.Call(null, m, a1, a2, a3)
                    );

            var res = Expression.Lambda <Func <string> >(e).Compile()();

            Assert.AreEqual("1,1,2", res);
        }
Beispiel #16
0
        public void MethodCall_Properties_Instance()
        {
            var substring = MethodInfoOf((string s) => s.Substring(default(int), default(int)));

            var parameters = substring.GetParameters();

            var startIndexParameter = parameters[0];
            var lengthParameter     = parameters[1];

            var obj        = Expression.Constant("bar");
            var startIndex = Expression.Constant(0);
            var length     = Expression.Constant(1);

            var arg0 = CSharpExpression.Bind(startIndexParameter, startIndex);
            var arg1 = CSharpExpression.Bind(lengthParameter, length);

            {
                var res = CSharpExpression.Call(obj, substring, arg0, arg1);

                Assert.AreEqual(CSharpExpressionType.Call, res.CSharpNodeType);
                Assert.AreSame(obj, res.Object);
                Assert.AreEqual(substring, res.Method);
                Assert.AreEqual(typeof(string), res.Type);
                Assert.IsTrue(res.Arguments.SequenceEqual(new[] { arg0, arg1 }));
            }

            {
                var res = CSharpExpression.Call(obj, substring, new[] { arg0, arg1 }.AsEnumerable());

                Assert.AreEqual(CSharpExpressionType.Call, res.CSharpNodeType);
                Assert.AreSame(obj, res.Object);
                Assert.AreEqual(substring, res.Method);
                Assert.AreEqual(typeof(string), res.Type);
                Assert.IsTrue(res.Arguments.SequenceEqual(new[] { arg0, arg1 }));
            }
        }
Beispiel #17
0
        public void MethodCall_Compile_NoCopyOptimization()
        {
            var method = MethodInfoOf(() => F(default(int), default(int), default(int)));

            var parameters = method.GetParameters();

            var parameterX = parameters[0];
            var parameterY = parameters[1];
            var parameterZ = parameters[2];

            var valueX = Expression.Constant(1);
            var valueY = Expression.Constant(2);
            var valueZ = Expression.Constant(3);

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterX, valueX),
                                                      CSharpExpression.Bind(parameterY, valueY)
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2)
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterY, valueY),
                                                      CSharpExpression.Bind(parameterX, valueX)
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2)
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterY, valueY),
                                                      CSharpExpression.Bind(parameterX, valueX),
                                                      CSharpExpression.Bind(parameterZ, valueZ)
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2, 3)
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterX, valueX),
                                                      CSharpExpression.Bind(parameterY, valueY),
                                                      CSharpExpression.Bind(parameterZ, valueZ)
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2, 3)
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterY, log(valueY, "Y")),
                                                      CSharpExpression.Bind(parameterX, valueX),
                                                      CSharpExpression.Bind(parameterZ, log(valueZ, "Z"))
                                                      ),
                                new LogAndResult <int> {
                Value = F(1, 2, 3), Log = { "Y", "Z" }
            }
                                );

            AssertCompile <int>(log =>
                                CSharpExpression.Call(method,
                                                      CSharpExpression.Bind(parameterY, log(valueY, "Y")),
                                                      CSharpExpression.Bind(parameterX, Expression.Default(typeof(int))),
                                                      CSharpExpression.Bind(parameterZ, log(valueZ, "Z"))
                                                      ),
                                new LogAndResult <int> {
                Value = F(0, 2, 3), Log = { "Y", "Z" }
            }
                                );
        }
Beispiel #18
0
        public void MethodCall_Compile_ByRef_Variable()
        {
            var method = MethodInfoOf((int x) => int.TryParse("", out x));

            var parameters = method.GetParameters();

            var parameterX = parameters[0];
            var parameterY = parameters[1];

            var valueX = Expression.Constant("42");
            var valueY = Expression.Parameter(typeof(int));

            AssertCompile <int>(log =>
                                Expression.Block(new[] { valueY },
                                                 CSharpExpression.Call(method,
                                                                       CSharpExpression.Bind(parameterX, log(valueX, "S")),
                                                                       CSharpExpression.Bind(parameterY, valueY)
                                                                       ),
                                                 valueY
                                                 ),
                                new LogAndResult <int> {
                Value = 42, Log = { "S" }
            }
                                );

            AssertCompile <int>(log =>
                                Expression.Block(new[] { valueY },
                                                 CSharpExpression.Call(method,
                                                                       CSharpExpression.Bind(parameterX, log(valueX, "S")),
                                                                       CSharpExpression.Bind(parameterY, log(valueY, "X"))
                                                                       ),
                                                 valueY
                                                 ),
                                new LogAndResult <int> {
                Value = 0, Log = { "S", "X" }
            }                                                           // log(...) is not writeable
                                );

            AssertCompile <int>(log =>
                                Expression.Block(new[] { valueY },
                                                 CSharpExpression.Call(method,
                                                                       CSharpExpression.Bind(parameterY, valueY),
                                                                       CSharpExpression.Bind(parameterX, log(valueX, "S"))
                                                                       ),
                                                 valueY
                                                 ),
                                new LogAndResult <int> {
                Value = 42, Log = { "S" }
            }
                                );

            AssertCompile <int>(log =>
                                Expression.Block(new[] { valueY },
                                                 CSharpExpression.Call(method,
                                                                       CSharpExpression.Bind(parameterY, log(valueY, "X")),
                                                                       CSharpExpression.Bind(parameterX, log(valueX, "S"))
                                                                       ),
                                                 valueY
                                                 ),
                                new LogAndResult <int> {
                Value = 0, Log = { "X", "S" }
            }                                                           // log(...) is not writeable
                                );
        }