Skip to content

Commit 78df826

Browse files
authored
Merge pull request swiftlang#72020 from slavapestov/ncgenerics-fixes-7
Non-copyable generics fixes
2 parents e0619c7 + e85f8e1 commit 78df826

35 files changed

+202
-131
lines changed

lib/AST/ASTMangler.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3697,14 +3697,21 @@ static unsigned conformanceRequirementIndex(
36973697
if (req.getKind() != RequirementKind::Conformance)
36983698
continue;
36993699

3700+
// This is an ABI compatibility hack for noncopyable generics.
3701+
// We should have really been skipping marker protocols here all along,
3702+
// but it's too late now, so skip Copyable and Escapable specifically.
3703+
if (req.getProtocolDecl()->getInvertibleProtocolKind())
3704+
continue;
3705+
37003706
if (req.getFirstType()->isEqual(entry.first) &&
37013707
req.getProtocolDecl() == entry.second)
37023708
return result;
37033709

37043710
++result;
37053711
}
37063712

3707-
llvm_unreachable("Conformance access path step is missing from requirements");
3713+
llvm::errs() <<"Conformance access path step is missing from requirements";
3714+
abort();
37083715
}
37093716

37103717
void ASTMangler::appendDependentProtocolConformance(

lib/AST/ASTPrinter.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7722,11 +7722,69 @@ void swift::printEnumElementsAsCases(
77227722
OS << ": " << getCodePlaceholder() << "\n";
77237723
});
77247724
}
7725+
/// For a protocol, don't consult getInherited() at all. Instead, rebuild
7726+
/// the inherited types from getInheritedProtocols(), getSuperclass(), and
7727+
/// the inverse requirement transform.
7728+
///
7729+
/// FIXME: This seems generally useful and should be moved elsewhere.
7730+
static void getSyntacticInheritanceClause(const ProtocolDecl *proto,
7731+
llvm::SmallVectorImpl<InheritedEntry> &Results) {
7732+
auto &ctx = proto->getASTContext();
7733+
7734+
if (auto superclassTy = proto->getSuperclass()) {
7735+
Results.emplace_back(TypeLoc::withoutLoc(superclassTy),
7736+
/*isUnchecked=*/false,
7737+
/*isRetroactive=*/false,
7738+
/*isPreconcurrency=*/false);
7739+
}
7740+
7741+
InvertibleProtocolSet inverses = InvertibleProtocolSet::full();
7742+
7743+
for (auto *inherited : proto->getInheritedProtocols()) {
7744+
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
7745+
if (auto ip = inherited->getInvertibleProtocolKind()) {
7746+
inverses.remove(*ip);
7747+
continue;
7748+
}
7749+
7750+
for (auto ip : InvertibleProtocolSet::full()) {
7751+
auto *proto = ctx.getProtocol(getKnownProtocolKind(ip));
7752+
if (inherited->inheritsFrom(proto))
7753+
inverses.remove(ip);
7754+
}
7755+
}
7756+
7757+
Results.emplace_back(TypeLoc::withoutLoc(inherited->getDeclaredInterfaceType()),
7758+
/*isUnchecked=*/false,
7759+
/*isRetroactive=*/false,
7760+
/*isPreconcurrency=*/false);
7761+
}
7762+
7763+
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
7764+
for (auto ip : inverses) {
7765+
InvertibleProtocolSet singleton;
7766+
singleton.insert(ip);
7767+
7768+
auto inverseTy = ProtocolCompositionType::get(
7769+
ctx, ArrayRef<Type>(), singleton,
7770+
/*hasExplicitAnyObject=*/false);
7771+
Results.emplace_back(TypeLoc::withoutLoc(inverseTy),
7772+
/*isUnchecked=*/false,
7773+
/*isRetroactive=*/false,
7774+
/*isPreconcurrency=*/false);
7775+
}
7776+
}
7777+
}
77257778

77267779
void
77277780
swift::getInheritedForPrinting(
77287781
const Decl *decl, const PrintOptions &options,
77297782
llvm::SmallVectorImpl<InheritedEntry> &Results) {
7783+
if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
7784+
getSyntacticInheritanceClause(proto, Results);
7785+
return;
7786+
}
7787+
77307788
InheritedTypes inherited = InheritedTypes(decl);
77317789

