Beispiel #1
0
def transform_return_stmt(builder: IRBuilder, stmt: ReturnStmt) -> None:
    if stmt.expr:
        retval = builder.accept(stmt.expr)
    else:
        retval = builder.builder.none()
    retval = builder.coerce(retval, builder.ret_types[-1], stmt.line)
    builder.nonlocal_control[-1].gen_return(builder, retval, stmt.line)
Beispiel #2
0
def create_mypyc_attrs_tuple(builder: IRBuilder, ir: ClassIR, line: int) -> Value:
    attrs = [name for ancestor in ir.mro for name in ancestor.attributes]
    if ir.inherits_python:
        attrs.append('__dict__')
    return builder.primitive_op(new_tuple_op,
                             [builder.load_static_unicode(attr) for attr in attrs],
                             line)
Beispiel #3
0
def translate_super_method_call(builder: IRBuilder, expr: CallExpr,
                                callee: SuperExpr) -> Value:
    if callee.info is None or callee.call.args:
        return translate_call(builder, expr, callee)
    ir = builder.mapper.type_to_ir[callee.info]
    # Search for the method in the mro, skipping ourselves.
    for base in ir.mro[1:]:
        if callee.name in base.method_decls:
            break
    else:
        return translate_call(builder, expr, callee)

    decl = base.method_decl(callee.name)
    arg_values = [builder.accept(arg) for arg in expr.args]
    arg_kinds, arg_names = expr.arg_kinds[:], expr.arg_names[:]

    if decl.kind != FUNC_STATICMETHOD:
        vself = next(iter(builder.environment.indexes))  # grab first argument
        if decl.kind == FUNC_CLASSMETHOD:
            vself = builder.primitive_op(type_op, [vself], expr.line)
        elif builder.fn_info.is_generator:
            # For generator classes, the self target is the 6th value
            # in the symbol table (which is an ordered dict). This is sort
            # of ugly, but we can't search by name since the 'self' parameter
            # could be named anything, and it doesn't get added to the
            # environment indexes.
            self_targ = list(builder.environment.symtable.values())[6]
            vself = builder.read(self_targ, builder.fn_info.fitem.line)
        arg_values.insert(0, vself)
        arg_kinds.insert(0, ARG_POS)
        arg_names.insert(0, None)

    return builder.builder.call(decl, arg_values, arg_kinds, arg_names,
                                expr.line)
Beispiel #4
0
def transform_try_finally_stmt(builder: IRBuilder,
                               try_body: GenFunc,
                               finally_body: GenFunc) -> None:
    """Generalized try/finally handling that takes functions to gen the bodies.

    The point of this is to also be able to support with."""
    # Finally is a big pain, because there are so many ways that
    # exits can occur. We emit 10+ basic blocks for every finally!

    err_handler, main_entry, return_entry, finally_block = (
        BasicBlock(), BasicBlock(), BasicBlock(), BasicBlock())

    # Compile the body of the try
    ret_reg = try_finally_try(
        builder, err_handler, return_entry, main_entry, try_body)

    # Set up the entry blocks for the finally statement
    old_exc = try_finally_entry_blocks(
        builder, err_handler, return_entry, main_entry, finally_block, ret_reg)

    # Compile the body of the finally
    cleanup_block, finally_control = try_finally_body(
        builder, finally_block, finally_body, ret_reg, old_exc)

    # Resolve the control flow out of the finally block
    out_block = try_finally_resolve_control(
        builder, cleanup_block, finally_control, old_exc, ret_reg)

    builder.activate_block(out_block)
Beispiel #5
0
def cache_class_attrs(builder: IRBuilder, attrs_to_cache: List[Lvalue], cdef: ClassDef) -> None:
    """Add class attributes to be cached to the global cache"""
    typ = builder.load_native_type_object(cdef.fullname)
    for lval in attrs_to_cache:
        assert isinstance(lval, NameExpr)
        rval = builder.py_get_attr(typ, lval.name, cdef.line)
        builder.init_final_static(lval, rval, cdef.name)
Beispiel #6
0
def find_non_ext_metaclass(builder: IRBuilder, cdef: ClassDef, bases: Value) -> Value:
    """Find the metaclass of a class from its defs and bases. """
    if cdef.metaclass:
        declared_metaclass = builder.accept(cdef.metaclass)
    else:
        declared_metaclass = builder.primitive_op(type_object_op, [], cdef.line)

    return builder.primitive_op(py_calc_meta_op, [declared_metaclass, bases], cdef.line)
