Ejemplo n.º 1
0
 def test_last_known_values_with_merge(self) -> None:
     t = UnionType.make_union(
         [self.fx.lit1_inst, self.fx.lit2_inst, self.fx.lit4_inst])
     assert remove_instance_last_known_values(t) == self.fx.a
     t = UnionType.make_union([
         self.fx.lit1_inst, self.fx.b, self.fx.lit2_inst, self.fx.lit4_inst
     ])
     self.assert_union_result(t, [self.fx.a, self.fx.b])
Ejemplo n.º 2
0
 def test_multiple_same_instances(self) -> None:
     t = UnionType.make_union([self.fx.a, self.fx.a])
     assert remove_instance_last_known_values(t) == self.fx.a
     t = UnionType.make_union([self.fx.a, self.fx.a, self.fx.b])
     self.assert_union_result(t, [self.fx.a, self.fx.b])
     t = UnionType.make_union(
         [self.fx.a, self.fx.nonet, self.fx.a, self.fx.b])
     self.assert_union_result(t, [self.fx.a, self.fx.nonet, self.fx.b])
Ejemplo n.º 3
0
def restrict_subtype_away(t: Type, s: Type) -> Type:
    """Return t minus s.

    If we can't determine a precise result, return a supertype of the
    ideal result (just t is a valid result).

    This is used for type inference of runtime type checks such as
    isinstance.

    Currently this just removes elements of a union type.
    """
    if isinstance(t, UnionType):
        # Since runtime type checks will ignore type arguments, erase the types.
        erased_s = erase_type(s)
        # TODO: Implement more robust support for runtime isinstance() checks,
        # see issue #3827
        new_items = [
            item for item in t.relevant_items()
            if (not (is_proper_subtype(erase_type(item), erased_s)
                     or is_proper_subtype(item, erased_s))
                or isinstance(item, AnyType))
        ]
        return UnionType.make_union(new_items)
    else:
        return t
Ejemplo n.º 4
0
 def visit_union_type(self, t: UnionType) -> Type:
     new = cast(UnionType, super().visit_union_type(t))
     # Erasure can result in many duplicate items; merge them.
     # Call make_simplified_union only on lists of instance types
     # that all have the same fullname, to avoid simplifying too
     # much.
     instances = [item for item in new.items
                  if isinstance(get_proper_type(item), Instance)]
     # Avoid merge in simple cases such as optional types.
     if len(instances) > 1:
         instances_by_name: Dict[str, List[Instance]] = {}
         new_items = get_proper_types(new.items)
         for item in new_items:
             if isinstance(item, Instance) and not item.args:
                 instances_by_name.setdefault(item.type.fullname, []).append(item)
         merged: List[Type] = []
         for item in new_items:
             if isinstance(item, Instance) and not item.args:
                 types = instances_by_name.get(item.type.fullname)
                 if types is not None:
                     if len(types) == 1:
                         merged.append(item)
                     else:
                         from mypy.typeops import make_simplified_union
                         merged.append(make_simplified_union(types))
                         del instances_by_name[item.type.fullname]
             else:
                 merged.append(item)
         return UnionType.make_union(merged)
     return new
Ejemplo n.º 5
0
    def get_args(self, is_method: bool,
                 base: CallableType, defaults: List[Optional[Type]],
                 callsites: List[Callsite]) -> List[List[Type]]:
        """Produce a list of type suggestions for each argument type."""
        types = []  # type: List[List[Type]]
        for i in range(len(base.arg_kinds)):
            # Make self args Any but this will get overriden somewhere in the checker
            # We call this a special form so that has_any_type doesn't consider it to be a real any
            if i == 0 and is_method:
                types.append([AnyType(TypeOfAny.special_form)])
                continue

            all_arg_types = []
            for call in callsites:
                for typ in call.arg_types[i - is_method]:
                    # Collect all the types except for implicit anys
                    if not is_implicit_any(typ):
                        all_arg_types.append(typ)
            # Add in any default argument types
            default = defaults[i]
            if default:
                all_arg_types.append(default)

            if len(all_arg_types) == 1 and isinstance(get_proper_type(all_arg_types[0]), NoneType):
                types.append(
                    [UnionType.make_union([all_arg_types[0],
                                           AnyType(TypeOfAny.explicit)])])
            elif all_arg_types:
                types.append(generate_type_combinations(all_arg_types))
            else:
                # If we don't have anything, we'll try Any and object
                # (Actually object usually is bad for downstream consumers...)
                # types.append([AnyType(TypeOfAny.explicit), self.builtin_type('builtins.object')])
                types.append([AnyType(TypeOfAny.explicit)])
        return types
Ejemplo n.º 6
0
    def get_field_lookup_exact_type(self, api: TypeChecker,
                                    field: Field) -> MypyType:
        if isinstance(field, (RelatedField, ForeignObjectRel)):
            related_model_cls = field.related_model
            primary_key_field = self.get_primary_key_field(related_model_cls)
            primary_key_type = self.get_field_get_type(api,
                                                       primary_key_field,
                                                       method='init')

            rel_model_info = helpers.lookup_class_typeinfo(
                api, related_model_cls)
            if rel_model_info is None:
                return AnyType(TypeOfAny.explicit)

            model_and_primary_key_type = UnionType.make_union(
                [Instance(rel_model_info, []), primary_key_type])
            return helpers.make_optional(model_and_primary_key_type)
            # return helpers.make_optional(Instance(rel_model_info, []))

        field_info = helpers.lookup_class_typeinfo(api, field.__class__)
        if field_info is None:
            return AnyType(TypeOfAny.explicit)
        return helpers.get_private_descriptor_type(field_info,
                                                   '_pyi_lookup_exact_type',
                                                   is_nullable=field.null)
Ejemplo n.º 7
0
def restrict_subtype_away(t: Type, s: Type) -> Type:
    """Return a supertype of (t intersect not s)

    Currently just remove elements of a union type.
    """
    if isinstance(t, UnionType):
        new_items = [item for item in t.items if not is_subtype(item, s)]
        return UnionType.make_union(new_items)
    else:
        return t
Ejemplo n.º 8
0
def restrict_subtype_away(t: Type, s: Type) -> Type:
    """Return a supertype of (t intersect not s)

    Currently just remove elements of a union type.
    """
    if isinstance(t, UnionType):
        new_items = [item for item in t.items if not is_subtype(item, s)]
        return UnionType.make_union(new_items)
    else:
        return t
Ejemplo n.º 9
0
def proper_types_hook(ctx: FunctionContext) -> Type:
    """Check if this get_proper_types() call is not redundant."""
    arg_types = ctx.arg_types[0]
    if arg_types:
        arg_type = arg_types[0]
        proper_type = get_proper_type_instance(ctx)
        item_type = UnionType.make_union([NoneTyp(), proper_type])
        ok_type = ctx.api.named_generic_type('typing.Iterable', [item_type])
        if is_proper_subtype(arg_type, ok_type):
            ctx.api.fail('Redundant call to get_proper_types()', ctx.context)
    return ctx.default_return_type
