Пример #1
0
        public void TypeSubstitutionExpressionVisitor_ChangeInterface()
        {
            var query = new[] { 2, 3, 5 }.AsQueryable().Where(x => x > 0).Select(x => x.ToString()).Expression;

            var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type>
            {
                { typeof(IQueryable <>), typeof(IEnumerable <>) }
            });
        }
        /// <summary>
        /// Casts expressions containing reactive interface types to metadata entity types.
        /// </summary>
        /// <param name="expression">The expression to replace types in.</param>
        /// <returns>The expression with interface types replaced by metadata entity types.</returns>
        private static Expression CastExpression(Expression expression)
        {
            var subst = new TypeSubstitutionExpressionVisitor(new Dictionary<Type, Type>
            {
                { typeof(TMetadataInterface), typeof(TMetadataEntity) },
            });

            var result = subst.Apply(expression);

            return result;
        }
Пример #3
0
        public void TypeSubstitutionExpressionVisitor_Anonymize()
        {
            var pers  = typeof(Person);
            var query = (Expression <Func <IEnumerable <Person>, IEnumerable <string> > >)(xs => from x in xs where x.Age > 10 let name = x.Name where name.StartsWith("B") select name.ToUpper() + " is " + x.Age);

            var check1 = new TypeErasureChecker(new[] { typeof(Person) });

            Assert.ThrowsException <InvalidOperationException>(() => check1.Visit(query));


            var anon = RuntimeCompiler.CreateAnonymousType(new[]
            {
                new KeyValuePair <string, Type>("Name", typeof(string)),
                new KeyValuePair <string, Type>("Age", typeof(int)),
            });

            var subst1 = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type>
            {
                { pers, anon }
            });

            var res1 = subst1.Apply(query);

            check1.Visit(res1);

            var check2 = new TypeErasureChecker(new[] { anon });

            Assert.ThrowsException <InvalidOperationException>(() => check2.Visit(res1));


            var f = ((LambdaExpression)res1).Compile();

            var cast       = ((MethodInfo)ReflectionHelpers.InfoOf(() => Enumerable.Cast <int>(null))).GetGenericMethodDefinition().MakeGenericMethod(anon);
            var peopleObj  = new[] { Activator.CreateInstance(anon, new object[] { "Bart", 10 }), Activator.CreateInstance(anon, new object[] { "Lisa", 8 }), Activator.CreateInstance(anon, new object[] { "Bart", 21 }) };
            var peopleAnon = cast.Invoke(obj: null, new object[] { peopleObj });
            var qres       = (IEnumerable <string>)f.DynamicInvoke(peopleAnon);

            Assert.IsTrue(new[] { "BART is 21" }.SequenceEqual(qres));

            var subst2 = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type>
            {
                { anon, pers }
            });

            var res2 = subst2.Apply(res1);

            check2.Visit(res2);

            Assert.ThrowsException <InvalidOperationException>(() => check1.Visit(res2));

            var eq = new ExpressionEqualityComparer();

            Assert.IsTrue(eq.Equals(query, res2));
        }
Пример #4
0
        public void TypeSubstitutionExpressionVisitor_ConstantChange_Fail()
        {
            Expression <Func <int> > f = () => 42;

            var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type>
            {
                { typeof(int), typeof(long) }
            });

            Assert.ThrowsException <InvalidOperationException>(() => subst.Apply(f));
        }
        protected override Expression LookupOther(string id, Type type, Type funcType)
        {
            if (!externalFunctions.TryGetValue(id, out var expr))
            {
                return(base.LookupOther(id, type, funcType));
            }

            var typeMap     = funcType.UnifyExact(expr.Type);
            var substitutor = new TypeSubstitutionExpressionVisitor(typeMap);
            var unifiedExpr = substitutor.Visit(expr);

            return(unifiedExpr);
        }
Пример #6
0
            /// <summary>
            /// Rewrites a stream to an untyped stream if the stream definition
            /// is closed over wildcard types, and the stream factory returns
            /// an untyped stream.
            /// </summary>
            /// <param name="key">The stream identifier.</param>
            /// <param name="expr">The stream expression.</param>
            /// <returns>
            /// The stream expression with types rewritten to the untyped stream
            /// variant if the expression meets the expected criteria.
            /// </returns>
            private Expression RewriteQuotedReactiveStreamToUntyped(string key, Expression expr)
            {
                // Search for free variables
                var freeVariables = FreeVariableScanner.Scan(expr).ToArray();

                // For now, with the absence of stream factory operators, it is safe to
                // throw if there is more than one free variable as all stream expressions
                // will be invocations of exactly one unbound stream factory parameter.
                if (freeVariables.Length > 1)
                {
                    throw new InvalidOperationException(
                              string.Format(CultureInfo.InvariantCulture, "Unexpected stream expression '{0}' for key '{1}' on query engine '{2}'.", expr.ToTraceString(), key, _queryEngine.Uri.ToCanonicalString()));
                }

                if (freeVariables.Length == 1)
                {
                    // Find single stream factory parameter expression
                    var streamFactoryParam = freeVariables[0];
                    if (streamFactoryParam != null)
                    {
                        // Resolve stream factory type from metadata
                        if (_queryEngine._registry.SubjectFactories.TryGetValue(streamFactoryParam.Name, out var streamFactoryDefinition))
                        {
                            // TODO: support rewrites based on stream factory classes
                            // If definition is a lambda expression, rewrite to the return type
                            var streamFactoryType = streamFactoryDefinition.Expression.Type;
                            var invokeMethod      = streamFactoryType.GetMethod("Invoke");
                            if (invokeMethod != null && invokeMethod.ReturnType == typeof(IMultiSubject))
                            {
                                var actualStreamType   = expr.Type;
                                var expectedStreamType = invokeMethod.ReturnType;
                                if (actualStreamType != expectedStreamType)
                                {
                                    var substitutionVisitor = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type>
                                    {
                                        { actualStreamType, expectedStreamType }
                                    });

                                    _queryEngine.TraceSource.LazyStream_TypeRewrite(key, actualStreamType, expectedStreamType, _queryEngine.Uri);

                                    return(substitutionVisitor.Apply(expr));
                                }
                            }
                        }
                    }
                }

                return(expr);
            }
