Ejemplo n.º 1
0
 def visit_instance(self, t: Instance) -> Type:
     if isinstance(self.s, Instance):
         si = self.s
         if t.type == si.type:
             if is_subtype(t, self.s) or is_subtype(self.s, t):
                 # Combine type arguments. We could have used join below
                 # equivalently.
                 args = []  # type: List[Type]
                 for i in range(len(t.args)):
                     args.append(self.meet(t.args[i], si.args[i]))
                 return Instance(t.type, args)
             else:
                 if experiments.STRICT_OPTIONAL:
                     return UninhabitedType()
                 else:
                     return NoneTyp()
         else:
             if is_subtype(t, self.s):
                 return t
             elif is_subtype(self.s, t):
                 # See also above comment.
                 return self.s
             else:
                 if experiments.STRICT_OPTIONAL:
                     return UninhabitedType()
                 else:
                     return NoneTyp()
     elif isinstance(self.s, TypeType):
         return meet_types(t, self.s)
     elif isinstance(self.s, TupleType):
         return meet_types(t, self.s)
     else:
         return self.default(self.s)
Ejemplo n.º 2
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.º 3
0
def true_only(t: Type) -> ProperType:
    """
    Restricted version of t with only True-ish values
    """
    t = get_proper_type(t)

    if not t.can_be_true:
        # All values of t are False-ish, so there are no true values in it
        return UninhabitedType(line=t.line, column=t.column)
    elif not t.can_be_false:
        # All values of t are already True-ish, so true_only is idempotent in this case
        return t
    elif isinstance(t, UnionType):
        # The true version of a union type is the union of the true versions of its components
        new_items = [true_only(item) for item in t.items]
        can_be_true_items = [item for item in new_items if item.can_be_true]
        return make_simplified_union(can_be_true_items,
                                     line=t.line,
                                     column=t.column)
    else:
        ret_type = _get_type_special_method_bool_ret_type(t)

        if ret_type and ret_type.can_be_false and not ret_type.can_be_true:
            new_t = copy_type(t)
            new_t.can_be_true = False
            return new_t

        new_t = copy_type(t)
        new_t.can_be_false = False
        return new_t
Ejemplo n.º 4
0
 def visit_starred_pattern(self, o: StarredPattern) -> PatternType:
     captures: Dict[Expression, Type] = {}
     if o.capture is not None:
         list_type = self.chk.named_generic_type('builtins.list',
                                                 [self.type_context[-1]])
         captures[o.capture] = list_type
     return PatternType(self.type_context[-1], UninhabitedType(), captures)
Ejemplo n.º 5
0
 def test_false_only_tuple(self) -> None:
     with strict_optional_set(False):
         fo = false_only(self.tuple(self.fx.a))
         assert_equal(fo, NoneType())
     with strict_optional_set(True):
         fo = false_only(self.tuple(self.fx.a))
         assert_equal(fo, UninhabitedType())
Ejemplo n.º 6
0
def solve_constraints(vars: List[TypeVarId], constraints: List[Constraint],
                      strict: bool =True) -> List[Optional[Type]]:
    """Solve type constraints.

    Return the best type(s) for type variables; each type can be None if the value of the variable
    could not be solved.

    If a variable has no constraints, if strict=True then arbitrarily
    pick NoneTyp as the value of the type variable.  If strict=False,
    pick AnyType.
    """
    # Collect a list of constraints for each type variable.
    cmap = defaultdict(list)  # type: Dict[TypeVarId, List[Constraint]]
    for con in constraints:
        cmap[con.type_var].append(con)

    res = []  # type: List[Optional[Type]]

    # Solve each type variable separately.
    for tvar in vars:
        bottom = None  # type: Optional[Type]
        top = None  # type: Optional[Type]
        candidate = None  # type: Optional[Type]

        # Process each constraint separately, and calculate the lower and upper
        # bounds based on constraints. Note that we assume that the constraint
        # targets do not have constraint references.
        for c in cmap.get(tvar, []):
            if c.op == SUPERTYPE_OF:
                if bottom is None:
                    bottom = c.target
                else:
                    bottom = join_types(bottom, c.target)
            else:
                if top is None:
                    top = c.target
                else:
                    top = meet_types(top, c.target)

        if isinstance(top, AnyType) or isinstance(bottom, AnyType):
            res.append(AnyType())
            continue
        elif bottom is None:
            if top:
                candidate = top
            else:
                # No constraints for type variable -- 'UninhabitedType' is the most specific type.
                if strict:
                    candidate = UninhabitedType()
                else:
                    candidate = AnyType()
        elif top is None:
            candidate = bottom
        elif is_subtype(bottom, top):
            candidate = bottom
        else:
            candidate = None
        res.append(candidate)

    return res
