示例#1
0
def test_var_more_unification():
    checker = Checker()
    T = checker.fresh_var()
    U = checker.fresh_var()

    checker.unify(Tuple(T, Bool), Tuple(Int, U))
    assert checker.unifiers.same_set(T, Int)
    assert checker.unifiers.same_set(U, Bool)
示例#2
0
    def infer_type(self, checker: check.Checker) -> typ.Type:
        pred_type = self.pred.infer_type(checker)
        checker.unify(pred_type, typ.Bool)

        yes_type = self.yes.infer_type(checker)
        no_type = self.no.infer_type(checker)
        checker.unify(yes_type, no_type)

        return checker.unifiers.concretize(yes_type)
示例#3
0
    def infer_type(self, checker: check.Checker) -> typ.Type:

        # In a new scope, infer the type of the body.
        # Scoped because `self.param` is valid only inside this scope.
        # Parameter types are non-generic while checking the body.
        with checker.new_scope(), checker.scoped_non_generic() as arg_type:
            checker.type_env[self.param] = arg_type
            body_type = self.body.infer_type(checker)

        # After inferring body's type, arg type might be known.
        arg_type = checker.unifiers.concretize(arg_type)

        return typ.Fn(arg_type, body_type)
示例#4
0
def std_env(checker: check.Checker) -> StdEnv:
    T = checker.fresh_var()
    U = checker.fresh_var()
    V = checker.fresh_var()
    W = checker.fresh_var()

    return env.Env(locals={
        syntax.Ident("null"): typ.Fn(typ.List(T), typ.Bool),
        syntax.Ident("tail"): typ.Fn(typ.List(U), typ.List(U)),
        syntax.Ident("zero"): typ.Fn(typ.Int, typ.Bool),
        syntax.Ident("succ"): typ.Fn(typ.Int, typ.Int),
        syntax.Ident("pred"): typ.Fn(typ.Int, typ.Int),
        syntax.Ident("times"): typ.Fn(typ.Int, typ.Fn(typ.Int, typ.Int)),
        syntax.Ident("pair"): typ.Fn(V, typ.Fn(W, typ.Tuple(V, W))),
    })
示例#5
0
def test_unification_error():
    checker = Checker()
    T = checker.fresh_var()

    with pytest.raises(UnificationError):
        checker.unify(Tuple(Bool, Int), Tuple(T, T))

    with pytest.raises(UnificationError):
        checker.unify(Tuple(Bool, Int), Tuple(Bool))

    with pytest.raises(UnificationError):
        checker.unify(Tuple(Bool, Int), Fn(Bool, Int))
示例#6
0
    def infer_type(self, checker: check.Checker) -> typ.Type:

        # Get best guess as to the type of `self.arg`.
        arg_type = self.arg.infer_type(checker)

        # Set up a function type.
        beta = checker.fresh_var()
        fn_type_joiner = typ.Fn(arg_type, beta)

        # Ensure the `self.fn` refers to a Fn type.
        fn_type = self.fn.infer_type(checker)

        checker.unify(fn_type, fn_type_joiner)

        # In case beta's root was changed in the last unification, get it's
        # current root.
        return checker.unifiers.concretize(beta)
示例#7
0
def test_concretize():
    checker = Checker()

    T = checker.fresh_var()
    U = checker.fresh_var()
    tup = Tuple(T, Fn(U, Int))

    checker.unify(T, List(Bool))
    checker.unify(U, T)

    concrete = checker.concretize(tup)
    assert concrete == Tuple(List(Bool), Fn(List(Bool), Int))
示例#8
0
    def infer_type(self, checker: check.Checker) -> typ.Type:

        # Scope the `left = right` binding.
        with checker.new_scope():

            # First, bind `left` to a fresh type variable. This allows
            # for recursive let statements.
            # Note: `alpha` is only non-generic while inferring `right`. TODO: Why tho?
            with checker.scoped_non_generic() as alpha:
                checker.type_env[self.left] = alpha

                # Next infer the type of `right` using the binding just created.
                right_type = self.right.infer_type(checker)

            # Link the type variable with the inferred type of `right`.
            checker.unify(alpha, right_type)

            # With the environment set up, now the body can be typechecked.
            return self.body.infer_type(checker)
示例#9
0
def test_basic_generic_non_generic_unification_reversed():
    checker = Checker()

    generic = checker.fresh_var()
    non_generic = checker.fresh_var(non_generic=True)

    checker.unify(non_generic, generic)

    assert checker.is_non_generic(generic)
示例#10
0
def test_complex_generic_non_generic_unification():
    checker = Checker()

    generic = checker.fresh_var()
    non_generic = checker.fresh_var(non_generic=True)

    t = Tuple(generic)
    checker.unify(non_generic, t)

    assert checker.is_non_generic(generic)
示例#11
0
def test_var_unification():
    checker = Checker()
    T = checker.fresh_var()
    U = checker.fresh_var()

    assert not checker.unifiers.same_set(T, U)

    checker.unify(T, U)
    assert checker.unifiers.same_set(T, U)

    checker.unify(T, Bool)
    assert checker.unifiers.same_set(T, Bool)
    assert checker.unifiers.same_set(U, Bool)
示例#12
0
def test_concrete_atom_unification():
    checker = Checker()
    checker.unify(Int, Int)
示例#13
0
def test_concrete_poly_unification():
    checker = Checker()
    checker.unify(Tuple(Int, Bool), Tuple(Int, Bool))
示例#14
0
 def infer_type(self, checker: check.Checker) -> typ.Type:
     return checker.duplicate_type(checker.type_env[self])
示例#15
0
@pg.production("expr : BOOL_LIT")
def bool_lit_expr(s):
    value = {"true": True, "false": False}[s[0].value]
    return syntax.Const(value, typ.Bool)


@pg.production("expr : IDENT")
def ident_expr(s):
    return syntax.Ident(s[0].value)


@pg.production("expr : LPAREN expr RPAREN")
def paren_expr(s):
    return s[1]


parser = pg.build()

if __name__ == '__main__':

    def parse(txt):
        return parser.parse(lexer.lexer.lex(txt))

    from hindley_milner.src.check import Checker
    checker = Checker()
    code = "let val f = fn a => a in pair (f true) (f 13) end"
    ast = parse(code)
    print(ast)
    ast.infer_type(checker)