Ejemplo n.º 10
0
def make_simplified_union(items: Sequence[Type],
                          line: int = -1,
                          column: int = -1,
                          *,
                          keep_erased: bool = False) -> ProperType:
    """Build union type with redundant union items removed.

    If only a single item remains, this may return a non-union type.

    Examples:

    * [int, str] -> Union[int, str]
    * [int, object] -> object
    * [int, int] -> int
    * [int, Any] -> Union[int, Any] (Any types are not simplified away!)
    * [Any, Any] -> Any

    Note: This must NOT be used during semantic analysis, since TypeInfos may not
          be fully initialized.
    The keep_erased flag is used for type inference against union types
    containing type variables. If set to True, keep all ErasedType items.
    """
    items = get_proper_types(items)
    while any(isinstance(typ, UnionType) for typ in items):
        all_items = []  # type: List[ProperType]
        for typ in items:
            if isinstance(typ, UnionType):
                all_items.extend(get_proper_types(typ.items))
            else:
                all_items.append(typ)
        items = all_items

    from mypy.subtypes import is_proper_subtype

    removed = set()  # type: Set[int]
    for i, ti in enumerate(items):
        if i in removed: continue
        # Keep track of the truishness info for deleted subtypes which can be relevant
        cbt = cbf = False
        for j, tj in enumerate(items):
            if i != j and is_proper_subtype(
                    tj, ti, keep_erased_types=keep_erased):
                # We found a redundant item in the union.
                removed.add(j)
                cbt = cbt or tj.can_be_true
                cbf = cbf or tj.can_be_false
        # if deleted subtypes had more general truthiness, use that
        if not ti.can_be_true and cbt:
            items[i] = true_or_false(ti)
        elif not ti.can_be_false and cbf:
            items[i] = true_or_false(ti)

    simplified_set = [items[i] for i in range(len(items)) if i not in removed]
    return UnionType.make_union(simplified_set, line, column)
Ejemplo n.º 11
0
    def _adjust_typeclass_type(self, ctx, instance_type):
        unified = list(filter(
            # It means that function was defined without annotation
            # or with explicit `Any`, we prevent our Union from polution.
            # Because `Union[Any, int]` is just `Any`.
            # We also clear accidential type vars.
            self._filter_out_unified_types,
            [instance_type, ctx.type.args[0]],
        ))

        if not isinstance(instance_type, TypeVarType):
            ctx.type.args[0] = UnionType.make_union(unified)
Ejemplo n.º 12
0
def proper_type_hook(ctx: FunctionContext) -> Type:
    """Check if this get_proper_type() call is not redundant."""
    arg_types = ctx.arg_types[0]
    if arg_types:
        arg_type = get_proper_type(arg_types[0])
        proper_type = get_proper_type_instance(ctx)
        if is_proper_subtype(arg_type, UnionType.make_union([NoneTyp(), proper_type])):
            # Minimize amount of spurious errors from overload machinery.
            # TODO: call the hook on the overload as a whole?
            if isinstance(arg_type, (UnionType, Instance)):
                ctx.api.fail('Redundant call to get_proper_type()', ctx.context)
    return ctx.default_return_type
Ejemplo n.º 13
0
def merge_with_any(constraint: Constraint) -> Constraint:
    """Transform a constraint target into a union with given Any type."""
    target = constraint.target
    if is_union_with_any(target):
        # Do not produce redundant unions.
        return constraint
    # TODO: if we will support multiple sources Any, use this here instead.
    any_type = AnyType(TypeOfAny.implementation_artifact)
    return Constraint(
        constraint.type_var,
        constraint.op,
        UnionType.make_union([target, any_type], target.line, target.column),
    )
Ejemplo n.º 14
0
def is_basic_index_sequence(type: Type):
    # From: https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html
    # >> Basic slicing occurs when obj is a slice object
    # >> an integer, o a tuple of slice objects and integers.
    # >> Ellipsis and newaxis objects can be interspersed with these as well.
    u = UnionType.make_union([
        int_type(),
        API.named_type('builtins.slice'),
        NoneTyp(),
        API.named_type('builtins.ellipsis'),
    ])
    return is_subtype(type, API.named_generic_type('typing.Sequence',
                                                   args=[u]))
Ejemplo n.º 15
0
 def visit_value_pattern(self, o: ValuePattern) -> PatternType:
     current_type = self.type_context[-1]
     typ = self.chk.expr_checker.accept(o.expr)
     typ = coerce_to_literal(typ)
     narrowed_type, rest_type = self.chk.conditional_types_with_intersection(
         current_type,
         [get_type_range(typ)],
         o,
         default=current_type
     )
     if not isinstance(get_proper_type(narrowed_type), (LiteralType, UninhabitedType)):
         return PatternType(narrowed_type, UnionType.make_union([narrowed_type, rest_type]), {})
     return PatternType(narrowed_type, rest_type, {})
Ejemplo n.º 16
0
    def analyze_literal_type(self, t: UnboundType) -> Type:
        if len(t.args) == 0:
            self.fail('Literal[...] must have at least one parameter', t)
            return AnyType(TypeOfAny.from_error)

        output = []  # type: List[Type]
        for i, arg in enumerate(t.args):
            analyzed_types = self.analyze_literal_param(i + 1, arg, t)
            if analyzed_types is None:
                return AnyType(TypeOfAny.from_error)
            else:
                output.extend(analyzed_types)
        return UnionType.make_union(output, line=t.line)
Ejemplo n.º 17
0
def transform_oas_type(
    oas_type: oas_model.OASType[Any],
    handler_type: ProperType,
    ctx: FunctionContext,
) -> Type:
    m_type: Optional[Type] = None
    union_members: List[Type] = []

    assert isinstance(ctx.api, TypeChecker)

    if isinstance(oas_type, oas_model.OASStringType):
        m_type = ctx.api.str_type()
    elif isinstance(oas_type, oas_model.OASBooleanType):
        m_type = ctx.api.named_type('bool')
    elif isinstance(oas_type, oas_model.OASNumberType):
        m_type = ctx.api.named_type(
            'int' if issubclass(int, oas_type.number_cls) else 'float', )
    elif isinstance(oas_type, oas_model.OASOneOfType):
        union_members = [
            transform_oas_type(
                nested_type,
                handler_type,
                ctx,
            ) for include_type, nested_type in oas_type.schemas if include_type
        ]
    elif isinstance(oas_type, oas_model.OASArrayType):
        m_type = ctx.api.named_generic_type(
            name='set' if oas_type.unique_items else 'list',
            args=[
                transform_oas_type(
                    oas_type.items_type,
                    handler_type,
                    ctx,
                )
            ],
        )
    elif isinstance(oas_type, oas_model.OASObjectType):
        m_type = transform_oas_object_type(oas_type, handler_type, ctx)
    else:
        raise NotImplementedError(f'{oas_type} not yet implemented')

    if m_type is not None:
        m_type.set_line(handler_type)
        union_members.append(m_type)

    if oas_type.nullable:
        union_members.append(NoneType())

    ut = simplify_union(UnionType.make_union(items=union_members))
    ut.set_line(handler_type)
    return ut
Ejemplo n.º 18
0
def _combine_hook(context: FunctionContext):
    result_types = []
    error_types = []
    env_types = []
    try:
        for effect_type in context.arg_types[0]:
            env_type, error_type, result_type = get_proper_type(
                effect_type).args
            env_types.append(env_type)
            error_types.append(error_type)
            result_types.append(result_type)
        map_return_type_def = _type_var_def(
            'R1', 'pfun.effect', context.api.named_type('builtins.object'))
        map_return_type = TypeVarType(map_return_type_def)
        map_function_type = CallableType(
            arg_types=result_types,
            arg_kinds=[ARG_POS for _ in result_types],
            arg_names=[None for _ in result_types],
            ret_type=map_return_type,
            variables=[map_return_type_def],
            fallback=context.api.named_type('builtins.function'))
        ret_type = context.default_return_type.ret_type
        combined_error_type = UnionType.make_union(
            sorted(set(error_types), key=str))
        ret_type_args = ret_type.args
        ret_type_args[1] = combined_error_type
        ret_type_args[2] = map_return_type
        env_types = [
            env_type for env_type in env_types
            if not isinstance(env_type, AnyType)
        ]
        if len(set(env_types)) == 1:
            combined_env_type = env_types[0]
        elif env_types and all(
                hasattr(env_type, 'type') and env_type.type.is_protocol
                for env_type in env_types):
            combined_env_type = reduce(_combine_protocols, env_types)
        else:
            combined_env_type = ret_type_args[0]
        ret_type_args[0] = combined_env_type
        ret_type = ret_type.copy_modified(args=ret_type_args)
        return CallableType(
            arg_types=[map_function_type],
            arg_kinds=[ARG_POS],
            arg_names=[None],
            variables=[map_return_type_def],
            ret_type=ret_type,
            fallback=context.api.named_type('builtins.function'))
    except AttributeError:
        return context.default_return_type
