Example #1
0
def unify_constraints(constraints, solution=None):
    """
    Blaze type unification. Two types unify if:

        - They have the same type constructor, and
        - They have an equal number of sub-terms which unify element-wise

    Our algorithm is different from a conventional implementation in that we
    have a different notion of equality since we allow coercion which we
    solve by generating new coercion constraints in the form of
    [(A coerces to B)], where A and B are type variables.

    Parameters
    ----------
    constraints : [(Mono, Mono)]
        List of constraints (blaze type equations)

    Returns: { TypeVar : set([ Mono ]) }
        Returns a solution to the set of constraints. The solution is a set
        of bindings (a substitution) from type variables to type sets.
    """
    solution = IdentityDict(solution)
    remaining = []

    # Initialize solution
    for t1, t2 in constraints:
        for freevar in chain(free(t1), free(t2)):
            if freevar not in solution:
                solution[freevar] = set()

    # Calculate solution
    for t1, t2 in constraints:
        unify_single(t1, t2, solution, remaining)

    return solution, remaining
Example #2
0
def unify_single(t1, t2, solution, remaining):
    """
    Unify a single type equation and update the solution and remaining
    constraints.
    """
    if isinstance(t1, TypeVar) and isinstance(t2, TypeVar):
        remaining.append((t1, t2))
    elif isinstance(t1, TypeVar):
        if t1 in free(t2):
            raise error.UnificationError("Cannot unify recursive types")
        solution[t1].add(t2)
        remaining.append((t1, t2))
    elif isinstance(t2, TypeVar):
        if t2 in free(t1):
            raise error.UnificationError("Cannot unify recursive types")
        solution[t2].add(t1)
    elif isinstance(t1, TypeConstructor):
        verify(t1, t2)
    elif not isinstance(t1, Mono) and not isinstance(t2, Mono):
        verify(t1, t2)
    elif getattr(t1, "cls", None) == MEASURE and getattr(t2, "cls", None) == MEASURE:
        # If both types are measures, verify they can be promoted
        promote_units(t1, t2)
    else:
        verify(t1, t2)
        for arg1, arg2 in zip(t1.parameters, t2.parameters):
            unify_single(arg1, arg2, solution, remaining)
Example #3
0
def unify_single(t1, t2, solution, remaining):
    """
    Unify a single type equation and update the solution and remaining
    constraints.
    """
    if isinstance(t1, TypeVar) and isinstance(t2, TypeVar):
        remaining.append((t1, t2))
    elif isinstance(t1, TypeVar):
        if t1 in free(t2):
            raise error.UnificationError("Cannot unify recursive types")
        solution[t1].add(t2)
        remaining.append((t1, t2))
    elif isinstance(t2, TypeVar):
        if t2 in free(t1):
            raise error.UnificationError("Cannot unify recursive types")
        solution[t2].add(t1)
    elif isinstance(t1, TypeConstructor):
        verify(t1, t2)
    elif not free(t1) and not free(t2):
        # No need to recurse, this will be caught by promote()
        pass
    else:
        verify(t1, t2)
        for arg1, arg2 in zip(t1.parameters, t2.parameters):
            unify_single(arg1, arg2, solution, remaining)
Example #4
0
def reify(solution, S=None):
    """
    Reify a typing solution, returning a new solution with types as concrete
    types as opposed to type sets.

    Parameters
    ----------
    solution : { TypeVar : set([ Type ]) }
        Typing solution

    Returns: { TypeVar : Type }
        Returns a solution reduced to concrete types only.
    """
    if S is None:
        S = IdentityDict()

    seen = set()
    queue = deque(dict_iteritems(solution))
    while queue:
        typevar, t = queue.popleft()
        t = frozenset(t)
        if typevar in S:
            continue

        typeset = solution[typevar]
        freevars = IdentityDict.fromkeys(chain(*[free(t) for t in typeset]))

        if not typeset:
            S[typevar] = typevar
            typeset.add(typevar)
            continue
        elif freevars and (typevar, t) not in seen:
            # Reify dependencies first
            queue.append((typevar, t))
            seen.add((typevar, t))
        elif freevars:
            typeset = set(substitute(S, t) for t in typeset)

        S[typevar] = promote_units(*typeset)

    return S