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

Initial attempt at fixing issue-17706 #17707

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions mypy/dmypy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from mypy.dmypy_os import alive, kill
from mypy.dmypy_util import DEFAULT_STATUS_FILE, receive, send
from mypy.ipc import IPCClient, IPCException
from mypy.main import RECURSION_LIMIT
from mypy.util import check_python_version, get_terminal_width, should_force_color
from mypy.version import __version__

Expand Down Expand Up @@ -267,6 +268,10 @@ class BadStatus(Exception):
def main(argv: list[str]) -> None:
"""The code is top-down."""
check_python_version("dmypy")

# set recursion limit consistent with mypy/main.py
sys.setrecursionlimit(RECURSION_LIMIT)

args = parser.parse_args(argv)
if not args.action:
parser.print_usage()
Expand Down
24 changes: 24 additions & 0 deletions mypy/fastparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,29 @@ def parse(
strip_function_bodies=strip_function_bodies,
path=fnam,
).visit(ast)

except RecursionError as e:
# For very complex expressions it is possible to hit recursion limit
# before reaching a leaf node.
# Should reject at top level instead at bottom, since bottom would already
# be at the threshold of the recursion limit, and may fail again later.
# E.G. x1+x2+x3+...+xn -> BinOp(left=BinOp(left=BinOp(left=...
try:
# But to prove that is the cause of this particular recursion error,
# try to walk the tree using builtin visitor
ast3.NodeVisitor().visit(ast)
except RecursionError:
errors.report(
-1, -1, "Source expression too complex to parse", blocker=False, code=codes.MISC
)

tree = MypyFile([], [], False, {})

else:
# re-raise original recursion error if it *can* be unparsed,
# maybe this is some other issue that shouldn't be silenced/misdirected
raise e

except SyntaxError as e:
# alias to please mypyc
is_py38_or_earlier = sys.version_info < (3, 9)
Expand Down Expand Up @@ -414,6 +437,7 @@ def visit(self, node: AST | None) -> Any:
method = "visit_" + node.__class__.__name__
visitor = getattr(self, method)
self.visitor_cache[typeobj] = visitor

return visitor(node)

def set_line(self, node: N, n: AstNode) -> N:
Expand Down
3 changes: 2 additions & 1 deletion mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

orig_stat: Final = os.stat
MEM_PROFILE: Final = False # If True, dump memory profile
RECURSION_LIMIT: Final = 2**14


def stat_proxy(path: str) -> os.stat_result:
Expand Down Expand Up @@ -63,7 +64,7 @@ def main(
util.check_python_version("mypy")
t0 = time.time()
# To log stat() calls: os.stat = stat_proxy
sys.setrecursionlimit(2**14)
sys.setrecursionlimit(RECURSION_LIMIT)
if args is None:
args = sys.argv[1:]

Expand Down
Loading