Пример #7
0
        public void Evaluate(Expression expression)
        {
            var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type>
            {
                { typeof(IQubjectFactory <>), typeof(ISubjectFactory <>) },
                { typeof(IQubject <>), typeof(ISubject <>) },
                { typeof(IQbservable <>), typeof(IObservable <>) },
                { typeof(IQbserver <>), typeof(IObserver <>) },
                { typeof(IQubscription), typeof(IDisposable) },
            });

            var expr = subst.Visit(expression);

            var fvs = FreeVariableScanner.Scan(expr);

            var map = new Dictionary <ParameterExpression, Expression>();

            foreach (var fv in fvs)
            {
                if (_registry.TryGetValue(fv.Name, out var res))
                {
                    if (res is Expression e)
                    {
                        var u = e.Type.UnifyExact(fv.Type);
                        var f = new TypeSubstitutionExpressionVisitor(u).Visit(e);
                        map.Add(fv, f);
                        continue;
                    }
                    else
                    {
                        e = Expression.Constant(res, fv.Type);
                        map.Add(fv, e);
                        continue;
                    }
                }

                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Could not bind '{0}'.", fv.Name));
            }

            var bound = new Binder(map).Bind(expr);

            if (bound.Type == typeof(void))
            {
                // TODO: Evaluate method could be more forgiving for void-returning delegates (no automatic coercion to object)
                bound = Expression.Block(bound, Expression.Default(typeof(object)));
            }

            bound.Evaluate();
        }
Пример #8
0
        public void TypeSubstitutionExpressionVisitor_NewArrayInit_Simple()
        {
            var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> {
                { typeof(string), typeof(bool) }
            });

            var expA = Expression.NewArrayInit(typeof(string), Expression.Parameter(typeof(string), "e1"), Expression.Parameter(typeof(string), "e2"));
            var expB = Expression.NewArrayInit(typeof(int), Expression.Parameter(typeof(int), "e1"), Expression.Parameter(typeof(int), "e2"));

            var res1 = subst.Apply(expA);
            var res2 = subst.Apply(expB);

            AssertEqual(res1, Expression.NewArrayInit(typeof(bool), Expression.Parameter(typeof(bool), "e1"), Expression.Parameter(typeof(bool), "e2")));
            Assert.AreSame(expB, res2);
        }
Пример #9
0
        public void TypeSubstitutionExpressionVisitor_NewArrayBounds_Simple()
        {
            var subst = new TypeSubstitutionExpressionVisitor(new Dictionary <Type, Type> {
                { typeof(string), typeof(bool) }
            });

            var expA = Expression.NewArrayBounds(typeof(string), Expression.Constant(1));
            var expB = Expression.NewArrayBounds(typeof(int), Expression.Constant(1));

            var res1 = subst.Apply(expA);
            var res2 = subst.Apply(expB);

            AssertEqual(res1, Expression.NewArrayBounds(typeof(bool), Expression.Constant(1)));
            Assert.AreSame(expB, res2);
        }
Пример #10
0
        /// <summary>
        /// Analyzes invocation expressions for the typical pattern of invoking a known resource. If a known resource is found, it gets bound using the definition in the registry.
        /// </summary>
        /// <param name="node">Expression to analyze.</param>
        /// <returns>Original expression if the invocation doesn't use a known resource; otherwise, the bound equivalent of the original expression.</returns>
        protected override Expression VisitInvocation(InvocationExpression node)
        {
            if (node.Expression is ParameterExpression p) // omitted unbound parameter check
            {
                var e = _registry[p.Name].Expression;

                var u = new TypeUnifier();
                u.Unify(p.Type, e.Type);

                if (u.Bindings.Count != 0)
                {
                    // assuming wildcards are on the left
                    e = new TypeSubstitutionExpressionVisitor(u.Bindings).Visit(e);
                }

                return(Expression.Invoke(e, Visit(node.Arguments))); // omited beta reduction
            }

            return(base.VisitInvocation(node));
        }
 /// <summary>
 /// Creates a new type substitution query expression visitor with the specified type substitutor.
 /// </summary>
 /// <param name="typeSubstitutor">Type substitutor to map source types onto target types.</param>
 public TypeSubstitutionQueryVisitor(TypeSubstitutor typeSubstitutor)
 {
     _subst = typeSubstitutor ?? throw new ArgumentNullException(nameof(typeSubstitutor));
     _lambdaBodyConverter = new TypeSubstitutionExpressionVisitor(_subst);
 }