Ejemplo n.º 7
0
def false_only(t: Type) -> ProperType:
    """
    Restricted version of t with only False-ish values
    """
    t = get_proper_type(t)

    if not t.can_be_false:
        if state.strict_optional:
            # All values of t are True-ish, so there are no false values in it
            return UninhabitedType(line=t.line)
        else:
            # When strict optional checking is disabled, everything can be
            # False-ish since anything can be None
            return NoneType(line=t.line)
    elif not t.can_be_true:
        # All values of t are already False-ish, so false_only is idempotent in this case
        return t
    elif isinstance(t, UnionType):
        # The false version of a union type is the union of the false versions of its components
        new_items = [false_only(item) for item in t.items]
        can_be_false_items = [item for item in new_items if item.can_be_false]
        return make_simplified_union(can_be_false_items,
                                     line=t.line,
                                     column=t.column)
    else:
        ret_type = _get_type_special_method_bool_ret_type(t)

        if ret_type and ret_type.can_be_true and not ret_type.can_be_false:
            new_t = copy_type(t)
            new_t.can_be_false = False
            return new_t

        new_t = copy_type(t)
        new_t.can_be_true = False
        return new_t
Ejemplo n.º 8
0
    def visit_mapping_pattern(self, o: MappingPattern) -> PatternType:
        current_type = get_proper_type(self.type_context[-1])
        can_match = True
        captures: Dict[Expression, Type] = {}
        for key, value in zip(o.keys, o.values):
            inner_type = self.get_mapping_item_type(o, current_type, key)
            if inner_type is None:
                can_match = False
                inner_type = self.chk.named_type("builtins.object")
            pattern_type = self.accept(value, inner_type)
            if is_uninhabited(pattern_type.type):
                can_match = False
            else:
                self.update_type_map(captures, pattern_type.captures)

        if o.rest is not None:
            mapping = self.chk.named_type("typing.Mapping")
            if is_subtype(current_type, mapping) and isinstance(current_type, Instance):
                mapping_inst = map_instance_to_supertype(current_type, mapping.type)
                dict_typeinfo = self.chk.lookup_typeinfo("builtins.dict")
                rest_type = Instance(dict_typeinfo, mapping_inst.args)
            else:
                object_type = self.chk.named_type("builtins.object")
                rest_type = self.chk.named_generic_type("builtins.dict",
                                                        [object_type, object_type])

            captures[o.rest] = rest_type

        if can_match:
            # We can't narrow the type here, as Mapping key is invariant.
            new_type = self.type_context[-1]
        else:
            new_type = UninhabitedType()
        return PatternType(new_type, current_type, captures)
Ejemplo n.º 9
0
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
    """Return the declared type narrowed down to another type."""
    # TODO: check infinite recursion for aliases here.
    declared = get_proper_type(declared)
    narrowed = get_proper_type(narrowed)

    if declared == narrowed:
        return declared
    if isinstance(declared, UnionType):
        return 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 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 get_proper_types(narrowed.args))):
            return declared
        return meet_types(declared, narrowed)
    return narrowed
