示例#1
0
def generate_attr_defaults_init(
        builder: IRBuilder, cdef: ClassDef,
        default_assignments: List[AssignmentStmt]) -> None:
    """Generate an initialization method for default attr values (from class vars)."""
    if not default_assignments:
        return
    cls = builder.mapper.type_to_ir[cdef.info]
    if cls.builtin_base:
        return

    with builder.enter_method(cls, '__mypyc_defaults_setup', bool_rprimitive):
        self_var = builder.self()
        for stmt in default_assignments:
            lvalue = stmt.lvalues[0]
            assert isinstance(lvalue, NameExpr)
            if not stmt.is_final_def and not is_constant(stmt.rvalue):
                builder.warning('Unsupported default attribute value',
                                stmt.rvalue.line)

            attr_type = cls.attr_type(lvalue.name)
            val = builder.coerce(builder.accept(stmt.rvalue), attr_type,
                                 stmt.line)
            init = SetAttr(self_var, lvalue.name, val, -1)
            init.mark_as_initializer()
            builder.add(init)

        builder.add(Return(builder.true()))
示例#2
0
文件: function.py 项目: wesleyks/mypy
def calculate_arg_defaults(builder: IRBuilder,
                           fn_info: FuncInfo,
                           env: Environment,
                           func_reg: Optional[Value]) -> None:
    """Calculate default argument values and store them.

    They are stored in statics for top level functions and in
    the function objects for nested functions (while constants are
    still stored computed on demand).
    """
    fitem = fn_info.fitem
    for arg in fitem.arguments:
        # Constant values don't get stored but just recomputed
        if arg.initializer and not is_constant(arg.initializer):
            value = builder.coerce(
                builder.accept(arg.initializer),
                env.lookup(arg.variable).type,
                arg.line
            )
            if not fn_info.is_nested:
                name = fitem.fullname + '.' + arg.variable.name
                builder.add(InitStatic(value, name, builder.module_name))
            else:
                assert func_reg is not None
                builder.add(SetAttr(func_reg, arg.variable.name, value, arg.line))
示例#3
0
 def assign(self, target: Union[Register, AssignmentTarget],
            rvalue_reg: Value, line: int) -> None:
     if isinstance(target, Register):
         self.add(Assign(target, rvalue_reg))
     elif isinstance(target, AssignmentTargetRegister):
         rvalue_reg = self.coerce(rvalue_reg, target.type, line)
         self.add(Assign(target.register, rvalue_reg))
     elif isinstance(target, AssignmentTargetAttr):
         if isinstance(target.obj_type, RInstance):
             rvalue_reg = self.coerce(rvalue_reg, target.type, line)
             self.add(SetAttr(target.obj, target.attr, rvalue_reg, line))
         else:
             key = self.load_static_unicode(target.attr)
             boxed_reg = self.builder.box(rvalue_reg)
             self.add(
                 PrimitiveOp([target.obj, key, boxed_reg], py_setattr_op,
                             line))
     elif isinstance(target, AssignmentTargetIndex):
         target_reg2 = self.gen_method_call(target.base, '__setitem__',
                                            [target.index, rvalue_reg],
                                            None, line)
         assert target_reg2 is not None, target.base.type
     elif isinstance(target, AssignmentTargetTuple):
         if isinstance(rvalue_reg.type, RTuple) and target.star_idx is None:
             rtypes = rvalue_reg.type.types
             assert len(rtypes) == len(target.items)
             for i in range(len(rtypes)):
                 item_value = self.add(TupleGet(rvalue_reg, i, line))
                 self.assign(target.items[i], item_value, line)
         else:
             self.process_iterator_tuple_assignment(target, rvalue_reg,
                                                    line)
     else:
         assert False, 'Unsupported assignment target'
