コード例 #1
0
ファイル: builder.py プロジェクト: Sole93/-cd-mypy
 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_str(target.attr)
             boxed_reg = self.builder.box(rvalue_reg)
             self.call_c(py_setattr_op, [target.obj, key, boxed_reg], 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)
         elif ((is_list_rprimitive(rvalue_reg.type) or is_tuple_rprimitive(rvalue_reg.type))
               and target.star_idx is None):
             self.process_sequence_assignment(target, rvalue_reg, line)
         else:
             self.process_iterator_tuple_assignment(target, rvalue_reg, line)
     else:
         assert False, 'Unsupported assignment target'
コード例 #2
0
def unsafe_index(
    builder: IRBuilder, target: Value, index: Value, line: int
) -> Value:
    """Emit a potentially unsafe curr_index into a target."""
    # This doesn't really fit nicely into any of our data-driven frameworks
    # since we want to use __getitem__ if we don't have an unsafe version,
    # so we just check manually.
    if is_list_rprimitive(target.type):
        return builder.primitive_op(list_get_item_unsafe_op, [target, index], line)
    else:
        return builder.gen_method_call(target, '__getitem__', [index], None, line)
コード例 #3
0
def sequence_from_generator_preallocate_helper(
        builder: IRBuilder, gen: GeneratorExpr,
        empty_op_llbuilder: Callable[[Value, int], Value],
        set_item_op: CFunctionDescription) -> Optional[Value]:
    """Generate a new tuple or list from a simple generator expression.

    Currently we only optimize for simplest generator expression, which means that
    there is no condition list in the generator and only one original sequence with
    one index is allowed.

    e.g.  (1) tuple(f(x) for x in a_list/a_tuple)
          (2) list(f(x) for x in a_list/a_tuple)
          (3) [f(x) for x in a_list/a_tuple]
    RTuple as an original sequence is not supported yet.

    Args:
        empty_op_llbuilder: A function that can generate an empty sequence op when
            passed in length. See `new_list_op_with_length` and `new_tuple_op_with_length`
            for detailed implementation.
        set_item_op: A primitive that can modify an arbitrary position of a sequence.
            The op should have three arguments:
                - Self
                - Target position
                - New Value
            See `new_list_set_item_op` and `new_tuple_set_item_op` for detailed
            implementation.
    """
    if len(gen.sequences) == 1 and len(gen.indices) == 1 and len(
            gen.condlists[0]) == 0:
        rtype = builder.node_type(gen.sequences[0])
        if (is_list_rprimitive(rtype) or is_tuple_rprimitive(rtype)
                or is_str_rprimitive(rtype)):
            sequence = builder.accept(gen.sequences[0])
            length = builder.builder.builtin_len(sequence,
                                                 gen.line,
                                                 use_pyssize_t=True)
            target_op = empty_op_llbuilder(length, gen.line)

            def set_item(item_index: Value) -> None:
                e = builder.accept(gen.left_expr)
                builder.call_c(set_item_op, [target_op, item_index, e],
                               gen.line)

            for_loop_helper_with_index(builder, gen.indices[0],
                                       gen.sequences[0], sequence, set_item,
                                       gen.line)

            return target_op
    return None
コード例 #4
0
ファイル: expression.py プロジェクト: pranavrajpal/mypy
def transform_index_expr(builder: IRBuilder, expr: IndexExpr) -> Value:
    index = expr.index
    base_type = builder.node_type(expr.base)
    is_list = is_list_rprimitive(base_type)
    can_borrow_base = is_list and is_borrow_friendly_expr(builder, index)

    base = builder.accept(expr.base, can_borrow=can_borrow_base)

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

    if isinstance(index, SliceExpr):
        value = try_gen_slice_op(builder, base, index)
        if value:
            return value

    index_reg = builder.accept(expr.index, can_borrow=is_list)
    return builder.gen_method_call(
        base, '__getitem__', [index_reg], builder.node_type(expr), expr.line)