Beispiel #7
0
def transform_index_expr(builder: IRBuilder, expr: IndexExpr) -> Value:
    base = builder.accept(expr.base)

    if isinstance(base.type, RTuple) and isinstance(expr.index, IntExpr):
        return builder.add(TupleGet(base, expr.index.value, expr.line))

    index_reg = builder.accept(expr.index)
    return builder.gen_method_call(base, '__getitem__', [index_reg],
                                   builder.node_type(expr), expr.line)
Beispiel #8
0
def transform_dict_expr(builder: IRBuilder, expr: DictExpr) -> Value:
    """First accepts all keys and values, then makes a dict out of them."""
    key_value_pairs = []
    for key_expr, value_expr in expr.items:
        key = builder.accept(key_expr) if key_expr is not None else None
        value = builder.accept(value_expr)
        key_value_pairs.append((key, value))

    return builder.builder.make_dict(key_value_pairs, expr.line)
Beispiel #9
0
def translate_isinstance(builder: IRBuilder, expr: CallExpr,
                         callee: RefExpr) -> Optional[Value]:
    # Special case builtins.isinstance
    if (len(expr.args) == 2 and expr.arg_kinds == [ARG_POS, ARG_POS]
            and isinstance(expr.args[1], (RefExpr, TupleExpr))):
        irs = builder.flatten_classes(expr.args[1])
        if irs is not None:
            return builder.builder.isinstance_helper(
                builder.accept(expr.args[0]), irs, expr.line)
    return None
Beispiel #10
0
def transform_for_stmt(builder: IRBuilder, s: ForStmt) -> None:
    def body() -> None:
        builder.accept(s.body)

    def else_block() -> None:
        assert s.else_body is not None
        builder.accept(s.else_body)

    builder.for_loop_helper(s.index, s.expr, body,
                            else_block if s.else_body else None, s.line)
Beispiel #11
0
def translate_len(builder: IRBuilder, expr: CallExpr,
                  callee: RefExpr) -> Optional[Value]:
    # Special case builtins.len
    if (len(expr.args) == 1 and expr.arg_kinds == [ARG_POS]):
        expr_rtype = builder.node_type(expr.args[0])
        if isinstance(expr_rtype, RTuple):
            # len() of fixed-length tuple can be trivially determined statically,
            # though we still need to evaluate it.
            builder.accept(expr.args[0])
            return builder.add(LoadInt(len(expr_rtype.types)))
    return None
Beispiel #12
0
def transform_dictionary_comprehension(builder: IRBuilder,
                                       o: DictionaryComprehension) -> Value:
    d = builder.primitive_op(new_dict_op, [], o.line)
    loop_params = list(zip(o.indices, o.sequences, o.condlists))

    def gen_inner_stmts() -> None:
        k = builder.accept(o.key)
        v = builder.accept(o.value)
        builder.primitive_op(dict_set_item_op, [d, k, v], o.line)

    builder.comprehension_helper(loop_params, gen_inner_stmts, o.line)
    return d
Beispiel #13
0
def transform_set_comprehension(builder: IRBuilder,
                                o: SetComprehension) -> Value:
    gen = o.generator
    set_ops = builder.primitive_op(new_set_op, [], o.line)
    loop_params = list(zip(gen.indices, gen.sequences, gen.condlists))

    def gen_inner_stmts() -> None:
        e = builder.accept(gen.left_expr)
        builder.primitive_op(set_add_op, [set_ops, e], o.line)

    builder.comprehension_helper(loop_params, gen_inner_stmts, o.line)
    return set_ops