示例#4
0
def instantiate_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> Value:
    """Create an instance of a callable class for a function.

    Calls to the function will actually call this instance.

    Note that fn_info refers to the function being assigned, whereas
    builder.fn_info refers to the function encapsulating the function
    being turned into a callable class.
    """
    fitem = fn_info.fitem
    func_reg = builder.add(Call(fn_info.callable_class.ir.ctor, [], fitem.line))

    # Set the environment attribute of the callable class to point at
    # the environment class defined in the callable class' immediate
    # outer scope. Note that there are three possible environment
    # class registers we may use. This depends on what the encapsulating
    # (parent) function is:
    #
    # - A nested function: the callable class is instantiated
    #   from the current callable class' '__call__' function, and hence
    #   the callable class' environment register is used.
    # - A generator function: the callable class is instantiated
    #   from the '__next__' method of the generator class, and hence the
    #   environment of the generator class is used.
    # - Regular function: we use the environment of the original function.
    curr_env_reg = None
    if builder.fn_info.is_generator:
        curr_env_reg = builder.fn_info.generator_class.curr_env_reg
    elif builder.fn_info.is_nested:
        curr_env_reg = builder.fn_info.callable_class.curr_env_reg
    elif builder.fn_info.contains_nested:
        curr_env_reg = builder.fn_info.curr_env_reg
    if curr_env_reg:
        builder.add(SetAttr(func_reg, ENV_ATTR_NAME, curr_env_reg, fitem.line))
    return func_reg
示例#5
0
def instantiate_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> Value:
    """
    Assigns a callable class to a register named after the given function definition. Note
    that fn_info refers to the function being assigned, whereas builder.fn_info refers to the
    function encapsulating the function being turned into a callable class.
    """
    fitem = fn_info.fitem
    func_reg = builder.add(Call(fn_info.callable_class.ir.ctor, [], fitem.line))

    # Set the callable class' environment attribute to point at the environment class
    # defined in the callable class' immediate outer scope. Note that there are three possible
    # environment class registers we may use. If the encapsulating function is:
    # - a generator function, then the callable class is instantiated from the generator class'
    #   __next__' function, and hence the generator class' environment register is used.
    # - a nested function, then the callable class is instantiated from the current callable
    #   class' '__call__' function, and hence the callable class' environment register is used.
    # - neither, then we use the environment register of the original function.
    curr_env_reg = None
    if builder.fn_info.is_generator:
        curr_env_reg = builder.fn_info.generator_class.curr_env_reg
    elif builder.fn_info.is_nested:
        curr_env_reg = builder.fn_info.callable_class.curr_env_reg
    elif builder.fn_info.contains_nested:
        curr_env_reg = builder.fn_info.curr_env_reg
    if curr_env_reg:
        builder.add(SetAttr(func_reg, ENV_ATTR_NAME, curr_env_reg, fitem.line))
    return func_reg
示例#6
0
文件: classdef.py 项目: alanhdu/mypy
def generate_attr_defaults(builder: IRBuilder, cdef: ClassDef) -> None:
    """Generate an initialization method for default attr values (from class vars)."""
    cls = builder.mapper.type_to_ir[cdef.info]
    if cls.builtin_base:
        return

    # Pull out all assignments in classes in the mro so we can initialize them
    # TODO: Support nested statements
    default_assignments = []
    for info in reversed(cdef.info.mro):
        if info not in builder.mapper.type_to_ir:
            continue
        for stmt in info.defn.defs.body:
            if (isinstance(stmt, AssignmentStmt)
                    and isinstance(stmt.lvalues[0], NameExpr)
                    and not is_class_var(stmt.lvalues[0])
                    and not isinstance(stmt.rvalue, TempNode)):
                name = stmt.lvalues[0].name
                if name == '__slots__':
                    continue

                if name == '__deletable__':
                    check_deletable_declaration(builder, cls, stmt.line)
                    continue

                # Skip type annotated assignments in dataclasses
                if is_dataclass(cdef) and stmt.type:
                    continue

                default_assignments.append(stmt)

    if not default_assignments:
        return

    builder.enter_method(cls, '__mypyc_defaults_setup', bool_rprimitive)

    self_var = builder.self()
    for stmt in default_assignments:
        lvalue = stmt.lvalues[0]
        assert isinstance(lvalue, NameExpr)
        if not stmt.is_final_def and not is_constant(stmt.rvalue):
            builder.warning('Unsupported default attribute value',
                            stmt.rvalue.line)

        # If the attribute is initialized to None and type isn't optional,
        # don't initialize it to anything.
        attr_type = cls.attr_type(lvalue.name)
        if isinstance(stmt.rvalue,
                      RefExpr) and stmt.rvalue.fullname == 'builtins.None':
            if (not is_optional_type(attr_type)
                    and not is_object_rprimitive(attr_type)
                    and not is_none_rprimitive(attr_type)):
                continue
        val = builder.coerce(builder.accept(stmt.rvalue), attr_type, stmt.line)
        builder.add(SetAttr(self_var, lvalue.name, val, -1))

    builder.add(Return(builder.true()))

    builder.leave_method()
