Ejemplo n.º 1
0
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
    """Return the declared type narrowed down to another type."""
    if declared == narrowed:
        return declared
    if isinstance(declared, UnionType):
        return UnionType.make_simplified_union([
            narrow_declared_type(x, narrowed)
            for x in declared.relevant_items()
        ])
    elif not is_overlapping_types(
            declared, narrowed, prohibit_none_typevar_overlap=True):
        if state.strict_optional:
            return UninhabitedType()
        else:
            return NoneType()
    elif isinstance(narrowed, UnionType):
        return UnionType.make_simplified_union([
            narrow_declared_type(declared, x)
            for x in narrowed.relevant_items()
        ])
    elif isinstance(narrowed, AnyType):
        return narrowed
    elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType):
        return TypeType.make_normalized(
            narrow_declared_type(declared.item, narrowed.item))
    elif isinstance(declared, (Instance, TupleType, TypeType, LiteralType)):
        return meet_types(declared, narrowed)
    elif isinstance(declared, TypedDictType) and isinstance(
            narrowed, Instance):
        # Special case useful for selecting TypedDicts from unions using isinstance(x, dict).
        if (narrowed.type.fullname() == 'builtins.dict'
                and all(isinstance(t, AnyType) for t in narrowed.args)):
            return declared
        return meet_types(declared, narrowed)
    return narrowed
Ejemplo n.º 2
0
def typed_dict_get_callback(ctx: MethodContext) -> Type:
    """Infer a precise return type for TypedDict.get with literal first argument."""
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.arg_types) >= 1
            and len(ctx.arg_types[0]) == 1):
        key = try_getting_str_literal(ctx.args[0][0], ctx.arg_types[0][0])
        if key is None:
            return ctx.default_return_type

        value_type = ctx.type.items.get(key)
        if value_type:
            if len(ctx.arg_types) == 1:
                return UnionType.make_simplified_union([value_type, NoneTyp()])
            elif (len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1
                  and len(ctx.args[1]) == 1):
                default_arg = ctx.args[1][0]
                if (isinstance(default_arg, DictExpr) and len(default_arg.items) == 0
                        and isinstance(value_type, TypedDictType)):
                    # Special case '{}' as the default for a typed dict type.
                    return value_type.copy_modified(required_keys=set())
                else:
                    return UnionType.make_simplified_union([value_type, ctx.arg_types[1][0]])
        else:
            ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context)
            return AnyType(TypeOfAny.from_error)
    return ctx.default_return_type
Ejemplo n.º 3
0
def typed_dict_pop_callback(ctx: MethodContext) -> Type:
    """Type check and infer a precise return type for TypedDict.pop."""
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.arg_types) >= 1
            and len(ctx.arg_types[0]) == 1):
        keys = try_getting_str_literals(ctx.args[0][0], ctx.arg_types[0][0])
        if keys is None:
            ctx.api.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context)
            return AnyType(TypeOfAny.from_error)

        value_types = []
        for key in keys:
            if key in ctx.type.required_keys:
                ctx.api.msg.typeddict_key_cannot_be_deleted(ctx.type, key, ctx.context)

            value_type = ctx.type.items.get(key)
            if value_type:
                value_types.append(value_type)
            else:
                ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context)
                return AnyType(TypeOfAny.from_error)

        if len(ctx.args[1]) == 0:
            return UnionType.make_simplified_union(value_types)
        elif (len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1
              and len(ctx.args[1]) == 1):
            return UnionType.make_simplified_union([*value_types, ctx.arg_types[1][0]])
    return ctx.default_return_type
Ejemplo n.º 4
0
def typed_dict_get_callback(ctx: MethodContext) -> Type:
    """Infer a precise return type for TypedDict.get with literal first argument."""
    if (isinstance(ctx.type, TypedDictType) and len(ctx.arg_types) >= 1
            and len(ctx.arg_types[0]) == 1):
        if isinstance(ctx.args[0][0], StrExpr):
            key = ctx.args[0][0].value
            value_type = ctx.type.items.get(key)
            if value_type:
                if len(ctx.arg_types) == 1:
                    return UnionType.make_simplified_union(
                        [value_type, NoneTyp()])
                elif (len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1
                      and len(ctx.args[1]) == 1):
                    default_arg = ctx.args[1][0]
                    if (isinstance(default_arg, DictExpr)
                            and len(default_arg.items) == 0
                            and isinstance(value_type, TypedDictType)):
                        # Special case '{}' as the default for a typed dict type.
                        return value_type.copy_modified(required_keys=set())
                    else:
                        return UnionType.make_simplified_union(
                            [value_type, ctx.arg_types[1][0]])
            else:
                ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context)
                return AnyType(TypeOfAny.from_error)
    return ctx.default_return_type
Ejemplo n.º 5
0
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
    """Return the declared type narrowed down to another type."""
    if declared == narrowed:
        return declared
    if isinstance(declared, UnionType):
        return UnionType.make_simplified_union([
            narrow_declared_type(x, narrowed)
            for x in declared.relevant_items()
        ])
    elif not is_overlapping_types(
            declared, narrowed, prohibit_none_typevar_overlap=True):
        if state.strict_optional:
            return UninhabitedType()
        else:
            return NoneTyp()
    elif isinstance(narrowed, UnionType):
        return UnionType.make_simplified_union([
            narrow_declared_type(declared, x)
            for x in narrowed.relevant_items()
        ])
    elif isinstance(narrowed, AnyType):
        return narrowed
    elif isinstance(declared, (Instance, TupleType)):
        return meet_types(declared, narrowed)
    elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType):
        return TypeType.make_normalized(
            narrow_declared_type(declared.item, narrowed.item))
    return narrowed
Ejemplo n.º 6
0
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
    """Return the declared type narrowed down to another type."""
    if declared == narrowed:
        return declared
    if isinstance(declared, UnionType):
        return UnionType.make_simplified_union([
            narrow_declared_type(x, narrowed)
            for x in declared.relevant_items()
        ])
    elif not is_overlapping_types(declared, narrowed, use_promotions=True):
        if experiments.STRICT_OPTIONAL:
            return UninhabitedType()
        else:
            return NoneTyp()
    elif isinstance(narrowed, UnionType):
        return UnionType.make_simplified_union([
            narrow_declared_type(declared, x)
            for x in narrowed.relevant_items()
        ])
    elif isinstance(narrowed, AnyType):
        return narrowed
    elif isinstance(declared, (Instance, TupleType)):
        return meet_types(declared, narrowed)
    elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType):
        return TypeType.make_normalized(
            narrow_declared_type(declared.item, narrowed.item))
    return narrowed
Ejemplo n.º 7
0
def typed_dict_get_signature_callback(ctx: MethodSigContext) -> CallableType:
    """Try to infer a better signature type for TypedDict.get.

    This is used to get better type context for the second argument that
    depends on a TypedDict value type.
    """
    signature = ctx.default_signature
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.args) == 2
            and len(ctx.args[0]) == 1
            and isinstance(ctx.args[0][0], StrExpr)
            and len(signature.arg_types) == 2
            and len(signature.variables) == 1
            and len(ctx.args[1]) == 1):
        key = ctx.args[0][0].value
        value_type = ctx.type.items.get(key)
        ret_type = signature.ret_type
        if value_type:
            default_arg = ctx.args[1][0]
            if (isinstance(value_type, TypedDictType)
                    and isinstance(default_arg, DictExpr)
                    and len(default_arg.items) == 0):
                # Caller has empty dict {} as default for typed dict.
                value_type = value_type.copy_modified(required_keys=set())
            # Tweak the signature to include the value type as context. It's
            # only needed for type inference since there's a union with a type
            # variable that accepts everything.
            tv = TypeVarType(signature.variables[0])
            return signature.copy_modified(
                arg_types=[signature.arg_types[0],
                           UnionType.make_simplified_union([value_type, tv])],
                ret_type=ret_type)
    return signature
Ejemplo n.º 8
0
def join_simple(declaration: Type, s: Type, t: Type) -> Type:
    """Return a simple least upper bound given the declared type."""

    if isinstance(s, AnyType):
        return s

    if isinstance(s, NoneTyp) and not isinstance(t, Void):
        return t

    if isinstance(s, ErasedType):
        return t

    if is_subtype(s, t):
        return t

    if is_subtype(t, s):
        return s

    if isinstance(declaration, UnionType):
        return UnionType.make_simplified_union([s, t])

    value = t.accept(TypeJoinVisitor(s))

    if value is None:
        # XXX this code path probably should be avoided.
        # It seems to happen when a line (x = y) is a type error, and
        # it's not clear that assuming that x is arbitrary afterward
        # is a good idea.
        return declaration

    if declaration is None or is_subtype(value, declaration):
        return value

    return declaration