Ejemplo n.º 10
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.º 11
0
 def visit_instance(self, t: Instance) -> ProperType:
     if isinstance(self.s, Instance):
         si = self.s
         if t.type == si.type:
             if is_subtype(t, self.s) or is_subtype(self.s, t):
                 # Combine type arguments. We could have used join below
                 # equivalently.
                 args = []  # type: List[Type]
                 # N.B: We use zip instead of indexing because the lengths might have
                 # mismatches during daemon reprocessing.
                 for ta, sia in zip(t.args, si.args):
                     args.append(self.meet(ta, sia))
                 return Instance(t.type, args)
             else:
                 if state.strict_optional:
                     return UninhabitedType()
                 else:
                     return NoneType()
         else:
             if is_subtype(t, self.s):
                 return t
             elif is_subtype(self.s, t):
                 # See also above comment.
                 return self.s
             else:
                 if state.strict_optional:
                     return UninhabitedType()
                 else:
                     return NoneType()
     elif isinstance(self.s, FunctionLike) and t.type.is_protocol:
         call = unpack_callback_protocol(t)
         if call:
             return meet_types(call, self.s)
     elif isinstance(self.s, FunctionLike) and self.s.is_type_obj(
     ) and t.type.is_metaclass():
         if is_subtype(self.s.fallback, t):
             return self.s
         return self.default(self.s)
     elif isinstance(self.s, TypeType):
         return meet_types(t, self.s)
     elif isinstance(self.s, TupleType):
         return meet_types(t, self.s)
     elif isinstance(self.s, LiteralType):
         return meet_types(t, self.s)
     elif isinstance(self.s, TypedDictType):
         return meet_types(t, self.s)
     return self.default(self.s)
Ejemplo n.º 12
0
 def default(self, typ: Type) -> Type:
     if isinstance(typ, UnboundType):
         return AnyType(TypeOfAny.special_form)
     else:
         if experiments.STRICT_OPTIONAL:
             return UninhabitedType()
         else:
             return NoneTyp()
Ejemplo n.º 13
0
 def get_non_partial_lvalue_type(self, lvalue: RefExpr) -> Type:
     if lvalue not in self.type_map:
         # Likely a block considered unreachable during type checking.
         return UninhabitedType()
     lvalue_type = self.type_map[lvalue]
     if isinstance(lvalue_type, PartialType):
         if isinstance(lvalue.node, Var) and lvalue.node.type:
             lvalue_type = lvalue.node.type
         else:
             # Probably a secondary, non-definition assignment that doesn't
             # result in a non-partial type. We won't be able to infer any
             # dependencies from this so just return something. (The first,
             # definition assignment with a partial type is handled
             # differently, in the semantic analyzer.)
             assert not lvalue.is_new_def
             return UninhabitedType()
     return lvalue_type
Ejemplo n.º 14
0
 def default(self, typ: Type) -> ProperType:
     if isinstance(typ, UnboundType):
         return AnyType(TypeOfAny.special_form)
     else:
         if state.strict_optional:
             return UninhabitedType()
         else:
             return NoneType()
Ejemplo n.º 15
0
 def visit_instance(self, t: Instance) -> ProperType:
     if isinstance(self.s, Instance):
         si = self.s
         if t.type == si.type:
             if is_subtype(t, self.s) or is_subtype(self.s, t):
                 # Combine type arguments. We could have used join below
                 # equivalently.
                 args = []  # type: List[Type]
                 for i in range(len(t.args)):
                     args.append(self.meet(t.args[i], si.args[i]))
                 return Instance(t.type, args)
             else:
                 if state.strict_optional:
                     return UninhabitedType()
                 else:
                     return NoneType()
         else:
             if is_subtype(t, self.s):
                 return t
             elif is_subtype(self.s, t):
                 # See also above comment.
                 return self.s
             else:
                 if state.strict_optional:
                     return UninhabitedType()
                 else:
                     return NoneType()
     elif isinstance(self.s, FunctionLike) and t.type.is_protocol:
         call = unpack_callback_protocol(t)
         if call:
             return meet_types(call, self.s)
     elif isinstance(self.s, FunctionLike) and self.s.is_type_obj(
     ) and t.type.is_metaclass():
         if is_subtype(self.s.fallback, t):
             return self.s
         return self.default(self.s)
     elif isinstance(self.s, TypeType):
         return meet_types(t, self.s)
     elif isinstance(self.s, TupleType):
         return meet_types(t, self.s)
     elif isinstance(self.s, LiteralType):
         return meet_types(t, self.s)
     elif isinstance(self.s, TypedDictType):
         return meet_types(t, self.s)
     return self.default(self.s)
