dadhi/FastExpressionCompiler

Working with ref return values

yanoska opened this issue · 2 comments

I am unable to work with functions which returns ref value. Calling method TestDynamicDelegateVariableAccess throws Property 'Int32 X' is not defined for type 'ConsoleApp3.Pars&' (Parameter 'property')' . Calling TestDynamicDelegateVariableAccess throws Expression of type 'ConsoleApp3.Pars&' cannot be used for assignment to type 'ConsoleApp3.Pars'' . What I am doing wrong?

using FastExpressionCompiler.LightExpression;
using System.Diagnostics;

namespace ConsoleApp3
{
    internal class Program
    {
        delegate void ValueProcessor();

        static void Main(string[] args)
        {
            var p = new ParamValue() { X = 5 };
            var pars = new ParamProcessor(p);

            pars.GetParameter().X++;

            void f(int step)
            {
                ref ParamValue q = ref pars.GetParameter();
                q.X += step;
            };

            f(10);

            Debug.Assert(pars.GetParameter().X == 16);

            TestDynamicDelegateDirectCall(pars);
            //TestDynamicDelegateVariableAccess(pars);
        }

        static void TestDynamicDelegateDirectCall(ParamProcessor pars)
        {
            var getParMethod = typeof(ParamProcessor).GetMethod(nameof(ParamProcessor.GetParameter));
            var ppInstance = Expression.Constant(pars);
            var getParCall = Expression.Call(ppInstance, getParMethod);
            var xProperty = typeof(ParamValue).GetProperty(nameof(ParamValue.X));
            var xPropertyAccess = Expression.MakeMemberAccess(getParCall, xProperty);
            var assignValue = Expression.Assign(xPropertyAccess, Expression.Constant(7));

            var f2 =
            Expression.Lambda<ValueProcessor>(assignValue)
                      .CompileSys();

            f2();

            Debug.Assert(pars.GetParameter().X == 7);
        }

        static void TestDynamicDelegateVariableAccess(ParamProcessor pars)
        {
            var getParMethod = typeof(ParamProcessor).GetMethod(nameof(ParamProcessor.GetParameter));
            var ppInstance = Expression.Constant(pars);
            var getParCall = Expression.Call(ppInstance, getParMethod);

            var variable = Expression.Variable(typeof(ParamValue).MakeByRefType(), "value");
            var variableAssign = Expression.Assign(variable, getParCall);


            var xProperty = typeof(ParamValue).GetProperty(nameof(ParamValue.X));
            var varibleMemberAccess = Expression.MakeMemberAccess(variable, xProperty);
            var assignValue = Expression.Assign(varibleMemberAccess, Expression.Constant(8));

            var block = Expression.Block(variableAssign, assignValue);

            var f2 =
            Expression.Lambda<ValueProcessor>(block, variable)
                      .CompileSys();

            f2();

            Debug.Assert(pars.GetParameter().X == 8);
        }
    }

    public struct ParamValue
    {
        public int X { get; set; }
    }

    public class ParamProcessor
    {
        private ParamValue _instance;

        public ParamProcessor(ParamValue pars)
        {
            _instance = pars;
        }

        public ref ParamValue GetParameter()
        {
            return ref _instance;
        }
    }
}`
dadhi commented

@yanoska Hi, I will check your examples. Thank you.

dadhi commented

@yanoska Hi there. I have fixed the issue in the upcoming FEC version. But you cannot do the CompileSys() because the System Expression trees do not support ref returning methods and ref variables.
So use the CompileFast().
I have rewrote your tests correctly here: https://github.com/dadhi/FastExpressionCompiler/blob/master/test/FastExpressionCompiler.IssueTests/Issue365_Working_with_ref_return_values.cs