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]); }
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]); }
protected internal override Expression VisitMethodCall(MethodCallCSharpExpression node) { Visited = true; return(base.VisitMethodCall(node)); }