Ejemplo n.º 16
0
 def visit_none_type(self, t: NoneType) -> Type:
     if state.strict_optional:
         if isinstance(self.s, NoneType) or (isinstance(self.s, Instance) and
                                            self.s.type.fullname() == 'builtins.object'):
             return t
         else:
             return UninhabitedType()
     else:
         return t
Ejemplo n.º 17
0
 def visit_none_type(self, t: NoneTyp) -> Type:
     if experiments.STRICT_OPTIONAL:
         if isinstance(self.s, NoneTyp) or (isinstance(self.s, Instance) and
                                            self.s.type.fullname() == 'builtins.object'):
             return t
         else:
             return UninhabitedType()
     else:
         return t
Ejemplo n.º 18
0
def join_type_list(types: List[Type]) -> Type:
    if not types:
        # This is a little arbitrary but reasonable. Any empty tuple should be compatible
        # with all variable length tuples, and this makes it possible.
        return UninhabitedType()
    joined = types[0]
    for t in types[1:]:
        joined = join_types(joined, t)
    return joined
Ejemplo n.º 19
0
 def default(self, typ):
     if isinstance(typ, UnboundType):
         return AnyType()
     elif isinstance(typ, Void) or isinstance(typ, ErrorType):
         return ErrorType()
     else:
         if experiments.STRICT_OPTIONAL:
             return UninhabitedType()
         else:
             return NoneTyp()
Ejemplo n.º 20
0
def trivial_meet(s: Type, t: Type) -> ProperType:
    """Return one of types (expanded) if it is a subtype of other, otherwise bottom type."""
    if is_subtype(s, t):
        return get_proper_type(s)
    elif is_subtype(t, s):
        return get_proper_type(t)
    else:
        if state.strict_optional:
            return UninhabitedType()
        else:
            return NoneType()
Ejemplo n.º 21
0
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
    """Return the declared type narrowed down to another type."""
    # TODO: check infinite recursion for aliases here.
    if isinstance(narrowed, TypeGuardedType):  # type: ignore[misc]
        # A type guard forces the new type even if it doesn't overlap the old.
        return narrowed.type_guard

    declared = get_proper_type(declared)
    narrowed = get_proper_type(narrowed)

    if declared == narrowed:
        return declared
    if isinstance(declared, UnionType):
        return make_simplified_union([
            narrow_declared_type(x, narrowed)
            for x in declared.relevant_items()
        ])
    if is_enum_overlapping_union(declared, narrowed):
        return narrowed
    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 make_simplified_union([
            narrow_declared_type(declared, x)
            for x in narrowed.relevant_items()
        ])
    elif isinstance(narrowed, AnyType):
        return narrowed
    elif isinstance(narrowed, TypeVarType) and is_subtype(
            narrowed.upper_bound, declared):
        return narrowed
    elif isinstance(declared, TypeType) and isinstance(narrowed, TypeType):
        return TypeType.make_normalized(
            narrow_declared_type(declared.item, narrowed.item))
    elif (isinstance(declared, TypeType) and isinstance(narrowed, Instance)
          and narrowed.type.is_metaclass()):
        # We'd need intersection types, so give up.
        return declared
    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 get_proper_types(narrowed.args))):
            return declared
        return meet_types(declared, narrowed)
    return narrowed
Ejemplo n.º 22
0
Archivo: join.py Proyecto: pgjones/mypy
def join_type_list(types: List[Type]) -> Type:
    if not types:
        # This is a little arbitrary but reasonable. Any empty tuple should be compatible
        # with all variable length tuples, and this makes it possible. A better approach
        # would be to use a special bottom type, which we do when strict Optional
        # checking is enabled.
        if experiments.STRICT_OPTIONAL:
            return UninhabitedType()
        else:
            return NoneTyp()
    joined = types[0]
    for t in types[1:]:
        joined = join_types(joined, t)
    return joined
