Print Sendable conformances for clang types

This commit is contained in:
Becca Royal-Gordon
2021-10-27 14:00:57 -07:00
parent e130826686
commit 36bae62b19
6 changed files with 65 additions and 8 deletions

View File

@@ -235,6 +235,10 @@ struct PrintOptions {
/// Whether to print unavailable parts of the AST. /// Whether to print unavailable parts of the AST.
bool SkipUnavailable = false; bool SkipUnavailable = false;
/// Whether to print synthesized extensions created by '@_nonSendable', even
/// if SkipImplicit or SkipUnavailable is set.
bool AlwaysPrintNonSendableExtensions = true;
bool SkipSwiftPrivateClangDecls = false; bool SkipSwiftPrivateClangDecls = false;
/// Whether to skip internal stdlib declarations. /// Whether to skip internal stdlib declarations.
@@ -667,6 +671,7 @@ struct PrintOptions {
PO.ShouldQualifyNestedDeclarations = QualifyNestedDeclarations::TypesOnly; PO.ShouldQualifyNestedDeclarations = QualifyNestedDeclarations::TypesOnly;
PO.PrintParameterSpecifiers = true; PO.PrintParameterSpecifiers = true;
PO.SkipImplicit = true; PO.SkipImplicit = true;
PO.AlwaysPrintNonSendableExtensions = false;
PO.AlwaysTryPrintParameterLabels = true; PO.AlwaysTryPrintParameterLabels = true;
return PO; return PO;
} }

View File

