Ejemplo n.º 1
0
        public override Element /*!*/ NontrivialJoin(Element /*!*/ first, Element /*!*/ second)
        {
            //Contract.Requires(second != null);
            //Contract.Requires(first != null);
            Contract.Ensures(Contract.Result <Element>() != null);
            Elt a = (Elt)first;
            Elt b = (Elt)second;

            Contract.Assert(a.what != What.Bottom && b.what != What.Bottom);
            if (a.what == What.Exact && b.what == What.Exact)
            {
                Contract.Assert(a.ty != null && b.ty != null);
                if (factory.IsTypeEqual(a.ty, b.ty))
                {
                    return(a);
                }
                else
                {
                    return(new Elt(What.Bounds, factory.JoinTypes(a.ty, b.ty)));
                }
            }

            // The result is going to be a Bounds, since at least one of the operands is a Bounds.
            Contract.Assert(1 <= a.BoundsCount && 1 <= b.BoundsCount); // a preconditions is that neither operand is Top
            int n = a.BoundsCount + b.BoundsCount;

            // Special case:  a and b each has exactly one bound
            if (n == 2)
            {
                Contract.Assert(a.ty != null && b.ty != null);
                IExpr join = factory.JoinTypes(a.ty, b.ty);
                Contract.Assert(join != null);
                if (join == a.ty && a.what == What.Bounds)
                {
                    return(a);
                }
                else if (join == b.ty && b.what == What.Bounds)
                {
                    return(b);
                }
                else
                {
                    return(new Elt(What.Bounds, join));
                }
            }

            // General case
            ArrayList /*IExpr*/  allBounds = new ArrayList/*IExpr*/ (n);  // final size
            ArrayList /*IExpr!*/ result    = new ArrayList/*IExpr!*/ (n); // a guess at the size, but could be as big as size(a)*size(b)

            if (a.ty != null)
            {
                allBounds.Add(a.ty);
            }
            else
            {
                allBounds.AddRange(cce.NonNull(a.manyBounds));
            }
            int bStart = allBounds.Count;

            if (b.ty != null)
            {
                allBounds.Add(b.ty);
            }
            else
            {
                allBounds.AddRange(cce.NonNull(b.manyBounds));
            }
            // compute the join of each pair, putting non-redundant joins into "result"
            for (int i = 0; i < bStart; i++)
            {
                IExpr /*!*/ aBound = cce.NonNull((IExpr /*!*/)allBounds[i]);
                for (int j = bStart; j < allBounds.Count; j++)
                {
                    IExpr /*!*/ bBound = (IExpr /*!*/)cce.NonNull(allBounds[j]);

                    IExpr /*!*/ join = factory.JoinTypes(aBound, bBound);
                    Contract.Assert(join != null);

                    int k = 0;
                    while (k < result.Count)
                    {
                        IExpr /*!*/ r = (IExpr /*!*/)cce.NonNull(result[k]);
                        if (factory.IsSubType(join, r))
                        {
                            // "join" is more restrictive than a bound already placed in "result",
                            // so toss out "join" and compute the join of the next pair
                            goto NEXT_PAIR;
                        }
                        else if (factory.IsSubType(r, join))
                        {
                            // "join" is less restrictive than a bound already placed in "result",
                            // so toss out that old bound
                            result.RemoveAt(k);
                        }
                        else
                        {
                            k++;
                        }
                    }
                    result.Add(join);
                    NEXT_PAIR : {
                    }
                }
            }
            return(new Elt(result, result.Count));
        }