Beispiel #14
0
def transform_with(builder: IRBuilder,
                   expr: Expression,
                   target: Optional[Lvalue],
                   body: GenFunc,
                   line: int) -> None:
    # This is basically a straight transcription of the Python code in PEP 343.
    # I don't actually understand why a bunch of it is the way it is.
    # We could probably optimize the case where the manager is compiled by us,
    # but that is not our common case at all, so.
    mgr_v = builder.accept(expr)
    typ = builder.primitive_op(type_op, [mgr_v], line)
    exit_ = builder.maybe_spill(builder.py_get_attr(typ, '__exit__', line))
    value = builder.py_call(
        builder.py_get_attr(typ, '__enter__', line), [mgr_v], line
    )
    mgr = builder.maybe_spill(mgr_v)
    exc = builder.maybe_spill_assignable(builder.primitive_op(true_op, [], -1))

    def try_body() -> None:
        if target:
            builder.assign(builder.get_assignment_target(target), value, line)
        body()

    def except_body() -> None:
        builder.assign(exc, builder.primitive_op(false_op, [], -1), line)
        out_block, reraise_block = BasicBlock(), BasicBlock()
        builder.add_bool_branch(
            builder.py_call(builder.read(exit_),
                            [builder.read(mgr)] + get_sys_exc_info(builder), line),
            out_block,
            reraise_block
        )
        builder.activate_block(reraise_block)
        builder.primitive_op(reraise_exception_op, [], NO_TRACEBACK_LINE_NO)
        builder.add(Unreachable())
        builder.activate_block(out_block)

    def finally_body() -> None:
        out_block, exit_block = BasicBlock(), BasicBlock()
        builder.add(
            Branch(builder.read(exc), exit_block, out_block, Branch.BOOL_EXPR)
        )
        builder.activate_block(exit_block)
        none = builder.none_object()
        builder.py_call(
            builder.read(exit_), [builder.read(mgr), none, none, none], line
        )
        builder.goto_and_activate(out_block)

    transform_try_finally_stmt(
        builder,
        lambda: transform_try_except(builder,
                                     try_body,
                                     [(None, None, except_body)],
                                     None,
                                     line),
        finally_body
    )
Beispiel #15
0
def transform_raise_stmt(builder: IRBuilder, s: RaiseStmt) -> None:
    if s.expr is None:
        builder.primitive_op(reraise_exception_op, [], NO_TRACEBACK_LINE_NO)
        builder.add(Unreachable())
        return

    exc = builder.accept(s.expr)
    builder.primitive_op(raise_exception_op, [exc], s.line)
    builder.add(Unreachable())
Beispiel #16
0
def translate_call(builder: IRBuilder, expr: CallExpr,
                   callee: Expression) -> Value:
    # The common case of calls is refexprs
    if isinstance(callee, RefExpr):
        return translate_refexpr_call(builder, expr, callee)

    function = builder.accept(callee)
    args = [builder.accept(arg) for arg in expr.args]
    return builder.py_call(function,
                           args,
                           expr.line,
                           arg_kinds=expr.arg_kinds,
                           arg_names=expr.arg_names)
Beispiel #17
0
def transform_basic_comparison(builder: IRBuilder, op: str, left: Value,
                               right: Value, line: int) -> Value:
    negate = False
    if op == 'is not':
        op, negate = 'is', True
    elif op == 'not in':
        op, negate = 'in', True

    target = builder.binary_op(left, right, op, line)

    if negate:
        target = builder.unary_op(target, 'not', line)
    return target
Beispiel #18
0
def load_non_ext_class(builder: IRBuilder,
                       ir: ClassIR,
                       non_ext: NonExtClassInfo,
                       line: int) -> Value:
    cls_name = builder.load_static_unicode(ir.name)

    finish_non_ext_dict(builder, non_ext, line)

    class_type_obj = builder.py_call(
        non_ext.metaclass,
        [cls_name, non_ext.bases, non_ext.dict],
        line
    )
    return class_type_obj
Beispiel #19
0
def dataclass_non_ext_info(builder: IRBuilder, cdef: ClassDef) -> Optional[NonExtClassInfo]:
    """Set up a NonExtClassInfo to track dataclass attributes.

    In addition to setting up a normal extension class for dataclasses,
    we also collect its class attributes like a non-extension class so
    that we can hand them to the dataclass decorator.
    """
    if is_dataclass(cdef):
        return NonExtClassInfo(
            builder.primitive_op(new_dict_op, [], cdef.line),
            builder.add(TupleSet([], cdef.line)),
            builder.primitive_op(new_dict_op, [], cdef.line),
            builder.primitive_op(type_object_op, [], cdef.line),
        )
    else:
        return None
Beispiel #20
0
def translate_refexpr_call(builder: IRBuilder, expr: CallExpr,
                           callee: RefExpr) -> Value:
    """Translate a non-method call."""

    # TODO: Allow special cases to have default args or named args. Currently they don't since
    # they check that everything in arg_kinds is ARG_POS.

    # If there is a specializer for this function, try calling it.
    if callee.fullname and (callee.fullname, None) in specializers:
        val = specializers[callee.fullname, None](builder, expr, callee)
        if val is not None:
            return val

    # Gen the argument values
    arg_values = [builder.accept(arg) for arg in expr.args]

    return builder.call_refexpr_with_args(expr, callee, arg_values)