Ejemplo n.º 23
0
    def visit_or_pattern(self, o: OrPattern) -> PatternType:
        current_type = self.type_context[-1]

        #
        # Check all the subpatterns
        #
        pattern_types = []
        for pattern in o.patterns:
            pattern_type = self.accept(pattern, current_type)
            pattern_types.append(pattern_type)
            current_type = pattern_type.rest_type

        #
        # Collect the final type
        #
        types = []
        for pattern_type in pattern_types:
            if not is_uninhabited(pattern_type.type):
                types.append(pattern_type.type)

        #
        # Check the capture types
        #
        capture_types: Dict[Var, List[Tuple[Expression,
                                            Type]]] = defaultdict(list)
        # Collect captures from the first subpattern
        for expr, typ in pattern_types[0].captures.items():
            node = get_var(expr)
            capture_types[node].append((expr, typ))

        # Check if other subpatterns capture the same names
        for i, pattern_type in enumerate(pattern_types[1:]):
            vars = {get_var(expr) for expr, _ in pattern_type.captures.items()}
            if capture_types.keys() != vars:
                self.msg.fail(message_registry.OR_PATTERN_ALTERNATIVE_NAMES,
                              o.patterns[i])
            for expr, typ in pattern_type.captures.items():
                node = get_var(expr)
                capture_types[node].append((expr, typ))

        captures: Dict[Expression, Type] = {}
        for var, capture_list in capture_types.items():
            typ = UninhabitedType()
            for _, other in capture_list:
                typ = join_types(typ, other)

            captures[capture_list[0][0]] = typ

        union_type = make_simplified_union(types)
        return PatternType(union_type, current_type, captures)
Ejemplo n.º 24
0
    def visit_as_pattern(self, o: AsPattern) -> PatternType:
        current_type = self.type_context[-1]
        if o.pattern is not None:
            pattern_type = self.accept(o.pattern, current_type)
            typ, rest_type, type_map = pattern_type
        else:
            typ, rest_type, type_map = current_type, UninhabitedType(), {}

        if not is_uninhabited(typ) and o.name is not None:
            typ, _ = self.chk.conditional_types_with_intersection(
                current_type, [get_type_range(typ)], o, default=current_type)
            if not is_uninhabited(typ):
                type_map[o.name] = typ

        return PatternType(typ, rest_type, type_map)
Ejemplo n.º 25
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.º 26
0
    def _analyze_iterable_item_type(self, expr: Expression) -> Type:
        """Return the item type given by 'expr' in an iterable context."""
        # This logic is copied from mypy's TypeChecker.analyze_iterable_item_type.
        iterable = get_proper_type(self.types[expr])
        echk = self.graph[self.module_name].type_checker().expr_checker
        iterator = echk.check_method_call_by_name('__iter__', iterable, [], [], expr)[0]

        from mypy.join import join_types
        if isinstance(iterable, TupleType):
            joined = UninhabitedType()  # type: Type
            for item in iterable.items:
                joined = join_types(joined, item)
            return joined
        else:
            # Non-tuple iterable.
            return echk.check_method_call_by_name('__next__', iterator, [], [], expr)[0]
Ejemplo n.º 27
0
    def visit_tuple_type(self, t: TupleType) -> Type:
        items = []
        for item in t.items:
            proper_item = get_proper_type(item)
            if isinstance(proper_item, UnpackType):
                unpacked_items = self.expand_unpack(proper_item)
                if unpacked_items is None:
                    # TODO: better error, something like tuple of unknown?
                    return UninhabitedType()
                elif isinstance(unpacked_items, Instance):
                    if len(t.items) == 1:
                        return unpacked_items
                    else:
                        assert False, "Invalid unpack of variable length tuple"
                elif isinstance(unpacked_items, AnyType):
                    return unpacked_items
                else:
                    items.extend(unpacked_items)
            else:
                items.append(proper_item.accept(self))

        return t.copy_modified(items=items)
