Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PEP 695] Generate error if 3.12 type alias is called #17320

Merged
merged 3 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4659,6 +4659,8 @@ def visit_type_application(self, tapp: TypeApplication) -> Type:
is due to slight differences in how type arguments are applied and checked.
"""
if isinstance(tapp.expr, RefExpr) and isinstance(tapp.expr.node, TypeAlias):
if tapp.expr.node.python_3_12_type_alias:
return self.named_type("typing.TypeAliasType")
# Subscription of a (generic) alias in runtime context, expand the alias.
item = instantiate_type_alias(
tapp.expr.node,
Expand Down Expand Up @@ -4721,6 +4723,8 @@ class LongName(Generic[T]): ...
x = A()
y = cast(A, ...)
"""
if alias.python_3_12_type_alias:
return self.named_type("typing.TypeAliasType")
if isinstance(alias.target, Instance) and alias.target.invalid: # type: ignore[misc]
# An invalid alias, error already has been reported
return AnyType(TypeOfAny.from_error)
Expand Down
6 changes: 6 additions & 0 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3578,6 +3578,7 @@ def f(x: B[T]) -> T: ... # without T, Any would be used here
"_is_recursive",
"eager",
"tvar_tuple_index",
"python_3_12_type_alias",
)

__match_args__ = ("name", "target", "alias_tvars", "no_args")
Expand All @@ -3593,6 +3594,7 @@ def __init__(
no_args: bool = False,
normalized: bool = False,
eager: bool = False,
python_3_12_type_alias: bool = False,
) -> None:
self._fullname = fullname
self.target = target
Expand All @@ -3605,6 +3607,7 @@ def __init__(
# it is the cached value.
self._is_recursive: bool | None = None
self.eager = eager
self.python_3_12_type_alias = python_3_12_type_alias
self.tvar_tuple_index = None
for i, t in enumerate(alias_tvars):
if isinstance(t, mypy.types.TypeVarTupleType):
Expand Down Expand Up @@ -3675,6 +3678,7 @@ def serialize(self) -> JsonDict:
"normalized": self.normalized,
"line": self.line,
"column": self.column,
"python_3_12_type_alias": self.python_3_12_type_alias,
}
return data

Expand All @@ -3692,6 +3696,7 @@ def deserialize(cls, data: JsonDict) -> TypeAlias:
normalized = data["normalized"]
line = data["line"]
column = data["column"]
python_3_12_type_alias = data["python_3_12_type_alias"]
return cls(
target,
fullname,
Expand All @@ -3700,6 +3705,7 @@ def deserialize(cls, data: JsonDict) -> TypeAlias:
alias_tvars=cast(List[mypy.types.TypeVarLikeType], alias_tvars),
no_args=no_args,
normalized=normalized,
python_3_12_type_alias=python_3_12_type_alias,
)


Expand Down
2 changes: 2 additions & 0 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -3922,6 +3922,7 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
alias_tvars=alias_tvars,
no_args=no_args,
eager=eager,
python_3_12_type_alias=pep_695,
)
if isinstance(s.rvalue, (IndexExpr, CallExpr, OpExpr)) and (
not isinstance(rvalue, OpExpr)
Expand Down Expand Up @@ -5368,6 +5369,7 @@ def visit_type_alias_stmt(self, s: TypeAliasStmt) -> None:
alias_tvars=alias_tvars,
no_args=False,
eager=eager,
python_3_12_type_alias=True,
)

existing = self.current_symbol_table().get(s.name.name)
Expand Down
47 changes: 47 additions & 0 deletions test-data/unit/check-python312.test
Original file line number Diff line number Diff line change
Expand Up @@ -1313,3 +1313,50 @@ reveal_type(E[int]().mm(b'x')) # N: Revealed type is "Tuple[__main__.E[builtins
reveal_type(F[str]().m()) # N: Revealed type is "__main__.F[builtins.str]"
reveal_type(F[str]().mm(b'x')) # N: Revealed type is "Tuple[__main__.F[builtins.str], builtins.bytes]"
[builtins fixtures/tuple.pyi]

[case testPEP695CallAlias]
# mypy: enable-incomplete-feature=NewGenericSyntax

class C:
def __init__(self, x: str) -> None: ...
type A = C

class D[T]: pass
type B[T] = D[T]

reveal_type(A) # N: Revealed type is "typing.TypeAliasType"
reveal_type(B) # N: Revealed type is "typing.TypeAliasType"
reveal_type(B[int]) # N: Revealed type is "typing.TypeAliasType"

A(1) # E: "TypeAliasType" not callable
B[int]() # E: "TypeAliasType" not callable

A2 = C
B2 = D
A2(1) # E: Argument 1 to "C" has incompatible type "int"; expected "str"
B2[int]()
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testPEP695IncrementalTypeAliasKinds]
# flags: --enable-incomplete-feature=NewGenericSyntax
import a

[file a.py]
from b import A

[file a.py.2]
from b import A, B, C
A()
B()
C()

[file b.py]
from typing_extensions import TypeAlias
type A = int
B = int
C: TypeAlias = int
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]
[out2]
tmp/a.py:2: error: "TypeAliasType" not callable
7 changes: 7 additions & 0 deletions test-data/unit/check-type-aliases.test
Original file line number Diff line number Diff line change
Expand Up @@ -1075,11 +1075,15 @@ x: TestType = 42
y: TestType = 'a'
z: TestType = object() # E: Incompatible types in assignment (expression has type "object", variable has type "Union[int, str]")

reveal_type(TestType) # N: Revealed type is "typing.TypeAliasType"
TestType() # E: "TypeAliasType" not callable

class A:
ClassAlias = TypeAliasType("ClassAlias", int)
xc: A.ClassAlias = 1
yc: A.ClassAlias = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testTypeAliasTypeInvalid]
from typing_extensions import TypeAliasType
Expand All @@ -1094,6 +1098,7 @@ T3 = TypeAliasType("T3", -1) # E: Invalid type: try using Literal[-1] instead?
t3: T3
reveal_type(t3) # N: Revealed type is "Any"
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testTypeAliasTypeGeneric]
from typing import Callable, Dict, Generic, TypeVar, Tuple
Expand Down Expand Up @@ -1140,6 +1145,7 @@ ParamAlias2 = TypeAliasType("ParamAlias2", G[P, T], type_params=(P, T))
xp: ParamAlias2[[int], str]
reveal_type(xp) # N: Revealed type is "__main__.G[[builtins.int], builtins.str]"
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]

[case testTypeAliasTypeInvalidGeneric]
from typing_extensions import TypeAliasType, TypeVarTuple, ParamSpec
Expand Down Expand Up @@ -1200,6 +1206,7 @@ class A(Generic[T]):
x: A.Ta11 = {"a": 1}
reveal_type(x) # N: Revealed type is "builtins.dict[builtins.str, Any]"
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]

[case testTypeAliasTypeNoUnpackInTypeParams311]
# flags: --python-version 3.11
Expand Down
1 change: 1 addition & 0 deletions test-data/unit/fixtures/typing-full.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ TypedDict = 0
NoReturn = 0
NewType = 0
Self = 0
Unpack = 0

T = TypeVar('T')
T_co = TypeVar('T_co', covariant=True)
Expand Down
Loading