示例#7
0
 def test_set_attr(self) -> None:
     self.assert_emit(
         SetAttr(self.r, 'y', self.m, 1),
         """if (((mod___AObject *)cpy_r_r)->_y != CPY_INT_TAG) {
                CPyTagged_DecRef(((mod___AObject *)cpy_r_r)->_y);
            }
            ((mod___AObject *)cpy_r_r)->_y = cpy_r_m;
            cpy_r_r0 = 1;
         """)
示例#8
0
def instantiate_generator_class(builder: IRBuilder) -> Value:
    fitem = builder.fn_info.fitem
    generator_reg = builder.add(Call(builder.fn_info.generator_class.ir.ctor, [], fitem.line))

    # Get the current environment register. If the current function is nested, then the
    # generator class gets instantiated from the callable class' '__call__' method, and hence
    # we use the callable class' environment register. Otherwise, we use the original
    # function's environment register.
    if builder.fn_info.is_nested:
        curr_env_reg = builder.fn_info.callable_class.curr_env_reg
    else:
        curr_env_reg = builder.fn_info.curr_env_reg

    # Set the generator class' environment attribute to point at the environment class
    # defined in the current scope.
    builder.add(SetAttr(generator_reg, ENV_ATTR_NAME, curr_env_reg, fitem.line))

    # Set the generator class' environment class' NEXT_LABEL_ATTR_NAME attribute to 0.
    zero = Integer(0)
    builder.add(SetAttr(curr_env_reg, NEXT_LABEL_ATTR_NAME, zero, fitem.line))
    return generator_reg
示例#9
0
def generate_singledispatch_callable_class_ctor(builder: IRBuilder) -> None:
    """Create an __init__ that sets registry and dispatch_cache to empty dicts"""
    line = -1
    class_ir = builder.fn_info.callable_class.ir
    with builder.enter_method(class_ir, '__init__', bool_rprimitive):
        empty_dict = builder.call_c(dict_new_op, [], line)
        builder.add(SetAttr(builder.self(), 'registry', empty_dict, line))
        cache_dict = builder.call_c(dict_new_op, [], line)
        dispatch_cache_str = builder.load_str('dispatch_cache')
        # use the py_setattr_op instead of SetAttr so that it also gets added to our __dict__
        builder.call_c(py_setattr_op,
                       [builder.self(), dispatch_cache_str, cache_dict], line)
        # the generated C code seems to expect that __init__ returns a char, so just return 1
        builder.add(Return(Integer(1, bool_rprimitive, line), line))
示例#10
0
def instantiate_env_class(builder: IRBuilder) -> Value:
    """Assign an environment class to a register named after the given function definition."""
    curr_env_reg = builder.add(
        Call(builder.fn_info.env_class.ctor, [], builder.fn_info.fitem.line))

    if builder.fn_info.is_nested:
        builder.fn_info.callable_class._curr_env_reg = curr_env_reg
        builder.add(
            SetAttr(curr_env_reg, ENV_ATTR_NAME,
                    builder.fn_info.callable_class.prev_env_reg,
                    builder.fn_info.fitem.line))
    else:
        builder.fn_info._curr_env_reg = curr_env_reg

    return curr_env_reg