Ejemplo n.º 19
0
    def conversion_type(self, p: str, context: Context, expr: FormatStringExpr,
                        format_call: bool = False) -> Optional[Type]:
        """Return the type that is accepted for a string interpolation conversion specifier type.

        Note that both Python's float (e.g. %f) and integer (e.g. %d)
        specifier types accept both float and integers.

        The 'format_call' argument indicates whether this type came from % interpolation or from
        a str.format() call, the meaning of few formatting types are different.
        """
        NUMERIC_TYPES = NUMERIC_TYPES_NEW if format_call else NUMERIC_TYPES_OLD
        INT_TYPES = REQUIRE_INT_NEW if format_call else REQUIRE_INT_OLD
        if p == 'b' and not format_call:
            if self.chk.options.python_version < (3, 5):
                self.msg.fail("Format character 'b' is only supported in Python 3.5 and later",
                              context, code=codes.STRING_FORMATTING)
                return None
            if not isinstance(expr, BytesExpr):
                self.msg.fail("Format character 'b' is only supported on bytes patterns", context,
                              code=codes.STRING_FORMATTING)
                return None
            return self.named_type('builtins.bytes')
        elif p == 'a':
            if self.chk.options.python_version < (3, 0):
                self.msg.fail("Format character 'a' is only supported in Python 3", context,
                              code=codes.STRING_FORMATTING)
                return None
            # TODO: return type object?
            return AnyType(TypeOfAny.special_form)
        elif p in ['s', 'r']:
            return AnyType(TypeOfAny.special_form)
        elif p in NUMERIC_TYPES:
            if p in INT_TYPES:
                numeric_types = [self.named_type('builtins.int')]
            else:
                numeric_types = [self.named_type('builtins.int'),
                                 self.named_type('builtins.float')]
                if not format_call:
                    if p in FLOAT_TYPES:
                        numeric_types.append(self.named_type('typing.SupportsFloat'))
                    else:
                        numeric_types.append(self.named_type('typing.SupportsInt'))
            return UnionType.make_union(numeric_types)
        elif p in ['c']:
            return UnionType([self.named_type('builtins.int'),
                              self.named_type('builtins.float'),
                              self.named_type('builtins.str')])
        else:
            self.msg.unsupported_placeholder(p, context)
            return None
Ejemplo n.º 20
0
    def get_args(self, is_method: bool, base: CallableType,
                 defaults: List[Optional[Type]], callsites: List[Callsite],
                 uses: List[List[Type]]) -> List[List[Type]]:
        """Produce a list of type suggestions for each argument type."""
        types = []  # type: List[List[Type]]
        for i in range(len(base.arg_kinds)):
            # Make self args Any but this will get overriden somewhere in the checker
            # We call this a special form so that has_any_type doesn't consider it to be a real any
            if i == 0 and is_method:
                types.append([AnyType(TypeOfAny.special_form)])
                continue

            all_arg_types = []
            for call in callsites:
                for typ in call.arg_types[i - is_method]:
                    # Collect all the types except for implicit anys
                    if not is_implicit_any(typ):
                        all_arg_types.append(typ)
            all_use_types = []
            for typ in uses[i]:
                # Collect all the types except for implicit anys
                if not is_implicit_any(typ):
                    all_use_types.append(typ)
            # Add in any default argument types
            default = defaults[i]
            if default:
                all_arg_types.append(default)
                if all_use_types:
                    all_use_types.append(default)

            arg_types = []

            if (all_arg_types and all(
                    isinstance(get_proper_type(tp), NoneType)
                    for tp in all_arg_types)):
                arg_types.append(
                    UnionType.make_union(
                        [all_arg_types[0],
                         AnyType(TypeOfAny.explicit)]))
            elif all_arg_types:
                arg_types.extend(generate_type_combinations(all_arg_types))
            else:
                arg_types.append(AnyType(TypeOfAny.explicit))

            if all_use_types:
                # This is a meet because the type needs to be compatible with all the uses
                arg_types.append(meet_type_list(all_use_types))

            types.append(arg_types)
        return types
Ejemplo n.º 21
0
def make_simplified_union(items: Sequence[Type],
                          line: int = -1,
                          column: int = -1,
                          *,
                          keep_erased: bool = False,
                          contract_literals: bool = True) -> ProperType:
    """Build union type with redundant union items removed.

    If only a single item remains, this may return a non-union type.

    Examples:

    * [int, str] -> Union[int, str]
    * [int, object] -> object
    * [int, int] -> int
    * [int, Any] -> Union[int, Any] (Any types are not simplified away!)
    * [Any, Any] -> Any

    Note: This must NOT be used during semantic analysis, since TypeInfos may not
          be fully initialized.

    The keep_erased flag is used for type inference against union types
    containing type variables. If set to True, keep all ErasedType items.

    The contract_literals flag indicates whether we need to contract literal types
    back into a sum type. Set it to False when called by try_expanding_sum_type_
    to_union().
    """
    items = get_proper_types(items)

    # Step 1: expand all nested unions
    while any(isinstance(typ, UnionType) for typ in items):
        all_items: List[ProperType] = []
        for typ in items:
            if isinstance(typ, UnionType):
                all_items.extend(get_proper_types(typ.items))
            else:
                all_items.append(typ)
        items = all_items

    # Step 2: remove redundant unions
    simplified_set = _remove_redundant_union_items(items, keep_erased)

    # Step 3: If more than one literal exists in the union, try to simplify
    if contract_literals and sum(
            isinstance(item, LiteralType) for item in simplified_set) > 1:
        simplified_set = try_contracting_literals_in_union(simplified_set)

    return UnionType.make_union(simplified_set, line, column)
Ejemplo n.º 22
0
def coerce_to_literal(typ: Type) -> Type:
    """Recursively converts any Instances that have a last_known_value or are
    instances of enum types with a single value into the corresponding LiteralType.
    """
    original_type = typ
    typ = get_proper_type(typ)
    if isinstance(typ, UnionType):
        new_items = [coerce_to_literal(item) for item in typ.items]
        return UnionType.make_union(new_items)
    elif isinstance(typ, Instance):
        if typ.last_known_value:
            return typ.last_known_value
        elif typ.type.is_enum:
            enum_values = get_enum_values(typ)
            if len(enum_values) == 1:
                return LiteralType(value=enum_values[0], fallback=typ)
    return original_type
Ejemplo n.º 23
0
def _effect_catch_call_hook(context: MethodContext) -> Type:
    f_type = _get_callable_type(context.arg_types[0][0], context)
    if len(context.type.args) == 1:
        return context.default_return_type.copy_modified(
            arg_types=f_type.arg_types,
            arg_kinds=f_type.arg_kinds,
            arg_names=f_type.arg_names)
    args = context.type.args
    error_union = UnionType.make_union(args)
    effect_type = get_proper_type(context.default_return_type.ret_type)
    r, e, a = effect_type.args
    effect_type = effect_type.copy_modified(args=[r, error_union, a])

    return context.default_return_type.copy_modified(
        ret_type=effect_type,
        arg_types=f_type.arg_types,
        arg_kinds=f_type.arg_kinds,
        arg_names=f_type.arg_names)