Ejemplo n.º 28
0
def solve_constraints(vars: List[TypeVarId], constraints: List[Constraint],
                      strict: bool =True) -> List[Optional[Type]]:
    """Solve type constraints.

    Return the best type(s) for type variables; each type can be None if the value of the variable
    could not be solved.

    If a variable has no constraints, if strict=True then arbitrarily
    pick NoneTyp as the value of the type variable.  If strict=False,
    pick AnyType.
    """
    # Collect a list of constraints for each type variable.
    cmap = defaultdict(list)  # type: Dict[TypeVarId, List[Constraint]]
    for con in constraints:
        cmap[con.type_var].append(con)

    res = []  # type: List[Optional[Type]]

    # Solve each type variable separately.
    for tvar in vars:
        bottom = None  # type: Optional[Type]
        top = None  # type: Optional[Type]
        candidate = None  # type: Optional[Type]

        # Process each constraint separately, and calculate the lower and upper
        # bounds based on constraints. Note that we assume that the constraint
        # targets do not have constraint references.
        for c in cmap.get(tvar, []):
            if c.op == SUPERTYPE_OF:
                if bottom is None:
                    bottom = c.target
                else:
                    bottom = join_types(bottom, c.target)
            else:
                if top is None:
                    top = c.target
                else:
                    top = meet_types(top, c.target)

        if isinstance(top, AnyType) or isinstance(bottom, AnyType):
            source_any = top if isinstance(top, AnyType) else bottom
            assert isinstance(source_any, AnyType)
            res.append(AnyType(TypeOfAny.from_another_any, source_any=source_any))
            continue
        elif bottom is None:
            if top:
                candidate = top
            else:
                # No constraints for type variable -- 'UninhabitedType' is the most specific type.
                if strict:
                    candidate = UninhabitedType()
                    candidate.ambiguous = True
                else:
                    candidate = AnyType(TypeOfAny.special_form)
        elif top is None:
            candidate = bottom
        elif is_subtype(bottom, top):
            candidate = bottom
        else:
            candidate = None
        res.append(candidate)

    return res
