Skip to content

Commit b67ace7

Browse files
authored
Merge pull request swiftlang#71137 from kavon/ncgenerics-enable-stdlib-v1
NCGenerics: synthesize Copyable/Escapable decls
2 parents 2092536 + 3908c81 commit b67ace7

29 files changed

+387
-102
lines changed

include/swift/AST/ASTContext.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,13 @@ class ASTContext final {
801801

802802
/// Retrieve a specific, known protocol.
803803
ProtocolDecl *getProtocol(KnownProtocolKind kind) const;
804+
805+
/// Synthesizes the given invertible protocol decl into the stdlib (preferred)
806+
/// or, if the stdlib is not available, the Builtin module.
807+
///
808+
/// Does *not* perform any name lookup to check whether, the module already
809+
/// contains a decl with the same name, only does synthesis.
810+
ProtocolDecl *synthesizeInvertibleProtocolDecl(InvertibleProtocolKind ip) const;
804811

805812
/// Determine whether the given nominal type is one of the standard
806813
/// library or Cocoa framework types that is known to be bridged by another

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ IDENTIFIER(enqueue)
9090
IDENTIFIER(erasing)
9191
IDENTIFIER(error)
9292
IDENTIFIER(errorDomain)
93+
IDENTIFIER(Escapable)
9394
IDENTIFIER(Failure)
9495
IDENTIFIER(first)
9596
IDENTIFIER(forKeyedSubscript)

lib/AST/ASTContext.cpp

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,8 @@ struct ASTContext::Implementation {
630630

631631
/// The declared interface type of Builtin.TheTupleType.
632632
BuiltinTupleType *TheTupleType = nullptr;
633+
634+
std::array<ProtocolDecl *, NumInvertibleProtocols> InvertibleProtocolDecls = {};
633635
};
634636

635637
ASTContext::Implementation::Implementation()
@@ -1195,6 +1197,47 @@ Type ASTContext::get##NAME##Type() const { \
11951197

11961198
#include "swift/AST/KnownSDKTypes.def"
11971199

1200+
ProtocolDecl *
1201+
ASTContext::synthesizeInvertibleProtocolDecl(InvertibleProtocolKind ip) const {
1202+
const uint8_t index = (uint8_t)ip;
1203+
if (auto *proto = getImpl().InvertibleProtocolDecls[index])
1204+
return proto;
1205+
1206+
ModuleDecl *stdlib = getStdlibModule();
1207+
FileUnit *file = nullptr;
1208+
if (stdlib) {
1209+
file = &stdlib->getFiles()[0]->getOrCreateSynthesizedFile();
1210+
} else {
1211+
file = &TheBuiltinModule->getMainFile(FileUnitKind::Builtin);
1212+
}
1213+
1214+
// No need to form an inheritance clause; invertible protocols do not
1215+
// implicitly inherit from other invertible protocols.
1216+
auto identifier = getIdentifier(getProtocolName(getKnownProtocolKind(ip)));
1217+
ProtocolDecl *protocol = new (*this) ProtocolDecl(file,
1218+
SourceLoc(), SourceLoc(),
1219+
identifier,
1220+
/*primaryAssocTypes=*/{},
1221+
/*inherited=*/{},
1222+
/*whereClause=*/nullptr);
1223+
protocol->setImplicit(true);
1224+
1225+
// @_marker
1226+
protocol->getAttrs().add(new (*this) MarkerAttr(/*implicit=*/true));
1227+
1228+
// public
1229+
protocol->setAccess(AccessLevel::Public);
1230+
1231+
// Hack to get name lookup to work after synthesizing it into the stdlib.
1232+
if (stdlib) {
1233+
cast<SynthesizedFileUnit>(file)->addTopLevelDecl(protocol);
1234+
stdlib->clearLookupCache();
1235+
}
1236+
1237+
getImpl().InvertibleProtocolDecls[index] = protocol;
1238+
return protocol;
1239+
}
1240+
11981241
ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
11991242
// Check whether we've already looked for and cached this protocol.
12001243
unsigned index = (unsigned)kind;
@@ -1206,6 +1249,7 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
12061249
SmallVector<ValueDecl *, 1> results;
12071250

12081251
const ModuleDecl *M;
1252+
NLKind NameLookupKind = NLKind::UnqualifiedLookup;
12091253
switch (kind) {
12101254
case KnownProtocolKind::BridgedNSError:
12111255
case KnownProtocolKind::BridgedStoredNSError:
@@ -1251,6 +1295,16 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
12511295
case KnownProtocolKind::UnsafeCxxMutableRandomAccessIterator:
12521296
M = getLoadedModule(Id_Cxx);
12531297
break;
1298+
case KnownProtocolKind::Copyable:
1299+
case KnownProtocolKind::Escapable:
1300+
// If there's no stdlib, do qualified lookup in the Builtin module,
1301+
// which will trigger the correct synthesis of the protocols in that module.
1302+
M = getStdlibModule();
1303+
if (!M) {
1304+
NameLookupKind = NLKind::QualifiedLookup;
1305+
M = TheBuiltinModule;
1306+
}
1307+
break;
12541308
default:
12551309
M = getStdlibModule();
12561310
break;
@@ -1259,7 +1313,7 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
12591313
if (!M)
12601314
return nullptr;
12611315
M->lookupValue(getIdentifier(getProtocolName(kind)),
1262-
NLKind::UnqualifiedLookup,
1316+
NameLookupKind,
12631317
ModuleLookupFlags::ExcludeMacroExpansions,
12641318
results);
12651319

@@ -1270,6 +1324,14 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
12701324
}
12711325
}
12721326