コード例 #5
0
ファイル: specialize.py プロジェクト: mmajewsk/mypy
def tuple_from_generator_helper(builder: IRBuilder,
                                gen: GeneratorExpr) -> Optional[Value]:

    if len(gen.sequences) == 1 and len(gen.condlists[0]) == 0:
        # Currently we only optimize for simplest generator expression
        rtype = builder.node_type(gen.sequences[0])
        if is_list_rprimitive(rtype) or is_tuple_rprimitive(rtype):
            tuple_ops = builder.builder.new_tuple_with_length(builder.accept(gen.sequences[0]),
                                                              gen.line)
            item, expr = gen.indices[0], gen.sequences[0]

            def set_tuple_item(item_index: Value) -> None:
                e = builder.accept(gen.left_expr)
                builder.call_c(new_tuple_set_item_op, [tuple_ops, item_index, e], gen.line)

            for_loop_helper_with_index(builder, item, expr,
                                       set_tuple_item, gen.line)

            return tuple_ops
    return None
コード例 #6
0
ファイル: ll_builder.py プロジェクト: polsani154/mypy
 def builtin_len(self, val: Value, line: int) -> Value:
     typ = val.type
     if is_list_rprimitive(typ) or is_tuple_rprimitive(typ):
         elem_address = self.add(GetElementPtr(val, PyVarObject, 'ob_size'))
         size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address, val))
         offset = self.add(LoadInt(1, line, rtype=c_pyssize_t_rprimitive))
         return self.binary_int_op(short_int_rprimitive, size_value, offset,
                                   BinaryIntOp.LEFT_SHIFT, line)
     elif is_dict_rprimitive(typ):
         size_value = self.call_c(dict_size_op, [val], line)
         offset = self.add(LoadInt(1, line, rtype=c_pyssize_t_rprimitive))
         return self.binary_int_op(short_int_rprimitive, size_value, offset,
                                   BinaryIntOp.LEFT_SHIFT, line)
     elif is_set_rprimitive(typ):
         elem_address = self.add(GetElementPtr(val, PySetObject, 'used'))
         size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address, val))
         offset = self.add(LoadInt(1, line, rtype=c_pyssize_t_rprimitive))
         return self.binary_int_op(short_int_rprimitive, size_value, offset,
                                   BinaryIntOp.LEFT_SHIFT, line)
     # generic case
     else:
         return self.call_c(generic_len_op, [val], line)
コード例 #7
0
ファイル: builder.py プロジェクト: Sole93/-cd-mypy
    def process_sequence_assignment(self,
                                    target: AssignmentTargetTuple,
                                    rvalue: Value,
                                    line: int) -> None:
        """Process assignment like 'x, y = s', where s is a variable-length list or tuple."""
        # Check the length of sequence.
        expected_len = Integer(len(target.items), c_pyssize_t_rprimitive)
        self.builder.call_c(check_unpack_count_op, [rvalue, expected_len], line)

        # Read sequence items.
        values = []
        for i in range(len(target.items)):
            item = target.items[i]
            index = self.builder.load_int(i)
            if is_list_rprimitive(rvalue.type):
                item_value = self.call_c(list_get_item_unsafe_op, [rvalue, index], line)
            else:
                item_value = self.builder.gen_method_call(
                    rvalue, '__getitem__', [index], item.type, line)
            values.append(item_value)

        # Assign sequence items to the target lvalues.
        for lvalue, value in zip(target.items, values):
            self.assign(lvalue, value, line)
