Module printing and serialization support for @unchecked Sendable

This commit is contained in:
Doug Gregor
2021-07-11 12:29:21 -07:00
parent 29f5d7a64a
commit 06bbc70b3e
31 changed files with 270 additions and 253 deletions

View File

@@ -20,6 +20,7 @@
#include "swift/AST/Module.h"
#include "swift/AST/ModuleNameLookup.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/ModuleInterfaceSupport.h"
@@ -301,7 +302,7 @@ class InheritedProtocolCollector {
using AvailableAttrList = TinyPtrVector<const AvailableAttr *>;
using ProtocolAndAvailability =
std::pair<ProtocolDecl *, AvailableAttrList>;
std::tuple<ProtocolDecl *, AvailableAttrList, bool /*isUnchecked*/>;
/// Protocols that will be included by the ASTPrinter without any extra work.
SmallVector<ProtocolDecl *, 8> IncludedProtocols;
@@ -338,30 +339,23 @@ class InheritedProtocolCollector {
}
static bool canPrintProtocolTypeNormally(Type type, const Decl *D) {
if (!isPublicOrUsableFromInline(type))
return false;
// Extensions and protocols can print marker protocols.
if (isa<ExtensionDecl>(D) || isa<ProtocolDecl>(D))
return true;
ExistentialLayout layout = type->getExistentialLayout();
for (ProtocolType *protoTy : layout.getProtocols()) {
if (protoTy->getDecl()->isMarkerProtocol())
return false;
}
return true;
return isPublicOrUsableFromInline(type);
}
static bool isUncheckedConformance(ProtocolConformance *conformance) {
if (auto normal = conformance->getRootNormalConformance())
return normal->isUnchecked();
return false;
}
/// For each type in \p directlyInherited, classify the protocols it refers to
/// as included for printing or not, and record them in the appropriate
/// vectors.
void recordProtocols(ArrayRef<TypeLoc> directlyInherited, const Decl *D,
bool skipSynthesized = false) {
void recordProtocols(ArrayRef<InheritedEntry> directlyInherited,
const Decl *D, bool skipSynthesized = false) {
Optional<AvailableAttrList> availableAttrs;
for (TypeLoc inherited : directlyInherited) {
for (InheritedEntry inherited : directlyInherited) {
Type inheritedTy = inherited.getType();
if (!inheritedTy || !inheritedTy->isExistentialType())
continue;
@@ -373,7 +367,8 @@ class InheritedProtocolCollector {
IncludedProtocols.push_back(protoTy->getDecl());
else
ExtraProtocols.push_back({protoTy->getDecl(),
getAvailabilityAttrs(D, availableAttrs)});
getAvailabilityAttrs(D, availableAttrs),
inherited.isUnchecked});
}
// FIXME: This ignores layout constraints, but currently we don't support
// any of those besides 'AnyObject'.
@@ -391,7 +386,8 @@ class InheritedProtocolCollector {
if (conf->getSourceKind() != ConformanceEntryKind::Synthesized)
continue;
ExtraProtocols.push_back({conf->getProtocol(),
getAvailabilityAttrs(D, availableAttrs)});
getAvailabilityAttrs(D, availableAttrs),
isUncheckedConformance(conf)});
}
}
}
@@ -423,7 +419,7 @@ public:
///
/// \sa recordProtocols
static void collectProtocols(PerTypeMap &map, const Decl *D) {
ArrayRef<TypeLoc> directlyInherited;
ArrayRef<InheritedEntry> directlyInherited;
const NominalTypeDecl *nominal;
const IterableDeclContext *memberContext;
@@ -549,7 +545,10 @@ public:
// of a protocol rather than the maximally available case.
SmallVector<ProtocolAndAvailability, 16> protocolsToPrint;
for (const auto &protoAndAvailability : ExtraProtocols) {
protoAndAvailability.first->walkInheritedProtocols(
auto proto = std::get<0>(protoAndAvailability);
auto availability = std::get<1>(protoAndAvailability);
auto isUnchecked = std::get<2>(protoAndAvailability);
proto->walkInheritedProtocols(
[&](ProtocolDecl *inherited) -> TypeWalker::Action {
if (!handledProtocols.insert(inherited).second)
return TypeWalker::Action::SkipChildren;
@@ -569,7 +568,7 @@ public:
if (isPublicOrUsableFromInline(inherited) &&
conformanceDeclaredInModule(M, nominal, inherited) &&
!M->isImportedImplementationOnly(inherited->getParentModule())) {
protocolsToPrint.push_back({inherited, protoAndAvailability.second});
protocolsToPrint.push_back({inherited, availability, isUnchecked});
return TypeWalker::Action::SkipChildren;
}
@@ -581,15 +580,16 @@ public:
for (const auto &protoAndAvailability : protocolsToPrint) {
StreamPrinter printer(out);
ProtocolDecl *proto = protoAndAvailability.first;
auto proto = std::get<0>(protoAndAvailability);
auto availability = std::get<1>(protoAndAvailability);
auto isUnchecked = std::get<2>(protoAndAvailability);
bool haveFeatureChecks = printOptions.PrintCompatibilityFeatureChecks &&
printCompatibilityFeatureChecksPre(printer, proto);
// FIXME: Shouldn't this be an implicit conversion?
TinyPtrVector<const DeclAttribute *> attrs;
attrs.insert(attrs.end(), protoAndAvailability.second.begin(),
protoAndAvailability.second.end());
attrs.insert(attrs.end(), availability.begin(), availability.end());
auto spiAttributes = proto->getAttrs().getAttributes<SPIAccessControlAttr>();
attrs.insert(attrs.end(), spiAttributes.begin(), spiAttributes.end());
DeclAttributes::print(printer, printOptions, attrs);
@@ -607,6 +607,9 @@ public:
}
printer << " : ";
if (isUnchecked)
printer << "@unchecked ";
proto->getDeclaredInterfaceType()->print(printer, printOptions);
printer << " {}";