示例#11
0
文件: builder.py 项目: wesleyks/mypy
    def add_var_to_env_class(self,
                             var: SymbolNode,
                             rtype: RType,
                             base: Union[FuncInfo, ImplicitClass],
                             reassign: bool = False) -> AssignmentTarget:
        # First, define the variable name as an attribute of the environment class, and then
        # construct a target for that attribute.
        self.fn_info.env_class.attributes[var.name] = rtype
        attr_target = AssignmentTargetAttr(base.curr_env_reg, var.name)

        if reassign:
            # Read the local definition of the variable, and set the corresponding attribute of
            # the environment class' variable to be that value.
            reg = self.read(self.environment.lookup(var), self.fn_info.fitem.line)
            self.add(SetAttr(base.curr_env_reg, var.name, reg, self.fn_info.fitem.line))

        # Override the local definition of the variable to instead point at the variable in
        # the environment class.
        return self.environment.add_target(var, attr_target)
示例#12
0
def generate_attr_defaults(builder: IRBuilder, cdef: ClassDef) -> None:
    """Generate an initialization method for default attr values (from class vars)."""
    cls = builder.mapper.type_to_ir[cdef.info]
    if cls.builtin_base:
        return

    # Pull out all assignments in classes in the mro so we can initialize them
    # TODO: Support nested statements
    default_assignments = []
    for info in reversed(cdef.info.mro):
        if info not in builder.mapper.type_to_ir:
            continue
        for stmt in info.defn.defs.body:
            if (isinstance(stmt, AssignmentStmt)
                    and isinstance(stmt.lvalues[0], NameExpr)
                    and not is_class_var(stmt.lvalues[0])
                    and not isinstance(stmt.rvalue, TempNode)):
                if stmt.lvalues[0].name == '__slots__':
                    continue

                # Skip type annotated assignments in dataclasses
                if is_dataclass(cdef) and stmt.type:
                    continue

                default_assignments.append(stmt)

    if not default_assignments:
        return

    builder.enter()
    builder.ret_types[-1] = bool_rprimitive

    rt_args = (RuntimeArg(SELF_NAME, RInstance(cls)), )
    self_var = builder.read(add_self_to_env(builder.environment, cls), -1)

    for stmt in default_assignments:
        lvalue = stmt.lvalues[0]
        assert isinstance(lvalue, NameExpr)
        if not stmt.is_final_def and not is_constant(stmt.rvalue):
            builder.warning('Unsupported default attribute value',
                            stmt.rvalue.line)

        # If the attribute is initialized to None and type isn't optional,
        # don't initialize it to anything.
        attr_type = cls.attr_type(lvalue.name)
        if isinstance(stmt.rvalue,
                      RefExpr) and stmt.rvalue.fullname == 'builtins.None':
            if (not is_optional_type(attr_type)
                    and not is_object_rprimitive(attr_type)
                    and not is_none_rprimitive(attr_type)):
                continue
        val = builder.coerce(builder.accept(stmt.rvalue), attr_type, stmt.line)
        builder.add(SetAttr(self_var, lvalue.name, val, -1))

    builder.add(Return(builder.true()))

    blocks, env, ret_type, _ = builder.leave()
    ir = FuncIR(
        FuncDecl('__mypyc_defaults_setup', cls.name, builder.module_name,
                 FuncSignature(rt_args, ret_type)), blocks, env)
    builder.functions.append(ir)
    cls.methods[ir.name] = ir
示例#13
0
 def test_set_attr(self) -> None:
     self.assert_emit(
         SetAttr(self.r, 'y', self.m, 1),
         "cpy_r_r0 = native_A_sety((mod___AObject *)cpy_r_r, cpy_r_m); /* y */"
     )