Ejemplo n.º 24
0
def _change_decorator_function_type(
    decorated: CallableType,
    decorator: CallableType,
    provided_arguments: List[str],
) -> CallableType:
    decorator.arg_kinds = decorated.arg_kinds
    decorator.arg_names = decorated.arg_names

    # Mark provided arguments as optional
    decorator.arg_types = copy.copy(decorated.arg_types)
    for argument in provided_arguments:
        index = decorated.arg_names.index(argument)
        decorated_type = decorated.arg_types[index]
        decorator.arg_types[index] = UnionType.make_union(
            [decorated_type, NoneType()])
        decorated.arg_kinds[index] = ARG_NAMED_OPT

    return decorator
Ejemplo n.º 25
0
def convert_any_to_type(typ: MypyType, referred_to_type: MypyType) -> MypyType:
    if isinstance(typ, UnionType):
        converted_items = []
        for item in typ.items:
            converted_items.append(convert_any_to_type(item, referred_to_type))
        return UnionType.make_union(converted_items, line=typ.line, column=typ.column)
    if isinstance(typ, Instance):
        args = []
        for default_arg in typ.args:
            if isinstance(default_arg, AnyType):
                args.append(referred_to_type)
            else:
                args.append(default_arg)
        return reparametrize_instance(typ, args)

    if isinstance(typ, AnyType):
        return referred_to_type

    return typ
Ejemplo n.º 26
0
def transform_parameter_to_type(
    param: oas.OASParameter,
    handler_arg_type: ProperType,
    handler_arg_default_value: HandlerArgDefaultValue,
    ctx: FunctionContext,
) -> Type:
    oas_is_required = param.required
    handler_has_default = (handler_arg_default_value
                           is not _ARG_NO_DEFAULT_VALUE_MARKER)
    if not oas_is_required and not handler_has_default:
        needs_optional = True
    elif isinstance(handler_arg_default_value, type(None)):
        needs_optional = True
    else:
        needs_optional = False

    if isinstance(param.schema, tuple):
        oas_type, _ = param.schema
        items = [transform_oas_type(
            oas_type,
            handler_arg_type,
            ctx,
        )]
    else:
        items = [
            transform_oas_type(
                v.schema,
                handler_arg_type,
                ctx,
            ) for v in param.schema.values()
        ]

    if needs_optional:
        items.append(NoneType())

    return simplify_union(
        UnionType.make_union(
            items=items,
            line=(handler_arg_type.line or handler_arg_type.end_line) or -1,
            column=handler_arg_type.column,
        ), )
Ejemplo n.º 27
0
 def build_dict_type(self, expr: FormatStringExpr) -> Type:
     """Build expected mapping type for right operand in % formatting."""
     any_type = AnyType(TypeOfAny.special_form)
     if self.chk.options.python_version >= (3, 0):
         if isinstance(expr, BytesExpr):
             bytes_type = self.chk.named_generic_type('builtins.bytes', [])
             return self.chk.named_generic_type('typing.Mapping',
                                                [bytes_type, any_type])
         elif isinstance(expr, StrExpr):
             str_type = self.chk.named_generic_type('builtins.str', [])
             return self.chk.named_generic_type('typing.Mapping',
                                                [str_type, any_type])
         else:
             assert False, "There should not be UnicodeExpr on Python 3"
     else:
         str_type = self.chk.named_generic_type('builtins.str', [])
         unicode_type = self.chk.named_generic_type('builtins.unicode', [])
         str_map = self.chk.named_generic_type('typing.Mapping',
                                               [str_type, any_type])
         unicode_map = self.chk.named_generic_type('typing.Mapping',
                                                   [unicode_type, any_type])
         return UnionType.make_union([str_map, unicode_map])
Ejemplo n.º 28
0
def _effect_lift_call_hook(context: MethodContext) -> Type:
    try:
        f = context.type.args[0]
        if isinstance(f, AnyType):
            return context.default_return_type
        as_ = []
        rs = []
        es = []
        for effect_type in context.arg_types:
            r, e, a = get_proper_type(effect_type[0]).args
            as_.append(a)
            rs.append(r)
            es.append(e)
        inferred = infer.infer_function_type_arguments(
            f, as_, [kind for kinds in context.arg_kinds for kind in kinds],
            [[i, i] for i in range(len(as_))])
        a = context.api.expr_checker.apply_inferred_arguments(
            f, inferred, context.context).ret_type
        r = reduce(_combine_environments, rs)
        e = UnionType.make_union(sorted(set(es), key=str))
        return context.default_return_type.copy_modified(args=[r, e, a])
    except AttributeError:
        return context.default_return_type
Ejemplo n.º 29
0
def restrict_subtype_away(t: Type, s: Type) -> Type:
    """Return t minus s.

    If we can't determine a precise result, return a supertype of the
    ideal result (just t is a valid result).

    This is used for type inference of runtime type checks such as
    isinstance.

    Currently this just removes elements of a union type.
    """
    if isinstance(t, UnionType):
        # Since runtime type checks will ignore type arguments, erase the types.
        erased_s = erase_type(s)
        # TODO: Implement more robust support for runtime isinstance() checks,
        # see issue #3827
        new_items = [item for item in t.relevant_items()
                     if (not (is_proper_subtype(erase_type(item), erased_s) or
                              is_proper_subtype(item, erased_s))
                         or isinstance(item, AnyType))]
        return UnionType.make_union(new_items)
    else:
        return t
Ejemplo n.º 30
0
def make_simplified_union(items: Sequence[Type],
                          line: int = -1,
                          column: int = -1,
                          *,
                          keep_erased: bool = False,
                          contract_literals: bool = True) -> ProperType:
    """Build union type with redundant union items removed.

    If only a single item remains, this may return a non-union type.

    Examples:

    * [int, str] -> Union[int, str]
    * [int, object] -> object
    * [int, int] -> int
    * [int, Any] -> Union[int, Any] (Any types are not simplified away!)
    * [Any, Any] -> Any

    Note: This must NOT be used during semantic analysis, since TypeInfos may not
          be fully initialized.
    The keep_erased flag is used for type inference against union types
    containing type variables. If set to True, keep all ErasedType items.
    """
    items = get_proper_types(items)
    while any(isinstance(typ, UnionType) for typ in items):
        all_items: List[ProperType] = []
        for typ in items:
            if isinstance(typ, UnionType):
                all_items.extend(get_proper_types(typ.items))
            else:
                all_items.append(typ)
        items = all_items

    from mypy.subtypes import is_proper_subtype

    removed: Set[int] = set()
    seen: Set[Tuple[str, str]] = set()

    # NB: having a separate fast path for Union of Literal and slow path for other things
    # would arguably be cleaner, however it breaks down when simplifying the Union of two
    # different enum types as try_expanding_enum_to_union works recursively and will
    # trigger intermediate simplifications that would render the fast path useless
    for i, item in enumerate(items):
        if i in removed:
            continue
        # Avoid slow nested for loop for Union of Literal of strings/enums (issue #9169)
        if is_simple_literal(item):
            assert isinstance(item, LiteralType)
            assert isinstance(item.value, str)
            k = (item.value, item.fallback.type.fullname)
            if k in seen:
                removed.add(i)
                continue

            # NB: one would naively expect that it would be safe to skip the slow path
            # always for literals. One would be sorely mistaken. Indeed, some simplifications
            # such as that of None/Optional when strict optional is false, do require that we
            # proceed with the slow path. Thankfully, all literals will have the same subtype
            # relationship to non-literal types, so we only need to do that walk for the first
            # literal, which keeps the fast path fast even in the presence of a mixture of
            # literals and other types.
            safe_skip = len(seen) > 0
            seen.add(k)
            if safe_skip:
                continue
        # Keep track of the truishness info for deleted subtypes which can be relevant
        cbt = cbf = False
        for j, tj in enumerate(items):
            # NB: we don't need to check literals as the fast path above takes care of that
            if (i != j and not is_simple_literal(tj) and is_proper_subtype(
                    tj, item, keep_erased_types=keep_erased)
                    and is_redundant_literal_instance(item, tj)  # XXX?
                ):
                # We found a redundant item in the union.
                removed.add(j)
                cbt = cbt or tj.can_be_true
                cbf = cbf or tj.can_be_false
        # if deleted subtypes had more general truthiness, use that
        if not item.can_be_true and cbt:
            items[i] = true_or_false(item)
        elif not item.can_be_false and cbf:
            items[i] = true_or_false(item)

    simplified_set = [items[i] for i in range(len(items)) if i not in removed]

    # If more than one literal exists in the union, try to simplify
    if (contract_literals
            and sum(isinstance(item, LiteralType)
                    for item in simplified_set) > 1):
        simplified_set = try_contracting_literals_in_union(simplified_set)

    return UnionType.make_union(simplified_set, line, column)