コード例 #8
0
    def emit_cast(self,
                  src: str,
                  dest: str,
                  typ: RType,
                  declare_dest: bool = False,
                  custom_message: Optional[str] = None,
                  optional: bool = False,
                  src_type: Optional[RType] = None,
                  likely: bool = True) -> None:
        """Emit code for casting a value of given type.

        Somewhat strangely, this supports unboxed types but only
        operates on boxed versions.  This is necessary to properly
        handle types such as Optional[int] in compatibility glue.

        Assign NULL (error value) to dest if the value has an incompatible type.

        Always copy/steal the reference in src.

        Args:
            src: Name of source C variable
            dest: Name of target C variable
            typ: Type of value
            declare_dest: If True, also declare the variable 'dest'
            likely: If the cast is likely to succeed (can be False for unions)
        """
        if custom_message is not None:
            err = custom_message
        else:
            err = 'CPy_TypeError("{}", {});'.format(self.pretty_name(typ), src)

        # Special case casting *from* optional
        if src_type and is_optional_type(
                src_type) and not is_object_rprimitive(typ):
            value_type = optional_value_type(src_type)
            assert value_type is not None
            if is_same_type(value_type, typ):
                if declare_dest:
                    self.emit_line('PyObject *{};'.format(dest))
                check = '({} != Py_None)'
                if likely:
                    check = '(likely{})'.format(check)
                self.emit_arg_check(src, dest, typ, check.format(src),
                                    optional)
                self.emit_lines('    {} = {};'.format(dest, src), 'else {',
                                err, '{} = NULL;'.format(dest), '}')
                return

        # TODO: Verify refcount handling.
        if (is_list_rprimitive(typ) or is_dict_rprimitive(typ)
                or is_set_rprimitive(typ) or is_float_rprimitive(typ)
                or is_str_rprimitive(typ) or is_int_rprimitive(typ)
                or is_bool_rprimitive(typ)):
            if declare_dest:
                self.emit_line('PyObject *{};'.format(dest))
            if is_list_rprimitive(typ):
                prefix = 'PyList'
            elif is_dict_rprimitive(typ):
                prefix = 'PyDict'
            elif is_set_rprimitive(typ):
                prefix = 'PySet'
            elif is_float_rprimitive(typ):
                prefix = 'CPyFloat'
            elif is_str_rprimitive(typ):
                prefix = 'PyUnicode'
            elif is_int_rprimitive(typ):
                prefix = 'PyLong'
            elif is_bool_rprimitive(typ) or is_bit_rprimitive(typ):
                prefix = 'PyBool'
            else:
                assert False, 'unexpected primitive type'
            check = '({}_Check({}))'
            if likely:
                check = '(likely{})'.format(check)
            self.emit_arg_check(src, dest, typ, check.format(prefix, src),
                                optional)
            self.emit_lines('    {} = {};'.format(dest, src), 'else {', err,
                            '{} = NULL;'.format(dest), '}')
        elif is_tuple_rprimitive(typ):
            if declare_dest:
                self.emit_line('{} {};'.format(self.ctype(typ), dest))
            check = '(PyTuple_Check({}))'
            if likely:
                check = '(likely{})'.format(check)
            self.emit_arg_check(src, dest, typ, check.format(src), optional)
            self.emit_lines('    {} = {};'.format(dest, src), 'else {', err,
                            '{} = NULL;'.format(dest), '}')
        elif isinstance(typ, RInstance):
            if declare_dest:
                self.emit_line('PyObject *{};'.format(dest))
            concrete = all_concrete_classes(typ.class_ir)
            # If there are too many concrete subclasses or we can't find any
            # (meaning the code ought to be dead or we aren't doing global opts),
            # fall back to a normal typecheck.
            # Otherwise check all the subclasses.
            if not concrete or len(
                    concrete) > FAST_ISINSTANCE_MAX_SUBCLASSES + 1:
                check = '(PyObject_TypeCheck({}, {}))'.format(
                    src, self.type_struct_name(typ.class_ir))
            else:
                full_str = '(Py_TYPE({src}) == {targets[0]})'
                for i in range(1, len(concrete)):
                    full_str += ' || (Py_TYPE({src}) == {targets[%d]})' % i
                if len(concrete) > 1:
                    full_str = '(%s)' % full_str
                check = full_str.format(
                    src=src,
                    targets=[self.type_struct_name(ir) for ir in concrete])
            if likely:
                check = '(likely{})'.format(check)
            self.emit_arg_check(src, dest, typ, check, optional)
            self.emit_lines('    {} = {};'.format(dest, src), 'else {', err,
                            '{} = NULL;'.format(dest), '}')
        elif is_none_rprimitive(typ):
            if declare_dest:
                self.emit_line('PyObject *{};'.format(dest))
            check = '({} == Py_None)'
            if likely:
                check = '(likely{})'.format(check)
            self.emit_arg_check(src, dest, typ, check.format(src), optional)
            self.emit_lines('    {} = {};'.format(dest, src), 'else {', err,
                            '{} = NULL;'.format(dest), '}')
        elif is_object_rprimitive(typ):
            if declare_dest:
                self.emit_line('PyObject *{};'.format(dest))
            self.emit_arg_check(src, dest, typ, '', optional)
            self.emit_line('{} = {};'.format(dest, src))
            if optional:
                self.emit_line('}')
        elif isinstance(typ, RUnion):
            self.emit_union_cast(src, dest, typ, declare_dest, err, optional,
                                 src_type)
        elif isinstance(typ, RTuple):
            assert not optional
            self.emit_tuple_cast(src, dest, typ, declare_dest, err, src_type)
        else:
            assert False, 'Cast not implemented: %s' % typ
