Skip to content
Merged
26 changes: 19 additions & 7 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@ def analyze_var_ref(self, var: Var, context: Context) -> Type:
if var.type:
var_type = get_proper_type(var.type)
if isinstance(var_type, Instance):
if var.fullname == "typing.Any":
# The typeshed type is 'object'; give a more useful type in runtime context
return self.named_type("typing._SpecialForm")
if self.is_literal_context() and var_type.last_known_value is not None:
return var_type.last_known_value
if var.name in {"True", "False"}:
Expand Down Expand Up @@ -4331,16 +4334,25 @@ def visit_index_with_type(
return self.nonliteral_tuple_index_helper(left_type, index)
elif isinstance(left_type, TypedDictType):
return self.visit_typeddict_index_expr(left_type, e.index)
elif (
isinstance(left_type, FunctionLike)
and left_type.is_type_obj()
and left_type.type_object().is_enum
):
return self.visit_enum_index_expr(left_type.type_object(), e.index, e)
elif isinstance(left_type, TypeVarType) and not self.has_member(
elif isinstance(left_type, FunctionLike) and left_type.is_type_obj():
if left_type.type_object().is_enum:
return self.visit_enum_index_expr(left_type.type_object(), e.index, e)
elif left_type.type_object().type_vars:
return self.named_type("types.GenericAlias")
elif (
left_type.type_object().fullname == "builtins.type"
and self.chk.options.python_version >= (3, 9)
):
# builtins.type is special: it's not generic in stubs, but it supports indexing
return self.named_type("typing._SpecialForm")

if isinstance(left_type, TypeVarType) and not self.has_member(
left_type.upper_bound, "__getitem__"
):
return self.visit_index_with_type(left_type.upper_bound, e, original_type)
elif isinstance(left_type, Instance) and left_type.type.fullname == "typing._SpecialForm":
# Allow special forms to be indexed and used to create union types
return self.named_type("typing._SpecialForm")
else:
result, method_type = self.check_method_call_by_name(
"__getitem__", left_type, [e.index], [ARG_POS], e, original_type=original_type
Expand Down
2 changes: 1 addition & 1 deletion mypy/stubgenc.py
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ def generate_property_stub(

def get_type_fullname(self, typ: type) -> str:
"""Given a type, return a string representation"""
if typ is Any:
if typ is Any: # type: ignore[comparison-overlap]
return "Any"
typename = getattr(typ, "__qualname__", typ.__name__)
module_name = self.get_obj_module(typ)
Expand Down
6 changes: 3 additions & 3 deletions mypyc/test-data/fixtures/typing-full.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ class _SpecialForm:

cast = 0
overload = 0
Any = 0
Union = 0
Any = object()
Optional = 0
TypeVar = 0
Generic = 0
Expand All @@ -28,11 +27,12 @@ Type = 0
no_type_check = 0
ClassVar = 0
Final = 0
Literal = 0
TypedDict = 0
NoReturn = 0
NewType = 0
Callable: _SpecialForm
Union: _SpecialForm
Literal: _SpecialForm

T = TypeVar('T')
T_co = TypeVar('T_co', covariant=True)
Expand Down
3 changes: 3 additions & 0 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -4786,12 +4786,15 @@ def g(x: Type[S]) -> str:
return reveal_type(x * 0) # N: Revealed type is "builtins.str"

[case testMetaclassGetitem]
import types

class M(type):
def __getitem__(self, key) -> int: return 1

class A(metaclass=M): pass

reveal_type(A[M]) # N: Revealed type is "builtins.int"
[builtins fixtures/tuple.pyi]

[case testMetaclassSelfType]
from typing import TypeVar, Type
Expand Down
5 changes: 2 additions & 3 deletions test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -1779,10 +1779,10 @@ def Arg(x, y): pass
F = Callable[[Arg(int, 'x')], int] # E: Invalid argument constructor "__main__.Arg"

[case testCallableParsingFromExpr]

from typing import Callable, List
from mypy_extensions import Arg, VarArg, KwArg
import mypy_extensions
import types # Needed for type checking

def WrongArg(x, y): return y
# Note that for this test, the 'Value of type "int" is not indexable' errors are silly,
Expand All @@ -1799,11 +1799,10 @@ L = Callable[[Arg(name='x', type=int)], int] # ok
# I have commented out the following test because I don't know how to expect the "defined here" note part of the error.
# M = Callable[[Arg(gnome='x', type=int)], int] E: Invalid type alias: expression is not a valid type E: Unexpected keyword argument "gnome" for "Arg"
N = Callable[[Arg(name=None, type=int)], int] # ok
O = Callable[[List[Arg(int)]], int] # E: Invalid type alias: expression is not a valid type # E: Value of type "int" is not indexable # E: Type expected within [...] # E: The type "Type[List[Any]]" is not generic and not indexable
O = Callable[[List[Arg(int)]], int] # E: Invalid type alias: expression is not a valid type # E: Value of type "int" is not indexable # E: Type expected within [...]
P = Callable[[mypy_extensions.VarArg(int)], int] # ok
Q = Callable[[Arg(int, type=int)], int] # E: Invalid type alias: expression is not a valid type # E: Value of type "int" is not indexable # E: "Arg" gets multiple values for keyword argument "type"
R = Callable[[Arg(int, 'x', name='y')], int] # E: Invalid type alias: expression is not a valid type # E: Value of type "int" is not indexable # E: "Arg" gets multiple values for keyword argument "name"

[builtins fixtures/dict.pyi]

[case testCallableParsing]
Expand Down
7 changes: 5 additions & 2 deletions test-data/unit/check-generics.test
Original file line number Diff line number Diff line change
Expand Up @@ -454,11 +454,13 @@ A[int, str, int]() # E: Type application has too many types (2 expected)
[out]

[case testInvalidTypeApplicationType]
import types
a: A
class A: pass
a[A]() # E: Value of type "A" is not indexable
A[A]() # E: The type "Type[A]" is not generic and not indexable
[out]
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testTypeApplicationArgTypes]
from typing import TypeVar, Generic
Expand Down Expand Up @@ -513,8 +515,9 @@ 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
[out]
[builtins fixtures/tuple.pyi]


-- Generic type aliases
Expand Down
52 changes: 52 additions & 0 deletions test-data/unit/check-python312.test
Original file line number Diff line number Diff line change
Expand Up @@ -1591,3 +1591,55 @@ c: E[str]
d: E[int] # E: Type argument "int" of "E" must be a subtype of "str"
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testPEP695TypeAliasWithDifferentTargetTypes]
# flags: --enable-incomplete-feature=NewGenericSyntax
import types # We need GenericAlias from here, and test stubs don't bring in 'types'
from typing import Any, Callable, List, Literal, TypedDict

# Test that various type expressions don't generate false positives as type alias
# values, as they are type checked as expressions. There is a similar test case in
# pythoneval.test that uses typeshed stubs.

class C[T]: pass

class TD(TypedDict):
x: int

type A1 = type[int]
type A2 = type[int] | None
type A3 = None | type[int]
type A4 = type[Any]

type B1[**P, R] = Callable[P, R] | None
type B2[**P, R] = None | Callable[P, R]
type B3 = Callable[[str], int]
type B4 = Callable[..., int]

type C1 = A1 | None
type C2 = None | A1

type D1 = Any | None
type D2 = None | Any

type E1 = List[int]
type E2 = List[int] | None
type E3 = None | List[int]

type F1 = Literal[1]
type F2 = Literal['x'] | None
type F3 = None | Literal[True]

type G1 = tuple[int, Any]
type G2 = tuple[int, Any] | None
type G3 = None | tuple[int, Any]

type H1 = TD
type H2 = TD | None
type H3 = None | TD

type I1 = C[int]
type I2 = C[Any] | None
type I3 = None | C[TD]
[builtins fixtures/type.pyi]
[typing fixtures/typing-full.pyi]
3 changes: 2 additions & 1 deletion test-data/unit/check-type-object-type-inference.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# flags: --python-version 3.9
from typing import TypeVar, Generic, Type
from abc import abstractmethod
import types # Explicitly bring in stubs for 'types'

T = TypeVar('T')
class E(Generic[T]):
Expand Down Expand Up @@ -37,5 +38,5 @@ def i(f: F):
f.f(tuple[int,tuple[int,str]]).e( (27,(28,'z')) ) # OK
reveal_type(f.f(tuple[int,tuple[int,str]]).e) # N: Revealed type is "def (t: Tuple[builtins.int, Tuple[builtins.int, builtins.str]]) -> builtins.str"

x = tuple[int,str][str] # E: The type "Type[Tuple[Any, ...]]" is not generic and not indexable
x = tuple[int,str][str] # False negative
[builtins fixtures/tuple.pyi]
4 changes: 3 additions & 1 deletion test-data/unit/fixtures/typing-async.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ from abc import abstractmethod, ABCMeta

cast = 0
overload = 0
Any = 0
Any = object()
Union = 0
Optional = 0
TypeVar = 0
Expand Down Expand Up @@ -125,3 +125,5 @@ class AsyncContextManager(Generic[T]):
def __aenter__(self) -> Awaitable[T]: pass
# Use Any because not all the precise types are in the fixtures.
def __aexit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> Awaitable[Any]: pass

class _SpecialForm: pass
7 changes: 5 additions & 2 deletions test-data/unit/fixtures/typing-full.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class GenericMeta(type): pass

class _SpecialForm:
def __getitem__(self, index: Any) -> Any: ...
def __or__(self, other): ...
def __ror__(self, other): ...
class TypeVar:
def __init__(self, name, *args, bound=None): ...
def __or__(self, other): ...
Expand All @@ -21,7 +23,7 @@ class TypeVarTuple: ...
def cast(t, o): ...
def assert_type(o, t): ...
overload = 0
Any = 0
Any = object()
Optional = 0
Generic = 0
Protocol = 0
Expand All @@ -31,14 +33,14 @@ Type = 0
no_type_check = 0
ClassVar = 0
Final = 0
Literal = 0
TypedDict = 0
NoReturn = 0
NewType = 0
Self = 0
Unpack = 0
Callable: _SpecialForm
Union: _SpecialForm
Literal: _SpecialForm

T = TypeVar('T')
T_co = TypeVar('T_co', covariant=True)
Expand Down Expand Up @@ -216,3 +218,4 @@ class TypeAliasType:
) -> None: ...

def __or__(self, other: Any) -> Any: ...
def __ror__(self, other: Any) -> Any: ...
2 changes: 1 addition & 1 deletion test-data/unit/fixtures/typing-medium.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

cast = 0
overload = 0
Any = 0
Any = object()
Union = 0
Optional = 0
TypeVar = 0
Expand Down
4 changes: 3 additions & 1 deletion test-data/unit/fixtures/typing-namedtuple.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
TypeVar = 0
Generic = 0
Any = 0
Any = object()
overload = 0
Type = 0
Literal = 0
Expand All @@ -26,3 +26,5 @@ class NamedTuple(tuple[Any, ...]):
def __init__(self, typename: str, fields: Iterable[tuple[str, Any]] = ...) -> None: ...
@overload
def __init__(self, typename: str, fields: None = None, **kwargs: Any) -> None: ...

class _SpecialForm: pass
5 changes: 3 additions & 2 deletions test-data/unit/fixtures/typing-override.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
TypeVar = 0
Generic = 0
Any = 0
Any = object()
overload = 0
Type = 0
Literal = 0
Expand All @@ -21,5 +21,6 @@ class Mapping(Iterable[KT], Generic[KT, T_co]):
def keys(self) -> Iterable[T]: pass # Approximate return type
def __getitem__(self, key: T) -> T_co: pass


def override(__arg: T) -> T: ...

class _SpecialForm: pass
4 changes: 3 additions & 1 deletion test-data/unit/fixtures/typing-typeddict-iror.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ from abc import ABCMeta
cast = 0
assert_type = 0
overload = 0
Any = 0
Any = object()
Union = 0
Optional = 0
TypeVar = 0
Expand Down Expand Up @@ -64,3 +64,5 @@ class _TypedDict(Mapping[str, object]):
def __ror__(self, __value: dict[str, Any]) -> dict[str, object]: ...
# supposedly incompatible definitions of __or__ and __ior__
def __ior__(self, __value: Self) -> Self: ... # type: ignore[misc]

class _SpecialForm: pass
4 changes: 3 additions & 1 deletion test-data/unit/fixtures/typing-typeddict.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ from abc import ABCMeta
cast = 0
assert_type = 0
overload = 0
Any = 0
Any = object()
Union = 0
Optional = 0
TypeVar = 0
Expand Down Expand Up @@ -71,3 +71,5 @@ class _TypedDict(Mapping[str, object]):
def pop(self, k: NoReturn, default: T = ...) -> object: ...
def update(self: T, __m: T) -> None: ...
def __delitem__(self, k: NoReturn) -> None: ...

class _SpecialForm: pass
4 changes: 3 additions & 1 deletion test-data/unit/lib-stub/types.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ class ModuleType:
__file__: str
def __getattr__(self, name: str) -> Any: pass

class GenericAlias: ...
class GenericAlias:
def __or__(self, o): ...
def __ror__(self, o): ...

if sys.version_info >= (3, 10):
class NoneType:
Expand Down
4 changes: 3 additions & 1 deletion test-data/unit/lib-stub/typing.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
cast = 0
assert_type = 0
overload = 0
Any = 0
Any = object()
Union = 0
Optional = 0
TypeVar = 0
Expand Down Expand Up @@ -63,3 +63,5 @@ class Coroutine(Awaitable[V], Generic[T, U, V]): pass
def final(meth: T) -> T: pass

def reveal_type(__obj: T) -> T: pass

class _SpecialForm: pass
Loading