Ejemplo n.º 31
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) == 0 and not t.empty_tuple_index:
                 # Bare 'Tuple' is same as 'tuple'
                 return self.builtin_type('builtins.tuple')
             if len(t.args) == 2 and isinstance(t.args[1], EllipsisType):
                 # Tuple[T, ...] (uniform, variable-length tuple)
                 instance = self.builtin_type('builtins.tuple', [t.args[0].accept(self)])
                 instance.line = t.line
                 return instance
             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:
             override = sym.type_override
             an_args = self.anal_array(t.args)
             all_vars = self.get_type_var_names(override)
             exp_len = len(all_vars)
             act_len = len(an_args)
             if exp_len > 0 and act_len == 0:
                 # Interpret bare Alias same as normal generic, i.e., Alias[Any, Any, ...]
                 return self.replace_alias_tvars(override, all_vars, [AnyType()] * exp_len,
                                                 t.line, t.column)
             if exp_len == 0 and act_len == 0:
                 return override
             if act_len != exp_len:
                 self.fail('Bad number of arguments for type alias, expected: %s, given: %s'
                           % (exp_len, act_len), t)
                 return t
             return self.replace_alias_tvars(override, all_vars, an_args, t.line, t.column)
         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()
             # Allow unbound type variables when defining an alias
             if not (self.aliasing and sym.kind == UNBOUND_TVAR):
                 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, t.column)
             tup = info.tuple_type
             if tup is not None:
                 # 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)
             td = info.typeddict_type
             if td is not None:
                 # The class has a TypedDict[...] base class so it will be
                 # represented as a typeddict type.
                 if t.args:
                     self.fail('Generic TypedDict types not supported', t)
                     return AnyType()
                 # Create a named TypedDictType
                 return td.copy_modified(item_types=self.anal_array(list(td.items.values())),
                                         fallback=instance)
             return instance
     else:
         return AnyType()
Ejemplo n.º 32
0
    def argument(self, ctx: 'mypy.plugin.ClassDefContext') -> Argument:
        """Return this attribute as an argument to __init__."""
        assert self.init
        init_type = self.info[self.name].type

        if self.converter.name:
            # When a converter is set the init_type is overridden by the first argument
            # of the converter method.
            converter = lookup_qualified_stnode(ctx.api.modules, self.converter.name, True)
            if not converter:
                # The converter may be a local variable. Check there too.
                converter = ctx.api.lookup_qualified(self.converter.name, self.info, True)

            # Get the type of the converter.
            converter_type = None
            if converter and isinstance(converter.node, TypeInfo):
                from mypy.checkmember import type_object_type  # To avoid import cycle.
                converter_type = type_object_type(converter.node, ctx.api.builtin_type)
            elif converter and isinstance(converter.node, OverloadedFuncDef):
                converter_type = converter.node.type
            elif converter and converter.type:
                converter_type = converter.type

            init_type = None
            if isinstance(converter_type, CallableType) and converter_type.arg_types:
                init_type = ctx.api.anal_type(converter_type.arg_types[0])
            elif isinstance(converter_type, Overloaded):
                types = []  # type: List[Type]
                for item in converter_type.items():
                    # Walk the overloads looking for methods that can accept one argument.
                    num_arg_types = len(item.arg_types)
                    if not num_arg_types:
                        continue
                    if num_arg_types > 1 and any(kind == ARG_POS for kind in item.arg_kinds[1:]):
                        continue
                    types.append(item.arg_types[0])
                # Make a union of all the valid types.
                if types:
                    args = UnionType.make_simplified_union(types)
                    init_type = ctx.api.anal_type(args)

            if self.converter.is_attr_converters_optional and init_type:
                # If the converter was attr.converter.optional(type) then add None to
                # the allowed init_type.
                init_type = UnionType.make_union([init_type, NoneTyp()])

            if not init_type:
                ctx.api.fail("Cannot determine __init__ type from converter", self.context)
                init_type = AnyType(TypeOfAny.from_error)
        elif self.converter.name == '':
            # This means we had a converter but it's not of a type we can infer.
            # Error was shown in _get_converter_name
            init_type = AnyType(TypeOfAny.from_error)

        if init_type is None:
            if ctx.api.options.disallow_untyped_defs:
                # This is a compromise.  If you don't have a type here then the
                # __init__ will be untyped. But since the __init__ is added it's
                # pointing at the decorator. So instead we also show the error in the
                # assignment, which is where you would fix the issue.
                node = self.info[self.name].node
                assert node is not None
                ctx.api.msg.need_annotation_for_var(node, self.context)

            # Convert type not set to Any.
            init_type = AnyType(TypeOfAny.unannotated)

        if self.kw_only:
            arg_kind = ARG_NAMED_OPT if self.has_default else ARG_NAMED
        else:
            arg_kind = ARG_OPT if self.has_default else ARG_POS

        # Attrs removes leading underscores when creating the __init__ arguments.
        return Argument(Var(self.name.lstrip("_"), init_type), init_type,
                        None,
                        arg_kind)
