Skip to content

Commit

Permalink
Make PEP 695 constructs give a reasonable error message (#16013)
Browse files Browse the repository at this point in the history
Mypy does not yet support PEP 695

Fixes #16011, linking #15238
  • Loading branch information
hauntsaninja authored and JukkaL committed Oct 10, 2023
1 parent e78df55 commit 4c963c9
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 1 deletion.
31 changes: 31 additions & 0 deletions mypy/fastparse.py
Expand Up @@ -144,6 +144,11 @@ def ast3_parse(
NamedExpr = ast3.NamedExpr
Constant = ast3.Constant

if sys.version_info >= (3, 12):
ast_TypeAlias = ast3.TypeAlias
else:
ast_TypeAlias = Any

if sys.version_info >= (3, 10):
Match = ast3.Match
MatchValue = ast3.MatchValue
Expand Down Expand Up @@ -936,6 +941,14 @@ def do_func_def(
arg_types = [AnyType(TypeOfAny.from_error)] * len(args)
return_type = AnyType(TypeOfAny.from_error)
else:
if sys.version_info >= (3, 12) and n.type_params:
self.fail(
ErrorMessage("PEP 695 generics are not yet supported", code=codes.VALID_TYPE),
n.type_params[0].lineno,
n.type_params[0].col_offset,
blocker=False,
)

arg_types = [a.type_annotation for a in args]
return_type = TypeConverter(
self.errors, line=n.returns.lineno if n.returns else lineno
Expand Down Expand Up @@ -1110,6 +1123,14 @@ def visit_ClassDef(self, n: ast3.ClassDef) -> ClassDef:
self.class_and_function_stack.append("C")
keywords = [(kw.arg, self.visit(kw.value)) for kw in n.keywords if kw.arg]

if sys.version_info >= (3, 12) and n.type_params:
self.fail(
ErrorMessage("PEP 695 generics are not yet supported", code=codes.VALID_TYPE),
n.type_params[0].lineno,
n.type_params[0].col_offset,
blocker=False,
)

cdef = ClassDef(
n.name,
self.as_required_block(n.body),
Expand Down Expand Up @@ -1717,6 +1738,16 @@ def visit_MatchOr(self, n: MatchOr) -> OrPattern:
node = OrPattern([self.visit(pattern) for pattern in n.patterns])
return self.set_line(node, n)

def visit_TypeAlias(self, n: ast_TypeAlias) -> AssignmentStmt:
self.fail(
ErrorMessage("PEP 695 type aliases are not yet supported", code=codes.VALID_TYPE),
n.lineno,
n.col_offset,
blocker=False,
)
node = AssignmentStmt([NameExpr(n.name.id)], self.visit(n.value))
return self.set_line(node, n)


class TypeConverter:
def __init__(
Expand Down
4 changes: 3 additions & 1 deletion mypy/test/helpers.py
Expand Up @@ -241,7 +241,9 @@ def num_skipped_suffix_lines(a1: list[str], a2: list[str]) -> int:


def testfile_pyversion(path: str) -> tuple[int, int]:
if path.endswith("python311.test"):
if path.endswith("python312.test"):
return 3, 12
elif path.endswith("python311.test"):
return 3, 11
elif path.endswith("python310.test"):
return 3, 10
Expand Down
2 changes: 2 additions & 0 deletions mypy/test/testcheck.py
Expand Up @@ -43,6 +43,8 @@
typecheck_files.remove("check-python310.test")
if sys.version_info < (3, 11):
typecheck_files.remove("check-python311.test")
if sys.version_info < (3, 12):
typecheck_files.remove("check-python312.test")

# Special tests for platforms with case-insensitive filesystems.
if sys.platform not in ("darwin", "win32"):
Expand Down
59 changes: 59 additions & 0 deletions test-data/unit/check-python312.test
@@ -0,0 +1,59 @@
[case test695TypeAlias]
type MyInt = int # E: PEP 695 type aliases are not yet supported

def f(x: MyInt) -> MyInt:
return reveal_type(x) # N: Revealed type is "builtins.int"

type MyList[T] = list[T] # E: PEP 695 type aliases are not yet supported \
# E: Name "T" is not defined

def g(x: MyList[int]) -> MyList[int]: # E: Variable "__main__.MyList" is not valid as a type \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
return reveal_type(x) # N: Revealed type is "MyList?[builtins.int]"

[case test695Class]
class MyGen[T]: # E: PEP 695 generics are not yet supported
def __init__(self, x: T) -> None: # E: Name "T" is not defined
self.x = x

def f(x: MyGen[int]): # E: "MyGen" expects no type arguments, but 1 given
reveal_type(x.x) # N: Revealed type is "Any"

[case test695Function]
def f[T](x: T) -> T: # E: PEP 695 generics are not yet supported \
# E: Name "T" is not defined
return reveal_type(x) # N: Revealed type is "Any"

reveal_type(f(1)) # N: Revealed type is "Any"

async def g[T](x: T) -> T: # E: PEP 695 generics are not yet supported \
# E: Name "T" is not defined
return reveal_type(x) # N: Revealed type is "Any"

reveal_type(g(1)) # E: Value of type "Coroutine[Any, Any, Any]" must be used \
# N: Are you missing an await? \
# N: Revealed type is "typing.Coroutine[Any, Any, Any]"

[case test695TypeVar]
from typing import Callable
type Alias1[T: int] = list[T] # E: PEP 695 type aliases are not yet supported
type Alias2[**P] = Callable[P, int] # E: PEP 695 type aliases are not yet supported \
# E: Value of type "int" is not indexable \
# E: Name "P" is not defined
type Alias3[*Ts] = tuple[*Ts] # E: PEP 695 type aliases are not yet supported \
# E: Type expected within [...] \
# E: The type "Type[Tuple[Any, ...]]" is not generic and not indexable \
# E: Name "Ts" is not defined

class Cls1[T: int]: ... # E: PEP 695 generics are not yet supported
class Cls2[**P]: ... # E: PEP 695 generics are not yet supported
class Cls3[*Ts]: ... # E: PEP 695 generics are not yet supported

def func1[T: int](x: T) -> T: ... # E: PEP 695 generics are not yet supported
def func2[**P](x: Callable[P, int]) -> Callable[P, str]: ... # E: PEP 695 generics are not yet supported \
# E: The first argument to Callable must be a list of types, parameter specification, or "..." \
# N: See https://mypy.readthedocs.io/en/stable/kinds_of_types.html#callable-types-and-lambdas \
# E: Name "P" is not defined
def func3[*Ts](x: tuple[*Ts]) -> tuple[int, *Ts]: ... # E: PEP 695 generics are not yet supported \
# E: Name "Ts" is not defined
[builtins fixtures/tuple.pyi]

0 comments on commit 4c963c9

Please sign in to comment.