Ejemplo n.º 9
0
def _autoconvertible_to_cdata(tp: Type, api: 'mypy.plugin.CheckerPluginInterface') -> Type:
    """Get a type that is compatible with all types that can be implicitly converted to the given
    CData type.

    Examples:
    * c_int -> Union[c_int, int]
    * c_char_p -> Union[c_char_p, bytes, int, NoneType]
    * MyStructure -> MyStructure
    """
    allowed_types = []
    # If tp is a union, we allow all types that are convertible to at least one of the union
    # items. This is not quite correct - strictly speaking, only types convertible to *all* of the
    # union items should be allowed. This may be worth changing in the future, but the more
    # correct algorithm could be too strict to be useful.
    for t in union_items(tp):
        # Every type can be converted from itself (obviously).
        allowed_types.append(t)
        if isinstance(t, Instance):
            unboxed = _find_simplecdata_base_arg(t, api)
            if unboxed is not None:
                # If _SimpleCData appears in tp's (direct or indirect) bases, its type argument
                # specifies the type's "unboxed" version, which can always be converted back to
                # the original "boxed" type.
                allowed_types.append(unboxed)

                if t.type.has_base('ctypes._PointerLike'):
                    # Pointer-like _SimpleCData subclasses can also be converted from
                    # an int or None.
                    allowed_types.append(api.named_generic_type('builtins.int', []))
                    allowed_types.append(NoneTyp())

    return UnionType.make_simplified_union(allowed_types)
Ejemplo n.º 10
0
def join_simple(declaration: Type, s: Type, t: Type) -> Type:
    """Return a simple least upper bound given the declared type."""

    if isinstance(s, AnyType):
        return s

    if isinstance(s, NoneTyp) and not isinstance(t, Void):
        return t

    if isinstance(s, ErasedType):
        return t

    if is_subtype(s, t):
        return t

    if is_subtype(t, s):
        return s

    if isinstance(declaration, UnionType):
        return UnionType.make_simplified_union([s, t])

    value = t.accept(TypeJoinVisitor(s))

    if value is None:
        # XXX this code path probably should be avoided.
        # It seems to happen when a line (x = y) is a type error, and
        # it's not clear that assuming that x is arbitrary afterward
        # is a good idea.
        return declaration

    if declaration is None or is_subtype(value, declaration):
        return value

    return declaration
Ejemplo n.º 11
0
def typed_dict_setdefault_callback(ctx: MethodContext) -> Type:
    """Type check TypedDict.setdefault and infer a precise return type."""
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.arg_types) == 2
            and len(ctx.arg_types[0]) == 1
            and len(ctx.arg_types[1]) == 1):
        keys = try_getting_str_literals(ctx.args[0][0], ctx.arg_types[0][0])
        if keys is None:
            ctx.api.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context)
            return AnyType(TypeOfAny.from_error)

        default_type = ctx.arg_types[1][0]

        value_types = []
        for key in keys:
            value_type = ctx.type.items.get(key)

            if value_type is None:
                ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context)
                return AnyType(TypeOfAny.from_error)

            # The signature_callback above can't always infer the right signature
            # (e.g. when the expression is a variable that happens to be a Literal str)
            # so we need to handle the check ourselves here and make sure the provided
            # default can be assigned to all key-value pairs we're updating.
            if not is_subtype(default_type, value_type):
                ctx.api.msg.typeddict_setdefault_arguments_inconsistent(
                    default_type, value_type, ctx.context)
                return AnyType(TypeOfAny.from_error)

            value_types.append(value_type)

        return UnionType.make_simplified_union(value_types)
    return ctx.default_return_type
Ejemplo n.º 12
0
def typed_dict_pop_callback(ctx: MethodContext) -> Type:
    """Type check and infer a precise return type for TypedDict.pop."""
    if (isinstance(ctx.type, TypedDictType) and len(ctx.arg_types) >= 1
            and len(ctx.arg_types[0]) == 1):
        if isinstance(ctx.args[0][0], StrExpr):
            key = ctx.args[0][0].value
            if key in ctx.type.required_keys:
                ctx.api.msg.typeddict_key_cannot_be_deleted(
                    ctx.type, key, ctx.context)
            value_type = ctx.type.items.get(key)
            if value_type:
                if len(ctx.args[1]) == 0:
                    return value_type
                elif (len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1
                      and len(ctx.args[1]) == 1):
                    return UnionType.make_simplified_union(
                        [value_type, ctx.arg_types[1][0]])
            else:
                ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context)
                return AnyType(TypeOfAny.from_error)
        else:
            ctx.api.fail(messages.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL,
                         ctx.context)
            return AnyType(TypeOfAny.from_error)
    return ctx.default_return_type
Ejemplo n.º 13
0
 def visit_type_var(self, left: TypeVarType) -> bool:
     right = self.right
     if isinstance(right, TypeVarType) and left.id == right.id:
         return True
     if left.values and is_subtype(UnionType.make_simplified_union(left.values), right):
         return True
     return is_subtype(left.upper_bound, self.right)
Ejemplo n.º 14
0
def _autoconvertible_to_cdata(
        tp: Type, api: 'mypy.plugin.CheckerPluginInterface') -> Type:
    """Get a type that is compatible with all types that can be implicitly converted to the given
    CData type.

    Examples:
    * c_int -> Union[c_int, int]
    * c_char_p -> Union[c_char_p, bytes, int, NoneType]
    * MyStructure -> MyStructure
    """
    allowed_types = []
    # If tp is a union, we allow all types that are convertible to at least one of the union
    # items. This is not quite correct - strictly speaking, only types convertible to *all* of the
    # union items should be allowed. This may be worth changing in the future, but the more
    # correct algorithm could be too strict to be useful.
    for t in union_items(tp):
        # Every type can be converted from itself (obviously).
        allowed_types.append(t)
        if isinstance(t, Instance):
            unboxed = _find_simplecdata_base_arg(t, api)
            if unboxed is not None:
                # If _SimpleCData appears in tp's (direct or indirect) bases, its type argument
                # specifies the type's "unboxed" version, which can always be converted back to
                # the original "boxed" type.
                allowed_types.append(unboxed)

                if t.type.has_base('ctypes._PointerLike'):
                    # Pointer-like _SimpleCData subclasses can also be converted from
                    # an int or None.
                    allowed_types.append(
                        api.named_generic_type('builtins.int', []))
                    allowed_types.append(
                        api.named_generic_type('builtins.NoneType', []))

    return UnionType.make_simplified_union(allowed_types)
Ejemplo n.º 15
0
def typed_dict_pop_signature_callback(ctx: MethodSigContext) -> CallableType:
    """Try to infer a better signature type for TypedDict.pop.

    This is used to get better type context for the second argument that
    depends on a TypedDict value type.
    """
    signature = ctx.default_signature
    str_type = ctx.api.named_generic_type('builtins.str', [])
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.args) == 2
            and len(ctx.args[0]) == 1
            and isinstance(ctx.args[0][0], StrExpr)
            and len(signature.arg_types) == 2
            and len(signature.variables) == 1
            and len(ctx.args[1]) == 1):
        key = ctx.args[0][0].value
        value_type = ctx.type.items.get(key)
        if value_type:
            # Tweak the signature to include the value type as context. It's
            # only needed for type inference since there's a union with a type
            # variable that accepts everything.
            tv = TypeVarType(signature.variables[0])
            typ = UnionType.make_simplified_union([value_type, tv])
            return signature.copy_modified(
                arg_types=[str_type, typ],
                ret_type=typ)
    return signature.copy_modified(arg_types=[str_type, signature.arg_types[1]])
