示例#1
0
        /// <summary>
        ///     Findes the smallest union type between the two types, with the assumption that 'wider' is a supertype of 'smaller'
        /// </summary>
        /// <param name="wider"></param>
        /// <param name="smaller"></param>
        /// <returns></returns>
        private static Type SelectSmallestUnion(this Type wider, Type smaller)
        {
            switch (wider)
            {
            case Var a:
                return(a);

            case ListType l when smaller is ListType lsmaller:
                return(new ListType(
                           l.InnerType.SelectSmallestUnion(
                               l.InnerType.SelectSmallestUnion(lsmaller.InnerType))));

            case Curry cWider when smaller is Curry cSmaller:
                var arg =
                    cWider.ArgType.SelectSmallestUnion(cSmaller.ArgType);
                var result =
                    cWider.ResultType.SelectSmallestUnion(cSmaller.ResultType);
                return(new Curry(arg, result));

            default:
                if (wider.IsSuperSet(smaller) && !smaller.IsSuperSet(wider))
                {
                    return(smaller);
                }

                return(wider);
            }
        }
示例#2
0
        public static IExpression SpecializeToSmallestType(this IExpression e)
        {
            if (e.Types.Count() == 1)
            {
                return(e);
            }

            Type smallest = null;

            foreach (var t in e.Types)
            {
                if (smallest == null)
                {
                    smallest = t;
                    continue;
                }

                var smallestIsSuperset = smallest.IsSuperSet(t);
                if (!t.IsSuperSet(smallest) && !smallestIsSuperset)
                {
                    // Neither one is smaller then the other, we can not compare them
                    return(e);
                }

                if (smallestIsSuperset)
                {
                    smallest = t;
                }
            }

            return(e.Specialize(new[] { smallest }));
        }
示例#3
0
        /// <summary>
        ///     The unification table is built when the type of an argument is introspected to see if it fits in the excpect type
        ///     t0 here is the **expected** (wider) type, whereas t1 is the **actual** argument type.
        ///     In other words, if we expect a `double`, a `pdouble` fits in there too.
        ///     If we expect a function capable of handling pdoubles and giving strings, a function capable of handling doubles and
        ///     giving bools will work just as well
        /// </summary>
        /// <param name="t0"></param>
        /// <param name="t1"></param>
        /// <returns></returns>
        public static Dictionary <string, Type> UnificationTable(this Type t0, Type t1,
                                                                 bool reverseSupersetRelation = false)
        {
            var substitutionsOn0 = new Dictionary <string, Type>();


            bool AddSubs(string key, Type valueToAdd)
            {
                if (substitutionsOn0.TryGetValue(key, out var oldSubs))
                {
                    return(oldSubs.Equals(valueToAdd));
                }

                substitutionsOn0[key] = valueToAdd;
                return(true);
            }

            bool AddAllSubs(Dictionary <string, Type> table)
            {
                if (table == null)
                {
                    return(false);
                }

                foreach (var(key, tp) in table)
                {
                    if (!AddSubs(key, tp))
                    {
                        return(false);
                    }
                }

                return(true);
            }

            switch (t0)
            {
            case Var a:
                if (!AddSubs(a.Name, t1))
                {
                    return(null);
                }

                break;

            case ListType l0 when t1 is ListType l1: {
                var table = l0.InnerType.UnificationTable(l1.InnerType, reverseSupersetRelation);
                if (!AddAllSubs(table))
                {
                    return(null);
                }

                break;
            }

            case Curry curry0 when t1 is Curry curry1: {
                // contravariance for arguments: reversed
                var tableA = curry0.ArgType.UnificationTable(curry1.ArgType, !reverseSupersetRelation);
                var tableB = curry0.ResultType.UnificationTable(curry1.ResultType, reverseSupersetRelation);
                if (!(AddAllSubs(tableA) && AddAllSubs(tableB)))
                {
                    return(null);
                }

                break;
            }

            default:

                if (t1 is Var v)
                {
                    AddSubs(v.Name, t0);
                    break;
                }

                if (!reverseSupersetRelation && !t0.IsSuperSet(t1))
                {
                    return(null);
                }

                if (reverseSupersetRelation && !t1.IsSuperSet(t0))
                {
                    return(null);
                }

                break;
            }

            // We have the unification table at this point
            // However, the unifications are transitive and this transitivity should be encoded
            // E.g. if the unification table is
            // { $a --> $x; $x --> string} it should be rewritten to {$a --> string; $x --> string}
            // This can happen e.g. when ($a -> string) is unified with ($x -> $x)
            // We do not have to worry about overlapping names, as they should be cleaned before calling this method

            bool appliedTransitivity;

            do
            {
                appliedTransitivity = false;
                var keys = substitutionsOn0.Keys.ToList();
                foreach (var key in keys)
                {
                    var val         = substitutionsOn0[key];
                    var usedVars    = val.UsedVariables();
                    var isContained = keys.Any(usedVars.Contains);
                    if (!isContained)
                    {
                        continue;
                    }

                    var newVal = val.Substitute(substitutionsOn0);
                    if (newVal.Equals(val))
                    {
                        continue;
                    }

                    if (newVal.UsedVariables().Contains(key) && !newVal.Equals(new Var(key)))
                    {
                        // The substitution contains itself; and it is bigger then itself
                        // This means that $a is substituted by e.g. ($a -> $x), implying an infinite and contradictory type
                        return(null);
                    }

                    substitutionsOn0[key] = newVal;
                    appliedTransitivity   = true;
                }
            } while (appliedTransitivity);

            return(substitutionsOn0);
        }