def attributes_assigned_in_init_can_be_used_in_methods_when_init_method_is_defined_after_other_method():
    init_func = nodes.func(
        name="__init__",
        args=nodes.args([nodes.arg("self_init")]),
        body=[
            nodes.assign(
                [nodes.attr(nodes.ref("self_init"), "message")],
                nodes.str_literal("Hello"),
                type=nodes.ref("str"),
            )
        ],
        type=nodes.signature(
            args=[nodes.signature_arg(nodes.ref("Self"))],
            returns=nodes.ref("none")
        ),
    )
    node = nodes.class_("User", [
        nodes.func(
            name="g",
            args=nodes.args([nodes.arg("self_g")]),
            body=[nodes.ret(nodes.attr(nodes.ref("self_g"), "message"))],
            type=nodes.signature(
                args=[nodes.signature_arg(nodes.ref("Self"))],
                returns=nodes.ref("str")
            ),
        ),
        init_func,
    ])
    _infer_class_type(node, ["__init__", "g"], [(init_func, ["self_init"])])
def method_can_call_method_on_same_instance_defined_later_in_body():
    node = nodes.class_("User", [
        nodes.func(
            name="f",
            args=nodes.args([nodes.arg("self_f")]),
            body=[
                nodes.ret(nodes.call(nodes.attr(nodes.ref("self_f"), "g"), []))
            ],
            type=nodes.signature(
                args=[nodes.signature_arg(nodes.ref("Self"))],
                returns=nodes.ref("none")
            ),
        ),
        nodes.func(
            name="g",
            args=nodes.args([nodes.arg("self_g")]),
            body=[
                nodes.ret(nodes.call(nodes.attr(nodes.ref("self_g"), "f"), []))
            ],
            type=nodes.signature(
                args=[nodes.signature_arg(nodes.ref("Self"))],
                returns=nodes.ref("none")
            ),
        )
    ])
    _infer_class_type(node, ["f", "g"])
def init_method_cannot_call_other_methods():
    node = nodes.class_("User", [
        nodes.func(
            name="__init__",
            args=nodes.args([nodes.arg("self_init")]),
            body=[
                nodes.assign([nodes.ref("x")], nodes.call(nodes.attr(nodes.ref("self_init"), "g"), []))
            ],
            type=nodes.signature(
                args=[nodes.signature_arg(nodes.ref("Self"))],
                returns=nodes.ref("none")
            ),
        ),
        nodes.func(
            name="g",
            args=nodes.args([nodes.arg("self_g")]),
            body=[],
            type=nodes.signature(
                args=[nodes.signature_arg(nodes.ref("Self"))],
                returns=nodes.ref("none")
            ),
        ),
    ])
    try:
        _infer_class_type(node, ["__init__", "g"])
        assert False, "Expected error"
    except errors.InitMethodCannotGetSelfAttributes as error:
        assert_equal("__init__ methods cannot get attributes of self", str(error))
Example #4
0
def can_parse_signature_with_multiple_args():
    expected_signature = nodes.signature(
        args=[
            nodes.signature_arg(nodes.ref("int")),
            nodes.signature_arg(nodes.ref("str"))
        ],
        returns=nodes.ref("str")
    )
    assert_equal(expected_signature, parse_explicit_type("int, str -> str"))
def init_method_is_used_as_call_method_on_meta_type():
    node = _create_class_with_init(
        signature=nodes.signature(
            args=[nodes.signature_arg(nodes.ref("Self")), nodes.signature_arg(nodes.ref("str"))],
            returns=nodes.ref("none")
        ),
        args=nodes.args([nodes.arg("self"), nodes.arg("name")]),
        body=[],
    )
    meta_type = _infer_meta_type(node, ["__init__"])
    assert_equal(types.func([types.str_type], meta_type.type), meta_type.attrs.type_of("__call__"))
Example #6
0
def can_parse_signature_with_function_type_as_argument():
    sub_signature = nodes.signature(
        args=[nodes.signature_arg(nodes.ref("int"))],
        returns=nodes.ref("str")
    )
    expected_signature = nodes.signature(
        args=[
            nodes.signature_arg(sub_signature)
        ],
        returns=nodes.ref("none")
    )
    assert_equal(expected_signature, parse_explicit_type("(int -> str) -> none"))