Ejemplo n.º 16
0
def typed_dict_get_callback(ctx: MethodContext) -> Type:
    """Infer a precise return type for TypedDict.get with literal first argument."""
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.arg_types) >= 1
            and len(ctx.arg_types[0]) == 1):
        keys = try_getting_str_literals(ctx.args[0][0], ctx.arg_types[0][0])
        if keys is None:
            return ctx.default_return_type

        output_types = []
        for key in keys:
            value_type = ctx.type.items.get(key)
            if value_type is None:
                ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context)
                return AnyType(TypeOfAny.from_error)

            if len(ctx.arg_types) == 1:
                output_types.append(value_type)
            elif (len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1
                  and len(ctx.args[1]) == 1):
                default_arg = ctx.args[1][0]
                if (isinstance(default_arg, DictExpr) and len(default_arg.items) == 0
                        and isinstance(value_type, TypedDictType)):
                    # Special case '{}' as the default for a typed dict type.
                    output_types.append(value_type.copy_modified(required_keys=set()))
                else:
                    output_types.append(value_type)
                    output_types.append(ctx.arg_types[1][0])

        if len(ctx.arg_types) == 1:
            output_types.append(NoneType())

        return UnionType.make_simplified_union(output_types)
    return ctx.default_return_type
Ejemplo n.º 17
0
def join_simple(declaration: Optional[Type], s: Type, t: Type) -> Type:
    """Return a simple least upper bound given the declared type."""

    if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false):
        # if types are restricted in different ways, use the more general versions
        s = true_or_false(s)
        t = true_or_false(t)

    if isinstance(s, AnyType):
        return s

    if isinstance(s, ErasedType):
        return t

    if is_proper_subtype(s, t):
        return t

    if is_proper_subtype(t, s):
        return s

    if isinstance(declaration, UnionType):
        return UnionType.make_simplified_union([s, t])

    if isinstance(s, NoneType) and not isinstance(t, NoneType):
        s, t = t, s

    if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType):
        s, t = t, s

    value = t.accept(TypeJoinVisitor(s))
    if declaration is None or is_subtype(value, declaration):
        return value

    return declaration
Ejemplo n.º 18
0
def typed_dict_get_signature_callback(
        object_type: Type, args: List[List[Expression]],
        signature: CallableType,
        named_generic_type: Callable[[str, List[Type]], Type]) -> CallableType:
    """Try to infer a better signature type for TypedDict.get.

    This is used to get better type context for the second argument that
    depends on a TypedDict value type.
    """
    if (isinstance(object_type, TypedDictType) and len(args) == 2
            and len(args[0]) == 1 and isinstance(args[0][0], StrExpr)
            and len(signature.arg_types) == 2
            and len(signature.variables) == 1):
        key = args[0][0].value
        value_type = object_type.items.get(key)
        if value_type:
            # Tweak the signature to include the value type as context. It's
            # only needed for type inference since there's a union with a type
            # variable that accepts everything.
            tv = TypeVarType(signature.variables[0])
            return signature.copy_modified(arg_types=[
                signature.arg_types[0],
                UnionType.make_simplified_union([value_type, tv])
            ])
    return signature
Ejemplo n.º 19
0
def typed_dict_get_signature_callback(ctx: MethodSigContext) -> CallableType:
    """Try to infer a better signature type for TypedDict.get.

    This is used to get better type context for the second argument that
    depends on a TypedDict value type.
    """
    signature = ctx.default_signature
    if (isinstance(ctx.type, TypedDictType) and len(ctx.args) == 2
            and len(ctx.args[0]) == 1 and isinstance(ctx.args[0][0], StrExpr)
            and len(signature.arg_types) == 2 and len(signature.variables) == 1
            and len(ctx.args[1]) == 1):
        key = ctx.args[0][0].value
        value_type = ctx.type.items.get(key)
        ret_type = signature.ret_type
        if value_type:
            default_arg = ctx.args[1][0]
            if (isinstance(value_type, TypedDictType)
                    and isinstance(default_arg, DictExpr)
                    and len(default_arg.items) == 0):
                # Caller has empty dict {} as default for typed dict.
                value_type = value_type.copy_modified(required_keys=set())
            # Tweak the signature to include the value type as context. It's
            # only needed for type inference since there's a union with a type
            # variable that accepts everything.
            tv = TypeVarType(signature.variables[0])
            return signature.copy_modified(arg_types=[
                signature.arg_types[0],
                UnionType.make_simplified_union([value_type, tv])
            ],
                                           ret_type=ret_type)
    return signature
Ejemplo n.º 20
0
def meet_simple_away(s: Type, t: Type) -> Type:
    if isinstance(s, UnionType):
        return UnionType.make_simplified_union([x for x in s.items
                                                if not is_subtype(x, t)])
    elif not isinstance(s, AnyType) and is_subtype(s, t):
        return Void()
    else:
        return s
Ejemplo n.º 21
0
def meet_simple_away(s: Type, t: Type) -> Type:
    if isinstance(s, UnionType):
        return UnionType.make_simplified_union([x for x in s.items
                                                if not is_subtype(x, t)])
    elif not isinstance(s, AnyType) and is_subtype(s, t):
        return Void()
    else:
        return s
Ejemplo n.º 22
0
def analyze_union_member_access(name: str, typ: UnionType,
                                mx: MemberContext) -> Type:
    mx.msg.disable_type_names += 1
    results = [
        _analyze_member_access(name, subtype, mx)
        for subtype in typ.relevant_items()
    ]
    mx.msg.disable_type_names -= 1
    return UnionType.make_simplified_union(results)
Ejemplo n.º 23
0
 def visit_union_type(self, t: UnionType) -> Type:
     if isinstance(self.s, UnionType):
         meets = []  # type: List[Type]
         for x in t.items:
             for y in self.s.items:
                 meets.append(meet_types(x, y))
     else:
         meets = [meet_types(x, self.s) for x in t.items]
     return UnionType.make_simplified_union(meets)
Ejemplo n.º 24
0
 def visit_union_type(self, t: UnionType) -> Type:
     if isinstance(self.s, UnionType):
         meets = []  # type: List[Type]
         for x in t.items:
             for y in self.s.items:
                 meets.append(meet_types(x, y))
     else:
         meets = [meet_types(x, self.s) for x in t.items]
     return UnionType.make_simplified_union(meets)
Ejemplo n.º 25
0
 def visit_none_type(self, t: NoneTyp) -> Type:
     if experiments.STRICT_OPTIONAL:
         if isinstance(self.s, (NoneTyp, UninhabitedType)):
             return t
         elif isinstance(self.s, UnboundType):
             return AnyType(TypeOfAny.special_form)
         else:
             return UnionType.make_simplified_union([self.s, t])
     else:
         return self.s
Ejemplo n.º 26
0
 def visit_none_type(self, t: NoneTyp) -> Type:
     if state.strict_optional:
         if isinstance(self.s, (NoneTyp, UninhabitedType)):
             return t
         elif isinstance(self.s, UnboundType):
             return AnyType(TypeOfAny.special_form)
         else:
             return UnionType.make_simplified_union([self.s, t])
     else:
         return self.s
Ejemplo n.º 27
0
 def visit_none_type(self, t: NoneTyp) -> Type:
     if experiments.STRICT_OPTIONAL:
         if isinstance(self.s, (NoneTyp, UninhabitedType)):
             return t
         elif isinstance(self.s, UnboundType):
             return AnyType(TypeOfAny.special_form)
         else:
             return UnionType.make_simplified_union([self.s, t])
     else:
         return self.s
Ejemplo n.º 28
0
def analyze_union_member_access(name: str, typ: UnionType,
                                mx: MemberContext) -> Type:
    mx.msg.disable_type_names += 1
    results = []
    for subtype in typ.relevant_items():
        # Self types should be bound to every individual item of a union.
        item_mx = mx.copy_modified(self_type=subtype)
        results.append(_analyze_member_access(name, subtype, item_mx))
    mx.msg.disable_type_names -= 1
    return UnionType.make_simplified_union(results)
Ejemplo n.º 29
0
Archivo: join.py Proyecto: chadrik/mypy
 def visit_none_type(self, t: NoneTyp) -> Type:
     if state.strict_optional:
         if isinstance(self.s, (NoneTyp, UninhabitedType)):
             return t
         elif isinstance(self.s, UnboundType):
             return AnyType(TypeOfAny.special_form)
         else:
             return UnionType.make_simplified_union([self.s, t])
     else:
         return self.s
Ejemplo n.º 30
0
def generate_type_combinations(types: List[Type]) -> List[Type]:
    """Generate possible combinations of a list of types.

    mypy essentially supports two different ways to do this: joining the types
    and unioning the types. We try both.
    """
    joined_type = join_type_list(types)
    union_type = UnionType.make_simplified_union(types)
    if is_same_type(joined_type, union_type):
        return [joined_type]
    else:
        return [joined_type, union_type]
