diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 23c9019700934..699b754721f63 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -260,6 +260,12 @@ std::string typeUSR(Type type) { if (!type) return ""; + if (type->is()) { + // ASTMangler does not support "module types". This can appear, for + // example, on the left-hand side of a `DotSyntaxBaseIgnoredExpr` for a + // module-qualified free function call: `Swift.print()`. + return ""; + } if (type->hasArchetype()) { type = type->mapTypeOutOfEnvironment(); } @@ -280,6 +286,13 @@ std::string declTypeUSR(const ValueDecl *D) { if (!D) return ""; + if (isa(D)) { + // ASTMangler does not support "module types". This can appear, for + // example, on the left-hand side of a `DotSyntaxBaseIgnoredExpr` for a + // module-qualified free function call: `Swift.print()`. + return ""; + } + std::string usr; llvm::raw_string_ostream os(usr); if (swift::ide::printDeclTypeUSR(D, os)) @@ -1471,7 +1484,11 @@ namespace { printFlag(value.isLocalCapture(), "is_local_capture"); printFlag(value.isDynamicSelfMetadata(), "is_dynamic_self_metadata"); if (auto *D = value.getDecl()) { - printRec(D, Label::always("decl")); + // We print the decl ref, not the full decl, to avoid infinite + // recursion when a function captures itself (and also because + // those decls are already printed elsewhere, so we don't need to + // print what could be a very large amount of information twice). + printDeclRefField(D, Label::always("decl")); } if (auto *E = value.getExpr()) { printRec(E, Label::always("expr")); @@ -1896,10 +1913,8 @@ namespace { printFoot(); } void visitAnyPattern(AnyPattern *P, Label label) { - if (P->isAsyncLet()) { - printCommon(P, "async_let ", label); - } printCommon(P, "pattern_any", label); + printFlag(P->isAsyncLet(), "async_let", DeclModifierColor); printFoot(); } void visitTypedPattern(TypedPattern *P, Label label) { diff --git a/test/Frontend/ast-dump-json-no-crash.swift b/test/Frontend/ast-dump-json-no-crash.swift index d7bc2a052ef16..e4db14fdc364e 100644 --- a/test/Frontend/ast-dump-json-no-crash.swift +++ b/test/Frontend/ast-dump-json-no-crash.swift @@ -484,3 +484,30 @@ dynamic func toBeReplaced(arg: Int) {} @_dynamicReplacement(for: toBeReplaced(arg:)) func toReplaceWith(arg: Int) {} + +// Regression test: Swift 6.2 and earlier crashed trying to form the type USR +// of the "module type" of a `DotSyntaxBaseIgnoredExpr` when calling a +// module-qualified free function. +func moduleTypeUSRRegressionTest() { + Swift.print("") +} + +// Regression test: When a function captures another function, don't print the +// entire captured decl. This causes infinite recursion in the dumper when a +// local (nested) function captures itself. +func outerFn() { + func innerFun(shouldRecurse: Bool) { + if shouldRecurse { + innerFun(shouldRecurse: false) + } + } + innerFun(shouldRecurse: true) +} + +// Regression test: Discarded async lets were calling `printCommon` twice, +// which resulted in invalid JSON (and not-so-great S-expression output) +// either. +func discardedAsyncLet() async { + func someTask() async {} + async let _ = someTask() +}