Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ std::string typeUSR(Type type) {
if (!type)
return "";

if (type->is<ModuleType>()) {
// 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();
}
Expand All @@ -280,6 +286,13 @@ std::string declTypeUSR(const ValueDecl *D) {
if (!D)
return "";

if (isa<ModuleDecl>(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))
Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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) {
Expand Down
27 changes: 27 additions & 0 deletions test/Frontend/ast-dump-json-no-crash.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}