Beispiel #21
0
def translate_dataclasses_field_call(builder: IRBuilder, expr: CallExpr,
                                     callee: RefExpr) -> Optional[Value]:
    # Special case for 'dataclasses.field' and 'attr.Factory' function calls
    # because the results of such calls are typechecked by mypy using the types
    # of the arguments to their respective functions, resulting in attempted
    # coercions by mypyc that throw a runtime error.
    builder.types[expr] = AnyType(TypeOfAny.from_error)
    return None
Beispiel #22
0
def try_finally_try(builder: IRBuilder,
                    err_handler: BasicBlock,
                    return_entry: BasicBlock,
                    main_entry: BasicBlock,
                    try_body: GenFunc) -> Optional[Register]:
    # Compile the try block with an error handler
    control = TryFinallyNonlocalControl(return_entry)
    builder.builder.push_error_handler(err_handler)

    builder.nonlocal_control.append(control)
    builder.goto_and_activate(BasicBlock())
    try_body()
    builder.goto(main_entry)
    builder.nonlocal_control.pop()
    builder.builder.pop_error_handler()

    return control.ret_reg
Beispiel #23
0
def try_finally_body(
        builder: IRBuilder,
        finally_block: BasicBlock,
        finally_body: GenFunc,
        ret_reg: Optional[Value],
        old_exc: Value) -> Tuple[BasicBlock, FinallyNonlocalControl]:
    cleanup_block = BasicBlock()
    # Compile the finally block with the nonlocal control flow overridden to restore exc_info
    builder.builder.push_error_handler(cleanup_block)
    finally_control = FinallyNonlocalControl(
        builder.nonlocal_control[-1], ret_reg, old_exc)
    builder.nonlocal_control.append(finally_control)
    builder.activate_block(finally_block)
    finally_body()
    builder.nonlocal_control.pop()

    return cleanup_block, finally_control
Beispiel #24
0
def transform_member_expr(builder: IRBuilder, expr: MemberExpr) -> Value:
    # First check if this is maybe a final attribute.
    final = builder.get_final_ref(expr)
    if final is not None:
        fullname, final_var, native = final
        value = builder.emit_load_final(final_var, fullname, final_var.name,
                                        native, builder.types[expr], expr.line)
        if value is not None:
            return value

    if isinstance(expr.node,
                  MypyFile) and expr.node.fullname in builder.imports:
        return builder.load_module(expr.node.fullname)

    obj = builder.accept(expr.expr)
    return builder.builder.get_attr(obj, expr.name, builder.node_type(expr),
                                    expr.line)
Beispiel #25
0
def translate_all_call(builder: IRBuilder, expr: CallExpr,
                       callee: RefExpr) -> Optional[Value]:
    if (len(expr.args) == 1 and expr.arg_kinds == [ARG_POS]
            and isinstance(expr.args[0], GeneratorExpr)):
        return any_all_helper(builder, expr.args[0], true_op,
                              lambda x: builder.unary_op(x, 'not', expr.line),
                              false_op)
    return None
Beispiel #26
0
def transform_tuple_expr(builder: IRBuilder, expr: TupleExpr) -> Value:
    if any(isinstance(item, StarExpr) for item in expr.items):
        # create a tuple of unknown length
        return _visit_tuple_display(builder, expr)

    # create a tuple of fixed length (RTuple)
    tuple_type = builder.node_type(expr)
    # When handling NamedTuple et. al we might not have proper type info,
    # so make some up if we need it.
    types = (tuple_type.types if isinstance(tuple_type, RTuple) else
             [object_rprimitive] * len(expr.items))

    items = []
    for item_expr, item_type in zip(expr.items, types):
        reg = builder.accept(item_expr)
        items.append(builder.coerce(reg, item_type, item_expr.line))
    return builder.add(TupleSet(items, expr.line))