Ejemplo n.º 29
0
    def __init__(self, variance: int = COVARIANT) -> None:
        # The 'object' class
        self.oi = self.make_type_info('builtins.object')  # class object
        self.o = Instance(self.oi, [])  # object

        # Type variables (these are effectively global)

        def make_type_var(name: str, id: int, values: List[Type],
                          upper_bound: Type, variance: int) -> TypeVarType:
            return TypeVarType(name, name, id, values, upper_bound, variance)

        self.t = make_type_var('T', 1, [], self.o,
                               variance)  # T`1 (type variable)
        self.tf = make_type_var('T', -1, [], self.o,
                                variance)  # T`-1 (type variable)
        self.tf2 = make_type_var('T', -2, [], self.o,
                                 variance)  # T`-2 (type variable)
        self.s = make_type_var('S', 2, [], self.o,
                               variance)  # S`2 (type variable)
        self.s1 = make_type_var('S', 1, [], self.o,
                                variance)  # S`1 (type variable)
        self.sf = make_type_var('S', -2, [], self.o,
                                variance)  # S`-2 (type variable)
        self.sf1 = make_type_var('S', -1, [], self.o,
                                 variance)  # S`-1 (type variable)

        # Simple types
        self.anyt = AnyType(TypeOfAny.special_form)
        self.nonet = NoneType()
        self.uninhabited = UninhabitedType()

        # Abstract class TypeInfos

        # class F
        self.fi = self.make_type_info('F', is_abstract=True)

        # class F2
        self.f2i = self.make_type_info('F2', is_abstract=True)

        # class F3(F)
        self.f3i = self.make_type_info('F3', is_abstract=True, mro=[self.fi])

        # Class TypeInfos
        self.std_tuplei = self.make_type_info('builtins.tuple',
                                              mro=[self.oi],
                                              typevars=['T'],
                                              variances=[COVARIANT
                                                         ])  # class tuple
        self.type_typei = self.make_type_info('builtins.type')  # class type
        self.bool_type_info = self.make_type_info('builtins.bool')
        self.functioni = self.make_type_info(
            'builtins.function')  # function TODO
        self.ai = self.make_type_info('A', mro=[self.oi])  # class A
        self.bi = self.make_type_info('B', mro=[self.ai,
                                                self.oi])  # class B(A)
        self.ci = self.make_type_info('C', mro=[self.ai,
                                                self.oi])  # class C(A)
        self.di = self.make_type_info('D', mro=[self.oi])  # class D
        # class E(F)
        self.ei = self.make_type_info('E', mro=[self.fi, self.oi])
        # class E2(F2, F)
        self.e2i = self.make_type_info('E2', mro=[self.f2i, self.fi, self.oi])
        # class E3(F, F2)
        self.e3i = self.make_type_info('E3', mro=[self.fi, self.f2i, self.oi])

        # Generic class TypeInfos
        # G[T]
        self.gi = self.make_type_info('G',
                                      mro=[self.oi],
                                      typevars=['T'],
                                      variances=[variance])
        # G2[T]
        self.g2i = self.make_type_info('G2',
                                       mro=[self.oi],
                                       typevars=['T'],
                                       variances=[variance])
        # H[S, T]
        self.hi = self.make_type_info('H',
                                      mro=[self.oi],
                                      typevars=['S', 'T'],
                                      variances=[variance, variance])
        # GS[T, S] <: G[S]
        self.gsi = self.make_type_info('GS',
                                       mro=[self.gi, self.oi],
                                       typevars=['T', 'S'],
                                       variances=[variance, variance],
                                       bases=[Instance(self.gi, [self.s])])
        # GS2[S] <: G[S]
        self.gs2i = self.make_type_info('GS2',
                                        mro=[self.gi, self.oi],
                                        typevars=['S'],
                                        variances=[variance],
                                        bases=[Instance(self.gi, [self.s1])])
        # list[T]
        self.std_listi = self.make_type_info('builtins.list',
                                             mro=[self.oi],
                                             typevars=['T'],
                                             variances=[variance])

        # Instance types
        self.std_tuple = Instance(self.std_tuplei, [self.anyt])  # tuple
        self.type_type = Instance(self.type_typei, [])  # type
        self.function = Instance(self.functioni, [])  # function TODO
        self.a = Instance(self.ai, [])  # A
        self.b = Instance(self.bi, [])  # B
        self.c = Instance(self.ci, [])  # C
        self.d = Instance(self.di, [])  # D

        self.e = Instance(self.ei, [])  # E
        self.e2 = Instance(self.e2i, [])  # E2
        self.e3 = Instance(self.e3i, [])  # E3

        self.f = Instance(self.fi, [])  # F
        self.f2 = Instance(self.f2i, [])  # F2
        self.f3 = Instance(self.f3i, [])  # F3

        # Generic instance types
        self.ga = Instance(self.gi, [self.a])  # G[A]
        self.gb = Instance(self.gi, [self.b])  # G[B]
        self.gd = Instance(self.gi, [self.d])  # G[D]
        self.go = Instance(self.gi, [self.o])  # G[object]
        self.gt = Instance(self.gi, [self.t])  # G[T`1]
        self.gtf = Instance(self.gi, [self.tf])  # G[T`-1]
        self.gtf2 = Instance(self.gi, [self.tf2])  # G[T`-2]
        self.gs = Instance(self.gi, [self.s])  # G[S]
        self.gdyn = Instance(self.gi, [self.anyt])  # G[Any]
        self.gn = Instance(self.gi, [NoneType()])  # G[None]

        self.g2a = Instance(self.g2i, [self.a])  # G2[A]

        self.gsaa = Instance(self.gsi, [self.a, self.a])  # GS[A, A]
        self.gsab = Instance(self.gsi, [self.a, self.b])  # GS[A, B]
        self.gsba = Instance(self.gsi, [self.b, self.a])  # GS[B, A]

        self.gs2a = Instance(self.gs2i, [self.a])  # GS2[A]
        self.gs2b = Instance(self.gs2i, [self.b])  # GS2[B]
        self.gs2d = Instance(self.gs2i, [self.d])  # GS2[D]

        self.hab = Instance(self.hi, [self.a, self.b])  # H[A, B]
        self.haa = Instance(self.hi, [self.a, self.a])  # H[A, A]
        self.hbb = Instance(self.hi, [self.b, self.b])  # H[B, B]
        self.hts = Instance(self.hi, [self.t, self.s])  # H[T, S]
        self.had = Instance(self.hi, [self.a, self.d])  # H[A, D]
        self.hao = Instance(self.hi, [self.a, self.o])  # H[A, object]

        self.lsta = Instance(self.std_listi, [self.a])  # List[A]
        self.lstb = Instance(self.std_listi, [self.b])  # List[B]

        self.lit1 = LiteralType(1, self.a)
        self.lit2 = LiteralType(2, self.a)
        self.lit3 = LiteralType("foo", self.d)
        self.lit4 = LiteralType(4, self.a)
        self.lit1_inst = Instance(self.ai, [], last_known_value=self.lit1)
        self.lit2_inst = Instance(self.ai, [], last_known_value=self.lit2)
        self.lit3_inst = Instance(self.di, [], last_known_value=self.lit3)
        self.lit4_inst = Instance(self.ai, [], last_known_value=self.lit4)

        self.type_a = TypeType.make_normalized(self.a)
        self.type_b = TypeType.make_normalized(self.b)
        self.type_c = TypeType.make_normalized(self.c)
        self.type_d = TypeType.make_normalized(self.d)
        self.type_t = TypeType.make_normalized(self.t)
        self.type_any = TypeType.make_normalized(self.anyt)

        self._add_bool_dunder(self.bool_type_info)
        self._add_bool_dunder(self.ai)
