Exemple #1
0
        /// <summary>
        /// Compares two trees.  If the trees differ only by constants then the list of constants which differ
        /// is provided as a list via an out-param.  The constants collected are the constants in the left
        /// side of the tree and only include constants which differ in value.
        /// </summary>
        public static bool Compare(Expression left, Expression right, out List <ConstantExpression> replacementNodes, out bool tooSpecific)
        {
            replacementNodes = null;
            tooSpecific      = false;

            FlatTreeWalker walkLeft  = new FlatTreeWalker();
            FlatTreeWalker walkRight = new FlatTreeWalker();

            walkLeft.Visit(left);

            Debug.Assert(walkLeft._templated == null);

            walkRight.Visit(right);

            // check the length first to see if the trees are obviously different
            if (walkLeft.Expressions.Count != walkRight.Expressions.Count)
            {
                return(false);
            }

            // then see if they differ by just constants which we could replace
            List <ConstantExpression> needsReplacement = new List <ConstantExpression>();

            VariableInfo varInfo = new VariableInfo();

            for (int i = 0; i < walkLeft.Expressions.Count; i++)
            {
                Expression currentLeft = walkLeft.Expressions[i], currentRight = walkRight.Expressions[i];

                // ReductionRewriter should have removed these

                if (currentLeft.NodeType != currentRight.NodeType)
                {
                    // different node types, they can't possibly be equal
                    return(false);
                }
                else if (currentLeft.Type != currentRight.Type)
                {
                    // they can't possibly be a match
                    return(false);
                }

                if (!CompareTwoNodes(walkRight, needsReplacement, varInfo, currentLeft, currentRight, ref tooSpecific))
                {
                    return(false);
                }
            }

            replacementNodes = needsReplacement;
            return(true);
        }
Exemple #2
0
        private static bool CompareTwoNodes(FlatTreeWalker walkRight, List <ConstantExpression> needsReplacement, VariableInfo varInfo, Expression currentLeft, Expression currentRight, ref bool tooSpecific)
        {
            switch (currentLeft.NodeType)
            {
            case ExpressionType.Dynamic:
                var dynLeft  = (DynamicExpression)currentLeft;
                var dynRight = (DynamicExpression)currentRight;

                if (!dynRight.Binder.CacheIdentity.Equals(dynLeft.Binder.CacheIdentity))
                {
                    return(false);
                }
                break;

            case ExpressionType.Constant:
                // check constant value
                ConstantExpression ceLeft  = (ConstantExpression)currentLeft;
                ConstantExpression ceRight = (ConstantExpression)currentRight;

                object leftValue  = ceLeft.Value;
                object rightValue = ceRight.Value;

                if (leftValue == null && rightValue == null)
                {
                    // both are null, no need to template this param.
                    break;
                }

                // See if they're both sites
                CallSite leftSite  = ceLeft.Value as CallSite;
                CallSite rightSite = ceRight.Value as CallSite;
                if (leftSite != null)
                {
                    if (rightSite == null)
                    {
                        return(false);
                    }

                    if (!leftSite.Binder.CacheIdentity.Equals(rightSite.Binder.CacheIdentity))
                    {
                        return(false);
                    }

                    return(true);
                }
                else if (rightSite != null)
                {
                    return(false);
                }

                // add if left is null and right's something else or
                // left and right aren't equal.  We'll also add it if
                // the existing rule has hoisted this value into a template
                // parameter.
                if (leftValue == null ||
                    !leftValue.Equals(rightValue) ||
                    walkRight.IsTemplatedConstant(ceRight))
                {
                    if (walkRight._templated != null && !walkRight.IsTemplatedConstant(ceRight))
                    {
                        // if we have template args on the right hand side and this isn't
                        // one of them we need to re-compile a more general rule.
                        tooSpecific = true;
                    }

                    needsReplacement.Add(ceLeft);
                }
                break;

            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
                if (!CompareEquality((BinaryExpression)currentLeft, (BinaryExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.Add:
            case ExpressionType.And:
            case ExpressionType.AndAlso:
            case ExpressionType.ArrayIndex:
            case ExpressionType.Divide:
            case ExpressionType.ExclusiveOr:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.LeftShift:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.Modulo:
            case ExpressionType.Multiply:
            case ExpressionType.Or:
            case ExpressionType.OrElse:
            case ExpressionType.RightShift:
            case ExpressionType.Subtract:
            case ExpressionType.AddAssign:
            case ExpressionType.SubtractAssign:
            case ExpressionType.MultiplyAssign:
            case ExpressionType.AddAssignChecked:
            case ExpressionType.SubtractAssignChecked:
            case ExpressionType.MultiplyAssignChecked:
            case ExpressionType.DivideAssign:
            case ExpressionType.ModuloAssign:
            case ExpressionType.PowerAssign:
            case ExpressionType.AndAssign:
            case ExpressionType.OrAssign:
            case ExpressionType.RightShiftAssign:
            case ExpressionType.LeftShiftAssign:
            case ExpressionType.ExclusiveOrAssign:
                if (!Compare((BinaryExpression)currentLeft, (BinaryExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.Call:
                if (!Compare((MethodCallExpression)currentLeft, (MethodCallExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.New:
                // chcek ConstructorInfo and BindingInfo
                if (!Compare((NewExpression)currentLeft, (NewExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.TypeIs:
            case ExpressionType.TypeEqual:
                // check type
                if (!Compare((TypeBinaryExpression)currentLeft, (TypeBinaryExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.Block:
                // compare factory method
                if (!Compare(varInfo, (BlockExpression)currentLeft, (BlockExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.MemberAccess:
                // compare member
                if (!Compare((MemberExpression)currentLeft, (MemberExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.Try:
                // compare catch finally blocks and their handler types
                if (!Compare(varInfo, (TryExpression)currentLeft, (TryExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.Parameter:
                if (!Compare(varInfo, (ParameterExpression)currentLeft, (ParameterExpression)currentRight))
                {
                    return(false);
                }
                break;

            case ExpressionType.Lambda:
            case ExpressionType.Assign:
            case ExpressionType.Goto:
            case ExpressionType.Throw:
            case ExpressionType.Loop:
            case ExpressionType.Default:
            case ExpressionType.Convert:
            case ExpressionType.TypeAs:
            case ExpressionType.Unbox:
            case ExpressionType.Negate:
            case ExpressionType.Not:
            case ExpressionType.Conditional:
            case ExpressionType.NewArrayInit:
            case ExpressionType.NewArrayBounds:
            case ExpressionType.Invoke:
                // these nodes children and types completely
                // define the node
                break;

            case ExpressionType.Label:
            // TODO: cache and compare labels
            case ExpressionType.Switch:
            // TODO: compare case values
            case ExpressionType.Extension:

                // we should have been reduced, but error on the side of being different.
                return(false);

            default:
                throw Assert.Unreachable;
            }
            return(true);
        }