Skip to content

Commit 1631f2f

Browse files
committed
Sema: finalizeDecl() no longer forces accessor synthesis
Previously we would synthesize accessors for any referenced storage, as well as any storage members of classes and protocols. Now that synthesis is sufficiently lazy this is no longer needed. The only remaining work done in finalizeDecl() is adding certain implicit members to ClassDecls; no other declaration kind ends up in DeclsToFinalize anymore.
1 parent 6694afa commit 1631f2f

File tree

4 files changed

+45
-106
lines changed

4 files changed

+45
-106
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 40 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,11 +2472,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24722472
(void) VD->isObjC();
24732473
(void) VD->isDynamic();
24742474

2475-
// Make sure we finalize this declaration.
2476-
if (isa<ClassDecl>(VD) || isa<ProtocolDecl>(VD) ||
2477-
isa<AbstractStorageDecl>(VD))
2478-
TC.DeclsToFinalize.insert(VD);
2479-
24802475
// If this is a member of a nominal type, don't allow it to have a name of
24812476
// "Type" or "Protocol" since we reserve the X.Type and X.Protocol
24822477
// expressions to mean something builtin to the language. We *do* allow
@@ -3155,6 +3150,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31553150

31563151

31573152
void visitClassDecl(ClassDecl *CD) {
3153+
TC.DeclsToFinalize.insert(CD);
3154+
31583155
TC.checkDeclAttributesEarly(CD);
31593156

31603157
checkUnsupportedNestedType(CD);
@@ -3499,7 +3496,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
34993496
if (auto nominal = ED->getExtendedNominal()) {
35003497
TC.validateDecl(nominal);
35013498
if (auto *classDecl = dyn_cast<ClassDecl>(nominal))
3502-
TC.requestNominalLayout(classDecl);
3499+
TC.requestClassLayout(classDecl);
35033500

35043501
// Check the raw values of an enum, since we might synthesize
35053502
// RawRepresentable while checking conformances on this extension.
@@ -4143,14 +4140,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
41434140

41444141
validateAttributes(*this, D);
41454142

4146-
// FIXME: IRGen likes to emit @objc protocol descriptors even if the
4147-
// protocol comes from a different module or translation unit.
4148-
//
4149-
// It would be nice if it didn't have to do that, then we could remove
4150-
// this case.
4151-
if (proto->isObjC())
4152-
requestNominalLayout(proto);
4153-
41544143
break;
41554144
}
41564145

@@ -4522,14 +4511,6 @@ void TypeChecker::validateDeclForNameLookup(ValueDecl *D) {
45224511
return;
45234512
proto->computeType();
45244513

4525-
// FIXME: IRGen likes to emit @objc protocol descriptors even if the
4526-
// protocol comes from a different module or translation unit.
4527-
//
4528-
// It would be nice if it didn't have to do that, then we could remove
4529-
// this case.
4530-
if (proto->isObjC())
4531-
requestNominalLayout(proto);
4532-
45334514
break;
45344515
}
45354516
case DeclKind::AssociatedType: {
@@ -4594,96 +4575,59 @@ void TypeChecker::validateDeclForNameLookup(ValueDecl *D) {
45944575
void TypeChecker::requestMemberLayout(ValueDecl *member) {
45954576
auto *dc = member->getDeclContext();
45964577
if (auto *classDecl = dyn_cast<ClassDecl>(dc))
4597-
requestNominalLayout(classDecl);
4598-
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(dc))
4599-
requestNominalLayout(protocolDecl);
4600-
4601-
// If this represents (abstract) storage, form the appropriate accessors.
4602-
if (auto storage = dyn_cast<AbstractStorageDecl>(member))
4603-
DeclsToFinalize.insert(storage);
4578+
requestClassLayout(classDecl);
46044579
}
46054580

4606-
void TypeChecker::requestNominalLayout(NominalTypeDecl *nominalDecl) {
4607-
if (isa<SourceFile>(nominalDecl->getModuleScopeContext()))
4608-
DeclsToFinalize.insert(nominalDecl);
4581+
void TypeChecker::requestClassLayout(ClassDecl *classDecl) {
4582+
if (isa<SourceFile>(classDecl->getModuleScopeContext()))
4583+
DeclsToFinalize.insert(classDecl);
46094584
}
46104585

46114586
void TypeChecker::requestSuperclassLayout(ClassDecl *classDecl) {
46124587
if (auto *superclassDecl = classDecl->getSuperclassDecl()) {
46134588
if (superclassDecl)
4614-
requestNominalLayout(superclassDecl);
4589+
requestClassLayout(superclassDecl);
46154590
}
46164591
}
46174592

4618-
/// "Finalize" the type so that SILGen can make copies of it, call
4619-
/// methods on it, etc. This requires forcing enough computation so
4620-
/// that (for example) a class can layout its vtable or a struct can
4621-
/// be laid out in memory.
4622-
static void finalizeType(TypeChecker &TC, NominalTypeDecl *nominal) {
4623-
assert(!nominal->hasClangNode());
4624-
assert(isa<SourceFile>(nominal->getModuleScopeContext()));
4625-
4626-
if (auto *CD = dyn_cast<ClassDecl>(nominal)) {
4627-
// We need to add implicit initializers and dtors because it
4628-
// affects vtable layout.
4629-
TC.addImplicitConstructors(CD);
4630-
CD->addImplicitDestructor();
4631-
4632-
// Force lowering of stored properties.
4633-
(void) nominal->getStoredProperties();
4634-
}
4635-
4636-
if (isa<ClassDecl>(nominal) || isa<ProtocolDecl>(nominal)) {
4637-
for (auto *D : nominal->getMembers()) {
4638-
if (auto *ASD = dyn_cast<AbstractStorageDecl>(D))
4639-
TC.DeclsToFinalize.insert(ASD);
4640-
}
4641-
}
4642-
4643-
if (auto *CD = dyn_cast<ClassDecl>(nominal)) {
4644-
// We need the superclass vtable layout as well.
4645-
TC.requestSuperclassLayout(CD);
4593+
void TypeChecker::finalizeDecl(ClassDecl *CD) {
4594+
if (Context.Stats)
4595+
Context.Stats->getFrontendCounters().NumDeclsFinalized++;
46464596

4647-
auto forceConformance = [&](ProtocolDecl *protocol) {
4648-
if (auto ref = TypeChecker::conformsToProtocol(
4649-
CD->getDeclaredInterfaceType(), protocol, CD,
4650-
ConformanceCheckFlags::SkipConditionalRequirements,
4651-
SourceLoc())) {
4652-
auto conformance = ref->getConcrete();
4653-
if (conformance->getDeclContext() == CD &&
4654-
conformance->getState() == ProtocolConformanceState::Incomplete) {
4655-
TC.checkConformance(conformance->getRootNormalConformance());
4656-
}
4657-
}
4658-
};
4597+
assert(!CD->hasClangNode());
4598+
assert(isa<SourceFile>(CD->getModuleScopeContext()));
46594599

4660-
// If the class is Encodable, Decodable or Hashable, force those
4661-
// conformances to ensure that the synthesized members appear in the vtable.
4662-
//
4663-
// FIXME: Generalize this to other protocols for which
4664-
// we can derive conformances.
4665-
forceConformance(TC.Context.getProtocol(KnownProtocolKind::Decodable));
4666-
forceConformance(TC.Context.getProtocol(KnownProtocolKind::Encodable));
4667-
forceConformance(TC.Context.getProtocol(KnownProtocolKind::Hashable));
4668-
}
4600+
validateDecl(CD);
46694601

4670-
if (auto PD = dyn_cast<ProtocolDecl>(nominal)) {
4671-
for (auto *inherited : PD->getInheritedProtocols())
4672-
TC.requestNominalLayout(inherited);
4673-
}
4674-
}
4602+
// We need to add implicit initializers and dtors because it
4603+
// affects vtable layout.
4604+
addImplicitConstructors(CD);
4605+
CD->addImplicitDestructor();
46754606

4676-
void TypeChecker::finalizeDecl(ValueDecl *decl) {
4677-
if (Context.Stats)
4678-
Context.Stats->getFrontendCounters().NumDeclsFinalized++;
4607+
// We need the superclass vtable layout as well.
4608+
requestSuperclassLayout(CD);
46794609

4680-
validateDecl(decl);
4610+
auto forceConformance = [&](ProtocolDecl *protocol) {
4611+
if (auto ref = TypeChecker::conformsToProtocol(
4612+
CD->getDeclaredInterfaceType(), protocol, CD,
4613+
ConformanceCheckFlags::SkipConditionalRequirements,
4614+
SourceLoc())) {
4615+
auto conformance = ref->getConcrete();
4616+
if (conformance->getDeclContext() == CD &&
4617+
conformance->getState() == ProtocolConformanceState::Incomplete) {
4618+
checkConformance(conformance->getRootNormalConformance());
4619+
}
4620+
}
4621+
};
46814622

4682-
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
4683-
finalizeType(*this, nominal);
4684-
} else if (auto storage = dyn_cast<AbstractStorageDecl>(decl)) {
4685-
addExpectedOpaqueAccessorsToStorage(storage);
4686-
}
4623+
// If the class is Encodable, Decodable or Hashable, force those
4624+
// conformances to ensure that the synthesized members appear in the vtable.
4625+
//
4626+
// FIXME: Generalize this to other protocols for which
4627+
// we can derive conformances.
4628+
forceConformance(Context.getProtocol(KnownProtocolKind::Decodable));
4629+
forceConformance(Context.getProtocol(KnownProtocolKind::Encodable));
4630+
forceConformance(Context.getProtocol(KnownProtocolKind::Hashable));
46874631
}
46884632

46894633
/// Determine whether this is a "pass-through" typealias, which has the

lib/Sema/TypeCheckPattern.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -809,8 +809,8 @@ static void requestLayoutForMetadataSources(TypeChecker &tc, Type type) {
809809
// parameter is of dependent type then the body of a function with said
810810
// parameter could potentially require the generic type's layout to
811811
// recover them.
812-
if (auto *nominalDecl = type->getAnyNominal()) {
813-
tc.requestNominalLayout(nominalDecl);
812+
if (auto *classDecl = type->getClassOrBoundGenericClass()) {
813+
tc.requestClassLayout(classDecl);
814814
}
815815
});
816816
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3693,11 +3693,6 @@ void ConformanceChecker::resolveValueWitnesses() {
36933693
auto witness = Conformance->getWitness(requirement).getDecl();
36943694
if (!witness) return;
36953695

3696-
// Make sure that we finalize the witness, so we can emit this
3697-
// witness table.
3698-
if (isa<AbstractStorageDecl>(witness))
3699-
TC.DeclsToFinalize.insert(witness);
3700-
37013696
// Objective-C checking for @objc requirements.
37023697
if (requirement->isObjC() &&
37033698
requirement->getFullName() == witness->getFullName() &&

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ class TypeChecker final : public LazyResolver {
556556
/// The list of declarations that we've done at least partial validation
557557
/// of during type-checking, but which will need to be finalized before
558558
/// we can hand them off to SILGen etc.
559-
llvm::SetVector<ValueDecl *> DeclsToFinalize;
559+
llvm::SetVector<ClassDecl *> DeclsToFinalize;
560560

561561
/// Track the index of the next declaration that needs to be finalized,
562562
/// from the \c DeclsToFinalize set.
@@ -810,7 +810,7 @@ class TypeChecker final : public LazyResolver {
810810

811811
/// Request that the given class needs to have all members validated
812812
/// after everything in the translation unit has been processed.
813-
void requestNominalLayout(NominalTypeDecl *nominalDecl);
813+
void requestClassLayout(ClassDecl *classDecl);
814814

815815
/// Request that the superclass of the given class, if any, needs to have
816816
/// all members validated after everything in the translation unit has
@@ -819,7 +819,7 @@ class TypeChecker final : public LazyResolver {
819819

820820
/// Perform final validation of a declaration after everything in the
821821
/// translation unit has been processed.
822-
void finalizeDecl(ValueDecl *D);
822+
void finalizeDecl(ClassDecl *CD);
823823

824824
/// Resolve a reference to the given type declaration within a particular
825825
/// context.

0 commit comments

Comments
 (0)