Ejemplo n.º 30
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.º 31
0
def bind_self(method: F,
              original_type: Optional[Type] = None,
              is_classmethod: bool = False) -> F:
    """Return a copy of `method`, with the type of its first parameter (usually
    self or cls) bound to original_type.

    If the type of `self` is a generic type (T, or Type[T] for classmethods),
    instantiate every occurrence of type with original_type in the rest of the
    signature and in the return type.

    original_type is the type of E in the expression E.copy(). It is None in
    compatibility checks. In this case we treat it as the erasure of the
    declared type of self.

    This way we can express "the type of self". For example:

    T = TypeVar('T', bound='A')
    class A:
        def copy(self: T) -> T: ...

    class B(A): pass

    b = B().copy()  # type: B

    """
    from mypy.infer import infer_type_arguments

    if isinstance(method, Overloaded):
        return cast(
            F,
            Overloaded([
                bind_self(c, original_type, is_classmethod)
                for c in method.items
            ]))
    assert isinstance(method, CallableType)
    func = method
    if not func.arg_types:
        # Invalid method, return something.
        return cast(F, func)
    if func.arg_kinds[0] == ARG_STAR:
        # The signature is of the form 'def foo(*args, ...)'.
        # In this case we shouldn't drop the first arg,
        # since func will be absorbed by the *args.

        # TODO: infer bounds on the type of *args?
        return cast(F, func)
    self_param_type = get_proper_type(func.arg_types[0])

    variables: Sequence[TypeVarLikeType] = []
    if func.variables and supported_self_type(self_param_type):
        if original_type is None:
            # TODO: type check method override (see #7861).
            original_type = erase_to_bound(self_param_type)
        original_type = get_proper_type(original_type)

        all_ids = func.type_var_ids()
        typeargs = infer_type_arguments(all_ids,
                                        self_param_type,
                                        original_type,
                                        is_supertype=True)
        if (is_classmethod
                # TODO: why do we need the extra guards here?
                and any(
                    isinstance(get_proper_type(t), UninhabitedType)
                    for t in typeargs) and isinstance(
                        original_type, (Instance, TypeVarType, TupleType))):
            # In case we call a classmethod through an instance x, fallback to type(x)
            typeargs = infer_type_arguments(all_ids,
                                            self_param_type,
                                            TypeType(original_type),
                                            is_supertype=True)

        ids = [
            tid for tid in all_ids
            if any(tid == t.id for t in get_type_vars(self_param_type))
        ]

        # Technically, some constrains might be unsolvable, make them <nothing>.
        to_apply = [
            t if t is not None else UninhabitedType() for t in typeargs
        ]

        def expand(target: Type) -> Type:
            return expand_type(target,
                               {id: to_apply[all_ids.index(id)]
                                for id in ids})

        arg_types = [expand(x) for x in func.arg_types[1:]]
        ret_type = expand(func.ret_type)
        variables = [v for v in func.variables if v.id not in ids]
    else:
        arg_types = func.arg_types[1:]
        ret_type = func.ret_type
        variables = func.variables

    original_type = get_proper_type(original_type)
    if isinstance(original_type, CallableType) and original_type.is_type_obj():
        original_type = TypeType.make_normalized(original_type.ret_type)
    res = func.copy_modified(arg_types=arg_types,
                             arg_kinds=func.arg_kinds[1:],
                             arg_names=func.arg_names[1:],
                             variables=variables,
                             ret_type=ret_type,
                             bound_args=[original_type])
    return cast(F, res)