Repository: python/mypy

Issue:
When there's a syntax error, print the comment used
Given the Python code:

```python
def big_function(
        x1, # type: Optional[int]
        x2, # type: Optional[int]
        x3, # type: Optional[int]
        x4, # type: Optional[int]
        x5, # type: Optional[int]]
        x6, # type: Optional[int]
        x7, # type: Optional[int]
):
    # type: (...) -> int
    return 123
```

Sometimes it's difficult to spot which comment has a syntax error. It would be nicer if mypy could print the comment it's looking at, to make it more obvious.

```
$ mypy --py2 bar.py
bar.py:1: error: syntax error in type comment
```


Discussion:
I agree, but I think this should be reported upstream to https://github.com/python/typed_ast.
It looks to me like the comment parsing happens in mypy: https://github.com/python/mypy/blob/master/mypy/fastparse2.py#L310-L312 . Presumably `n.type_comment` has the comment we're interested in?
Yes, I think it is possible for Python 2 to do this in mypy without changes to ``typed_ast``. On the contrary Python 3 type annotations are parsed by Python parser and should be syntactically correct.

Resolving patch:
diff --git a/mypy/fastparse.py b/mypy/fastparse.py
--- a/mypy/fastparse.py
+++ b/mypy/fastparse.py
@@ -192,7 +192,9 @@ def parse_type_comment(type_comment: str,
         typ = ast3_parse(type_comment, '<type_comment>', 'eval')
     except SyntaxError as e:
         if errors is not None:
-            errors.report(line, e.offset, TYPE_COMMENT_SYNTAX_ERROR, blocker=True)
+            stripped_type = type_comment.split("#", 2)[0].strip()
+            err_msg = "{} '{}'".format(TYPE_COMMENT_SYNTAX_ERROR, stripped_type)
+            errors.report(line, e.offset, err_msg, blocker=True)
             return False, None
         else:
             raise
@@ -470,8 +472,10 @@ def do_func_def(self, n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef],
                 if self.in_method_scope() and len(arg_types) < len(args):
                     arg_types.insert(0, AnyType(TypeOfAny.special_form))
             except SyntaxError:
-                self.fail(TYPE_COMMENT_SYNTAX_ERROR, lineno, n.col_offset)
-                if n.type_comment and n.type_comment[0] != "(":
+                stripped_type = n.type_comment.split("#", 2)[0].strip()
+                err_msg = "{} '{}'".format(TYPE_COMMENT_SYNTAX_ERROR, stripped_type)
+                self.fail(err_msg, lineno, n.col_offset)
+                if n.type_comment and n.type_comment[0] not in ["(", "#"]:
                     self.note('Suggestion: wrap argument types in parentheses',
                               lineno, n.col_offset)
                 arg_types = [AnyType(TypeOfAny.from_error)] * len(args)
diff --git a/mypy/fastparse2.py b/mypy/fastparse2.py
--- a/mypy/fastparse2.py
+++ b/mypy/fastparse2.py
@@ -358,7 +358,9 @@ def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement:
                 if self.in_method_scope() and len(arg_types) < len(args):
                     arg_types.insert(0, AnyType(TypeOfAny.special_form))
             except SyntaxError:
-                self.fail(TYPE_COMMENT_SYNTAX_ERROR, lineno, n.col_offset)
+                stripped_type = type_comment.split("#", 2)[0].strip()
+                err_msg = "{} '{}'".format(TYPE_COMMENT_SYNTAX_ERROR, stripped_type)
+                self.fail(err_msg, lineno, n.col_offset)
                 arg_types = [AnyType(TypeOfAny.from_error)] * len(args)
                 return_type = AnyType(TypeOfAny.from_error)
         else:


Test patch:
diff --git a/test-data/unit/check-fastparse.test b/test-data/unit/check-fastparse.test
--- a/test-data/unit/check-fastparse.test
+++ b/test-data/unit/check-fastparse.test
@@ -4,7 +4,7 @@
 
 [case testFastParseTypeCommentSyntaxError]
 
-x = None # type: a : b  # E: syntax error in type comment
+x = None # type: a : b  # E: syntax error in type comment 'a : b'
 
 [case testFastParseInvalidTypeComment]
 
@@ -14,13 +14,13 @@ x = None # type: a + b  # E: Invalid type comment or annotation
 -- This happens in both parsers.
 [case testFastParseFunctionAnnotationSyntaxError]
 
-def f():  # E: syntax error in type comment # N: Suggestion: wrap argument types in parentheses
+def f():  # E: syntax error in type comment 'None -> None' # N: Suggestion: wrap argument types in parentheses
   # type: None -> None
   pass
 
 [case testFastParseFunctionAnnotationSyntaxErrorSpaces]
 
-def f():  # E: syntax error in type comment # N: Suggestion: wrap argument types in parentheses
+def f():  # E: syntax error in type comment 'None -> None' # N: Suggestion: wrap argument types in parentheses
   # type:             None -> None
   pass
 
diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test
--- a/test-data/unit/check-literal.test
+++ b/test-data/unit/check-literal.test
@@ -18,7 +18,7 @@ reveal_type(g2)  # E: Revealed type is 'def (x: Literal['A B'])'
 
 [case testLiteralInvalidTypeComment]
 from typing_extensions import Literal
-def f(x):  # E: syntax error in type comment
+def f(x):  # E: syntax error in type comment '(A[) -> None'
     # type: (A[) -> None
     pass
 
diff --git a/test-data/unit/parse-errors.test b/test-data/unit/parse-errors.test
--- a/test-data/unit/parse-errors.test
+++ b/test-data/unit/parse-errors.test
@@ -113,86 +113,117 @@ file:1: error: invalid syntax
 0
 x = 0 # type: A A
 [out]
-file:2: error: syntax error in type comment
+file:2: error: syntax error in type comment 'A A'
 
 [case testInvalidTypeComment2]
 0
 x = 0 # type: A[
 [out]
-file:2: error: syntax error in type comment
+file:2: error: syntax error in type comment 'A['
 
 [case testInvalidTypeComment3]
 0
 x = 0 # type:
 [out]
-file:2: error: syntax error in type comment
+file:2: error: syntax error in type comment ''
 
 [case testInvalidTypeComment4]
 0
 x = 0 # type: *
 [out]
-file:2: error: syntax error in type comment
+file:2: error: syntax error in type comment '*'
+
+[case testInvalidTypeComment5]
+0
+x = 0 # type:# some comment
+[out]
+file:2: error: syntax error in type comment ''
+
+[case testInvalidTypeComment6]
+0
+x = 0 # type: *# comment #6
+[out]
+file:2: error: syntax error in type comment '*'
+
+[case testInvalidTypeComment7]
+0
+x = 0 # type: A B #comment #7
+[out]
+file:2: error: syntax error in type comment 'A B'
 
 [case testInvalidSignatureInComment1]
 def f(): # type: x
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment 'x'
 file:1: note: Suggestion: wrap argument types in parentheses
 
 [case testInvalidSignatureInComment2]
 def f(): # type:
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment ''
 
 [case testInvalidSignatureInComment3]
 def f(): # type: (
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '('
 
 [case testInvalidSignatureInComment4]
 def f(): # type: (.
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '(.'
 
 [case testInvalidSignatureInComment5]
 def f(): # type: (x
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '(x'
 
 [case testInvalidSignatureInComment6]
 def f(): # type: (x)
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '(x)'
 
 [case testInvalidSignatureInComment7]
 def f(): # type: (x) -
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '(x) -'
 
 [case testInvalidSignatureInComment8]
 def f(): # type: (x) ->
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '(x) ->'
 
 [case testInvalidSignatureInComment9]
 def f(): # type: (x) -> .
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '(x) -> .'
 
 [case testInvalidSignatureInComment10]
 def f(): # type: (x) -> x x
   pass
 [out]
-file:1: error: syntax error in type comment
+file:1: error: syntax error in type comment '(x) -> x x'
+
+[case testInvalidSignatureInComment11]
+def f(): # type: # abc comment
+  pass
+[out]
+file:1: error: syntax error in type comment ''
+
+[case testInvalidSignatureInComment12]
+def f(): # type: (x) -> x x # comment #2
+  pass
+[out]
+file:1: error: syntax error in type comment '(x) -> x x'
+
 
 [case testDuplicateSignatures1]
 def f() -> None: # type: () -> None