diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 2f4122bf3bfa..386bfb94800c 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -130,6 +130,8 @@ def ast3_parse(source: Union[str, bytes], filename: str, mode: str, INVALID_TYPE_IGNORE: Final = 'Invalid "type: ignore" comment' +INVALID_SLICE_ERROR: Final = 'Slice usage in type annotation is invalid' + TYPE_IGNORE_PATTERN = re.compile(r'[^#]*#\s*type:\s*ignore\s*(.*)') @@ -1560,12 +1562,12 @@ def visit_Subscript(self, n: ast3.Subscript) -> Type: if (isinstance(sliceval, ast3.Slice) or (isinstance(sliceval, ast3.Tuple) and any(isinstance(x, ast3.Slice) for x in sliceval.elts))): - self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1)) + self.fail(INVALID_SLICE_ERROR, self.line, getattr(n, 'col_offset', -1)) return AnyType(TypeOfAny.from_error) else: # Python 3.8 or earlier use a different AST structure for subscripts if not isinstance(n.slice, Index): - self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1)) + self.fail(INVALID_SLICE_ERROR, self.line, getattr(n, 'col_offset', -1)) return AnyType(TypeOfAny.from_error) sliceval = n.slice.value diff --git a/test-data/unit/check-fastparse.test b/test-data/unit/check-fastparse.test index 497ed9b1d2b2..03aa1e4c3214 100644 --- a/test-data/unit/check-fastparse.test +++ b/test-data/unit/check-fastparse.test @@ -322,7 +322,7 @@ x @= 1 from typing import Dict x = None # type: Dict[x: y] [out] -main:3: error: syntax error in type comment +main:3: error: Slice usage in type annotation is invalid [case testPrintStatementTrailingCommaFastParser_python2] diff --git a/test-data/unit/parse.test b/test-data/unit/parse.test index 22b1ab28481d..f9bbb7dda5a4 100644 --- a/test-data/unit/parse.test +++ b/test-data/unit/parse.test @@ -949,6 +949,88 @@ main:1: error: invalid syntax [out version>=3.10] main:1: error: invalid syntax. Perhaps you forgot a comma? +[case testSliceInAnnotation39] +# flags: --python-version 3.9 +a: Annotated[int, 1:2] # E: Slice usage in type annotation is invalid +b: Dict[int, x:y] # E: Slice usage in type annotation is invalid +c: Dict[x:y] # E: Slice usage in type annotation is invalid +[out] + +[case testSliceInAnnotation38] +# flags: --python-version 3.8 +a: Annotated[int, 1:2] # E: Slice usage in type annotation is invalid +b: Dict[int, x:y] # E: Slice usage in type annotation is invalid +c: Dict[x:y] # E: Slice usage in type annotation is invalid +[out] + +[case testSliceInAnnotationTypeComment39] +# flags: --python-version 3.9 +a = None # type: Annotated[int, 1:2] # E: Slice usage in type annotation is invalid +b = None # type: Dict[int, x:y] # E: Slice usage in type annotation is invalid +c = None # type: Dict[x:y] # E: Slice usage in type annotation is invalid +[out] + +[case testCorrectSlicesInAnnotations39] +# flags: --python-version 3.9 +a: Annotated[int, slice(1, 2)] +b: Dict[int, {x:y}] +c: Dict[{x:y}] +[out] +MypyFile:1( + AssignmentStmt:2( + NameExpr(a) + TempNode:2( + Any) + Annotated?[int?, None]) + AssignmentStmt:3( + NameExpr(b) + TempNode:3( + Any) + Dict?[int?, None]) + AssignmentStmt:4( + NameExpr(c) + TempNode:4( + Any) + Dict?[None])) + +[case testCorrectSlicesInAnnotations38] +# flags: --python-version 3.8 +a: Annotated[int, slice(1, 2)] +b: Dict[int, {x:y}] +c: Dict[{x:y}] +[out] +MypyFile:1( + AssignmentStmt:2( + NameExpr(a) + TempNode:2( + Any) + Annotated?[int?, None]) + AssignmentStmt:3( + NameExpr(b) + TempNode:3( + Any) + Dict?[int?, None]) + AssignmentStmt:4( + NameExpr(c) + TempNode:4( + Any) + Dict?[None])) + +[case testSliceInList39] +# flags: --python-version 3.9 +x = [1, 2][1:2] +[out] +MypyFile:1( + AssignmentStmt:2( + NameExpr(x) + IndexExpr:2( + ListExpr:2( + IntExpr(1) + IntExpr(2)) + SliceExpr:2( + IntExpr(1) + IntExpr(2))))) + [case testDictionaryExpression] {} {1:x}