Ejemplo n.º 33
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 make_optional_type(self.visit_unbound_type(t))
     sym = self.lookup(t.name, t, suppress_errors=self.third_pass)  # type: ignore
     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(TypeOfAny.special_form)
         fullname = sym.node.fullname()
         hook = self.plugin.get_type_analyze_hook(fullname)
         if hook:
             return hook(AnalyzeTypeContext(t, t, self))
         if (fullname in nongen_builtins and t.args and
                 not sym.normalized and not self.allow_unnormalized):
             self.fail(no_subscript_builtin_alias(fullname), t)
         if self.tvar_scope:
             tvar_def = self.tvar_scope.get_binding(sym)
         else:
             tvar_def = None
         if self.warn_bound_tvar and sym.kind == TVAR and tvar_def is not None:
             self.fail('Can\'t use bound type variable "{}"'
                       ' to define generic alias'.format(t.name), t)
             return AnyType(TypeOfAny.from_error)
         elif sym.kind == TVAR and tvar_def is not None:
             if len(t.args) > 0:
                 self.fail('Type variable "{}" used with arguments'.format(
                     t.name), t)
             return TypeVarType(tvar_def, t.line)
         elif fullname == 'builtins.None':
             return NoneTyp()
         elif fullname == 'typing.Any' or fullname == 'builtins.Any':
             return AnyType(TypeOfAny.explicit)
         elif fullname == 'typing.Tuple':
             if len(t.args) == 0 and not t.empty_tuple_index:
                 # Bare 'Tuple' is same as 'tuple'
                 if self.options.disallow_any_generics and not self.is_typeshed_stub:
                     self.fail(messages.BARE_GENERIC, t)
                 typ = self.named_type('builtins.tuple', line=t.line, column=t.column)
                 typ.from_generic_builtin = True
                 return typ
             if len(t.args) == 2 and isinstance(t.args[1], EllipsisType):
                 # Tuple[T, ...] (uniform, variable-length tuple)
                 instance = self.named_type('builtins.tuple', [self.anal_type(t.args[0])])
                 instance.line = t.line
                 return instance
             return self.tuple_type(self.anal_array(t.args))
         elif fullname == 'typing.Union':
             items = self.anal_array(t.args)
             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(TypeOfAny.from_error)
             item = self.anal_type(t.args[0])
             return make_optional_type(item)
         elif fullname == 'typing.Callable':
             return self.analyze_callable_type(t)
         elif fullname == 'typing.Type':
             if len(t.args) == 0:
                 any_type = AnyType(TypeOfAny.from_omitted_generics,
                                    line=t.line, column=t.column)
                 return TypeType(any_type, line=t.line, column=t.column)
             if len(t.args) != 1:
                 self.fail('Type[...] must have exactly one type argument', t)
             item = self.anal_type(t.args[0])
             return TypeType.make_normalized(item, line=t.line)
         elif fullname == 'typing.ClassVar':
             if self.nesting_level > 0:
                 self.fail('Invalid type: ClassVar nested inside other type', t)
             if len(t.args) == 0:
                 return AnyType(TypeOfAny.from_omitted_generics, line=t.line, column=t.column)
             if len(t.args) != 1:
                 self.fail('ClassVar[...] must have at most one type argument', t)
                 return AnyType(TypeOfAny.from_error)
             item = self.anal_type(t.args[0])
             if isinstance(item, TypeVarType) or get_type_vars(item):
                 self.fail('Invalid type: ClassVar cannot be generic', t)
                 return AnyType(TypeOfAny.from_error)
             return item
         elif fullname in ('mypy_extensions.NoReturn', 'typing.NoReturn'):
             return UninhabitedType(is_noreturn=True)
         elif sym.kind == TYPE_ALIAS:
             override = sym.type_override
             all_vars = sym.alias_tvars
             assert override is not None
             an_args = self.anal_array(t.args)
             if all_vars is not None:
                 exp_len = len(all_vars)
             else:
                 exp_len = 0
             act_len = len(an_args)
             if exp_len > 0 and act_len == 0:
                 # Interpret bare Alias same as normal generic, i.e., Alias[Any, Any, ...]
                 assert all_vars is not None
                 return set_any_tvars(override, all_vars, t.line, t.column)
             if exp_len == 0 and act_len == 0:
                 return override
             if act_len != exp_len:
                 self.fail('Bad number of arguments for type alias, expected: %s, given: %s'
                           % (exp_len, act_len), t)
                 return set_any_tvars(override, all_vars or [],
                                      t.line, t.column, implicit=False)
             assert all_vars is not None
             return replace_alias_tvars(override, all_vars, an_args, t.line, t.column)
         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(TypeOfAny.from_unimported_type)
             # Allow unbound type variables when defining an alias
             if not (self.aliasing and sym.kind == TVAR and
                     (not self.tvar_scope or self.tvar_scope.get_binding(sym) is None)):
                 if (not self.third_pass and not self.in_dynamic_func and
                         not (isinstance(sym.node, (FuncDef, Decorator)) or
                              isinstance(sym.node, Var) and sym.node.is_ready) and
                         not (sym.kind == TVAR and tvar_def is None)):
                     if t.args and not self.global_scope:
                         self.fail('Unsupported forward reference to "{}"'.format(t.name), t)
                         return AnyType(TypeOfAny.from_error)
                     return ForwardRef(t)
                 self.fail('Invalid type "{}"'.format(name), t)
                 if self.third_pass and sym.kind == TVAR:
                     self.note_func("Forward references to type variables are prohibited", t)
             return t
         info = sym.node  # type: TypeInfo
         if len(t.args) > 0 and info.fullname() == 'builtins.tuple':
             fallback = Instance(info, [AnyType(TypeOfAny.special_form)], t.line)
             return TupleType(self.anal_array(t.args), fallback, 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, t.column)
             instance.from_generic_builtin = sym.normalized
             tup = info.tuple_type
             if tup is not None:
                 # 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(TypeOfAny.from_error)
                 return tup.copy_modified(items=self.anal_array(tup.items),
                                          fallback=instance)
             td = info.typeddict_type
             if td is not None:
                 # The class has a TypedDict[...] base class so it will be
                 # represented as a typeddict type.
                 if t.args:
                     self.fail('Generic TypedDict types not supported', t)
                     return AnyType(TypeOfAny.from_error)
                 # Create a named TypedDictType
                 return td.copy_modified(item_types=self.anal_array(list(td.items.values())),
                                         fallback=instance)
             return instance
     else:
         if self.third_pass:
             self.fail('Invalid type "{}"'.format(t.name), t)
             return AnyType(TypeOfAny.from_error)
         return AnyType(TypeOfAny.special_form)
