Skip to content

Replace bespoke Sendable and Copyable conformance on tuples with tuple conformances #67839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
17 changes: 9 additions & 8 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1258,13 +1258,16 @@ class ASTContext final {
unsigned bumpGeneration() { return CurrentGeneration++; }

/// Produce a "normal" conformance for a nominal type.
///
/// For ordinary conformance lookups, use ModuleDecl::lookupConformance()
/// instead.
NormalProtocolConformance *
getConformance(Type conformingType,
ProtocolDecl *protocol,
SourceLoc loc,
DeclContext *dc,
ProtocolConformanceState state,
bool isUnchecked);
getNormalConformance(Type conformingType,
ProtocolDecl *protocol,
SourceLoc loc,
DeclContext *dc,
ProtocolConformanceState state,
bool isUnchecked);

/// Produce a self-conformance for the given protocol.
SelfProtocolConformance *
Expand All @@ -1273,8 +1276,6 @@ class ASTContext final {
/// Produce the builtin conformance for some structural type to some protocol.
BuiltinProtocolConformance *
getBuiltinConformance(Type type, ProtocolDecl *protocol,
GenericSignature genericSig,
ArrayRef<Requirement> conditionalRequirements,
BuiltinConformanceKind kind);

/// A callback used to produce a diagnostic for an ill-formed protocol
Expand Down
7 changes: 0 additions & 7 deletions include/swift/AST/DiagnosticsCommon.def
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,6 @@ ERROR(macro_experimental,none,
ERROR(ambiguous_macro_reference,none,
"ambiguous reference to macro %0", (DeclName))

//------------------------------------------------------------------------------
// MARK: tuple conformances
//------------------------------------------------------------------------------
ERROR(experimental_tuple_extension,none,
"tuple extensions are experimental",
())

//------------------------------------------------------------------------------
// MARK: bridged diagnostics
//------------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2335,6 +2335,9 @@ NOTE(composition_in_extended_type_alternative,none,
ERROR(extension_access_with_conformances,none,
"%0 modifier cannot be used with extensions that declare "
"protocol conformances", (DeclAttribute))
ERROR(experimental_tuple_extension,none,
"tuple extensions are experimental",
())
ERROR(extension_metatype,none,
"cannot extend a metatype %0", (Type))
ERROR(extension_placeholder,none,
Expand Down
28 changes: 8 additions & 20 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,23 +1019,13 @@ enum class BuiltinConformanceKind {

/// A builtin conformance appears when a non-nominal type has a
/// conformance that is synthesized by the implementation.
class BuiltinProtocolConformance final : public RootProtocolConformance,
private llvm::TrailingObjects<BuiltinProtocolConformance, Requirement> {
class BuiltinProtocolConformance final : public RootProtocolConformance {
friend ASTContext;
friend TrailingObjects;

ProtocolDecl *protocol;
GenericSignature genericSig;
size_t numConditionalRequirements : 31;
unsigned builtinConformanceKind : 1;

size_t numTrailingObjects(OverloadToken<Requirement>) const {
return numConditionalRequirements;
}
unsigned builtinConformanceKind;

BuiltinProtocolConformance(Type conformingType, ProtocolDecl *protocol,
GenericSignature genericSig,
ArrayRef<Requirement> conditionalRequirements,
BuiltinConformanceKind kind);

public:
Expand All @@ -1044,16 +1034,14 @@ class BuiltinProtocolConformance final : public RootProtocolConformance,
return protocol;
}

/// Retrieve the generic signature that describes the type parameters used
/// within the conforming type.
GenericSignature getGenericSignature() const {
return genericSig;
}

BuiltinConformanceKind getBuiltinConformanceKind() const {
return static_cast<BuiltinConformanceKind>(builtinConformanceKind);
}

GenericSignature getGenericSignature() const {
return GenericSignature();
}

/// Whether this represents a "missing" conformance that should be diagnosed
/// later.
bool isMissing() const {
Expand All @@ -1063,12 +1051,12 @@ class BuiltinProtocolConformance final : public RootProtocolConformance,
/// Get any requirements that must be satisfied for this conformance to apply.
llvm::Optional<ArrayRef<Requirement>>
getConditionalRequirementsIfAvailable() const {
return getConditionalRequirements();
return ArrayRef<Requirement>();
}

/// Get any requirements that must be satisfied for this conformance to apply.
ArrayRef<Requirement> getConditionalRequirements() const {
return {getTrailingObjects<Requirement>(), numConditionalRequirements};
return {};
}

/// Get the declaration context that contains the nominal type declaration.
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ NODE(BoundGenericOtherNominalType)
NODE(BoundGenericTypeAlias)
NODE(BoundGenericFunction)
NODE(BuiltinTypeName)
NODE(BuiltinTupleType)
NODE(CFunctionPointer)
NODE(ClangType)
CONTEXT_NODE(Class)
Expand Down
70 changes: 50 additions & 20 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2638,12 +2638,12 @@ void ASTContext::setExternalSourceLocs(const Decl *D,
}

NormalProtocolConformance *
ASTContext::getConformance(Type conformingType,
ProtocolDecl *protocol,
SourceLoc loc,
DeclContext *dc,
ProtocolConformanceState state,
bool isUnchecked) {
ASTContext::getNormalConformance(Type conformingType,
ProtocolDecl *protocol,
SourceLoc loc,
DeclContext *dc,
ProtocolConformanceState state,
bool isUnchecked) {
assert(dc->isTypeContext());

llvm::FoldingSetNodeID id;
Expand Down Expand Up @@ -2681,23 +2681,15 @@ ASTContext::getSelfConformance(ProtocolDecl *protocol) {

/// Produce the builtin conformance for some non-nominal to some protocol.
BuiltinProtocolConformance *
ASTContext::getBuiltinConformance(
Type type, ProtocolDecl *protocol,
GenericSignature genericSig,
ArrayRef<Requirement> conditionalRequirements,
BuiltinConformanceKind kind
) {
ASTContext::getBuiltinConformance(Type type, ProtocolDecl *protocol,
BuiltinConformanceKind kind) {
auto key = std::make_pair(type, protocol);
AllocationArena arena = getArena(type->getRecursiveProperties());
auto &builtinConformances = getImpl().getArena(arena).BuiltinConformances;

auto &entry = builtinConformances[key];
if (!entry) {
auto size = BuiltinProtocolConformance::
totalSizeToAlloc<Requirement>(conditionalRequirements.size());
auto mem = this->Allocate(size, alignof(BuiltinProtocolConformance), arena);
entry = new (mem) BuiltinProtocolConformance(
type, protocol, genericSig, conditionalRequirements, kind);
entry = new (*this) BuiltinProtocolConformance(type, protocol, kind);
}
return entry;
}
Expand Down Expand Up @@ -3726,7 +3718,9 @@ BoundGenericType *BoundGenericType::get(NominalTypeDecl *TheDecl,
}

NominalType *NominalType::get(NominalTypeDecl *D, Type Parent, const ASTContext &C) {
assert((isa<ProtocolDecl>(D) || !D->getGenericParams()) &&
assert((isa<ProtocolDecl>(D) ||
isa<BuiltinTupleDecl>(D) ||
!D->getGenericParams()) &&
"must be a non-generic type decl");
assert((!Parent || Parent->is<NominalType>() ||
Parent->is<BoundGenericType>() ||
Expand All @@ -3742,6 +3736,8 @@ NominalType *NominalType::get(NominalTypeDecl *D, Type Parent, const ASTContext
return ClassType::get(cast<ClassDecl>(D), Parent, C);
case DeclKind::Protocol: {
return ProtocolType::get(cast<ProtocolDecl>(D), Parent, C);
case DeclKind::BuiltinTuple:
return BuiltinTupleType::get(cast<BuiltinTupleDecl>(D), Parent, C);
}

default:
Expand Down Expand Up @@ -6292,10 +6288,44 @@ BuiltinTupleDecl *ASTContext::getBuiltinTupleDecl() {
if (result)
return result;

result = new (*this) BuiltinTupleDecl(Id_TheTupleType,
TheBuiltinModule->getFiles()[0]);
auto *dc = TheBuiltinModule->getFiles()[0];

result = new (*this) BuiltinTupleDecl(Id_TheTupleType, dc);
result->setAccess(AccessLevel::Public);

// Cook up conditional conformances to Sendable and Copyable.
auto buildFakeExtension = [&](ProtocolDecl *proto) {
auto protoTy = proto->getDeclaredInterfaceType();

// extension Builtin.TheTupleType: P { ... }
SmallVector<InheritedEntry, 1> inherited;
inherited.emplace_back(TypeLoc::withoutLoc(protoTy));
auto *ext = ExtensionDecl::create(*this, SourceLoc(), nullptr,
AllocateCopy(inherited),
dc, nullptr);

// <each T where repeat each T: P>
auto genericSig = result->getGenericSignature();
auto params = genericSig.getGenericParams();
assert(params.size() == 1);
Requirement req(RequirementKind::Conformance, params[0], protoTy);
genericSig = GenericSignature::get(params, req);
ext->setGenericSignature(genericSig);

// Bind the extension.
evaluator.cacheOutput(ExtendedTypeRequest{ext},
result->getDeclaredInterfaceType());
ext->setExtendedNominal(result);

result->addExtension(ext);
};

if (auto *proto = getProtocol(KnownProtocolKind::Sendable))
buildFakeExtension(proto);

if (auto *proto = getProtocol(KnownProtocolKind::Copyable))
buildFakeExtension(proto);

return result;
}

Expand Down
10 changes: 5 additions & 5 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2583,6 +2583,11 @@ void ASTMangler::appendSymbolicReference(SymbolicReferent referent) {
}

void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
auto *nominal = dyn_cast<NominalTypeDecl>(decl);

if (nominal && isa<BuiltinTupleDecl>(nominal))
return appendOperator("BT");

// Check for certain standard types.
if (tryAppendStandardSubstitution(decl))
return;
Expand All @@ -2592,8 +2597,6 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
appendOpaqueDeclName(opaque);
return;
}

auto *nominal = dyn_cast<NominalTypeDecl>(decl);

// For generic types, this uses the unbound type.
if (nominal) {
Expand All @@ -2612,9 +2615,6 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
return;
}

if (nominal && isa<BuiltinTupleDecl>(nominal))
return appendOperator("BT");

appendContextOf(decl);

// Always use Clang names for imported Clang declarations, unless they don't
Expand Down
13 changes: 8 additions & 5 deletions lib/AST/ConformanceLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
for (auto conf : conformances) {
protocols.push_back({conf->getProtocol(), SourceLoc(), SourceLoc()});
}
} else if (next->getParentSourceFile()) {
} else if (next->getParentSourceFile() ||
next->getParentModule()->isBuiltinModule()) {
bool anyObject = false;
for (const auto &found :
getDirectlyInheritedNominalTypeDecls(next, anyObject)) {
Expand Down Expand Up @@ -418,8 +419,10 @@ void ConformanceLookupTable::loadAllConformances(
ArrayRef<ProtocolConformance*> conformances) {
// If this declaration context came from source, there's nothing to
// do here.
if (dc->getParentSourceFile())
if (dc->getParentSourceFile() ||
dc->getParentModule()->isBuiltinModule()) {
return;
}

// Add entries for each loaded conformance.
for (auto conformance : conformances) {
Expand Down Expand Up @@ -928,9 +931,9 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal,

// Create or find the normal conformance.
auto normalConf =
ctx.getConformance(conformingType, protocol, conformanceLoc,
conformingDC, ProtocolConformanceState::Incomplete,
entry->Source.getUncheckedLoc().isValid());
ctx.getNormalConformance(conformingType, protocol, conformanceLoc,
conformingDC, ProtocolConformanceState::Incomplete,
entry->Source.getUncheckedLoc().isValid());
// Invalid code may cause the getConformance call below to loop, so break
// the infinite recursion by setting this eagerly to shortcircuit with the
// early return at the start of this function.
Expand Down
Loading