def error_if_type_signature_has_different_number_of_args_from_def():
    signature = nodes.signature(
        args=[nodes.signature_arg(nodes.ref("int")), nodes.signature_arg(nodes.ref("int"))],
        returns=nodes.ref("int")
    )
    args = nodes.arguments([nodes.argument("x")])
    body = [nodes.ret(nodes.ref("x"))]
    node = nodes.func("f", args, body, type=signature)
    try:
        _infer_func_type(node)
        assert False, "Expected error"
    except errors.ArgumentsError as error:
        assert_equal("args length mismatch: def has 1, signature has 2", str(error))
def can_infer_type_of_function_with_args_and_no_return():
    signature = nodes.signature(
        args=[
            nodes.signature_arg(nodes.ref("int")),
            nodes.signature_arg(nodes.ref("str")),
        ],
        returns=nodes.ref("none"),
    )
    args = nodes.arguments([
        nodes.argument("x"),
        nodes.argument("y"),
    ])
    node = nodes.func("f", args=args, body=[], type=signature)
    assert_equal(types.func([types.int_type, types.str_type], types.none_type), _infer_func_type(node))
Example #9
0
def attributes_assigned_in_init_can_be_used_outside_of_class():
    init_func = nodes.func(
        name="__init__",
        args=nodes.args([nodes.arg("self_init")]),
        body=[
            nodes.assign(
                [nodes.attr(nodes.ref("self_init"), "message")],
                nodes.str_literal("Hello"),
                type=nodes.ref("str"),
            )
        ],
        type=nodes.signature(
            args=[nodes.signature_arg(nodes.ref("Self"))],
            returns=nodes.ref("none")
        )
    )
    class_node = nodes.class_("User", [init_func])
    
    node = [
        class_node,
        nodes.assign([nodes.ref("x")], nodes.attr(nodes.call(nodes.ref("User"), []), "message")),
    ]
    
    context = _update_context(node, declared_names_in_node=NodeDict([
        (class_node, ["Self", "__init__"]),
        (init_func, ["self_init"]),
    ]))
    
    assert_equal(types.str_type, context.lookup_name("x"))
Example #10
0
def can_parse_signature_comment_with_one_formal_type_parameter():
    expected_signature = nodes.signature(
        type_params=[nodes.formal_type_parameter("T")],
        args=[nodes.signature_arg(nodes.ref("T"))],
        returns=nodes.ref("T")
    )
    assert_equal(expected_signature, parse_explicit_type("T => T -> T"))
Example #11
0
def type_parameters_of_function_are_definitely_bound():
    param = nodes.formal_type_parameter("T")
    arg_ref = nodes.ref("T")
    returns_ref = nodes.ref("T")
    explicit_type = nodes.signature(type_params=[param], args=[nodes.signature_arg(arg_ref)], returns=returns_ref)
    func_node = nodes.func("f", nodes.arguments([]), [], type=explicit_type)
    
    _updated_bindings(func_node)
def function_adds_arguments_to_context():
    signature = nodes.signature(
        args=[nodes.signature_arg(nodes.ref("int"))],
        returns=nodes.ref("int")
    )
    args = nodes.arguments([nodes.argument("x")])
    body = [nodes.ret(nodes.ref("x"))]
    node = nodes.func("f", args, body, type=signature)
    assert_equal(types.func([types.int_type], types.int_type), _infer_func_type(node))
def init_method_is_not_present_on_instance():
    node = _create_class_with_init(
        signature=nodes.signature(
            args=[nodes.signature_arg(nodes.ref("Self"))],
            returns=nodes.ref("none")
        ),
        args=nodes.args([nodes.arg("self")]),
        body=[],
    )
    meta_type = _infer_meta_type(node, ["__init__"])
    assert not "__init__" in meta_type.type.attrs
def type_of_function_signature_is_metatype_of_function():
    type_bindings = {
        "str": types.meta_type(types.str_type),
        "int": types.meta_type(types.int_type),
    }
    node = nodes.signature(
        args=[nodes.signature_arg(nodes.ref("int"))],
        returns=nodes.ref("str")
    )
    inferred_type = infer(node, type_bindings=type_bindings)
    assert types.is_meta_type(inferred_type)
    assert_equal(types.func([types.int_type], types.str_type), inferred_type.type)
def error_if_name_of_argument_does_not_match_name_in_signature():
    signature = nodes.signature(
        args=[nodes.signature_arg("y", nodes.ref("int"))],
        returns=nodes.ref("int")
    )
    args = nodes.arguments([nodes.argument("x")])
    body = [nodes.ret(nodes.ref("x"))]
    node = nodes.func("f", args, body, type=signature)
    try:
        _infer_func_type(node)
        assert False, "Expected error"
    except errors.ArgumentsError as error:
        assert_equal("argument 'x' has name 'y' in signature", str(error))