Ejemplo n.º 34
0
Archivo: meet.py Proyecto: chadrik/mypy
def is_overlapping_types(left: Type,
                         right: Type,
                         ignore_promotions: bool = False,
                         prohibit_none_typevar_overlap: bool = False) -> bool:
    """Can a value of type 'left' also be of type 'right' or vice-versa?

    If 'ignore_promotions' is True, we ignore promotions while checking for overlaps.
    If 'prohibit_none_typevar_overlap' is True, we disallow None from overlapping with
    TypeVars (in both strict-optional and non-strict-optional mode).
    """

    def _is_overlapping_types(left: Type, right: Type) -> bool:
        '''Encode the kind of overlapping check to perform.

        This function mostly exists so we don't have to repeat keyword arguments everywhere.'''
        return is_overlapping_types(
            left, right,
            ignore_promotions=ignore_promotions,
            prohibit_none_typevar_overlap=prohibit_none_typevar_overlap)

    # We should never encounter this type.
    if isinstance(left, PartialType) or isinstance(right, PartialType):
        assert False, "Unexpectedly encountered partial type"

    # We should also never encounter these types, but it's possible a few
    # have snuck through due to unrelated bugs. For now, we handle these
    # in the same way we handle 'Any'.
    #
    # TODO: Replace these with an 'assert False' once we are more confident.
    illegal_types = (UnboundType, ErasedType, DeletedType)
    if isinstance(left, illegal_types) or isinstance(right, illegal_types):
        return True

    # 'Any' may or may not be overlapping with the other type
    if isinstance(left, AnyType) or isinstance(right, AnyType):
        return True

    # When running under non-strict optional mode, simplify away types of
    # the form 'Union[A, B, C, None]' into just 'Union[A, B, C]'.

    if not state.strict_optional:
        if isinstance(left, UnionType):
            left = UnionType.make_union(left.relevant_items())
        if isinstance(right, UnionType):
            right = UnionType.make_union(right.relevant_items())

    # We check for complete overlaps next as a general-purpose failsafe.
    # If this check fails, we start checking to see if there exists a
    # *partial* overlap between types.
    #
    # These checks will also handle the NoneTyp and UninhabitedType cases for us.

    if (is_proper_subtype(left, right, ignore_promotions=ignore_promotions)
            or is_proper_subtype(right, left, ignore_promotions=ignore_promotions)):
        return True

    # See the docstring for 'get_possible_variants' for more info on what the
    # following lines are doing.

    left_possible = get_possible_variants(left)
    right_possible = get_possible_variants(right)

    # We start by checking multi-variant types like Unions first. We also perform
    # the same logic if either type happens to be a TypeVar.
    #
    # Handling the TypeVars now lets us simulate having them bind to the corresponding
    # type -- if we deferred these checks, the "return-early" logic of the other
    # checks will prevent us from detecting certain overlaps.
    #
    # If both types are singleton variants (and are not TypeVars), we've hit the base case:
    # we skip these checks to avoid infinitely recursing.

    def is_none_typevar_overlap(t1: Type, t2: Type) -> bool:
        return isinstance(t1, NoneTyp) and isinstance(t2, TypeVarType)

    if prohibit_none_typevar_overlap:
        if is_none_typevar_overlap(left, right) or is_none_typevar_overlap(right, left):
            return False

    if (len(left_possible) > 1 or len(right_possible) > 1
            or isinstance(left, TypeVarType) or isinstance(right, TypeVarType)):
        for l in left_possible:
            for r in right_possible:
                if _is_overlapping_types(l, r):
                    return True
        return False

    # Now that we've finished handling TypeVars, we're free to end early
    # if one one of the types is None and we're running in strict-optional mode.
    # (None only overlaps with None in strict-optional mode).
    #
    # We must perform this check after the TypeVar checks because
    # a TypeVar could be bound to None, for example.

    if state.strict_optional and isinstance(left, NoneTyp) != isinstance(right, NoneTyp):
        return False

    # Next, we handle single-variant types that may be inherently partially overlapping:
    #
    # - TypedDicts
    # - Tuples
    #
    # If we cannot identify a partial overlap and end early, we degrade these two types
    # into their 'Instance' fallbacks.

    if isinstance(left, TypedDictType) and isinstance(right, TypedDictType):
        return are_typed_dicts_overlapping(left, right, ignore_promotions=ignore_promotions)
    elif isinstance(left, TypedDictType):
        left = left.fallback
    elif isinstance(right, TypedDictType):
        right = right.fallback

    if is_tuple(left) and is_tuple(right):
        return are_tuples_overlapping(left, right, ignore_promotions=ignore_promotions)
    elif isinstance(left, TupleType):
        left = left.fallback
    elif isinstance(right, TupleType):
        right = right.fallback

    # Next, we handle single-variant types that cannot be inherently partially overlapping,
    # but do require custom logic to inspect.
    #
    # As before, we degrade into 'Instance' whenever possible.

    if isinstance(left, TypeType) and isinstance(right, TypeType):
        # TODO: Can Callable[[...], T] and Type[T] be partially overlapping?
        return _is_overlapping_types(left.item, right.item)

    if isinstance(left, CallableType) and isinstance(right, CallableType):
        return is_callable_compatible(left, right,
                                      is_compat=_is_overlapping_types,
                                      ignore_pos_arg_names=True,
                                      allow_partial_overlap=True)
    elif isinstance(left, CallableType):
        left = left.fallback
    elif isinstance(right, CallableType):
        right = right.fallback

    if isinstance(left, LiteralType) and isinstance(right, LiteralType):
        return left == right
    elif isinstance(left, LiteralType):
        left = left.fallback
    elif isinstance(right, LiteralType):
        right = right.fallback

    # Finally, we handle the case where left and right are instances.

    if isinstance(left, Instance) and isinstance(right, Instance):
        if left.type.is_protocol and is_protocol_implementation(right, left):
            return True
        if right.type.is_protocol and is_protocol_implementation(left, right):
            return True

        # Two unrelated types cannot be partially overlapping: they're disjoint.
        # We don't need to handle promotions because they've already been handled
        # by the calls to `is_subtype(...)` up above (and promotable types never
        # have any generic arguments we need to recurse on).
        if left.type.has_base(right.type.fullname()):
            left = map_instance_to_supertype(left, right.type)
        elif right.type.has_base(left.type.fullname()):
            right = map_instance_to_supertype(right, left.type)
        else:
            return False

        if len(left.args) == len(right.args):
            # Note: we don't really care about variance here, since the overlapping check
            # is symmetric and since we want to return 'True' even for partial overlaps.
            #
            # For example, suppose we have two types Wrapper[Parent] and Wrapper[Child].
            # It doesn't matter whether Wrapper is covariant or contravariant since
            # either way, one of the two types will overlap with the other.
            #
            # Similarly, if Wrapper was invariant, the two types could still be partially
            # overlapping -- what if Wrapper[Parent] happened to contain only instances of
            # specifically Child?
            #
            # Or, to use a more concrete example, List[Union[A, B]] and List[Union[B, C]]
            # would be considered partially overlapping since it's possible for both lists
            # to contain only instances of B at runtime.
            for left_arg, right_arg in zip(left.args, right.args):
                if _is_overlapping_types(left_arg, right_arg):
                    return True

        return False

    # We ought to have handled every case by now: we conclude the
    # two types are not overlapping, either completely or partially.
    #
    # Note: it's unclear however, whether returning False is the right thing
    # to do when inferring reachability -- see  https://github.com/python/mypy/issues/5529

    assert type(left) != type(right)
    return False