コード例 #9
0
ファイル: emit.py プロジェクト: pranavrajpal/mypy
    def emit_cast(self,
                  src: str,
                  dest: str,
                  typ: RType,
                  *,
                  declare_dest: bool = False,
                  error: Optional[ErrorHandler] = None,
                  raise_exception: bool = True,
                  optional: bool = False,
                  src_type: Optional[RType] = None,
                  likely: bool = True) -> None:
        """Emit code for casting a value of given type.

        Somewhat strangely, this supports unboxed types but only
        operates on boxed versions.  This is necessary to properly
        handle types such as Optional[int] in compatibility glue.

        By default, assign NULL (error value) to dest if the value has
        an incompatible type and raise TypeError. These can be customized
        using 'error' and 'raise_exception'.

        Always copy/steal the reference in 'src'.

        Args:
            src: Name of source C variable
            dest: Name of target C variable
            typ: Type of value
            declare_dest: If True, also declare the variable 'dest'
            error: What happens on error
            raise_exception: If True, also raise TypeError on failure
            likely: If the cast is likely to succeed (can be False for unions)
        """
        error = error or AssignHandler()
        if isinstance(error, AssignHandler):
            handle_error = '%s = NULL;' % dest
        elif isinstance(error, GotoHandler):
            handle_error = 'goto %s;' % error.label
        else:
            assert isinstance(error, ReturnHandler)
            handle_error = 'return %s;' % error.value
        if raise_exception:
            raise_exc = f'CPy_TypeError("{self.pretty_name(typ)}", {src}); '
            err = raise_exc + handle_error
        else:
            err = handle_error

        # Special case casting *from* optional
        if src_type and is_optional_type(src_type) and not is_object_rprimitive(typ):
            value_type = optional_value_type(src_type)
            assert value_type is not None
            if is_same_type(value_type, typ):
                if declare_dest:
                    self.emit_line(f'PyObject *{dest};')
                check = '({} != Py_None)'
                if likely:
                    check = f'(likely{check})'
                self.emit_arg_check(src, dest, typ, check.format(src), optional)
                self.emit_lines(
                    f'    {dest} = {src};',
                    'else {',
                    err,
                    '}')
                return

        # TODO: Verify refcount handling.
        if (is_list_rprimitive(typ) or is_dict_rprimitive(typ) or is_set_rprimitive(typ)
                or is_str_rprimitive(typ) or is_range_rprimitive(typ) or is_float_rprimitive(typ)
                or is_int_rprimitive(typ) or is_bool_rprimitive(typ) or is_bit_rprimitive(typ)):
            if declare_dest:
                self.emit_line(f'PyObject *{dest};')
            if is_list_rprimitive(typ):
                prefix = 'PyList'
            elif is_dict_rprimitive(typ):
                prefix = 'PyDict'
            elif is_set_rprimitive(typ):
                prefix = 'PySet'
            elif is_str_rprimitive(typ):
                prefix = 'PyUnicode'
            elif is_range_rprimitive(typ):
                prefix = 'PyRange'
            elif is_float_rprimitive(typ):
                prefix = 'CPyFloat'
            elif is_int_rprimitive(typ):
                prefix = 'PyLong'
            elif is_bool_rprimitive(typ) or is_bit_rprimitive(typ):
                prefix = 'PyBool'
            else:
                assert False, 'unexpected primitive type'
            check = '({}_Check({}))'
            if likely:
                check = f'(likely{check})'
            self.emit_arg_check(src, dest, typ, check.format(prefix, src), optional)
            self.emit_lines(
                f'    {dest} = {src};',
                'else {',
                err,
                '}')
        elif is_bytes_rprimitive(typ):
            if declare_dest:
                self.emit_line(f'PyObject *{dest};')
            check = '(PyBytes_Check({}) || PyByteArray_Check({}))'
            if likely:
                check = f'(likely{check})'
            self.emit_arg_check(src, dest, typ, check.format(src, src), optional)
            self.emit_lines(
                f'    {dest} = {src};',
                'else {',
                err,
                '}')
        elif is_tuple_rprimitive(typ):
            if declare_dest:
                self.emit_line(f'{self.ctype(typ)} {dest};')
            check = '(PyTuple_Check({}))'
            if likely:
                check = f'(likely{check})'
            self.emit_arg_check(src, dest, typ,
                                check.format(src), optional)
            self.emit_lines(
                f'    {dest} = {src};',
                'else {',
                err,
                '}')
        elif isinstance(typ, RInstance):
            if declare_dest:
                self.emit_line(f'PyObject *{dest};')
            concrete = all_concrete_classes(typ.class_ir)
            # If there are too many concrete subclasses or we can't find any
            # (meaning the code ought to be dead or we aren't doing global opts),
            # fall back to a normal typecheck.
            # Otherwise check all the subclasses.
            if not concrete or len(concrete) > FAST_ISINSTANCE_MAX_SUBCLASSES + 1:
                check = '(PyObject_TypeCheck({}, {}))'.format(
                    src, self.type_struct_name(typ.class_ir))
            else:
                full_str = '(Py_TYPE({src}) == {targets[0]})'
                for i in range(1, len(concrete)):
                    full_str += ' || (Py_TYPE({src}) == {targets[%d]})' % i
                if len(concrete) > 1:
                    full_str = '(%s)' % full_str
                check = full_str.format(
                    src=src, targets=[self.type_struct_name(ir) for ir in concrete])
            if likely:
                check = f'(likely{check})'
            self.emit_arg_check(src, dest, typ, check, optional)
            self.emit_lines(
                f'    {dest} = {src};',
                'else {',
                err,
                '}')
        elif is_none_rprimitive(typ):
            if declare_dest:
                self.emit_line(f'PyObject *{dest};')
            check = '({} == Py_None)'
            if likely:
                check = f'(likely{check})'
            self.emit_arg_check(src, dest, typ,
                                check.format(src), optional)
            self.emit_lines(
                f'    {dest} = {src};',
                'else {',
                err,
                '}')
        elif is_object_rprimitive(typ):
            if declare_dest:
                self.emit_line(f'PyObject *{dest};')
            self.emit_arg_check(src, dest, typ, '', optional)
            self.emit_line(f'{dest} = {src};')
            if optional:
                self.emit_line('}')
        elif isinstance(typ, RUnion):
            self.emit_union_cast(src, dest, typ, declare_dest, err, optional, src_type)
        elif isinstance(typ, RTuple):
            assert not optional
            self.emit_tuple_cast(src, dest, typ, declare_dest, err, src_type)
        else:
            assert False, 'Cast not implemented: %s' % typ