Ejemplo n.º 31
0
def meet_simple(s: Type, t: Type, default_right: bool = True) -> Type:
    if s == t:
        return s
    if isinstance(s, UnionType):
        return UnionType.make_simplified_union([meet_types(x, t) for x in s.items])
    elif not is_overlapping_types(s, t):
        return Void()
    else:
        if default_right:
            return t
        else:
            return s
Ejemplo n.º 32
0
def generate_type_combinations(types: List[Type]) -> List[Type]:
    """Generate possible combinations of a list of types.

    mypy essentially supports two different ways to do this: joining the types
    and unioning the types. We try both.
    """
    joined_type = join_type_list(types)
    union_type = UnionType.make_simplified_union(types)
    if is_same_type(joined_type, union_type):
        return [joined_type]
    else:
        return [joined_type, union_type]
Ejemplo n.º 33
0
def meet_simple(s: Type, t: Type, default_right: bool = True) -> Type:
    if s == t:
        return s
    if isinstance(s, UnionType):
        return UnionType.make_simplified_union([meet_types(x, t) for x in s.items])
    elif not is_overlapping_types(s, t):
        return Void()
    else:
        if default_right:
            return t
        else:
            return s
Ejemplo n.º 34
0
def typed_dict_get_callback(object_type: Type, arg_types: List[List[Type]],
                            args: List[List[Expression]],
                            inferred_return_type: Type,
                            context: PluginContext) -> Type:
    """Infer a precise return type for TypedDict.get with literal first argument."""
    if (isinstance(object_type, TypedDictType) and len(arg_types) >= 1
            and len(arg_types[0]) == 1):
        if isinstance(args[0][0], StrExpr):
            key = args[0][0].value
            value_type = object_type.items.get(key)
            if value_type:
                if len(arg_types) == 1:
                    return UnionType.make_simplified_union(
                        [value_type, NoneTyp()])
                elif len(arg_types) == 2 and len(arg_types[1]) == 1:
                    return UnionType.make_simplified_union(
                        [value_type, arg_types[1][0]])
            else:
                context.msg.typeddict_item_name_not_found(
                    object_type, key, context.context)
                return AnyType()
    return inferred_return_type
Ejemplo n.º 35
0
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
    """Return the declared type narrowed down to another type."""
    if declared == narrowed:
        return declared
    if isinstance(declared, UnionType):
        return UnionType.make_simplified_union([narrow_declared_type(x, narrowed)
                                                for x in declared.relevant_items()])
    elif not is_overlapping_types(declared, narrowed, use_promotions=True):
        if experiments.STRICT_OPTIONAL:
            return UninhabitedType()
        else:
            return NoneTyp()
    elif isinstance(narrowed, UnionType):
        return UnionType.make_simplified_union([narrow_declared_type(declared, x)
                                                for x in narrowed.relevant_items()])
    elif isinstance(narrowed, AnyType):
        return narrowed
    elif isinstance(declared, (Instance, TupleType)):
        return meet_types(declared, narrowed)
    elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType):
        return TypeType.make_normalized(narrow_declared_type(declared.item, narrowed.item))
    return narrowed
Ejemplo n.º 36
0
Archivo: meet.py Proyecto: chadrik/mypy
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
    """Return the declared type narrowed down to another type."""
    if declared == narrowed:
        return declared
    if isinstance(declared, UnionType):
        return UnionType.make_simplified_union([narrow_declared_type(x, narrowed)
                                                for x in declared.relevant_items()])
    elif not is_overlapping_types(declared, narrowed,
                                  prohibit_none_typevar_overlap=True):
        if state.strict_optional:
            return UninhabitedType()
        else:
            return NoneTyp()
    elif isinstance(narrowed, UnionType):
        return UnionType.make_simplified_union([narrow_declared_type(declared, x)
                                                for x in narrowed.relevant_items()])
    elif isinstance(narrowed, AnyType):
        return narrowed
    elif isinstance(declared, (Instance, TupleType)):
        return meet_types(declared, narrowed)
    elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType):
        return TypeType.make_normalized(narrow_declared_type(declared.item, narrowed.item))
    return narrowed
Ejemplo n.º 37
0
def meet_simple(s: Type, t: Type, default_right: bool = True) -> Type:
    if s == t:
        return s
    if isinstance(s, UnionType):
        return UnionType.make_simplified_union([meet_types(x, t) for x in s.items])
    elif not is_overlapping_types(s, t, use_promotions=True):
        if experiments.STRICT_OPTIONAL:
            return UninhabitedType()
        else:
            return NoneTyp()
    else:
        if default_right:
            return t
        else:
            return s
Ejemplo n.º 38
0
 def visit_none_type(self, t: NoneTyp) -> Type:
     if experiments.STRICT_OPTIONAL:
         if isinstance(self.s, (NoneTyp, UninhabitedType)):
             return t
         elif isinstance(self.s, UnboundType):
             return AnyType()
         elif isinstance(self.s, Void) or isinstance(self.s, ErrorType):
             return ErrorType()
         else:
             return UnionType.make_simplified_union([self.s, t])
     else:
         if not isinstance(self.s, Void):
             return self.s
         else:
             return self.default(self.s)
Ejemplo n.º 39
0
Archivo: meet.py Proyecto: ecprice/mypy
def meet_simple(s: Type, t: Type, default_right: bool = True) -> Type:
    if s == t:
        return s
    if isinstance(s, UnionType):
        return UnionType.make_simplified_union([meet_types(x, t) for x in s.items])
    elif not is_overlapping_types(s, t, use_promotions=True):
        if experiments.STRICT_OPTIONAL:
            return UninhabitedType()
        else:
            return NoneTyp()
    else:
        if default_right:
            return t
        else:
            return s
Ejemplo n.º 40
0
 def visit_none_type(self, t: NoneTyp) -> Type:
     if experiments.STRICT_OPTIONAL:
         if isinstance(self.s, (NoneTyp, UninhabitedType)):
             return t
         elif isinstance(self.s, UnboundType):
             return AnyType()
         elif isinstance(self.s, Void) or isinstance(self.s, ErrorType):
             return ErrorType()
         else:
             return UnionType.make_simplified_union([self.s, t])
     else:
         if not isinstance(self.s, Void):
             return self.s
         else:
             return self.default(self.s)
Ejemplo n.º 41
0
def array_raw_callback(ctx: 'mypy.plugin.AttributeContext') -> Type:
    """Callback to provide an accurate type for ctypes.Array.raw."""
    et = _get_array_element_type(ctx.type)
    if et is not None:
        types = []  # type: List[Type]
        for tp in union_items(et):
            if (isinstance(tp, AnyType) or isinstance(tp, Instance)
                    and tp.type.fullname() == 'ctypes.c_char'):
                types.append(_get_bytes_type(ctx.api))
            else:
                ctx.api.msg.fail(
                    'ctypes.Array attribute "raw" is only available'
                    ' with element type c_char, not "{}"'.format(et),
                    ctx.context)
        return UnionType.make_simplified_union(types)
    return ctx.default_attr_type
Ejemplo n.º 42
0
def array_raw_callback(ctx: 'mypy.plugin.AttributeContext') -> Type:
    """Callback to provide an accurate type for ctypes.Array.raw."""
    et = _get_array_element_type(ctx.type)
    if et is not None:
        types = []  # type: List[Type]
        for tp in union_items(et):
            if (isinstance(tp, AnyType)
                    or isinstance(tp, Instance) and tp.type.fullname() == 'ctypes.c_char'):
                types.append(_get_bytes_type(ctx.api))
            else:
                ctx.api.msg.fail(
                    'ctypes.Array attribute "raw" is only available'
                    ' with element type c_char, not "{}"'
                    .format(et),
                    ctx.context)
        return UnionType.make_simplified_union(types)
    return ctx.default_attr_type