def can_type_check_generic_function_with_type_parameters():
    signature = nodes.signature(
        type_params=[nodes.formal_type_parameter("T")],
        args=[
            nodes.signature_arg(nodes.ref("T")),
        ],
        returns=nodes.ref("T"),
    )
    args = nodes.arguments([
        nodes.argument("value"),
    ])
    node = nodes.func("f", args=args, body=[nodes.ret(nodes.ref("value"))], type=signature)
    assert_equal(types.func([types.int_type], types.int_type), _infer_func_type(node).instantiate([types.int_type]))
def error_if_type_signature_argument_is_optional_but_def_argument_is_not_optional():
    signature = nodes.signature(
        args=[nodes.signature_arg(nodes.ref("int"), optional=True)],
        returns=nodes.type_union([nodes.ref("int"), nodes.ref("none")])
    )
    args = nodes.arguments([nodes.argument("x")])
    body = [nodes.ret(nodes.ref("x"))]
    node = nodes.func("f", args, body, type=signature)
    try:
        _infer_func_type(node)
        assert False, "Expected error"
    except errors.ArgumentsError as error:
        assert_equal("optional argument 'x' must have default value", str(error))
def type_of_generic_function_signature_is_metatype_of_function():
    node = nodes.signature(
        type_params=[nodes.formal_type_parameter("T")],
        args=[nodes.signature_arg(nodes.ref("T"))],
        returns=nodes.ref("T")
    )
    inferred_type = infer(node)
    assert types.is_meta_type(inferred_type)
    assert types.is_generic_func(inferred_type.type)
    formal_type_param, = inferred_type.type.formal_type_params
    assert_equal(
        types.func([formal_type_param], formal_type_param),
        inferred_type.type.instantiate([formal_type_param]),
    )
def first_argument_in_method_signature_can_be_strict_supertype_of_class():
    node = nodes.class_("User", [
        nodes.func(
            name="is_person",
            args=nodes.args([nodes.arg("self")]),
            body=[nodes.ret(nodes.bool_literal(True))],
            type=nodes.signature(
                args=[nodes.signature_arg(nodes.ref("object"))],
                returns=nodes.ref("bool")
            ),
        )
    ])
    class_type = _infer_class_type(node, ["is_person"])
    assert_equal(types.func([], types.bool_type), class_type.attrs.type_of("is_person"))
def init_method_must_return_none():
    node = _create_class_with_init(
        signature=nodes.signature(
            args=[nodes.signature_arg(nodes.ref("Self"))],
            returns=nodes.ref("str")
        ),
        args=nodes.args([nodes.arg("self")]),
        body=[nodes.ret(nodes.str_literal(""))],
    )
    try:
        _infer_meta_type(node, ["__init__"])
        assert False, "Expected error"
    except errors.InitMethodsMustReturnNoneError as error:
        assert_equal(node.body[0], error.node)
def attributes_with_function_type_defined_in_class_definition_body_are_bound_to_class_type():
    node = nodes.class_("User", [
        nodes.func(
            name="is_person",
            args=nodes.args([nodes.arg("self")]),
            body=[nodes.ret(nodes.bool_literal(True))],
            type=nodes.signature(
                args=[nodes.signature_arg(nodes.ref("Self"))],
                returns=nodes.ref("bool")
            ),
        ),
    ])
    class_type = _infer_class_type(node, ["is_person"])
    assert_equal(types.func([], types.bool_type), class_type.attrs.type_of("is_person"))
def argument_type_in_signature_is_unioned_with_none_if_argument_is_optional():
    signature = nodes.signature(
        args=[nodes.signature_arg(nodes.ref("int"))],
        returns=nodes.ref("int")
    )
    args = nodes.arguments([nodes.argument("x", optional=True)])
    body = [nodes.ret(nodes.ref("x"))]
    node = nodes.func("f", args, body, type=signature)
    try:
        _infer_func_type(node)
        assert False, "Expected error"
    except errors.UnexpectedValueTypeError as error:
        assert_equal(types.int_type, error.expected)
        assert_equal(types.union(types.int_type, types.none_type), error.actual)
Example #23
0
def function_definition_signature_has_names_resolved():
    int_ref = nodes.ref("int")
    str_ref = nodes.ref("str")
    
    signature = nodes.signature(
        args=[nodes.signature_arg(int_ref)],
        returns=str_ref,
    )
    node = nodes.func("f", nodes.arguments([]), [], type=signature)
    
    declarations = _create_declarations(["f", "int", "str"])
    references = resolve(node, declarations)
    assert_is(declarations.declaration("int"), references.referenced_declaration(int_ref))
    assert_is(declarations.declaration("str"), references.referenced_declaration(str_ref))