@@ -1769,6 +1769,24 @@ bool ShouldPrintChecker::shouldPrint(const Pattern *P,
return ShouldPrint; return ShouldPrint;
} }
bool isNonSendableExtension(const Decl *D) {
ASTContext &ctx = D->getASTContext();
const ExtensionDecl *ED = dyn_cast<ExtensionDecl>(D);
if (!ED || !ED->getAttrs().isUnavailable(ctx))
return false;
auto nonSendable =
ED->getExtendedNominal()->getAttrs().getEffectiveSendableAttr();
if (!isa_and_nonnull<NonSendableAttr>(nonSendable))
return false;
// GetImplicitSendableRequest::evaluate() creates its extension with the
// attribute's AtLoc, so this is a good way to quickly check if the extension
// was synthesized for an '@_nonSendable' attribute.
return ED->getLocFromSource() == nonSendable->AtLoc;
}
bool ShouldPrintChecker::shouldPrint(const Decl *D, bool ShouldPrintChecker::shouldPrint(const Decl *D,
const PrintOptions &Options) { const PrintOptions &Options) {
#if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB #if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB
@@ -1791,15 +1809,18 @@ bool ShouldPrintChecker::shouldPrint(const Decl *D,
return false; return false;
} }
if (Options.SkipImplicit && D->isImplicit()) { // Optionally skip these checks for extensions synthesized for '@_nonSendable'
const auto &IgnoreList = Options.TreatAsExplicitDeclList; if (!Options.AlwaysPrintNonSendableExtensions || !isNonSendableExtension(D)) {
if (std::find(IgnoreList.begin(), IgnoreList.end(), D) == IgnoreList.end()) if (Options.SkipImplicit && D->isImplicit()) {
const auto &IgnoreList = Options.TreatAsExplicitDeclList;
if (!llvm::is_contained(IgnoreList, D))
return false; return false;
} }
if (Options.SkipUnavailable && if (Options.SkipUnavailable &&
D->getAttrs().isUnavailable(D->getASTContext())) D->getAttrs().isUnavailable(D->getASTContext()))
return false; return false;
}
if (Options.ExplodeEnumCaseDecls) { if (Options.ExplodeEnumCaseDecls) {
if (isa<EnumElementDecl>(D)) if (isa<EnumElementDecl>(D))

View File

@@ -909,6 +909,28 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
void ModuleDecl::getDisplayDecls(SmallVectorImpl<Decl*> &Results) const { void ModuleDecl::getDisplayDecls(SmallVectorImpl<Decl*> &Results) const {
// FIXME: Should this do extra access control filtering? // FIXME: Should this do extra access control filtering?
FORWARD(getDisplayDecls, (Results)); FORWARD(getDisplayDecls, (Results));
// Force Sendable on all types, which might synthesize some extensions.
// FIXME: We can remove this if @_nonSendable stops creating extensions.
for (auto result : Results) {
if (auto NTD = dyn_cast<NominalTypeDecl>(result))
(void)swift::isSendableType(const_cast<ModuleDecl *>(this),
NTD->getDeclaredInterfaceType());
}
// Re-add anything from synthesized file units...
auto oldCutoff = Results.size();
for (auto file : getFiles())
if (auto synthFile = dyn_cast<SynthesizedFileUnit>(file))
synthFile->getDisplayDecls(Results);
// And then remove anything that was already in the results.
auto oldResults = makeArrayRef(Results).take_front(oldCutoff);
auto uniqueEnd = std::remove_if(Results.begin() + oldCutoff, Results.end(),
[&](auto result) {
return llvm::is_contained(oldResults, result);
});
Results.erase(uniqueEnd, Results.end());
} }
ProtocolConformanceRef ProtocolConformanceRef

View File

@@ -4004,6 +4004,8 @@ NormalProtocolConformance *GetImplicitSendableRequest::evaluate(
auto inherits = ctx.AllocateCopy(makeArrayRef( auto inherits = ctx.AllocateCopy(makeArrayRef(
InheritedEntry(TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()), InheritedEntry(TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
/*isUnchecked*/true))); /*isUnchecked*/true)));
// If you change the use of AtLoc in the ExtensionDecl, make sure you
// update isNonSendableExtension() in ASTPrinter.
auto extension = ExtensionDecl::create(ctx, attrMakingUnavailable->AtLoc, auto extension = ExtensionDecl::create(ctx, attrMakingUnavailable->AtLoc,
nullptr, inherits, nullptr, inherits,
nominal->getModuleScopeContext(), nominal->getModuleScopeContext(),

View File

@@ -23,10 +23,17 @@ import _Concurrency
// CHECK-SAME: @unchecked Sendable // CHECK-SAME: @unchecked Sendable
// CHECK-LABEL: class NonSendableClass // CHECK-LABEL: class NonSendableClass
// CHECK: @available(*, unavailable)
// CHECK-NEXT: extension NonSendableClass : @unchecked Sendable {
// CHECK-LABEL: class AuditedSendable : // CHECK-LABEL: class AuditedSendable :
// CHECK-SAME: @unchecked Sendable // CHECK-SAME: @unchecked Sendable
// CHECK-LABEL: class AuditedNonSendable // CHECK-LABEL: class AuditedNonSendable
// CHECK: @available(*, unavailable)
// CHECK-NEXT: extension AuditedNonSendable : @unchecked Sendable {
// CHECK-LABEL: class AuditedBoth // CHECK-LABEL: class AuditedBoth
// CHECK: @available(*, unavailable)
// CHECK-NEXT: extension AuditedBoth : @unchecked Sendable {

View File

@@ -10,7 +10,7 @@
// RUN: %target-swift-frontend -emit-module -DPROTOCOL_LIB -DAFTER %s -module-name protocol_lib -emit-module-path %t/protocol_lib.swiftmodule // RUN: %target-swift-frontend -emit-module -DPROTOCOL_LIB -DAFTER %s -module-name protocol_lib -emit-module-path %t/protocol_lib.swiftmodule
// The conforming library's types should still deserialize. // The conforming library's types should still deserialize.
// RUN: %target-swift-ide-test -print-module -source-filename %s -module-to-print conforms_lib -I %t | %FileCheck %s // RUN: %target-swift-ide-test -print-module -source-filename %s -module-to-print conforms_lib -I %t -allow-compiler-errors | %FileCheck %s
// Protocols that use a missing protocol have to disappear (see the FileCheck // Protocols that use a missing protocol have to disappear (see the FileCheck
// lines). // lines).