Ejemplo n.º 43
0
def open_return_type(api: CheckerPluginInterface,
                     args: List[List[Expression]]) -> Optional[Type]:
    def return_type(word: Literal["Text", "Buffered", "Raw"]) -> Type:
        return api.named_generic_type(
            "typing.Awaitable",
            [api.named_generic_type("trio._Async{}IOBase".format(word), [])],
        )

    if len(args) < 2 or len(args[1]) == 0:
        # If mode is unspecified, the default is text
        return return_type("Text")

    if len(args[1]) == 1:
        # Mode was specified
        mode_arg = args[1][0]
        if isinstance(mode_arg, StrExpr):
            # Mode is a string constant
            if "b" not in mode_arg.value:
                # If there's no "b" in it, it's a text mode
                return return_type("Text")
            # Otherwise it's binary -- determine whether buffered or not
            if len(args) >= 3 and len(args[2]) == 1:
                # Buffering was specified
                buffering_arg = args[2][0]
                if isinstance(buffering_arg, IntExpr):
                    # Buffering is a constant -- zero means
                    # unbuffered, otherwise buffered
                    if buffering_arg.value == 0:
                        return return_type("Raw")
                    return return_type("Buffered")
                # Not a constant, so we're not sure which it is.
                options = [
                    api.named_generic_type("trio._AsyncRawIOBase", []),
                    api.named_generic_type("trio._AsyncBufferedIOBase", []),
                ]  # type: List[Type]
                return api.named_generic_type(
                    "typing.Awaitable",
                    [UnionType.make_simplified_union(options)])
            else:
                # Buffering is default if not specified
                return return_type("Buffered")

    # Mode wasn't a constant or we couldn't make sense of it
    return None
Ejemplo n.º 44
0
def _autounboxed_cdata(tp: Type) -> Type:
    """Get the auto-unboxed version of a CData type, if applicable.

    For *direct* _SimpleCData subclasses, the only type argument of _SimpleCData in the bases list
    is returned.
    For all other CData types, including indirect _SimpleCData subclasses, tp is returned as-is.
    """
    if isinstance(tp, UnionType):
        return UnionType.make_simplified_union([_autounboxed_cdata(t) for t in tp.items])
    elif isinstance(tp, Instance):
        for base in tp.type.bases:
            if base.type.fullname() == 'ctypes._SimpleCData':
                # If tp has _SimpleCData as a direct base class,
                # the auto-unboxed type is the single type argument of the _SimpleCData type.
                assert len(base.args) == 1
                return base.args[0]
    # If tp is not a concrete type, or if there is no _SimpleCData in the bases,
    # the type is not auto-unboxed.
    return tp
Ejemplo n.º 45
0
def join_simple(declaration: Optional[Type], s: Type, t: Type) -> Type:
    """Return a simple least upper bound given the declared type."""

    if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false):
        # if types are restricted in different ways, use the more general versions
        s = true_or_false(s)
        t = true_or_false(t)

    if isinstance(s, AnyType):
        return s

    if isinstance(s, ErasedType):
        return t

    if is_proper_subtype(s, t):
        return t

    if is_proper_subtype(t, s):
        return s

    if isinstance(declaration, UnionType):
        return UnionType.make_simplified_union([s, t])

    if isinstance(s, NoneTyp) and not isinstance(t, NoneTyp):
        s, t = t, s

    if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType):
        s, t = t, s

    value = t.accept(TypeJoinVisitor(s))

    if value is None:
        # XXX this code path probably should be avoided.
        # It seems to happen when a line (x = y) is a type error, and
        # it's not clear that assuming that x is arbitrary afterward
        # is a good idea.
        return declaration

    if declaration is None or is_subtype(value, declaration):
        return value

    return declaration
Ejemplo n.º 46
0
def join_simple(declaration: Optional[Type], s: Type, t: Type) -> Type:
    """Return a simple least upper bound given the declared type."""

    if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false):
        # if types are restricted in different ways, use the more general versions
        s = true_or_false(s)
        t = true_or_false(t)

    if isinstance(s, AnyType):
        return s

    if isinstance(s, ErasedType):
        return t

    if is_proper_subtype(s, t):
        return t

    if is_proper_subtype(t, s):
        return s

    if isinstance(declaration, UnionType):
        return UnionType.make_simplified_union([s, t])

    if isinstance(s, NoneTyp) and not isinstance(t, NoneTyp):
        s, t = t, s

    if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType):
        s, t = t, s

    value = t.accept(TypeJoinVisitor(s))

    if value is None:
        # XXX this code path probably should be avoided.
        # It seems to happen when a line (x = y) is a type error, and
        # it's not clear that assuming that x is arbitrary afterward
        # is a good idea.
        return declaration

    if declaration is None or is_subtype(value, declaration):
        return value

    return declaration
Ejemplo n.º 47
0
def typed_dict_pop_callback(ctx: MethodContext) -> Type:
    """Type check and infer a precise return type for TypedDict.pop."""
    if (isinstance(ctx.type, TypedDictType)
            and len(ctx.arg_types) >= 1
            and len(ctx.arg_types[0]) == 1):
        key = try_getting_str_literal(ctx.args[0][0], ctx.arg_types[0][0])
        if key is None:
            ctx.api.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context)
            return AnyType(TypeOfAny.from_error)

        if key in ctx.type.required_keys:
            ctx.api.msg.typeddict_key_cannot_be_deleted(ctx.type, key, ctx.context)
        value_type = ctx.type.items.get(key)
        if value_type:
            if len(ctx.args[1]) == 0:
                return value_type
            elif (len(ctx.arg_types) == 2 and len(ctx.arg_types[1]) == 1
                  and len(ctx.args[1]) == 1):
                return UnionType.make_simplified_union([value_type, ctx.arg_types[1][0]])
        else:
            ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context)
            return AnyType(TypeOfAny.from_error)
    return ctx.default_return_type
Ejemplo n.º 48
0
 def visit_unbound_type(self, t: UnboundType) -> Type:
     if t.optional:
         t.optional = False
         # We don't need to worry about double-wrapping Optionals or
         # wrapping Anys: Union simplification will take care of that.
         return UnionType.make_simplified_union([self.visit_unbound_type(t), NoneTyp()])
     sym = self.lookup(t.name, t)
     if sym is not None:
         if sym.node is None:
             # UNBOUND_IMPORTED can happen if an unknown name was imported.
             if sym.kind != UNBOUND_IMPORTED:
                 self.fail('Internal error (node is None, kind={})'.format(sym.kind), t)
             return AnyType()
         fullname = sym.node.fullname()
         if sym.kind == BOUND_TVAR:
             if len(t.args) > 0:
                 self.fail('Type variable "{}" used with arguments'.format(
                     t.name), t)
             assert sym.tvar_def is not None
             return TypeVarType(sym.tvar_def, t.line)
         elif fullname == 'builtins.None':
             if experiments.STRICT_OPTIONAL:
                 return NoneTyp(is_ret_type=t.is_ret_type)
             else:
                 return Void()
         elif fullname == 'typing.Any':
             return AnyType()
         elif fullname == 'typing.Tuple':
             if len(t.args) == 2 and isinstance(t.args[1], EllipsisType):
                 # Tuple[T, ...] (uniform, variable-length tuple)
                 node = self.lookup_fqn_func('builtins.tuple')
                 tuple_info = cast(TypeInfo, node.node)
                 return Instance(tuple_info, [t.args[0].accept(self)], t.line)
             return self.tuple_type(self.anal_array(t.args))
         elif fullname == 'typing.Union':
             items = self.anal_array(t.args)
             items = [item for item in items if not isinstance(item, Void)]
             return UnionType.make_union(items)
         elif fullname == 'typing.Optional':
             if len(t.args) != 1:
                 self.fail('Optional[...] must have exactly one type argument', t)
                 return AnyType()
             items = self.anal_array(t.args)
             if experiments.STRICT_OPTIONAL:
                 return UnionType.make_simplified_union([items[0], NoneTyp()])
             else:
                 # Without strict Optional checking Optional[t] is just an alias for t.
                 return items[0]
         elif fullname == 'typing.Callable':
             return self.analyze_callable_type(t)
         elif fullname == 'typing.Type':
             if len(t.args) == 0:
                 return TypeType(AnyType(), line=t.line)
             if len(t.args) != 1:
                 self.fail('Type[...] must have exactly one type argument', t)
             items = self.anal_array(t.args)
             item = items[0]
             return TypeType(item, line=t.line)
         elif sym.kind == TYPE_ALIAS:
             # TODO: Generic type aliases.
             return sym.type_override
         elif not isinstance(sym.node, TypeInfo):
             name = sym.fullname
             if name is None:
                 name = sym.node.name()
             if isinstance(sym.node, Var) and isinstance(sym.node.type, AnyType):
                 # Something with an Any type -- make it an alias for Any in a type
                 # context. This is slightly problematic as it allows using the type 'Any'
                 # as a base class -- however, this will fail soon at runtime so the problem
                 # is pretty minor.
                 return AnyType()
             self.fail('Invalid type "{}"'.format(name), t)
             return t
         info = sym.node  # type: TypeInfo
         if len(t.args) > 0 and info.fullname() == 'builtins.tuple':
             return TupleType(self.anal_array(t.args),
                              Instance(info, [AnyType()], t.line),
                              t.line)
         else:
             # Analyze arguments and construct Instance type. The
             # number of type arguments and their values are
             # checked only later, since we do not always know the
             # valid count at this point. Thus we may construct an
             # Instance with an invalid number of type arguments.
             instance = Instance(info, self.anal_array(t.args), t.line)
             tup = info.tuple_type
             if tup is None:
                 return instance
             else:
                 # The class has a Tuple[...] base class so it will be
                 # represented as a tuple type.
                 if t.args:
                     self.fail('Generic tuple types not supported', t)
                     return AnyType()
                 return tup.copy_modified(items=self.anal_array(tup.items),
                                          fallback=instance)
     else:
         return AnyType()