1327+
// If the invertible protocol wasn't found in the stdlib, synthesize it there.
1328+
if (auto ip = getInvertibleProtocolKind(kind)) {
1329+
assert(M == getStdlibModule());
1330+
auto *protocol = synthesizeInvertibleProtocolDecl(*ip);
1331+
getImpl().KnownProtocols[index] = protocol;
1332+
return protocol;
1333+
}
1334+
12731335
return nullptr;
12741336
}
12751337

@@ -6408,7 +6470,7 @@ BuiltinTupleDecl *ASTContext::getBuiltinTupleDecl() {
64086470
if (result)
64096471
return result;
64106472

6411-
auto *dc = TheBuiltinModule->getFiles()[0];
6473+
auto *dc = &TheBuiltinModule->getMainFile(FileUnitKind::Builtin);
64126474

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

lib/AST/Builtins.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2404,6 +2404,11 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
24042404
if (Id == Context.Id_TheTupleType)
24052405
return Context.getBuiltinTupleDecl();
24062406

2407+
if (Id == Context.Id_Copyable)
2408+
return Context.synthesizeInvertibleProtocolDecl(InvertibleProtocolKind::Copyable);
2409+
if (Id == Context.Id_Escapable)
2410+
return Context.synthesizeInvertibleProtocolDecl(InvertibleProtocolKind::Escapable);
2411+
24072412
SmallVector<Type, 4> Types;
24082413
StringRef OperationName = getBuiltinBaseName(Context, Id.str(), Types);
24092414

lib/AST/Decl.cpp

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4931,7 +4931,7 @@ InverseMarking TypeDecl::getMarking(InvertibleProtocolKind ip) const {
49314931
static TypeDecl::CanBeInvertible::Result
49324932
conformanceExists(TypeDecl const *decl, InvertibleProtocolKind ip) {
49334933
auto *proto = decl->getASTContext().getProtocol(getKnownProtocolKind(ip));
4934-
assert(proto);
4934+
assert(proto && "missing Copyable/Escapable from stdlib!");
49354935

49364936
// Handle protocols specially, without building a GenericSignature.
49374937
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl))
@@ -6624,34 +6624,35 @@ bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const {
66246624
}
66256625

66266626
bool ProtocolDecl::requiresInvertible(InvertibleProtocolKind ip) const {
6627-
// Specially handle when asking if an invertible protocol requires another.
6627+
// Protocols don't inherit from themselves.
66286628
if (auto thisIP = getInvertibleProtocolKind()) {
6629-
if (SWIFT_ENABLE_EXPERIMENTAL_NONCOPYABLE_GENERICS) {
6630-
// Hardcode that the invertible protocols do not require themselves.
6631-
// Otherwise, defer to what the stdlib says by walking the protocol.
6632-
if (thisIP == ip)
6633-
return false;
6634-
} else {
6635-
// The stdlib was NOT built with noncopyable generics, so claim that
6636-
// this invertible protocol require no others.
6637-
// FIXME: this configuration will eventually go away.
6629+
if (thisIP == ip)
66386630
return false;
6639-
}
66406631
}
66416632

66426633
auto kp = ::getKnownProtocolKind(ip);
6634+
6635+
// Otherwise, check for inverses on all of the inherited protocols. If there
6636+
// is one protocol missing an inverse for this `super` protocol, then it is
6637+
// implicitly inherited.
66436638
return walkInheritedProtocols([kp, ip](ProtocolDecl *proto) {
66446639
if (proto->isSpecificProtocol(kp))
6645-
return TypeWalker::Action::Stop; // it is required.
6640+
return TypeWalker::Action::Stop; // It is explicitly inherited.
6641+
6642+
// There is no implicit inheritance of an invertible protocol requirement
6643+
// on an invertible protocol itself.
6644+
if (proto->getInvertibleProtocolKind())
6645+
return TypeWalker::Action::Continue;
66466646

6647+
// Otherwise, check to see if there's an inverse on this protocol.
66476648
switch (proto->getMarking(ip).getInverse().getKind()) {
66486649
case InverseMarking::Kind::None:
6649-
return TypeWalker::Action::Stop; // it is required.
6650+
return TypeWalker::Action::Stop; // No inverse, so implicitly inherited.
66506651

66516652
case InverseMarking::Kind::LegacyExplicit:
66526653
case InverseMarking::Kind::Explicit:
66536654
case InverseMarking::Kind::Inferred:
6654-
// the implicit requirement was suppressed on this protocol, keep looking.
6655+
// The implicit requirement was suppressed on this protocol, keep looking.
66556656
return TypeWalker::Action::Continue;
66566657
}
66576658
});
@@ -6784,6 +6785,7 @@ ProtocolDecl::setLazyPrimaryAssociatedTypeMembers(
67846785
void ProtocolDecl::computeKnownProtocolKind() const {
67856786
auto module = getModuleContext();
67866787
if (module != module->getASTContext().getStdlibModule() &&
6788+
module != module->getASTContext().TheBuiltinModule &&
67876789
!module->getName().is("Foundation") &&
67886790
!module->getName().is("_Differentiation") &&
67896791
!module->getName().is("_Concurrency") &&

lib/AST/Requirement.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,7 @@ void InverseRequirement::expandDefaults(
358358
auto protos = InverseRequirement::expandDefault(gp);
359359
for (auto ip : protos) {
360360
auto proto = ctx.getProtocol(getKnownProtocolKind(ip));
361-
if (!proto)
362-
llvm_unreachable("failed to load Copyable/Escapable/etc from stdlib!");
361+
assert(proto && "missing Copyable/Escapable from stdlib!");
363362

364363
auto protoTy = proto->getDeclaredInterfaceType();
365364
result.push_back({{RequirementKind::Conformance, gp, protoTy},

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,10 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
10371037

10381038
desugarRequirements(result, inverses, errors);
10391039

1040-
InverseRequirement::expandDefaults(ctx, needsDefaultRequirements, result);
1040+
// We do not expand defaults for invertible protocols themselves.
1041+
if (!proto->getInvertibleProtocolKind())
1042+
InverseRequirement::expandDefaults(ctx, needsDefaultRequirements, result);
1043+
10411044
applyInverses(ctx, needsDefaultRequirements, inverses, result, errors);
10421045

10431046
diagnoseRequirementErrors(ctx, errors,

lib/AST/Type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ static void expandDefaultProtocols(
388388
continue;
389389

390390
auto proto = ctx.getProtocol(getKnownProtocolKind(ip));
391-
assert(proto);
391+
assert(proto && "missing Copyable/Escapable from stdlib!");
392392

393393
protocols.push_back(proto);
394394
}

lib/SILGen/SILGenTopLevel.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,8 @@ void SILGenTopLevel::visitSourceFile(SourceFile *SF) {
377377

378378
if (auto *SynthesizedFile = SF->getSynthesizedFile()) {
379379
for (auto *D : SynthesizedFile->getTopLevelDecls()) {
380-
if (isa<ExtensionDecl>(D)) {
381-
visit(D);
382-
}
380+
assert(isa<ExtensionDecl>(D) || isa<ProtocolDecl>(D));
381+
visit(D);
383382
}
384383
}
385384

lib/Sema/TypeCheckInvertible.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ static void tryEmitContainmentFixits(InFlightDiagnostic &&diag,
161161
static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
162162
auto &ctx = type->getASTContext();
163163

164-
auto *invertible = ctx.getProtocol(getKnownProtocolKind(ip));
165-
assert(invertible && "failed to load Copyable/Escapable from stdlib!");
164+
auto *proto = ctx.getProtocol(getKnownProtocolKind(ip));
165+
assert(proto && "missing Copyable/Escapable from stdlib!");
166166

167167
// Must not have a type parameter!
168168
assert(!type->hasTypeParameter() && "caller forgot to mapTypeIntoContext!");
@@ -177,8 +177,8 @@ static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) {
177177
SILTokenType>()));
178178

179179
const bool conforms =
180-
(bool) invertible->getParentModule()->checkConformance(
181-
type, invertible,
180+
(bool) proto->getParentModule()->checkConformance(
181+
type, proto,
182182
/*allowMissing=*/false);
183183

184184
return conforms;
@@ -468,13 +468,9 @@ ProtocolConformance *deriveConformanceForInvertible(Evaluator &evaluator,
468468
// All types already start with conformances to the invertible protocols in
469469
// this case, within `NominalTypeDecl::prepareConformanceTable`.
470470
//
471-
// I'm currently unsure what happens when rebuilding a module from its
472-
// interface, so this might not be unreachable code just yet.
473-
if (SWIFT_ENABLE_EXPERIMENTAL_NONCOPYABLE_GENERICS &&
474-
file->getKind() != FileUnitKind::Synthesized) {
475-
llvm_unreachable("when can this actually happen??");
476-
}
477-
471+
// There are various other kinds of SourceFiles, like SIL, which instead
472+
// get their conformances here instead.
473+
//
478474
// If there's no inverse, we infer a positive IP conformance.
479475
return generateConformance(nominal);
480476
}

0 commit comments

Comments
 (0)