Skip to content

Commit 36bae62

Browse files
committed
Print Sendable conformances for clang types
1 parent e130826 commit 36bae62

File tree

6 files changed

+65
-8
lines changed

6 files changed

+65
-8
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ struct PrintOptions {
235235
/// Whether to print unavailable parts of the AST.
236236
bool SkipUnavailable = false;
237237

238+
/// Whether to print synthesized extensions created by '@_nonSendable', even
239+
/// if SkipImplicit or SkipUnavailable is set.
240+
bool AlwaysPrintNonSendableExtensions = true;
241+
238242
bool SkipSwiftPrivateClangDecls = false;
239243

240244
/// Whether to skip internal stdlib declarations.
@@ -667,6 +671,7 @@ struct PrintOptions {
667671
PO.ShouldQualifyNestedDeclarations = QualifyNestedDeclarations::TypesOnly;
668672
PO.PrintParameterSpecifiers = true;
669673
PO.SkipImplicit = true;
674+
PO.AlwaysPrintNonSendableExtensions = false;
670675
PO.AlwaysTryPrintParameterLabels = true;
671676
return PO;
672677
}

lib/AST/ASTPrinter.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,24 @@ bool ShouldPrintChecker::shouldPrint(const Pattern *P,
17691769
return ShouldPrint;
17701770
}
17711771

1772+
bool isNonSendableExtension(const Decl *D) {
1773+
ASTContext &ctx = D->getASTContext();
1774+
1775+
const ExtensionDecl *ED = dyn_cast<ExtensionDecl>(D);
1776+
if (!ED || !ED->getAttrs().isUnavailable(ctx))
1777+
return false;
1778+
1779+
auto nonSendable =
1780+
ED->getExtendedNominal()->getAttrs().getEffectiveSendableAttr();
1781+
if (!isa_and_nonnull<NonSendableAttr>(nonSendable))
1782+
return false;
1783+
1784+
// GetImplicitSendableRequest::evaluate() creates its extension with the
1785+
// attribute's AtLoc, so this is a good way to quickly check if the extension
1786+
// was synthesized for an '@_nonSendable' attribute.
1787+
return ED->getLocFromSource() == nonSendable->AtLoc;
1788+
}
1789+
17721790
bool ShouldPrintChecker::shouldPrint(const Decl *D,
17731791
const PrintOptions &Options) {
17741792
#if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB
@@ -1791,15 +1809,18 @@ bool ShouldPrintChecker::shouldPrint(const Decl *D,
17911809
return false;
17921810
}
17931811

1794-
if (Options.SkipImplicit && D->isImplicit()) {
1795-
const auto &IgnoreList = Options.TreatAsExplicitDeclList;
1796-
if (std::find(IgnoreList.begin(), IgnoreList.end(), D) == IgnoreList.end())
1812+
// Optionally skip these checks for extensions synthesized for '@_nonSendable'
1813+
if (!Options.AlwaysPrintNonSendableExtensions || !isNonSendableExtension(D)) {
1814+
if (Options.SkipImplicit && D->isImplicit()) {
1815+
const auto &IgnoreList = Options.TreatAsExplicitDeclList;
1816+
if (!llvm::is_contained(IgnoreList, D))
17971817
return false;
1798-
}
1818+
}
17991819

1800-
if (Options.SkipUnavailable &&
1801-
D->getAttrs().isUnavailable(D->getASTContext()))
1802-
return false;
1820+
if (Options.SkipUnavailable &&
1821+
D->getAttrs().isUnavailable(D->getASTContext()))
1822+
return false;
1823+
}
18031824

18041825
if (Options.ExplodeEnumCaseDecls) {
18051826
if (isa<EnumElementDecl>(D))

lib/AST/Module.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,28 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
909909
void ModuleDecl::getDisplayDecls(SmallVectorImpl<Decl*> &Results) const {
910910
// FIXME: Should this do extra access control filtering?
911911
FORWARD(getDisplayDecls, (Results));
912+
913+
// Force Sendable on all types, which might synthesize some extensions.
914+
// FIXME: We can remove this if @_nonSendable stops creating extensions.
915+
for (auto result : Results) {
916+
if (auto NTD = dyn_cast<NominalTypeDecl>(result))
917+
(void)swift::isSendableType(const_cast<ModuleDecl *>(this),
918+
NTD->getDeclaredInterfaceType());
919+
}
920+
921+
// Re-add anything from synthesized file units...
922+
auto oldCutoff = Results.size();
923+
for (auto file : getFiles())
924+
if (auto synthFile = dyn_cast<SynthesizedFileUnit>(file))
925+
synthFile->getDisplayDecls(Results);
926+
927+
// And then remove anything that was already in the results.
928+
auto oldResults = makeArrayRef(Results).take_front(oldCutoff);
929+
auto uniqueEnd = std::remove_if(Results.begin() + oldCutoff, Results.end(),
930+
[&](auto result) {
931+
return llvm::is_contained(oldResults, result);
932+
});
933+
Results.erase(uniqueEnd, Results.end());
912934
}
913935

914936
ProtocolConformanceRef

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4004,6 +4004,8 @@ NormalProtocolConformance *GetImplicitSendableRequest::evaluate(
40044004
auto inherits = ctx.AllocateCopy(makeArrayRef(
40054005
InheritedEntry(TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
40064006
/*isUnchecked*/true)));
4007+
// If you change the use of AtLoc in the ExtensionDecl, make sure you
4008+
// update isNonSendableExtension() in ASTPrinter.
40074009
auto extension = ExtensionDecl::create(ctx, attrMakingUnavailable->AtLoc,
40084010
nullptr, inherits,
40094011
nominal->getModuleScopeContext(),

test/IDE/print_objc_concurrency_interface.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,17 @@ import _Concurrency
2323
// CHECK-SAME: @unchecked Sendable
2424

2525
// CHECK-LABEL: class NonSendableClass
26+
// CHECK: @available(*, unavailable)
27+
// CHECK-NEXT: extension NonSendableClass : @unchecked Sendable {
2628

2729
// CHECK-LABEL: class AuditedSendable :
2830
// CHECK-SAME: @unchecked Sendable
2931

3032
// CHECK-LABEL: class AuditedNonSendable
33+
// CHECK: @available(*, unavailable)
34+
// CHECK-NEXT: extension AuditedNonSendable : @unchecked Sendable {
3135

3236
// CHECK-LABEL: class AuditedBoth
37+
// CHECK: @available(*, unavailable)
38+
// CHECK-NEXT: extension AuditedBoth : @unchecked Sendable {
39+

test/Serialization/Recovery/private-conformances.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// RUN: %target-swift-frontend -emit-module -DPROTOCOL_LIB -DAFTER %s -module-name protocol_lib -emit-module-path %t/protocol_lib.swiftmodule
1111

1212
// The conforming library's types should still deserialize.
13-
// RUN: %target-swift-ide-test -print-module -source-filename %s -module-to-print conforms_lib -I %t | %FileCheck %s
13+
// RUN: %target-swift-ide-test -print-module -source-filename %s -module-to-print conforms_lib -I %t -allow-compiler-errors | %FileCheck %s
1414

1515
// Protocols that use a missing protocol have to disappear (see the FileCheck
1616
// lines).

0 commit comments

Comments
 (0)