Ejemplo n.º 49
0
def analyze_member_access(name: str,
                          typ: Type,
                          node: Context,
                          is_lvalue: bool,
                          is_super: bool,
                          is_operator: bool,
                          builtin_type: Callable[[str], Instance],
                          not_ready_callback: Callable[[str, Context], None],
                          msg: MessageBuilder, *,
                          original_type: Type,
                          chk: 'mypy.checker.TypeChecker',
                          override_info: Optional[TypeInfo] = None) -> Type:
    """Return the type of attribute `name` of typ.

    This is a general operation that supports various different variations:

      1. lvalue or non-lvalue access (i.e. setter or getter access)
      2. supertype access (when using super(); is_super == True and
         override_info should refer to the supertype)

    original_type is the most precise inferred or declared type of the base object
    that we have available. typ is generally a supertype of original_type.
    When looking for an attribute of typ, we may perform recursive calls targeting
    the fallback type, for example.
    original_type is always the type used in the initial call.
    """
    # TODO: this and following functions share some logic with subtypes.find_member,
    # consider refactoring.
    if isinstance(typ, Instance):
        if name == '__init__' and not is_super:
            # Accessing __init__ in statically typed code would compromise
            # type safety unless used via super().
            msg.fail(messages.CANNOT_ACCESS_INIT, node)
            return AnyType(TypeOfAny.from_error)

        # The base object has an instance type.

        info = typ.type
        if override_info:
            info = override_info

        if (experiments.find_occurrences and
                info.name() == experiments.find_occurrences[0] and
                name == experiments.find_occurrences[1]):
            msg.note("Occurrence of '{}.{}'".format(*experiments.find_occurrences), node)

        # Look up the member. First look up the method dictionary.
        method = info.get_method(name)
        if method:
            if method.is_property:
                assert isinstance(method, OverloadedFuncDef)
                first_item = cast(Decorator, method.items[0])
                return analyze_var(name, first_item.var, typ, info, node, is_lvalue, msg,
                                   original_type, not_ready_callback, chk=chk)
            if is_lvalue:
                msg.cant_assign_to_method(node)
            signature = function_type(method, builtin_type('builtins.function'))
            signature = freshen_function_type_vars(signature)
            if name == '__new__':
                # __new__ is special and behaves like a static method -- don't strip
                # the first argument.
                pass
            else:
                signature = bind_self(signature, original_type)
            typ = map_instance_to_supertype(typ, method.info)
            member_type = expand_type_by_instance(signature, typ)
            freeze_type_vars(member_type)
            return member_type
        else:
            # Not a method.
            return analyze_member_var_access(name, typ, info, node,
                                             is_lvalue, is_super, builtin_type,
                                             not_ready_callback, msg,
                                             original_type=original_type, chk=chk)
    elif isinstance(typ, AnyType):
        # The base object has dynamic type.
        return AnyType(TypeOfAny.from_another_any, source_any=typ)
    elif isinstance(typ, NoneTyp):
        if chk.should_suppress_optional_error([typ]):
            return AnyType(TypeOfAny.from_error)
        # The only attribute NoneType has are those it inherits from object
        return analyze_member_access(name, builtin_type('builtins.object'), node, is_lvalue,
                                     is_super, is_operator, builtin_type, not_ready_callback, msg,
                                     original_type=original_type, chk=chk)
    elif isinstance(typ, UnionType):
        # The base object has dynamic type.
        msg.disable_type_names += 1
        results = [analyze_member_access(name, subtype, node, is_lvalue, is_super,
                                         is_operator, builtin_type, not_ready_callback, msg,
                                         original_type=original_type, chk=chk)
                   for subtype in typ.relevant_items()]
        msg.disable_type_names -= 1
        return UnionType.make_simplified_union(results)
    elif isinstance(typ, TupleType):
        # Actually look up from the fallback instance type.
        return analyze_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                     is_operator, builtin_type, not_ready_callback, msg,
                                     original_type=original_type, chk=chk)
    elif isinstance(typ, TypedDictType):
        # Actually look up from the fallback instance type.
        return analyze_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                     is_operator, builtin_type, not_ready_callback, msg,
                                     original_type=original_type, chk=chk)
    elif isinstance(typ, FunctionLike) and typ.is_type_obj():
        # Class attribute.
        # TODO super?
        ret_type = typ.items()[0].ret_type
        if isinstance(ret_type, TupleType):
            ret_type = ret_type.fallback
        if isinstance(ret_type, Instance):
            if not is_operator:
                # When Python sees an operator (eg `3 == 4`), it automatically translates that
                # into something like `int.__eq__(3, 4)` instead of `(3).__eq__(4)` as an
                # optimization.
                #
                # While it normally it doesn't matter which of the two versions are used, it
                # does cause inconsistencies when working with classes. For example, translating
                # `int == int` to `int.__eq__(int)` would not work since `int.__eq__` is meant to
                # compare two int _instances_. What we really want is `type(int).__eq__`, which
                # is meant to compare two types or classes.
                #
                # This check makes sure that when we encounter an operator, we skip looking up
                # the corresponding method in the current instance to avoid this edge case.
                # See https://github.com/python/mypy/pull/1787 for more info.
                result = analyze_class_attribute_access(ret_type, name, node, is_lvalue,
                                                        builtin_type, not_ready_callback, msg,
                                                        original_type=original_type)
                if result:
                    return result
            # Look up from the 'type' type.
            return analyze_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                         is_operator, builtin_type, not_ready_callback, msg,
                                         original_type=original_type, chk=chk)
        else:
            assert False, 'Unexpected type {}'.format(repr(ret_type))
    elif isinstance(typ, FunctionLike):
        # Look up from the 'function' type.
        return analyze_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                     is_operator, builtin_type, not_ready_callback, msg,
                                     original_type=original_type, chk=chk)
    elif isinstance(typ, TypeVarType):
        return analyze_member_access(name, typ.upper_bound, node, is_lvalue, is_super,
                                     is_operator, builtin_type, not_ready_callback, msg,
                                     original_type=original_type, chk=chk)
    elif isinstance(typ, DeletedType):
        msg.deleted_as_rvalue(typ, node)
        return AnyType(TypeOfAny.from_error)
    elif isinstance(typ, TypeType):
        # Similar to FunctionLike + is_type_obj() above.
        item = None
        fallback = builtin_type('builtins.type')
        ignore_messages = msg.copy()
        ignore_messages.disable_errors()
        if isinstance(typ.item, Instance):
            item = typ.item
        elif isinstance(typ.item, AnyType):
            return analyze_member_access(name, fallback, node, is_lvalue, is_super,
                                     is_operator, builtin_type, not_ready_callback,
                                     ignore_messages, original_type=original_type, chk=chk)
        elif isinstance(typ.item, TypeVarType):
            if isinstance(typ.item.upper_bound, Instance):
                item = typ.item.upper_bound
        elif isinstance(typ.item, TupleType):
            item = typ.item.fallback
        elif isinstance(typ.item, FunctionLike) and typ.item.is_type_obj():
            item = typ.item.fallback
        elif isinstance(typ.item, TypeType):
            # Access member on metaclass object via Type[Type[C]]
            if isinstance(typ.item.item, Instance):
                item = typ.item.item.type.metaclass_type
        if item and not is_operator:
            # See comment above for why operators are skipped
            result = analyze_class_attribute_access(item, name, node, is_lvalue,
                                                    builtin_type, not_ready_callback, msg,
                                                    original_type=original_type)
            if result:
                if not (isinstance(result, AnyType) and item.type.fallback_to_any):
                    return result
                else:
                    # We don't want errors on metaclass lookup for classes with Any fallback
                    msg = ignore_messages
        if item is not None:
            fallback = item.type.metaclass_type or fallback
        return analyze_member_access(name, fallback, node, is_lvalue, is_super,
                                     is_operator, builtin_type, not_ready_callback, msg,
                                     original_type=original_type, chk=chk)

    if chk.should_suppress_optional_error([typ]):
        return AnyType(TypeOfAny.from_error)
    return msg.has_no_attr(original_type, typ, name, node)