Ejemplo n.º 35
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.º 36
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 make_optional_type(self.visit_unbound_type(t))
     sym = self.lookup(t.name, t,
                       suppress_errors=self.third_pass)  # type: ignore
     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(errorcode.INTERNAL_ERROR_NODE_IS_NONE(sym.kind),
                           t)
             return AnyType(TypeOfAny.special_form)
         fullname = sym.node.fullname()
         hook = self.plugin.get_type_analyze_hook(fullname)
         if hook:
             return hook(AnalyzeTypeContext(t, t, self))
         if (fullname in nongen_builtins and t.args and not sym.normalized
                 and not self.allow_unnormalized):
             self.fail(errorcode.NO_SUBSCRIPT_BUILTIN_ALIAS(fullname), t)
         if self.tvar_scope:
             tvar_def = self.tvar_scope.get_binding(sym)
         else:
             tvar_def = None
         if self.warn_bound_tvar and sym.kind == TVAR and tvar_def is not None:
             self.fail(
                 errorcode.
                 CANNOT_USE_BOUND_TYPE_VAR_TO_DEFINE_GENERIC_ALIAS(t.name),
                 t)
             return AnyType(TypeOfAny.from_error)
         elif sym.kind == TVAR and tvar_def is not None:
             if len(t.args) > 0:
                 self.fail(errorcode.TYPE_VAR_USED_WITH_ARG(t.name), t)
             return TypeVarType(tvar_def, t.line)
         elif fullname == 'builtins.None':
             return NoneTyp()
         elif fullname == 'typing.Any' or fullname == 'builtins.Any':
             return AnyType(TypeOfAny.explicit)
         elif fullname == 'typing.Tuple':
             if len(t.args) == 0 and not t.empty_tuple_index:
                 # Bare 'Tuple' is same as 'tuple'
                 if self.options.disallow_any_generics and not self.is_typeshed_stub:
                     self.fail(errorcode.BARE_GENERIC(), t)
                 typ = self.named_type('builtins.tuple',
                                       line=t.line,
                                       column=t.column)
                 typ.from_generic_builtin = True
                 return typ
             if len(t.args) == 2 and isinstance(t.args[1], EllipsisType):
                 # Tuple[T, ...] (uniform, variable-length tuple)
                 instance = self.named_type('builtins.tuple',
                                            [self.anal_type(t.args[0])])
                 instance.line = t.line
                 return instance
             return self.tuple_type(self.anal_array(t.args))
         elif fullname == 'typing.Union':
             items = self.anal_array(t.args)
             return UnionType.make_union(items)
         elif fullname == 'typing.Optional':
             if len(t.args) != 1:
                 self.fail(errorcode.OPTIONAL_MUST_HAVE_ONE_ARGUMENT(), t)
                 return AnyType(TypeOfAny.from_error)
             item = self.anal_type(t.args[0])
             return make_optional_type(item)
         elif fullname == 'typing.Callable':
             return self.analyze_callable_type(t)
         elif fullname == 'typing.Type':
             if len(t.args) == 0:
                 any_type = AnyType(TypeOfAny.from_omitted_generics,
                                    line=t.line,
                                    column=t.column)
                 return TypeType(any_type, line=t.line, column=t.column)
             if len(t.args) != 1:
                 self.fail(errorcode.TYPE_MUST_HAVE_EXACTLY_ONE_TYPE(), t)
             item = self.anal_type(t.args[0])
             return TypeType.make_normalized(item, line=t.line)
         elif fullname == 'typing.ClassVar':
             if self.nesting_level > 0:
                 self.fail(
                     errorcode.INVALID_TYPE_CLASSVAR_NESTED_INSIDE_TYPE(),
                     t)
             if len(t.args) == 0:
                 return AnyType(TypeOfAny.from_omitted_generics,
                                line=t.line,
                                column=t.column)
             if len(t.args) != 1:
                 self.fail(
                     errorcode.CLASS_VAR_MUST_HAVE_AT_MOST_ONE_TYPE_ARG(),
                     t)
                 return AnyType(TypeOfAny.from_error)
             item = self.anal_type(t.args[0])
             if isinstance(item, TypeVarType) or get_type_vars(item):
                 self.fail(errorcode.CLASSVAR_CANNOT_BE_GENERIC(), t)
                 return AnyType(TypeOfAny.from_error)
             return item
         elif fullname in ('mypy_extensions.NoReturn', 'typing.NoReturn'):
             return UninhabitedType(is_noreturn=True)
         elif sym.kind == TYPE_ALIAS:
             override = sym.type_override
             all_vars = sym.alias_tvars
             assert override is not None
             an_args = self.anal_array(t.args)
             if all_vars is not None:
                 exp_len = len(all_vars)
             else:
                 exp_len = 0
             act_len = len(an_args)
             if exp_len > 0 and act_len == 0:
                 # Interpret bare Alias same as normal generic, i.e., Alias[Any, Any, ...]
                 assert all_vars is not None
                 return set_any_tvars(override, all_vars, t.line, t.column)
             if exp_len == 0 and act_len == 0:
                 return override
             if act_len != exp_len:
                 self.fail(
                     errorcode.BAD_NUMBER_ARGUMENT_FOR_TYPEALIAS(
                         exp_len, act_len), t)
                 return set_any_tvars(override,
                                      all_vars or [],
                                      t.line,
                                      t.column,
                                      implicit=False)
             assert all_vars is not None
             return replace_alias_tvars(override, all_vars, an_args, t.line,
                                        t.column)
         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(TypeOfAny.from_unimported_type)
             # Allow unbound type variables when defining an alias
             if not (self.aliasing and sym.kind == TVAR and
                     (not self.tvar_scope
                      or self.tvar_scope.get_binding(sym) is None)):
                 if (not self.third_pass and not self.in_dynamic_func
                         and not (isinstance(sym.node, (FuncDef, Decorator))
                                  or isinstance(sym.node, Var)
                                  and sym.node.is_ready)
                         and not (sym.kind == TVAR and tvar_def is None)):
                     if t.args and not self.global_scope:
                         self.fail(
                             errorcode.UNSUPPORTED_FORWARD_REFERENCE(
                                 t.name), t)
                         return AnyType(TypeOfAny.from_error)
                     return ForwardRef(t)
                 self.fail(errorcode.INVALID_TYPE_X(name), t)
                 if self.third_pass and sym.kind == TVAR:
                     self.note_func(
                         errorcode.FORWARD_REERENCES_TO_TYPE_VAR_PROHIBITED(
                         ), t)
             return t
         info = sym.node  # type: TypeInfo
         if len(t.args) > 0 and info.fullname() == 'builtins.tuple':
             fallback = Instance(info, [AnyType(TypeOfAny.special_form)],
                                 t.line)
             return TupleType(self.anal_array(t.args), fallback, 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,
                                 t.column)
             instance.from_generic_builtin = sym.normalized
             tup = info.tuple_type
             if tup is not None:
                 # The class has a Tuple[...] base class so it will be
                 # represented as a tuple type.
                 if t.args:
                     self.fail(
                         errorcode.GENERIC_TUPLE_TYPES_NOT_SUPPORTED(), t)
                     return AnyType(TypeOfAny.from_error)
                 return tup.copy_modified(items=self.anal_array(tup.items),
                                          fallback=instance)
             td = info.typeddict_type
             if td is not None:
                 # The class has a TypedDict[...] base class so it will be
                 # represented as a typeddict type.
                 if t.args:
                     self.fail(
                         errorcode.GENERIC_TYPEDDICT_TYPES_NOT_SUPPORTED(),
                         t)
                     return AnyType(TypeOfAny.from_error)
                 # Create a named TypedDictType
                 return td.copy_modified(item_types=self.anal_array(
                     list(td.items.values())),
                                         fallback=instance)
             return instance
     else:
         if self.third_pass:
             self.fail(errorcode.INVALID_TYPE_X(t.name), t)
             return AnyType(TypeOfAny.from_error)
         return AnyType(TypeOfAny.special_form)
Ejemplo n.º 37
0
 def visit_unbound_type(self, t: UnboundType) -> Type:
     sym = self.lookup(t.name, t)
     if sym is not None:
         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)
             tvar_expr = cast(TypeVarExpr, sym.node)
             return TypeVarType(t.name, sym.tvar_id, tvar_expr.values,
                                self.builtin_type('builtins.object'),
                                tvar_expr.variance,
                                t.line)
         elif fullname == 'builtins.None':
             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')
                 info = cast(TypeInfo, node.node)
                 return Instance(info, [t.args[0].accept(self)], t.line)
             return TupleType(self.anal_array(t.args),
                              self.builtin_type('builtins.tuple'))
         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)
             items = self.anal_array(t.args)
             # Currently Optional[t] is just an alias for t.
             return items[0]
         elif fullname == 'typing.Callable':
             return self.analyze_callable_type(t)
         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 = cast(TypeInfo, sym.node)
         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)
             if info.tuple_type 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 TupleType(self.anal_array(info.tuple_type.items),
                                  fallback=instance,
                                  line=t.line)
     else:
         return t
Ejemplo n.º 38
0
def make_optional(typ: MypyType) -> MypyType:
    return UnionType.make_union([typ, NoneTyp()])
Ejemplo n.º 39
0
 def visit_unbound_type(self, t: UnboundType) -> Type:
     sym = self.lookup(t.name, t)
     if sym is not None:
         fullname = sym.node.fullname()
         if sym.kind == TVAR:
             if len(t.args) > 0:
                 self.fail('Type variable "{}" used with arguments'.format(
                     t.name), t)
             values = cast(TypeVarExpr, sym.node).values
             return TypeVarType(t.name, sym.tvar_id, values,
                                self.builtin_type('builtins.object'),
                                t.line)
         elif fullname == 'builtins.None':
             return Void()
         elif fullname == 'typing.Any':
             return AnyType()
         elif fullname == 'typing.Tuple':
             return TupleType(self.anal_array(t.args),
                              self.builtin_type('builtins.tuple'))
         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)
             items = self.anal_array(t.args)
             # Currently Optional[t] is just an alias for t.
             return items[0]
         elif fullname == 'typing.Callable':
             return self.analyze_function_type(t)
         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()
             self.fail('Invalid type "{}"'.format(name), t)
             return t
         info = cast(TypeInfo, sym.node)
         if len(t.args) > 0 and info.fullname() == 'builtins.tuple':
             return TupleType(self.anal_array(t.args),
                              Instance(info, [], 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)
             if info.tuple_type is None:
                 return instance
             else:
                 # The class has a Tuple[...] base class so it will be
                 # represented as a tuple type.
                 return TupleType(self.anal_array(info.tuple_type.items),
                                  fallback=instance,
                                  line=t.line)
     else:
         return t