diff --git a/mypy/fastparse.py b/mypy/fastparse.py index a47ed9b536da..78f662bd227b 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -384,7 +384,7 @@ def __init__( self.type_ignores: dict[int, list[str]] = {} # Cache of visit_X methods keyed by type of visited object - self.visitor_cache: dict[type, Callable[[AST | None], Any]] = {} + self.visitor_cache: dict[type[object], Callable[[AST | None], Any]] = {} def note(self, msg: str, line: int, column: int) -> None: self.errors.report(line, column, msg, severity="note", code=codes.SYNTAX) diff --git a/mypy/message_registry.py b/mypy/message_registry.py index c0b422d4a35d..380c00845783 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -179,6 +179,10 @@ def with_additional_msg(self, info: str) -> ErrorMessage: IMPLICIT_GENERIC_ANY_BUILTIN: Final = ( 'Implicit generic "Any". Use "{}" and specify generic parameters' ) +BUILTIN_TYPE_USED_AS_GENERIC = ( + '"builtins.type" is indexable as a type hint but neither a generic class nor a generic ' + "function" +) INVALID_UNPACK: Final = "{} cannot be unpacked (must be tuple or TypeVarTuple)" INVALID_UNPACK_POSITION: Final = "Unpack is only valid in a variadic position" INVALID_PARAM_SPEC_LOCATION: Final = "Invalid location for ParamSpec {}" diff --git a/mypy/messages.py b/mypy/messages.py index d63df92c80a7..cdd530b8dc1d 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -422,6 +422,13 @@ def has_no_attr( # Indexed get. # TODO: Fix this consistently in format_type if isinstance(original_type, FunctionLike) and original_type.is_type_obj(): + if ( + isinstance(original_type, CallableType) + and isinstance(ret_type := get_proper_type(original_type.ret_type), Instance) + and (ret_type.type.fullname == "builtins.type") + ): + self.fail(message_registry.BUILTIN_TYPE_USED_AS_GENERIC, context) + return None self.fail( "The type {} is not generic and not indexable".format( format_type(original_type, self.options) @@ -2113,7 +2120,7 @@ def report_protocol_problems( # note: method, attr MAX_ITEMS = 2 # Maximum number of conflicts, missing members, and overloads shown # List of special situations where we don't want to report additional problems - exclusions: dict[type, list[str]] = { + exclusions: dict[type[object], list[str]] = { TypedDictType: ["typing.Mapping"], TupleType: ["typing.Iterable", "typing.Sequence"], } diff --git a/mypy/nodes.py b/mypy/nodes.py index dabfb463cc95..1abc1e6590c5 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -3509,7 +3509,7 @@ class FakeInfo(TypeInfo): def __init__(self, msg: str) -> None: self.msg = msg - def __getattribute__(self, attr: str) -> type: + def __getattribute__(self, attr: str) -> type[object]: # Handle __class__ so that isinstance still works... if attr == "__class__": return object.__getattribute__(self, attr) # type: ignore[no-any-return] diff --git a/mypy/semanal.py b/mypy/semanal.py index 59e4594353f0..4e589ab5bda3 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -2511,7 +2511,10 @@ def analyze_base_classes( try: base = self.expr_to_analyzed_type( - base_expr, allow_placeholder=True, allow_type_any=True + base_expr, + allow_placeholder=True, + allow_type_any=True, + builtin_type_is_type_type=not refers_to_fullname(base_expr, "builtins.type"), ) except TypeTranslationError: name = self.get_name_repr_of_expr(base_expr) @@ -2561,10 +2564,14 @@ def configure_base_classes( elif isinstance(base, TypedDictType): base_types.append(base.fallback) else: - msg = "Invalid base class" - name = self.get_name_repr_of_expr(base_expr) - if name: - msg += f' "{name}"' + if isinstance(base_expr, IndexExpr) and refers_to_fullname( + base_expr.base, "builtins.type" + ): + msg = message_registry.BUILTIN_TYPE_USED_AS_GENERIC + else: + msg = "Invalid base class" + if name := self.get_name_repr_of_expr(base_expr): + msg += f' "{name}"' self.fail(msg, base_expr) info.fallback_to_any = True if self.options.disallow_any_unimported and has_any_from_unimported_type(base): @@ -3827,6 +3834,7 @@ def analyze_alias( name: str, rvalue: Expression, allow_placeholder: bool = False, + builtin_type_is_type_type: bool = False, declared_type_vars: TypeVarLikeList | None = None, all_declared_type_params_names: list[str] | None = None, python_3_12_type_alias: bool = False, @@ -3876,6 +3884,7 @@ def analyze_alias( in_dynamic_func=dynamic, global_scope=global_scope, allowed_alias_tvars=tvar_defs, + builtin_type_is_type_type=builtin_type_is_type_type, alias_type_params_names=all_declared_type_params_names, python_3_12_type_alias=python_3_12_type_alias, ) @@ -3995,6 +4004,9 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool: lvalue.name, rvalue, allow_placeholder=True, + builtin_type_is_type_type=( + (s.type is not None) or not refers_to_fullname(s.rvalue, "builtins.type") + ), declared_type_vars=type_params, all_declared_type_params_names=all_type_params_names, ) @@ -7252,6 +7264,7 @@ def expr_to_analyzed_type( allow_unbound_tvars: bool = False, allow_param_spec_literals: bool = False, allow_unpack: bool = False, + builtin_type_is_type_type: bool = True, ) -> Type | None: if isinstance(expr, CallExpr): # This is a legacy syntax intended mostly for Python 2, we keep it for @@ -7283,6 +7296,9 @@ def expr_to_analyzed_type( allow_unbound_tvars=allow_unbound_tvars, allow_param_spec_literals=allow_param_spec_literals, allow_unpack=allow_unpack, + builtin_type_is_type_type=( + builtin_type_is_type_type or not refers_to_fullname(expr, "builtins.type") + ), ) def analyze_type_expr(self, expr: Expression) -> None: @@ -7308,6 +7324,7 @@ def type_analyzer( report_invalid_types: bool = True, prohibit_self_type: str | None = None, allow_type_any: bool = False, + builtin_type_is_type_type: bool = True, ) -> TypeAnalyser: if tvar_scope is None: tvar_scope = self.tvar_scope @@ -7327,6 +7344,7 @@ def type_analyzer( allow_unpack=allow_unpack, prohibit_self_type=prohibit_self_type, allow_type_any=allow_type_any, + builtin_type_is_type_type=builtin_type_is_type_type, ) tpan.in_dynamic_func = bool(self.function_stack and self.function_stack[-1].is_dynamic()) tpan.global_scope = not self.type and not self.function_stack @@ -7351,6 +7369,7 @@ def anal_type( report_invalid_types: bool = True, prohibit_self_type: str | None = None, allow_type_any: bool = False, + builtin_type_is_type_type: bool = True, ) -> Type | None: """Semantically analyze a type. @@ -7386,6 +7405,7 @@ def anal_type( report_invalid_types=report_invalid_types, prohibit_self_type=prohibit_self_type, allow_type_any=allow_type_any, + builtin_type_is_type_type=builtin_type_is_type_type, ) tag = self.track_incomplete_refs() typ = typ.accept(a) diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index 1cd709b9d603..e957770b9be2 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -758,7 +758,7 @@ def generate_property_stub( rw_properties.append(f"{self._indent}{name}: {inferred_type}") - def get_type_fullname(self, typ: type) -> str: + def get_type_fullname(self, typ: type[object]) -> str: """Given a type, return a string representation""" if typ is Any: # type: ignore[comparison-overlap] return "Any" @@ -769,7 +769,7 @@ def get_type_fullname(self, typ: type) -> str: typename = f"{module_name}.{typename}" return typename - def get_base_types(self, obj: type) -> list[str]: + def get_base_types(self, obj: type[object]) -> list[str]: all_bases = type.mro(obj) if all_bases[-1] is object: # TODO: Is this always object? @@ -781,14 +781,18 @@ def get_base_types(self, obj: type) -> list[str]: # remove the class itself all_bases = all_bases[1:] # Remove base classes of other bases as redundant. - bases: list[type] = [] + bases: list[type[object]] = [] for base in all_bases: if not any(issubclass(b, base) for b in bases): bases.append(base) return [self.strip_or_import(self.get_type_fullname(base)) for base in bases] def generate_class_stub( - self, class_name: str, cls: type, output: list[str], parent_class: ClassInfo | None = None + self, + class_name: str, + cls: type[object], + output: list[str], + parent_class: ClassInfo | None = None, ) -> None: """Generate stub for a single class using runtime introspection. diff --git a/mypy/stubutil.py b/mypy/stubutil.py index 3f917ca7665d..7294ef88492a 100644 --- a/mypy/stubutil.py +++ b/mypy/stubutil.py @@ -311,7 +311,7 @@ def __init__( name: str, self_var: str, docstring: str | None = None, - cls: type | None = None, + cls: type[object] | None = None, parent: ClassInfo | None = None, ) -> None: self.name = name diff --git a/mypy/subtypes.py b/mypy/subtypes.py index a63db93fd9cb..b9df86a6b42f 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1098,6 +1098,30 @@ def visit_type_type(self, left: TypeType) -> bool: # of x is Type[int]. It's unclear what's the right way to address this. return True item = left.item + if ( + right.type.is_protocol + and len(right.type.protocol_members) == 1 + and right.type.protocol_members[0] == "__hash__" + and (symtab := right.type.get("__hash__")) is not None + and isinstance(hash_ := get_proper_type(symtab.type), CallableType) + and len(hash_.arg_names) == 1 + and hash_.arg_names[0] == "self" + and isinstance(ret := get_proper_type(hash_.ret_type), Instance) + and ret.type.fullname == "builtins.int" + ): + if isinstance(item, AnyType): + return True + if isinstance(item, Instance): + if (mtype := item.type.metaclass_type) is None or ( + mtype.type.get("__hash__") is None + ): + return True + supertype = get_proper_type(find_member("__hash__", right, mtype)) + assert supertype is not None + subtype = mypy.typeops.get_protocol_member(mtype, "__hash__", False) + assert subtype is not None + if is_subtype(subtype, supertype, ignore_pos_arg_names=True): + return True if isinstance(item, TypeVarType): item = get_proper_type(item.upper_bound) if isinstance(item, Instance): diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index 4a80207d3ec7..7747eb8f7157 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -313,14 +313,14 @@ def assert_equal(a: object, b: object, fmt: str = "{} != {}") -> None: raise AssertionError(fmt.format(good_repr(a), good_repr(b))) -def typename(t: type) -> str: +def typename(t: type[object]) -> str: if "." in str(t): return str(t).split(".")[-1].rstrip("'>") else: return str(t)[8:-2] -def assert_type(typ: type, value: object) -> None: +def assert_type(typ: type[object], value: object) -> None: __tracebackhide__ = True if type(value) != typ: raise AssertionError(f"Invalid type {typename(type(value))}, expected {typename(typ)}") diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 0c241f5c0f99..77cb01077612 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -155,6 +155,7 @@ def analyze_type_alias( in_dynamic_func: bool = False, global_scope: bool = True, allowed_alias_tvars: list[TypeVarLikeType] | None = None, + builtin_type_is_type_type: bool = True, alias_type_params_names: list[str] | None = None, python_3_12_type_alias: bool = False, ) -> tuple[Type, set[str]]: @@ -175,6 +176,7 @@ def analyze_type_alias( allow_placeholder=allow_placeholder, prohibit_self_type="type alias target", allowed_alias_tvars=allowed_alias_tvars, + builtin_type_is_type_type=builtin_type_is_type_type, alias_type_params_names=alias_type_params_names, python_3_12_type_alias=python_3_12_type_alias, ) @@ -231,6 +233,7 @@ def __init__( prohibit_self_type: str | None = None, allowed_alias_tvars: list[TypeVarLikeType] | None = None, allow_type_any: bool = False, + builtin_type_is_type_type: bool = True, alias_type_params_names: list[str] | None = None, ) -> None: self.api = api @@ -279,6 +282,7 @@ def __init__( self.allow_type_any = allow_type_any self.allow_type_var_tuple = False self.allow_unpack = allow_unpack + self.builtin_type_is_type_type = builtin_type_is_type_type def lookup_qualified( self, name: str, ctx: Context, suppress_errors: bool = False @@ -645,7 +649,9 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ and (self.always_allow_new_syntax or self.options.python_version >= (3, 9)) ): if len(t.args) == 0: - if fullname == "typing.Type": + if fullname == "typing.Type" or ( + self.builtin_type_is_type_type and (fullname == "builtins.type") + ): any_type = self.get_omitted_any(t) return TypeType(any_type, line=t.line, column=t.column) else: diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 5ce80faaee18..a4c917ea7d07 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2287,7 +2287,7 @@ tmp/foo.pyi:8: note: def __add__(self, int, /) -> A tmp/foo.pyi:8: note: @overload tmp/foo.pyi:8: note: def __add__(self, str, /) -> A tmp/foo.pyi:8: note: @overload -tmp/foo.pyi:8: note: def __add__(self, type, /) -> A +tmp/foo.pyi:8: note: def __add__(self, Type[Any], /) -> A tmp/foo.pyi:8: note: Overloaded operator methods can't have wider argument types in overrides [case testOverloadedOperatorMethodOverrideWithSwitchedItemOrder] @@ -3580,7 +3580,7 @@ def foo(arg: Type[Any]): from typing import Type, Any def foo(arg: Type[Any]): reveal_type(arg.__str__) # N: Revealed type is "def () -> builtins.str" - reveal_type(arg.mro()) # N: Revealed type is "builtins.list[builtins.type]" + reveal_type(arg.mro()) # N: Revealed type is "builtins.list[Type[Any]]" [builtins fixtures/type.pyi] [out] @@ -3920,7 +3920,7 @@ def f(a: type) -> None: pass f(3) # E: No overload variant of "f" matches argument type "int" \ # N: Possible overload variants: \ # N: def f(a: Type[User]) -> None \ - # N: def f(a: type) -> None + # N: def f(a: Type[Any]) -> None [builtins fixtures/classmethod.pyi] [out] @@ -5651,8 +5651,7 @@ def f() -> type: return M class C1(six.with_metaclass(M), object): pass # E: Unsupported dynamic base class "six.with_metaclass" class C2(C1, six.with_metaclass(M)): pass # E: Unsupported dynamic base class "six.with_metaclass" class C3(six.with_metaclass(A)): pass # E: Metaclasses not inheriting from "type" are not supported -@six.add_metaclass(A) # E: Metaclasses not inheriting from "type" are not supported \ - # E: Argument 1 to "add_metaclass" has incompatible type "Type[A]"; expected "Type[type]" +@six.add_metaclass(A) # E: Metaclasses not inheriting from "type" are not supported class D3(A): pass class C4(six.with_metaclass(M), metaclass=M): pass # E: Multiple metaclass definitions diff --git a/test-data/unit/check-generic-alias.test b/test-data/unit/check-generic-alias.test index 3ae815a5cd48..f4860857447a 100644 --- a/test-data/unit/check-generic-alias.test +++ b/test-data/unit/check-generic-alias.test @@ -107,7 +107,7 @@ reveal_type(t6) # N: Revealed type is "Tuple[builtins.int, builtins.str]" reveal_type(t7) # N: Revealed type is "builtins.tuple[builtins.int, ...]" reveal_type(t8) # N: Revealed type is "builtins.dict[Any, Any]" reveal_type(t9) # N: Revealed type is "builtins.dict[builtins.int, builtins.str]" -reveal_type(t10) # N: Revealed type is "builtins.type" +reveal_type(t10) # N: Revealed type is "Type[Any]" reveal_type(t11) # N: Revealed type is "Type[builtins.int]" [builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index b8cc0422b749..89d7635e8654 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -515,9 +515,7 @@ Alias[int]("a") # E: Argument 1 to "Node" has incompatible type "str"; expected [out] [case testTypeApplicationCrash] -import types -type[int] # this was crashing, see #2302 (comment) # E: The type "Type[type]" is not generic and not indexable -[builtins fixtures/tuple.pyi] +type[int] # this was crashing, see #2302 (comment) # E: "builtins.type" is indexable as a type hint but neither a generic class nor a generic function -- Generic type aliases diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 8fa1bc1ca1ac..cc7abad5375b 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -1907,7 +1907,7 @@ if issubclass(y): # E: Missing positional argument "t" in call to "issubclass" [case testIsInstanceTooManyArgs] isinstance(1, 1, 1) # E: Too many arguments for "isinstance" \ - # E: Argument 2 to "isinstance" has incompatible type "int"; expected "Union[type, Tuple[Any, ...]]" + # E: Argument 2 to "isinstance" has incompatible type "int"; expected "Union[Type[Any], Tuple[Any, ...]]" x: object if isinstance(x, str, 1): # E: Too many arguments for "isinstance" reveal_type(x) # N: Revealed type is "builtins.object" diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 2f94b5df0f83..0306351ca5aa 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -1486,13 +1486,13 @@ Alias = Literal[3] isinstance(3, Literal[3]) # E: Cannot use isinstance() with Literal type isinstance(3, Alias) # E: Cannot use isinstance() with Literal type \ - # E: Argument 2 to "isinstance" has incompatible type ""; expected "Union[type, Tuple[Any, ...]]" + # E: Argument 2 to "isinstance" has incompatible type ""; expected "Union[Type[Any], Tuple[Any, ...]]" isinstance(3, Renamed[3]) # E: Cannot use isinstance() with Literal type isinstance(3, indirect.Literal[3]) # E: Cannot use isinstance() with Literal type issubclass(int, Literal[3]) # E: Cannot use issubclass() with Literal type issubclass(int, Alias) # E: Cannot use issubclass() with Literal type \ - # E: Argument 2 to "issubclass" has incompatible type ""; expected "Union[type, Tuple[Any, ...]]" + # E: Argument 2 to "issubclass" has incompatible type ""; expected "Union[Type[Any], Tuple[Any, ...]]" issubclass(int, Renamed[3]) # E: Cannot use issubclass() with Literal type issubclass(int, indirect.Literal[3]) # E: Cannot use issubclass() with Literal type [builtins fixtures/isinstancelist.pyi] diff --git a/test-data/unit/check-lowercase.test b/test-data/unit/check-lowercase.test index ab6d68929f8e..17daa478b1d6 100644 --- a/test-data/unit/check-lowercase.test +++ b/test-data/unit/check-lowercase.test @@ -45,10 +45,10 @@ x = 3 # E: Incompatible types in assignment (expression has type "int", variabl [case testTypeLowercaseSettingOff] # flags: --python-version 3.9 --no-force-uppercase-builtins -x: type[type] +x: type[type] # E: Type[...] can't contain another Type[...] y: int -y = x # E: Incompatible types in assignment (expression has type "type[type]", variable has type "int") +y = x # E: Incompatible types in assignment (expression has type "type[Any]", variable has type "int") [case testLowercaseSettingOnTypeAnnotationHint] # flags: --python-version 3.9 --no-force-uppercase-builtins diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index d740708991d0..640532f699d5 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -656,6 +656,37 @@ else: reveal_type(y["model"]) # N: Revealed type is "Union[TypedDict('__main__.Model1', {'key': Literal['A']}), TypedDict('__main__.Model2', {'key': Literal['B']})]" [builtins fixtures/primitives.pyi] +[case testNarrowingTypingTypeTypeAndBuiltinTypeTypeExplicitAny] +# flags: --python-version 3.9 --warn-unreachable --disallow-any-generics + +from typing import Any, Type + +t1: Type[Any] +t2: type[Any] + +class C: ... + +if isinstance(t1, C): + reveal_type(t1) # E: Statement is unreachable +if isinstance(t2, C): + reveal_type(t2) # E: Statement is unreachable +[builtins fixtures/isinstance.pyi] + +[case testNarrowingTypingTypeTypeAndBuiltinTypeTypeImplicitAny] +# flags: --python-version 3.9 --warn-unreachable --disallow-any-generics + +from typing import Type + +t1: Type # E: Missing type parameters for generic type "Type" +t2: type # E: Missing type parameters for generic type "type" +class C: ... + +if isinstance(t1, C): + reveal_type(t1) # E: Statement is unreachable +if isinstance(t2, C): + reveal_type(t2) # E: Statement is unreachable +[builtins fixtures/isinstance.pyi] + [case testNarrowingExprPropagation] from typing import Union from typing_extensions import Literal @@ -1442,7 +1473,7 @@ else: raw: tuple[type, ...] if isinstance(some, raw): - reveal_type(some) # N: Revealed type is "Union[builtins.int, __main__.Base]" + reveal_type(some) # N: Revealed type is "Any" else: reveal_type(some) # N: Revealed type is "Union[builtins.int, __main__.Base]" [builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index fe02ac3ccd5e..fb4607f24465 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -3240,3 +3240,54 @@ class b: x = x[1] # E: Cannot resolve name "x" (possible cyclic definition) y = 1[y] # E: Value of type "int" is not indexable \ # E: Cannot determine type of "y" + +[case testBuiltinTypeType] +# flags: --python-version 3.10 --disallow-any-generics + +import types +from typing import Any, cast, Union, TypeVar +from typing_extensions import TypeAlias + +a: type # E: Missing type parameters for generic type "type" +reveal_type(a) # N: Revealed type is "Type[Any]" + +b: Any +c = cast(type, b) # E: Missing type parameters for generic type "type" +reveal_type(c) # N: Revealed type is "Type[Any]" + +d: list[type] # E: Missing type parameters for generic type "type" +reveal_type(d) # N: Revealed type is "builtins.list[Type[Any]]" + +class E(list[type]): ... # E: Missing type parameters for generic type "type" +reveal_type(E()[0]) # N: Revealed type is "Type[Any]" + +class F(tuple[type]): ... # E: Missing type parameters for generic type "type" +reveal_type(F()[0]) # N: Revealed type is "Type[Any]" + +class G(tuple[list[Union[type, int]], ...]): ... # E: Missing type parameters for generic type "type" +reveal_type(G()[0]) # N: Revealed type is "builtins.list[Union[Type[Any], builtins.int]]" + +h: Union[type, int] # E: Missing type parameters for generic type "type" +reveal_type(h) # N: Revealed type is "Union[Type[Any], builtins.int]" + +i: type | int # E: Missing type parameters for generic type "type" +reveal_type(i) # N: Revealed type is "Union[Type[Any], builtins.int]" + +j: TypeAlias = type # E: Missing type parameters for generic type "type" +class K(metaclass=j): ... # E: Invalid metaclass "j" +l: j +reveal_type(l) # N: Revealed type is "Type[Any]" + +m = type +class N(metaclass=m): ... + +O = TypeVar("O", bound=type) # E: Missing type parameters for generic type "type" +def p(q: O) -> O: ... +reveal_type(p(str)) # N: Revealed type is "def () -> builtins.str" +p(1) # E: Value of type variable "O" of "p" cannot be "int" + +type[str](1) # E: "GenericAlias" not callable +r = type[str]("r", (), {}) # E: "GenericAlias" not callable +class S(type[str]): ... # E: "builtins.type" is indexable as a type hint but neither a generic class nor a generic function + +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 5ed2351e33e6..63dfe729477c 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -323,6 +323,50 @@ var: MyHashable = C() # E: Incompatible types in assignment (expression has typ # N: Following member(s) of "C" have conflicts: \ # N: __my_hash__: expected "Callable[[], int]", got "None" +[case testTypeTypeIsHashable] +# flags: --python-version 3.9 + +from typing import Any, Hashable + +def f(x: Hashable) -> None: ... + +def g0(x: type[Any]) -> None: + f(x) + +class C1: ... +def g1(x: type[C1]) -> None: + f(x) + +class C2(metaclass=type): ... +def g2(x: type[C2]) -> None: + f(x) + +class M1(type): ... +class C3(metaclass=M1): ... +def g3(x: type[C3]) -> None: + f(x) + +class M2(M1): + __hash__ = None +class C4(metaclass=M2): ... +def g4(x: type[C4]) -> None: + f(x) # E: Argument 1 to "f" has incompatible type "Type[C4]"; expected "Hashable" + +class M3(M1): + def __hash__(self) -> None: ... +class C5(metaclass=M3): ... +def g5(x: type[C5]) -> None: + f(x) # E: Argument 1 to "f" has incompatible type "Type[C5]"; expected "Hashable" + +class M4(M3): + def __hash__(self) -> int: ... # type: ignore +class C6(metaclass=M4): ... +def g6(x: type[C6]) -> None: + f(x) + +[builtins fixtures/dict.pyi] +[typing fixtures/typing-full.pyi] + [case testNoneDisablesProtocolSubclassingWithStrictOptional] from typing import Protocol diff --git a/test-data/unit/fixtures/dict.pyi b/test-data/unit/fixtures/dict.pyi index ed2287511161..e1dae1cda407 100644 --- a/test-data/unit/fixtures/dict.pyi +++ b/test-data/unit/fixtures/dict.pyi @@ -6,8 +6,18 @@ from _typeshed import SupportsKeysAndGetItem import _typeshed from typing import ( - TypeVar, Generic, Iterable, Iterator, Mapping, Tuple, overload, Optional, Union, Sequence, + Any, + Generic, + Iterable, + Iterator, + Mapping, + overload, + Optional, Self, + Sequence, + Tuple, + TypeVar, + Union, ) T = TypeVar('T') @@ -57,8 +67,9 @@ class function: pass class float: pass class complex: pass class bool(int): pass -class ellipsis: pass +class ellipsis: + __class__: object class BaseException: pass -def isinstance(x: object, t: Union[type, Tuple[type, ...]]) -> bool: pass +def isinstance(x: object, t: Union[type[Any], Tuple[type[Any], ...]]) -> bool: pass # type: ignore[misc] def iter(__iterable: Iterable[T]) -> Iterator[T]: pass diff --git a/test-data/unit/fixtures/isinstance.pyi b/test-data/unit/fixtures/isinstance.pyi index 12cef2035c2b..ae75fb204faf 100644 --- a/test-data/unit/fixtures/isinstance.pyi +++ b/test-data/unit/fixtures/isinstance.pyi @@ -7,7 +7,7 @@ class object: class type: def __init__(self, x) -> None: pass - def __or__(self, other: type) -> type: pass + def __or__(self, other: type[Any]) -> type[Any]: pass class tuple(Generic[T]): pass diff --git a/test-data/unit/fixtures/tuple.pyi b/test-data/unit/fixtures/tuple.pyi index 3b62d7fc1513..8f965de634eb 100644 --- a/test-data/unit/fixtures/tuple.pyi +++ b/test-data/unit/fixtures/tuple.pyi @@ -1,7 +1,18 @@ # Builtins stub used in tuple-related test cases. import _typeshed -from typing import Iterable, Iterator, TypeVar, Generic, Sequence, Optional, overload, Tuple, Type +from typing import ( + Any, + Iterable, + Iterator, + TypeVar, + Generic, + Sequence, + Optional, + overload, + Tuple, + Type, +) _T = TypeVar("_T") _Tco = TypeVar('_Tco', covariant=True) @@ -48,7 +59,7 @@ class list(Sequence[_T], Generic[_T]): def __contains__(self, item: object) -> bool: ... def __iter__(self) -> Iterator[_T]: ... -def isinstance(x: object, t: type) -> bool: pass +def isinstance(x: object, t: type[Any]) -> bool: pass # type: ignore[misc] class BaseException: pass