Ejemplo n.º 50
0
def analyze_member_access(
    name: str,
    typ: Type,
    node: Context,
    is_lvalue: bool,
    is_super: bool,
    is_operator: bool,
    builtin_type: Callable[[str], Instance],
    not_ready_callback: Callable[[str, Context], None],
    msg: MessageBuilder,
    override_info: TypeInfo = None,
    report_type: Type = None,
    chk: "mypy.checker.TypeChecker" = None,
) -> Type:
    """Analyse attribute access.

    This is a general operation that supports various different variations:

      1. lvalue or non-lvalue access (i.e. setter or getter access)
      2. supertype access (when using super(); is_super == True and
         override_info should refer to the supertype)
    """
    report_type = report_type or typ
    if isinstance(typ, Instance):
        if name == "__init__" and not is_super:
            # Accessing __init__ in statically typed code would compromise
            # type safety unless used via super().
            msg.fail(messages.CANNOT_ACCESS_INIT, node)
            return AnyType()

        # The base object has an instance type.

        info = typ.type
        if override_info:
            info = override_info

        # Look up the member. First look up the method dictionary.
        method = info.get_method(name)
        if method:
            if method.is_property:
                assert isinstance(method, OverloadedFuncDef)
                return analyze_var(name, method.items[0].var, typ, info, node, is_lvalue, msg, not_ready_callback)
            if is_lvalue:
                msg.cant_assign_to_method(node)
            typ = map_instance_to_supertype(typ, method.info)
            if name == "__new__":
                # __new__ is special and behaves like a static method -- don't strip
                # the first argument.
                signature = function_type(method, builtin_type("builtins.function"))
            else:
                signature = method_type_with_fallback(method, builtin_type("builtins.function"))
            return expand_type_by_instance(signature, typ)
        else:
            # Not a method.
            return analyze_member_var_access(
                name,
                typ,
                info,
                node,
                is_lvalue,
                is_super,
                builtin_type,
                not_ready_callback,
                msg,
                report_type=report_type,
                chk=chk,
            )
    elif isinstance(typ, AnyType):
        # The base object has dynamic type.
        return AnyType()
    elif isinstance(typ, NoneTyp):
        if chk and chk.should_suppress_optional_error([typ]):
            return AnyType()
        # The only attribute NoneType has are those it inherits from object
        return analyze_member_access(
            name,
            builtin_type("builtins.object"),
            node,
            is_lvalue,
            is_super,
            is_operator,
            builtin_type,
            not_ready_callback,
            msg,
            report_type=report_type,
            chk=chk,
        )
    elif isinstance(typ, UnionType):
        # The base object has dynamic type.
        msg.disable_type_names += 1
        results = [
            analyze_member_access(
                name, subtype, node, is_lvalue, is_super, is_operator, builtin_type, not_ready_callback, msg, chk=chk
            )
            for subtype in typ.items
        ]
        msg.disable_type_names -= 1
        return UnionType.make_simplified_union(results)
    elif isinstance(typ, TupleType):
        # Actually look up from the fallback instance type.
        return analyze_member_access(
            name, typ.fallback, node, is_lvalue, is_super, is_operator, builtin_type, not_ready_callback, msg, chk=chk
        )
    elif isinstance(typ, FunctionLike) and typ.is_type_obj():
        # Class attribute.
        # TODO super?
        ret_type = typ.items()[0].ret_type
        if isinstance(ret_type, TupleType):
            ret_type = ret_type.fallback
        if isinstance(ret_type, Instance):
            if not is_operator:
                # When Python sees an operator (eg `3 == 4`), it automatically translates that
                # into something like `int.__eq__(3, 4)` instead of `(3).__eq__(4)` as an
                # optimation.
                #
                # While it normally it doesn't matter which of the two versions are used, it
                # does cause inconsistencies when working with classes. For example, translating
                # `int == int` to `int.__eq__(int)` would not work since `int.__eq__` is meant to
                # compare two int _instances_. What we really want is `type(int).__eq__`, which
                # is meant to compare two types or classes.
                #
                # This check makes sure that when we encounter an operator, we skip looking up
                # the corresponding method in the current instance to avoid this edge case.
                # See https://github.com/python/mypy/pull/1787 for more info.
                result = analyze_class_attribute_access(
                    ret_type, name, node, is_lvalue, builtin_type, not_ready_callback, msg
                )
                if result:
                    return result
            # Look up from the 'type' type.
            return analyze_member_access(
                name,
                typ.fallback,
                node,
                is_lvalue,
                is_super,
                is_operator,
                builtin_type,
                not_ready_callback,
                msg,
                report_type=report_type,
                chk=chk,
            )
        else:
            assert False, "Unexpected type {}".format(repr(ret_type))
    elif isinstance(typ, FunctionLike):
        # Look up from the 'function' type.
        return analyze_member_access(
            name,
            typ.fallback,
            node,
            is_lvalue,
            is_super,
            is_operator,
            builtin_type,
            not_ready_callback,
            msg,
            report_type=report_type,
            chk=chk,
        )
    elif isinstance(typ, TypeVarType):
        return analyze_member_access(
            name,
            typ.upper_bound,
            node,
            is_lvalue,
            is_super,
            is_operator,
            builtin_type,
            not_ready_callback,
            msg,
            report_type=report_type,
            chk=chk,
        )
    elif isinstance(typ, DeletedType):
        msg.deleted_as_rvalue(typ, node)
        return AnyType()
    elif isinstance(typ, TypeType):
        # Similar to FunctionLike + is_type_obj() above.
        item = None
        if isinstance(typ.item, Instance):
            item = typ.item
        elif isinstance(typ.item, TypeVarType):
            if isinstance(typ.item.upper_bound, Instance):
                item = typ.item.upper_bound
        if item and not is_operator:
            # See comment above for why operators are skipped
            result = analyze_class_attribute_access(item, name, node, is_lvalue, builtin_type, not_ready_callback, msg)
            if result:
                return result
        fallback = builtin_type("builtins.type")
        return analyze_member_access(
            name,
            fallback,
            node,
            is_lvalue,
            is_super,
            is_operator,
            builtin_type,
            not_ready_callback,
            msg,
            report_type=report_type,
            chk=chk,
        )

    if chk and chk.should_suppress_optional_error([typ]):
        return AnyType()
    return msg.has_no_attr(report_type, name, node)
Ejemplo n.º 51
0
 def visit_union_type(self, t: UnionType) -> Type:
     erased_items = [erase_type(item) for item in t.items]
     return UnionType.make_simplified_union(erased_items)
Ejemplo n.º 52
0
 def visit_union_type(self, t: UnionType) -> Type:
     # After substituting for type variables in t.items,
     # some of the resulting types might be subtypes of others.
     return UnionType.make_simplified_union(self.expand_types(t.items), t.line)
Ejemplo n.º 53
0
 def visit_union_type(self, t: UnionType) -> Type:
     if is_subtype(self.s, t):
         return t
     else:
         return UnionType.make_simplified_union([self.s, t])