def can_infer_type_of_function_with_optional_arg():
    signature = nodes.signature(
        args=[
            nodes.signature_arg(nodes.ref("int"), optional=True),
        ],
        returns=nodes.ref("none")
    )
    args = nodes.arguments([
        nodes.argument("x", optional=True),
    ])
    node = nodes.func("f", args=args, body=[], type=signature)
    assert_equal(
        types.func([types.func_arg(None, types.int_type, optional=True)], types.none_type),
        _infer_func_type(node)
    )
def can_infer_type_of_function_with_named_arg():
    signature = nodes.signature(
        args=[
            nodes.signature_arg("message", nodes.ref("int")),
        ],
        returns=nodes.ref("none")
    )
    args = nodes.arguments([
        nodes.argument("message"),
    ])
    node = nodes.func("f", args=args, body=[], type=signature)
    assert_equal(
        types.func([types.func_arg("message", types.int_type)], types.none_type),
        _infer_func_type(node)
    )
Example #26
0
def generic_function_definition_signature_has_names_resolved():
    param = nodes.formal_type_parameter("T")
    arg_ref = nodes.ref("T")
    return_ref = nodes.ref("T")
    
    signature = nodes.signature(
        type_params=[param],
        args=[nodes.signature_arg(arg_ref)],
        returns=return_ref,
    )
    node = nodes.func("f", nodes.arguments([]), [], type=signature)
    
    declarations = _create_declarations(["f"])
    references = resolve(node, declarations)
    assert not declarations.is_declared("T")
    assert_is(references.referenced_declaration(param), references.referenced_declaration(arg_ref))
    assert_is(references.referenced_declaration(param), references.referenced_declaration(return_ref))
def self_argument_in_method_signature_cannot_be_unrelated_type():
    func_node = nodes.func(
        name="is_person",
        args=nodes.args([nodes.arg("self")]),
        body=[nodes.ret(nodes.bool_literal(True))],
        type=nodes.signature(
            args=[nodes.signature_arg(nodes.ref("bool"))],
            returns=nodes.ref("bool")
        ),
    )
    node = nodes.class_("User", [func_node])
    try:
        _infer_class_type(node, ["is_person"])
        assert False, "Expected error"
    except errors.UnexpectedReceiverTypeError as error:
        assert_equal(func_node, error.node)
        assert_equal(types.bool_type, error.receiver_type)
        assert_equal("first argument of methods should have Self type but was 'bool'", str(error))
def _infer_meta_type(class_node, names, names_in_nodes=None, type_bindings=None):
    if type_bindings is None:
        type_bindings = {}
    else:
        type_bindings = type_bindings.copy()
    if names_in_nodes is None:
        names_in_nodes = []
    
    type_bindings["bool"] = types.meta_type(types.bool_type)
    type_bindings["object"] = types.meta_type(types.object_type)
    type_bindings["none"] = types.meta_type(types.none_type)
    type_bindings["str"] = types.meta_type(types.str_type)
    context = update_context(
        class_node,
        declared_names_in_node=NodeDict(names_in_nodes + [(class_node, names + ["Self"])]),
        type_bindings=type_bindings,
    )
    meta_type = context.lookup(class_node)
    assert isinstance(meta_type, types.MetaType)
    assert types.is_class_type(meta_type.type) or types.is_generic_type(meta_type.type)
    return meta_type


def _infer_class_type(class_node, names, names_in_nodes=None, type_bindings=None):
    return _infer_meta_type(class_node, names, names_in_nodes, type_bindings=type_bindings).type
    
_no_arg_init_signature = nodes.signature(
    args=[nodes.signature_arg(nodes.ref("Self"))],
    returns=nodes.ref("none")
)
Example #29
0
def can_parse_signature_with_named_arg():
    expected_signature = nodes.signature(
        args=[nodes.signature_arg("x", nodes.ref("int"))],
        returns=nodes.ref("str"),
    )
    assert_equal(expected_signature, parse_explicit_type("x: int -> str"))
Example #30
0
def can_parse_signature_with_optional_arg():
    expected_signature = nodes.signature(
        args=[nodes.signature_arg(nodes.ref("int"), optional=True)],
        returns=nodes.ref("str")
    )
    assert_equal(expected_signature, parse_explicit_type("?int -> str"))