77327790
// Collect explicit inherited types.
@@ -7753,6 +7811,10 @@ swift::getInheritedForPrinting(
77537811
llvm::TinyPtrVector<ProtocolDecl *> uncheckedProtocols;
77547812
for (auto attr : decl->getAttrs().getAttributes<SynthesizedProtocolAttr>()) {
77557813
if (auto *proto = attr->getProtocol()) {
7814+
// FIXME: Reconstitute inverses here
7815+
if (proto->getInvertibleProtocolKind())
7816+
continue;
7817+
77567818
// The SerialExecutor conformance is only synthesized on the root
77577819
// actor class, so we can just test resilience immediately.
77587820
if (proto->isSpecificProtocol(KnownProtocolKind::SerialExecutor) &&
@@ -7788,6 +7850,10 @@ swift::getInheritedForPrinting(
77887850
continue;
77897851
}
77907852

7853+
// FIXME: Reconstitute inverses here
7854+
if (proto->getInvertibleProtocolKind())
7855+
continue;
7856+
77917857
Results.push_back({TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
77927858
isUnchecked,
77937859
/*isRetroactive=*/false,

lib/AST/Decl.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,15 @@ InheritedEntry::InheritedEntry(const TypeLoc &typeLoc)
15631563
}
15641564
}
15651565

1566+
InheritedTypes::InheritedTypes(const TypeDecl *typeDecl) : Decl(typeDecl) {
1567+
Entries = typeDecl->Inherited;
1568+
}
1569+
1570+
InheritedTypes::InheritedTypes(const ExtensionDecl *extensionDecl)
1571+
: Decl(extensionDecl) {
1572+
Entries = extensionDecl->Inherited;
1573+
}
1574+
15661575
InheritedTypes::InheritedTypes(
15671576
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl)
15681577
: Decl(decl) {
@@ -1641,15 +1650,6 @@ SourceRange InheritedTypes::getRemovalRange(unsigned i) const {
16411650
return SourceRange(afterPriorLoc, afterMyEndLoc);
16421651
}
16431652

1644-
InheritedTypes::InheritedTypes(const TypeDecl *typeDecl) : Decl(typeDecl) {
1645-
Entries = typeDecl->Inherited;
1646-
}
1647-
1648-
InheritedTypes::InheritedTypes(const ExtensionDecl *extensionDecl)
1649-
: Decl(extensionDecl) {
1650-
Entries = extensionDecl->Inherited;
1651-
}
1652-
16531653
Type InheritedTypes::getResolvedType(unsigned i,
16541654
TypeResolutionStage stage) const {
16551655
ASTContext &ctx = Decl.is<const ExtensionDecl *>()

lib/ConstExtract/ConstExtract.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,10 @@ void writeResultBuilderInformation(llvm::json::OStream &JSON,
776776

777777
for (ProtocolDecl *Decl :
778778
TypeDecl->getLocalProtocols(ConformanceLookupKind::All)) {
779+
// FIXME(noncopyable_generics): Should these be included?
780+
if (Decl->getInvertibleProtocolKind())
781+
continue;
782+
779783
for (auto Member : Decl->getMembers()) {
780784
if (auto *VD = dyn_cast<swift::VarDecl>(Member)) {
781785
if (VD->getName() != VarDecl->getName())
@@ -840,9 +844,16 @@ void writeSubstitutedOpaqueTypeAliasDetails(
840844
// Ignore requirements whose subject type is that of the owner decl
841845
if (!Requirement.getFirstType()->isEqual(OpaqueTy.getInterfaceType()))
842846
continue;
843-
if (Requirement.getKind() == RequirementKind::Conformance)
844-
JSON.value(
845-
toFullyQualifiedProtocolNameString(*Requirement.getProtocolDecl()));
847+
848+
if (Requirement.getKind() != RequirementKind::Conformance)
849+
continue;
850+
851+
// FIXME(noncopyable_generics): Should these be included?
852+
if (Requirement.getProtocolDecl()->getInvertibleProtocolKind())
853+
continue;
854+
855+
JSON.value(
856+
toFullyQualifiedProtocolNameString(*Requirement.getProtocolDecl()));
846857
}
847858
});
848859

@@ -920,7 +931,11 @@ void writeProperties(llvm::json::OStream &JSON,
920931
void writeConformances(llvm::json::OStream &JSON,
921932
const NominalTypeDecl &NomTypeDecl) {
922933
JSON.attributeArray("conformances", [&] {
923-
for (auto &Protocol : NomTypeDecl.getAllProtocols()) {
934+
for (auto *Protocol : NomTypeDecl.getAllProtocols()) {
935+
// FIXME(noncopyable_generics): Should these be included?
936+
if (Protocol->getInvertibleProtocolKind())
937+
continue;
938+
924939
JSON.value(toFullyQualifiedProtocolNameString(*Protocol));
925940
}
926941
});

lib/Index/Index.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,8 +1589,22 @@ bool IndexSwiftASTWalker::report(ValueDecl *D) {
15891589
return false;
15901590
}
15911591
} else if (auto NTD = dyn_cast<NominalTypeDecl>(D)) {
1592-
if (!reportInheritedTypeRefs(NTD->getInherited(), NTD))
1593-
return false;
1592+
auto *PD = dyn_cast<ProtocolDecl>(D);
1593+
if (PD && PD->wasDeserialized()) {
1594+
// Deserialized protocols don't have an inheritance clause.
1595+
for (auto *inherited : PD->getInheritedProtocols()) {
1596+
// FIXME(noncopyable_generics): Do we want to include these?
1597+
if (inherited->getInvertibleProtocolKind())
1598+
continue;
1599+
1600+
if (!reportRelatedRef(inherited, SourceLoc(), /*isImplicit=*/false,
1601+
(SymbolRoleSet) SymbolRole::RelationBaseOf, PD))
1602+
return false;
1603+
}
1604+
} else {
1605+
if (!reportInheritedTypeRefs(NTD->getInherited(), NTD))
1606+
return false;
1607+
}
15941608
}
15951609
} else {
15961610
// Even if we don't record a local property we still need to walk its

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4234,6 +4234,9 @@ swift::diagnoseConformanceAvailability(SourceLoc loc,
42344234
bool warnIfConformanceUnavailablePreSwift6) {
42354235
assert(!where.isImplicit());
42364236

4237+
if (conformance.isInvalid() || conformance.isAbstract())
4238+
return false;
4239+
42374240
if (conformance.isPack()) {
42384241
bool diagnosed = false;
42394242
auto *pack = conformance.getPack();
@@ -4245,12 +4248,14 @@ swift::diagnoseConformanceAvailability(SourceLoc loc,
42454248
return diagnosed;
42464249
}
42474250

4248-
if (conformance.isInvalid() || conformance.isAbstract())
4249-
return false;
4250-
42514251
const ProtocolConformance *concreteConf = conformance.getConcrete();
42524252
const RootProtocolConformance *rootConf = concreteConf->getRootConformance();
42534253

4254+
// Conformance to Copyable and Escapable doesn't have its own availability
4255+
// independent of the type.
4256+
if (rootConf->getProtocol()->getInvertibleProtocolKind())
4257+
return false;
4258+
42544259
// Diagnose "missing" conformances where we needed a conformance but
42554260
// didn't have one.
42564261
auto *DC = where.getDeclContext();

lib/Serialization/Deserialization.cpp

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3216,21 +3216,6 @@ class DeclDeserializer {
32163216
decl.get<ExtensionDecl *>()->setInherited(inherited);
32173217
}
32183218

3219-
void handleInherited(ProtocolDecl *P,
3220-
ArrayRef<ProtocolDecl *> inherited) {
3221-
SmallVector<InheritedEntry, 2> inheritedTypes;
3222-
llvm::transform(inherited, std::back_inserter(inheritedTypes), [](auto *I) {
3223-
return InheritedEntry(TypeLoc::withoutLoc(I->getDeclaredInterfaceType()),
3224-
/*isUnchecked=*/false,
3225-
/*isRetroactive=*/false,
3226-
/*isPreconcurrency=*/false);
3227-
});
3228-
3229-
P->setInherited(ctx.AllocateCopy(inheritedTypes));
3230-
ctx.evaluator.cacheOutput(InheritedProtocolsRequest{P},
3231-
ctx.AllocateCopy(inherited));
3232-
}
3233-
32343219
public:
32353220
DeclDeserializer(ModuleFile &MF, Serialized<Decl *> &declOrOffset)
32363221
: MF(MF), ctx(MF.getContext()), declOrOffset(declOrOffset) {}
@@ -4517,7 +4502,8 @@ class DeclDeserializer {
45174502
if (!MF.readInheritedProtocols(inherited))
45184503
return MF.diagnoseFatal();
45194504

4520-
handleInherited(proto, inherited);
4505+
ctx.evaluator.cacheOutput(InheritedProtocolsRequest{proto},
4506+
ctx.AllocateCopy(inherited));
45214507

45224508
auto genericParams = MF.maybeReadGenericParams(DC);
45234509
assert(genericParams && "protocol with no generic parameters?");
@@ -8256,7 +8242,7 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
82568242
auto maybeConformance = getConformanceChecked(conformanceID);
82578243
if (maybeConformance) {
82588244
reqConformances.push_back(maybeConformance.get());
8259-
} else if (allowCompilerErrors()) {
8245+
} else if (getContext().LangOpts.EnableDeserializationRecovery) {
82608246
diagnoseAndConsumeError(maybeConformance.takeError());
82618247
reqConformances.push_back(ProtocolConformanceRef::forInvalid());
82628248
} else {

lib/SymbolGraphGen/Edge.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,11 @@ void Edge::serialize(llvm::json::OStream &OS) const {
4747
SmallVector<Requirement, 4> FilteredRequirements;
4848
filterGenericRequirements(
4949
ConformanceExtension->getGenericRequirements(),
50-
ConformanceExtension->getExtendedNominal()
51-
->getDeclContext()->getSelfNominalTypeDecl(),
50+
ConformanceExtension->getExtendedProtocolDecl(),
5251
FilteredRequirements);
5352
if (!FilteredRequirements.empty()) {
5453
OS.attributeArray("swiftConstraints", [&](){
55-
for (const auto &Req :
56-
ConformanceExtension->getGenericRequirements()) {
54+
for (const auto &Req : FilteredRequirements) {
5755
::serialize(Req, OS);
5856
}
5957
});

lib/SymbolGraphGen/JSON.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ swift::symbolgraphgen::filterGenericParams(
216216
}
217217
}
218218

219+
// FIXME: This is wrong. We should instead compute the new requirements of a
220+
// member declaration by comparing against the generic signature of its
221+
// parent, with getRequirementsNotSatisfiedBy().
219222
static bool containsParams(swift::Type Ty, llvm::ArrayRef<const swift::GenericTypeParamType*> Others) {
220223
return Ty.findIf([&](swift::Type T) -> bool {
221224
if (auto AT = T->getAs<swift::ArchetypeType>()) {
@@ -232,20 +235,23 @@ static bool containsParams(swift::Type Ty, llvm::ArrayRef<const swift::GenericTy
232235

233236
void swift::symbolgraphgen::filterGenericRequirements(
234237
ArrayRef<Requirement> Requirements,
235-
const NominalTypeDecl *Self,
238+
const ProtocolDecl *Self,
236239
SmallVectorImpl<Requirement> &FilteredRequirements,
237240
SubstitutionMap SubMap,
238241
ArrayRef<const GenericTypeParamType *> FilteredParams) {
239242

240243
for (const auto &Req : Requirements) {
244+
// FIXME: We're just dropping "Self: AnyObject", etc.
241245
if (Req.getKind() == RequirementKind::Layout) {
242246
continue;
243247
}
244248
// extension /* protocol */ Q {
245249
// func foo() {}
246250
// }
247251
// ignore Self : Q, obvious
248-
if (Req.getSecondType()->getAnyNominal() == Self) {
252+
if (Self &&
253+
Req.getKind() == RequirementKind::Conformance &&
254+
Req.getProtocolDecl() == Self) {
249255
continue;
250256
}
251257

@@ -274,21 +280,31 @@ void swift::symbolgraphgen::filterGenericRequirements(
274280
void
275281
swift::symbolgraphgen::filterGenericRequirements(const ExtensionDecl *Extension,
276282
SmallVectorImpl<Requirement> &FilteredRequirements) {
277-
for (const auto &Req : Extension->getGenericRequirements()) {
278-
if (Req.getKind() == RequirementKind::Layout) {
279-
continue;
280-
}
283+
auto Sig = Extension->getGenericSignature();
284+
if (!Sig)
285+
return;
281286

282-
if (!isa<ProtocolDecl>(Extension->getExtendedNominal()) &&
283-
Req.getFirstType()->isEqual(Extension->getExtendedType())) {
287+
SmallVector<Requirement, 2> Reqs;
288+
SmallVector<InverseRequirement, 2> InverseReqs;
289+
Sig->getRequirementsWithInverses(Reqs, InverseReqs);
290+
// FIXME(noncopyable_generics): Do something with InverseReqs, or just use
291+
// getRequirements() above and update the tests.
292+
293+
for (const auto &Req : Reqs) {
294+
if (Req.getKind() == RequirementKind::Layout) {
284295
continue;
285296
}
286297

287298
// extension /* protocol */ Q
288299
// ignore Self : Q, obvious
289-
if (Req.getSecondType()->isEqual(Extension->getExtendedType())) {
290-
continue;
300+
if (auto *Proto = Extension->getExtendedProtocolDecl()) {
301+
if (Req.getKind() == RequirementKind::Conformance &&
302+
Req.getFirstType()->isEqual(Extension->getSelfInterfaceType()) &&
303+
Req.getProtocolDecl() == Proto) {
304+
continue;
305+
}
291306
}
307+
292308
FilteredRequirements.push_back(Req);
293309
}
294310
}

lib/SymbolGraphGen/JSON.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void filterGenericParams(
5353
/// Filter generic requirements on an extension that aren't relevant
5454
/// for documentation.
5555
void filterGenericRequirements(
56-
ArrayRef<Requirement> Requirements, const NominalTypeDecl *Self,
56+
ArrayRef<Requirement> Requirements, const ProtocolDecl *Self,
5757
SmallVectorImpl<Requirement> &FilteredRequirements,
5858
SubstitutionMap SubMap = {},
5959
ArrayRef<const GenericTypeParamType *> FilteredParams = {});

0 commit comments

Comments
 (0)