Ejemplo n.º 54
0
def analyze_descriptor_access(instance_type: Type,
                              descriptor_type: Type,
                              builtin_type: Callable[[str], Instance],
                              msg: MessageBuilder,
                              context: Context, *,
                              chk: 'mypy.checker.TypeChecker') -> Type:
    """Type check descriptor access.

    Arguments:
        instance_type: The type of the instance on which the descriptor
            attribute is being accessed (the type of ``a`` in ``a.f`` when
            ``f`` is a descriptor).
        descriptor_type: The type of the descriptor attribute being accessed
            (the type of ``f`` in ``a.f`` when ``f`` is a descriptor).
        context: The node defining the context of this inference.
    Return:
        The return type of the appropriate ``__get__`` overload for the descriptor.
    """
    if isinstance(descriptor_type, UnionType):
        # Map the access over union types
        return UnionType.make_simplified_union([
            analyze_descriptor_access(instance_type, typ, builtin_type,
                                      msg, context, chk=chk)
            for typ in descriptor_type.items
        ])
    elif not isinstance(descriptor_type, Instance):
        return descriptor_type

    if not descriptor_type.type.has_readable_member('__get__'):
        return descriptor_type

    dunder_get = descriptor_type.type.get_method('__get__')

    if dunder_get is None:
        msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context)
        return AnyType(TypeOfAny.from_error)

    function = function_type(dunder_get, builtin_type('builtins.function'))
    bound_method = bind_self(function, descriptor_type)
    typ = map_instance_to_supertype(descriptor_type, dunder_get.info)
    dunder_get_type = expand_type_by_instance(bound_method, typ)

    if isinstance(instance_type, FunctionLike) and instance_type.is_type_obj():
        owner_type = instance_type.items()[0].ret_type
        instance_type = NoneTyp()
    elif isinstance(instance_type, TypeType):
        owner_type = instance_type.item
        instance_type = NoneTyp()
    else:
        owner_type = instance_type

    _, inferred_dunder_get_type = chk.expr_checker.check_call(
        dunder_get_type,
        [TempNode(instance_type), TempNode(TypeType.make_normalized(owner_type))],
        [ARG_POS, ARG_POS], context)

    if isinstance(inferred_dunder_get_type, AnyType):
        # check_call failed, and will have reported an error
        return inferred_dunder_get_type

    if not isinstance(inferred_dunder_get_type, CallableType):
        msg.fail(message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(descriptor_type), context)
        return AnyType(TypeOfAny.from_error)

    return inferred_dunder_get_type.ret_type
Ejemplo n.º 55
0
def analyze_member_access(name: str, typ: Type, node: Context, is_lvalue: bool,
                          is_super: bool,
                          builtin_type: Callable[[str], Instance],
                          not_ready_callback: Callable[[str, Context], None],
                          msg: MessageBuilder, override_info: TypeInfo = None,
                          report_type: Type = None) -> Type:
    """Analyse attribute access.

    This is a general operation that supports various different variations:

      1. lvalue or non-lvalue access (i.e. setter or getter access)
      2. supertype access (when using super(); is_super == True and
         override_info should refer to the supertype)
    """
    report_type = report_type or typ
    if isinstance(typ, Instance):
        if name == '__init__' and not is_super:
            # Accessing __init__ in statically typed code would compromise
            # type safety unless used via super().
            msg.fail(messages.CANNOT_ACCESS_INIT, node)
            return AnyType()

        # The base object has an instance type.

        info = typ.type
        if override_info:
            info = override_info

        # Look up the member. First look up the method dictionary.
        method = info.get_method(name)
        if method:
            if method.is_property:
                assert isinstance(method, OverloadedFuncDef)
                method = cast(OverloadedFuncDef, method)
                return analyze_var(name, method.items[0].var, typ, info, node, is_lvalue, msg,
                                   not_ready_callback)
            if is_lvalue:
                msg.cant_assign_to_method(node)
            typ = map_instance_to_supertype(typ, method.info)
            if name == '__new__':
                # __new__ is special and behaves like a static method -- don't strip
                # the first argument.
                signature = function_type(method, builtin_type('builtins.function'))
            else:
                signature = method_type_with_fallback(method, builtin_type('builtins.function'))
            return expand_type_by_instance(signature, typ)
        else:
            # Not a method.
            return analyze_member_var_access(name, typ, info, node,
                                             is_lvalue, is_super, builtin_type,
                                             not_ready_callback, msg,
                                             report_type=report_type)
    elif isinstance(typ, AnyType):
        # The base object has dynamic type.
        return AnyType()
    elif isinstance(typ, UnionType):
        # The base object has dynamic type.
        msg.disable_type_names += 1
        results = [analyze_member_access(name, subtype, node, is_lvalue,
                                         is_super, builtin_type, not_ready_callback, msg)
                   for subtype in typ.items]
        msg.disable_type_names -= 1
        return UnionType.make_simplified_union(results)
    elif isinstance(typ, TupleType):
        # Actually look up from the fallback instance type.
        return analyze_member_access(name, typ.fallback, node, is_lvalue,
                                     is_super, builtin_type, not_ready_callback, msg)
    elif isinstance(typ, FunctionLike) and typ.is_type_obj():
        # Class attribute.
        # TODO super?
        ret_type = typ.items()[0].ret_type
        if isinstance(ret_type, TupleType):
            ret_type = ret_type.fallback
        if isinstance(ret_type, Instance):
            result = analyze_class_attribute_access(ret_type, name, node, is_lvalue,
                                                    builtin_type, not_ready_callback, msg)
            if result:
                return result
            # Look up from the 'type' type.
            return analyze_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                         builtin_type, not_ready_callback, msg,
                                         report_type=report_type)
        else:
            assert False, 'Unexpected type {}'.format(repr(ret_type))
    elif isinstance(typ, FunctionLike):
        # Look up from the 'function' type.
        return analyze_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                     builtin_type, not_ready_callback, msg,
                                     report_type=report_type)
    elif isinstance(typ, TypeVarType):
        return analyze_member_access(name, typ.upper_bound, node, is_lvalue, is_super,
                                     builtin_type, not_ready_callback, msg,
                                     report_type=report_type)
    elif isinstance(typ, DeletedType):
        msg.deleted_as_rvalue(typ, node)
        return AnyType()
    return msg.has_no_attr(report_type, name, node)
Ejemplo n.º 56
0
def simplify_union(t: Type) -> Type:
    if isinstance(t, UnionType):
        return UnionType.make_simplified_union(t.items)
    return t
Ejemplo n.º 57
0
def analyse_member_access(name: str, typ: Type, node: Context, is_lvalue: bool,
                          is_super: bool,
                          builtin_type: Function[[str], Instance],
                          msg: MessageBuilder, override_info: TypeInfo = None,
                          report_type: Type = None) -> Type:
    """Analyse attribute access.

    This is a general operation that supports various different variations:

      1. lvalue or non-lvalue access (i.e. setter or getter access)
      2. supertype access (when using super(); is_super == True and
         override_info should refer to the supertype)
    """
    report_type = report_type or typ
    if isinstance(typ, Instance):
        if name == '__init__' and not is_super:
            # Accessing __init__ in statically typed code would compromise
            # type safety unless used via super().
            msg.fail(messages.CANNOT_ACCESS_INIT, node)
            return AnyType()

        # The base object has an instance type.

        info = typ.type
        if override_info:
            info = override_info

        # Look up the member. First look up the method dictionary.
        method = info.get_method(name)
        if method:
            if is_lvalue:
                msg.cant_assign_to_method(node)
            typ = map_instance_to_supertype(typ, method.info)
            return expand_type_by_instance(
                method_type(method, builtin_type('builtins.function')), typ)
        else:
            # Not a method.
            return analyse_member_var_access(name, typ, info, node,
                                             is_lvalue, is_super, msg,
                                             report_type=report_type)
    elif isinstance(typ, AnyType):
        # The base object has dynamic type.
        return AnyType()
    elif isinstance(typ, UnionType):
        # The base object has dynamic type.
        msg.disable_type_names += 1
        results = [analyse_member_access(name, subtype, node, is_lvalue,
                                         is_super, builtin_type, msg)
                   for subtype in typ.items]
        msg.disable_type_names -= 1
        return UnionType.make_simplified_union(results)
    elif isinstance(typ, TupleType):
        # Actually look up from the fallback instance type.
        return analyse_member_access(name, typ.fallback, node, is_lvalue,
                                     is_super, builtin_type, msg)
    elif (isinstance(typ, FunctionLike) and
          cast(FunctionLike, typ).is_type_obj()):
        # Class attribute.
        # TODO super?
        sig = cast(FunctionLike, typ)
        itype = cast(Instance, sig.items()[0].ret_type)
        result = analyse_class_attribute_access(itype, name, node, is_lvalue, builtin_type, msg)
        if result:
            return result
        # Look up from the 'type' type.
        return analyse_member_access(name, sig.fallback, node, is_lvalue, is_super,
                                     builtin_type, msg, report_type=report_type)
    elif isinstance(typ, FunctionLike):
        # Look up from the 'function' type.
        return analyse_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                     builtin_type, msg, report_type=report_type)
    return msg.has_no_attr(report_type, name, node)
Ejemplo n.º 58
0
def analyze_union_member_access(name: str, typ: UnionType, mx: MemberContext) -> Type:
    mx.msg.disable_type_names += 1
    results = [_analyze_member_access(name, subtype, mx)
               for subtype in typ.relevant_items()]
    mx.msg.disable_type_names -= 1
    return UnionType.make_simplified_union(results)