@@ -239,6 +239,29 @@ def parse(
239239 strip_function_bodies = strip_function_bodies ,
240240 path = fnam ,
241241 ).visit (ast )
242+
243+ except RecursionError as e :
244+ # For very complex expressions it is possible to hit recursion limit
245+ # before reaching a leaf node.
246+ # Should reject at top level instead at bottom, since bottom would already
247+ # be at the threshold of the recursion limit, and may fail again later.
248+ # E.G. x1+x2+x3+...+xn -> BinOp(left=BinOp(left=BinOp(left=...
249+ try :
250+ # But to prove that is the cause of this particular recursion error,
251+ # try to walk the tree using builtin visitor
252+ ast3 .NodeVisitor ().visit (ast )
253+ except RecursionError :
254+ errors .report (
255+ - 1 , - 1 , "Source expression too complex to parse" , blocker = False , code = codes .MISC
256+ )
257+
258+ tree = MypyFile ([], [], False , {})
259+
260+ else :
261+ # re-raise original recursion error if it *can* be unparsed,
262+ # maybe this is some other issue that shouldn't be silenced/misdirected
263+ raise e
264+
242265 except SyntaxError as e :
243266 message = e .msg
244267 if feature_version > sys .version_info .minor and message .startswith ("invalid syntax" ):
@@ -381,7 +404,7 @@ def __init__(
381404 def note (self , msg : str , line : int , column : int ) -> None :
382405 self .errors .report (line , column , msg , severity = "note" , code = codes .SYNTAX )
383406
384- def fail (self , msg : ErrorMessage , line : int , column : int , blocker : bool = True ) -> None :
407+ def fail (self , msg : ErrorMessage , line : int , column : int , blocker : bool ) -> None :
385408 if blocker or not self .options .ignore_errors :
386409 # Make sure self.errors reflects any type ignores that we have parsed
387410 self .errors .set_file_ignored_lines (
@@ -406,6 +429,7 @@ def visit(self, node: AST | None) -> Any:
406429 method = "visit_" + node .__class__ .__name__
407430 visitor = getattr (self , method )
408431 self .visitor_cache [typeobj ] = visitor
432+
409433 return visitor (node )
410434
411435 def set_line (self , node : N , n : AstNode ) -> N :
@@ -921,7 +945,12 @@ def do_func_def(
921945 ):
922946 if n .returns :
923947 # PEP 484 disallows both type annotations and type comments
924- self .fail (message_registry .DUPLICATE_TYPE_SIGNATURES , lineno , n .col_offset )
948+ self .fail (
949+ message_registry .DUPLICATE_TYPE_SIGNATURES ,
950+ lineno ,
951+ n .col_offset ,
952+ blocker = False ,
953+ )
925954 arg_types = [
926955 (
927956 a .type_annotation
@@ -933,7 +962,12 @@ def do_func_def(
933962 else :
934963 # PEP 484 disallows both type annotations and type comments
935964 if n .returns or any (a .type_annotation is not None for a in args ):
936- self .fail (message_registry .DUPLICATE_TYPE_SIGNATURES , lineno , n .col_offset )
965+ self .fail (
966+ message_registry .DUPLICATE_TYPE_SIGNATURES ,
967+ lineno ,
968+ n .col_offset ,
969+ blocker = False ,
970+ )
937971 translated_args : list [Type ] = TypeConverter (
938972 self .errors , line = lineno , override_column = n .col_offset
939973 ).translate_expr_list (func_type_ast .argtypes )
@@ -948,7 +982,7 @@ def do_func_def(
948982 except SyntaxError :
949983 stripped_type = n .type_comment .split ("#" , 2 )[0 ].strip ()
950984 err_msg = message_registry .TYPE_COMMENT_SYNTAX_ERROR_VALUE .format (stripped_type )
951- self .fail (err_msg , lineno , n .col_offset )
985+ self .fail (err_msg , lineno , n .col_offset , blocker = False )
952986 if n .type_comment and n .type_comment [0 ] not in ["(" , "#" ]:
953987 self .note (
954988 "Suggestion: wrap argument types in parentheses" , lineno , n .col_offset
@@ -970,7 +1004,12 @@ def do_func_def(
9701004 func_type = None
9711005 if any (arg_types ) or return_type :
9721006 if len (arg_types ) != 1 and any (isinstance (t , EllipsisType ) for t in arg_types ):
973- self .fail (message_registry .ELLIPSIS_WITH_OTHER_TYPEARGS , lineno , n .col_offset )
1007+ self .fail (
1008+ message_registry .ELLIPSIS_WITH_OTHER_TYPEARGS ,
1009+ lineno ,
1010+ n .col_offset ,
1011+ blocker = False ,
1012+ )
9741013 elif len (arg_types ) > len (arg_kinds ):
9751014 self .fail (
9761015 message_registry .TYPE_SIGNATURE_TOO_MANY_ARGS ,
@@ -1097,7 +1136,12 @@ def make_argument(
10971136 annotation = arg .annotation
10981137 type_comment = arg .type_comment
10991138 if annotation is not None and type_comment is not None :
1100- self .fail (message_registry .DUPLICATE_TYPE_SIGNATURES , arg .lineno , arg .col_offset )
1139+ self .fail (
1140+ message_registry .DUPLICATE_TYPE_SIGNATURES ,
1141+ arg .lineno ,
1142+ arg .col_offset ,
1143+ blocker = False ,
1144+ )
11011145 arg_type = None
11021146 if annotation is not None :
11031147 arg_type = TypeConverter (self .errors , line = arg .lineno ).visit (annotation )
@@ -1118,7 +1162,7 @@ def make_argument(
11181162 return argument
11191163
11201164 def fail_arg (self , msg : str , arg : ast3 .arg ) -> None :
1121- self .fail (ErrorMessage (msg ), arg .lineno , arg .col_offset )
1165+ self .fail (ErrorMessage (msg ), arg .lineno , arg .col_offset , blocker = True )
11221166
11231167 # ClassDef(identifier name,
11241168 # expr* bases,
@@ -1164,18 +1208,21 @@ def validate_type_param(self, type_param: ast_TypeVar) -> None:
11641208 message_registry .TYPE_VAR_YIELD_EXPRESSION_IN_BOUND ,
11651209 type_param .lineno ,
11661210 type_param .col_offset ,
1211+ blocker = True ,
11671212 )
11681213 if isinstance (incorrect_expr , ast3 .NamedExpr ):
11691214 self .fail (
11701215 message_registry .TYPE_VAR_NAMED_EXPRESSION_IN_BOUND ,
11711216 type_param .lineno ,
11721217 type_param .col_offset ,
1218+ blocker = True ,
11731219 )
11741220 if isinstance (incorrect_expr , ast3 .Await ):
11751221 self .fail (
11761222 message_registry .TYPE_VAR_AWAIT_EXPRESSION_IN_BOUND ,
11771223 type_param .lineno ,
11781224 type_param .col_offset ,
1225+ blocker = True ,
11791226 )
11801227
11811228 def translate_type_params (self , type_params : list [Any ]) -> list [TypeParam ]:
@@ -1790,11 +1837,26 @@ def validate_type_alias(self, n: ast_TypeAlias) -> None:
17901837 if incorrect_expr is None :
17911838 return
17921839 if isinstance (incorrect_expr , (ast3 .Yield , ast3 .YieldFrom )):
1793- self .fail (message_registry .TYPE_ALIAS_WITH_YIELD_EXPRESSION , n .lineno , n .col_offset )
1840+ self .fail (
1841+ message_registry .TYPE_ALIAS_WITH_YIELD_EXPRESSION ,
1842+ n .lineno ,
1843+ n .col_offset ,
1844+ blocker = True ,
1845+ )
17941846 if isinstance (incorrect_expr , ast3 .NamedExpr ):
1795- self .fail (message_registry .TYPE_ALIAS_WITH_NAMED_EXPRESSION , n .lineno , n .col_offset )
1847+ self .fail (
1848+ message_registry .TYPE_ALIAS_WITH_NAMED_EXPRESSION ,
1849+ n .lineno ,
1850+ n .col_offset ,
1851+ blocker = True ,
1852+ )
17961853 if isinstance (incorrect_expr , ast3 .Await ):
1797- self .fail (message_registry .TYPE_ALIAS_WITH_AWAIT_EXPRESSION , n .lineno , n .col_offset )
1854+ self .fail (
1855+ message_registry .TYPE_ALIAS_WITH_AWAIT_EXPRESSION ,
1856+ n .lineno ,
1857+ n .col_offset ,
1858+ blocker = True ,
1859+ )
17981860
17991861 # TypeAlias(identifier name, type_param* type_params, expr value)
18001862 def visit_TypeAlias (self , n : ast_TypeAlias ) -> TypeAliasStmt | AssignmentStmt :
0 commit comments