Skip to content

Commit 8805d94

Browse files
committed
[ASTDumper] Print decl-refs, not full decls, for function captures.
This avoids infinite recursion when a function captures itself; e.g., ```swift func foo() { func bar() { bar() } bar() } ``` It also just avoids printing unnecessarily verbose information, since those decls would have already been dumped elsewhere in the tree.
1 parent 7cca6d6 commit 8805d94

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

lib/AST/ASTDumper.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1484,7 +1484,11 @@ namespace {
14841484
printFlag(value.isLocalCapture(), "is_local_capture");
14851485
printFlag(value.isDynamicSelfMetadata(), "is_dynamic_self_metadata");
14861486
if (auto *D = value.getDecl()) {
1487-
printRec(D, Label::always("decl"));
1487+
// We print the decl ref, not the full decl, to avoid infinite
1488+
// recursion when a function captures itself (and also because
1489+
// those decls are already printed elsewhere, so we don't need to
1490+
// print what could be a very large amount of information twice).
1491+
printDeclRefField(D, Label::always("decl"));
14881492
}
14891493
if (auto *E = value.getExpr()) {
14901494
printRec(E, Label::always("expr"));

test/Frontend/ast-dump-json-no-crash.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,3 +491,15 @@ func toReplaceWith(arg: Int) {}
491491
func moduleTypeUSRRegressionTest() {
492492
Swift.print("")
493493
}
494+
495+
// Regression test: When a function captures another function, don't print the
496+
// entire captured decl. This causes infinite recursion in the dumper when a
497+
// local (nested) function captures itself.
498+
func outerFn() {
499+
func innerFun(shouldRecurse: Bool) {
500+
if shouldRecurse {
501+
innerFun(shouldRecurse: false)
502+
}
503+
}
504+
innerFun(shouldRecurse: true)
505+
}

0 commit comments

Comments
 (0)