Beispiel #27
0
def add_non_ext_class_attr(builder: IRBuilder, non_ext: NonExtClassInfo, lvalue: NameExpr,
                           stmt: AssignmentStmt, cdef: ClassDef,
                           attr_to_cache: List[Lvalue]) -> None:
    """
    Add a class attribute to __annotations__ of a non-extension class. If the
    attribute is assigned to a value, it is also added to __dict__.
    """

    # We populate __annotations__ because dataclasses uses it to determine
    # which attributes to compute on.
    # TODO: Maybe generate more precise types for annotations
    key = builder.load_static_unicode(lvalue.name)
    typ = builder.primitive_op(type_object_op, [], stmt.line)
    builder.primitive_op(dict_set_item_op, [non_ext.anns, key, typ], stmt.line)

    # Only add the attribute to the __dict__ if the assignment is of the form:
    # x: type = value (don't add attributes of the form 'x: type' to the __dict__).
    if not isinstance(stmt.rvalue, TempNode):
        rvalue = builder.accept(stmt.rvalue)
        builder.add_to_non_ext_dict(non_ext, lvalue.name, rvalue, stmt.line)
        # We cache enum attributes to speed up enum attribute lookup since they
        # are final.
        if (
            cdef.info.bases
            and cdef.info.bases[0].type.fullname == 'enum.Enum'
            # Skip "_order_" and "__order__", since Enum will remove it
            and lvalue.name not in ('_order_', '__order__')
        ):
            attr_to_cache.append(lvalue)
Beispiel #28
0
def finish_non_ext_dict(builder: IRBuilder, non_ext: NonExtClassInfo, line: int) -> None:
    # Add __annotations__ to the class dict.
    builder.primitive_op(dict_set_item_op,
                      [non_ext.dict, builder.load_static_unicode('__annotations__'),
                       non_ext.anns], -1)

    # We add a __doc__ attribute so if the non-extension class is decorated with the
    # dataclass decorator, dataclass will not try to look for __text_signature__.
    # https://github.com/python/cpython/blob/3.7/Lib/dataclasses.py#L957
    filler_doc_str = 'mypyc filler docstring'
    builder.add_to_non_ext_dict(
        non_ext, '__doc__', builder.load_static_unicode(filler_doc_str), line)
    builder.add_to_non_ext_dict(
        non_ext, '__module__', builder.load_static_unicode(builder.module_name), line)
Beispiel #29
0
def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value:
    assert expr.node, "RefExpr not resolved"
    fullname = expr.node.fullname
    if fullname in name_ref_ops:
        # Use special access op for this particular name.
        desc = name_ref_ops[fullname]
        assert desc.result_type is not None
        return builder.add(PrimitiveOp([], desc, expr.line))

    if isinstance(expr.node, Var) and expr.node.is_final:
        value = builder.emit_load_final(
            expr.node,
            fullname,
            expr.name,
            builder.is_native_ref_expr(expr),
            builder.types[expr],
            expr.line,
        )
        if value is not None:
            return value

    if isinstance(expr.node,
                  MypyFile) and expr.node.fullname in builder.imports:
        return builder.load_module(expr.node.fullname)

    # If the expression is locally defined, then read the result from the corresponding
    # assignment target and return it. Otherwise if the expression is a global, load it from
    # the globals dictionary.
    # Except for imports, that currently always happens in the global namespace.
    if expr.kind == LDEF and not (isinstance(expr.node, Var)
                                  and expr.node.is_suppressed_import):
        # Try to detect and error when we hit the irritating mypy bug
        # where a local variable is cast to None. (#5423)
        if (isinstance(expr.node, Var)
                and is_none_rprimitive(builder.node_type(expr))
                and expr.node.is_inferred):
            builder.error(
                "Local variable '{}' has inferred type None; add an annotation"
                .format(expr.node.name), expr.node.line)

        # TODO: Behavior currently only defined for Var and FuncDef node types.
        return builder.read(builder.get_assignment_target(expr), expr.line)

    return builder.load_global(expr)
Beispiel #30
0
def populate_non_ext_bases(builder: IRBuilder, cdef: ClassDef) -> Value:
    """
    Populate the base-class tuple passed to the metaclass constructor
    for non-extension classes.
    """
    ir = builder.mapper.type_to_ir[cdef.info]
    bases = []
    for cls in cdef.info.mro[1:]:
        if cls.fullname == 'builtins.object':
            continue
        # Add the current class to the base classes list of concrete subclasses
        if cls in builder.mapper.type_to_ir:
            base_ir = builder.mapper.type_to_ir[cls]
            if base_ir.children is not None:
                base_ir.children.append(ir)

        base = builder.load_global_str(cls.name, cdef.line)
        bases.append(base)
    return builder.primitive_op(new_tuple_op, bases, cdef.line)