Skip to content

Commit 283854a

Browse files
Harlan HaskinsCodaFi
authored andcommitted
[Sema] Requestify hasMissingDesignatedInitializers
We’re going to start serializing this for public types that have non-public-or-@usableFromInline initializers, so turn it into a request that we can query and cache it in the existing bit.
1 parent 8e45f44 commit 283854a

File tree

8 files changed

+103
-18
lines changed

8 files changed

+103
-18
lines changed

include/swift/AST/Decl.h

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ class alignas(1 << DeclAlignInBits) Decl {
539539
RawForeignKind : 2,
540540

541541
/// \see ClassDecl::getEmittedMembers()
542-
HasForcedEmittedMembers : 1,
542+
HasForcedEmittedMembers : 1,
543543

544544
HasMissingDesignatedInitializers : 1,
545545
ComputedHasMissingDesignatedInitializers : 1,
@@ -3833,6 +3833,25 @@ class ClassDecl final : public NominalTypeDecl {
38333833
return None;
38343834
}
38353835

3836+
Optional<bool> getCachedHasMissingDesignatedInitializers() const {
3837+
if (!Bits.ClassDecl.ComputedHasMissingDesignatedInitializers) {
3838+
// Force loading all the members, which will add this attribute if any of
3839+
// members are determined to be missing while loading.
3840+
auto mutableThis = const_cast<ClassDecl *>(this);
3841+
(void)mutableThis->lookupDirect(DeclBaseName::createConstructor());
3842+
}
3843+
3844+
if (Bits.ClassDecl.ComputedHasMissingDesignatedInitializers)
3845+
return Bits.ClassDecl.HasMissingDesignatedInitializers;
3846+
3847+
return None;
3848+
}
3849+
3850+
void setHasMissingDesignatedInitializers(bool value) {
3851+
Bits.ClassDecl.HasMissingDesignatedInitializers = value;
3852+
Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = true;
3853+
}
3854+
38363855
/// Marks that this class inherits convenience initializers from its
38373856
/// superclass.
38383857
void setInheritsSuperclassInitializers(bool value) {
@@ -3843,6 +3862,7 @@ class ClassDecl final : public NominalTypeDecl {
38433862
friend class SuperclassDeclRequest;
38443863
friend class SuperclassTypeRequest;
38453864
friend class EmittedMembersRequest;
3865+
friend class HasMissingDesignatedInitializersRequest;
38463866
friend class InheritsSuperclassInitializersRequest;
38473867
friend class TypeChecker;
38483868

@@ -3949,11 +3969,6 @@ class ClassDecl final : public NominalTypeDecl {
39493969
/// initializers that cannot be represented in Swift.
39503970
bool hasMissingDesignatedInitializers() const;
39513971

3952-
void setHasMissingDesignatedInitializers(bool newValue = true) {
3953-
Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = 1;
3954-
Bits.ClassDecl.HasMissingDesignatedInitializers = newValue;
3955-
}
3956-
39573972
/// Returns true if the class has missing members that require vtable entries.
39583973
///
39593974
/// In this case, the class cannot be subclassed, because we cannot construct
@@ -3992,7 +4007,7 @@ class ClassDecl final : public NominalTypeDecl {
39924007

39934008
/// Determine whether this class inherits the convenience initializers
39944009
/// from its superclass.
3995-
bool inheritsSuperclassInitializers();
4010+
bool inheritsSuperclassInitializers() const;
39964011

39974012
/// Walks the class hierarchy starting from this class, checking various
39984013
/// conditions.

include/swift/AST/NameLookupRequests.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,29 @@ class SuperclassDeclRequest :
161161
void cacheResult(ClassDecl *value) const;
162162
};
163163

164+
/// Requests whether or not this class has designated initializers that are
165+
/// not public or @usableFromInline.
166+
class HasMissingDesignatedInitializersRequest :
167+
public SimpleRequest<HasMissingDesignatedInitializersRequest,
168+
bool(ClassDecl *),
169+
CacheKind::SeparatelyCached> {
170+
public:
171+
using SimpleRequest::SimpleRequest;
172+
173+
private:
174+
friend SimpleRequest;
175+
176+
// Evaluation.
177+
llvm::Expected<bool>
178+
evaluate(Evaluator &evaluator, ClassDecl *subject) const;
179+
180+
public:
181+
// Caching
182+
bool isCached() const { return true; }
183+
Optional<bool> getCachedResult() const;
184+
void cacheResult(bool) const;
185+
};
186+
164187
/// Request the nominal declaration extended by a given extension declaration.
165188
class ExtendedNominalRequest :
166189
public SimpleRequest<ExtendedNominalRequest,

include/swift/AST/NameLookupTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ SWIFT_REQUEST(NameLookup, SelfBoundsFromWhereClauseRequest,
5656
Uncached, NoLocationInfo)
5757
SWIFT_REQUEST(NameLookup, SuperclassDeclRequest, ClassDecl *(NominalTypeDecl *),
5858
SeparatelyCached, NoLocationInfo)
59+
SWIFT_REQUEST(NameLookup, HasMissingDesignatedInitializersRequest,
60+
bool(ClassDecl *),
61+
SeparatelyCached, NoLocationInfo)
5962
SWIFT_REQUEST(NameLookup, TypeDeclsFromWhereClauseRequest,
6063
DirectlyReferencedTypeDecls(ExtensionDecl *), Uncached,
6164
NoLocationInfo)

lib/AST/Decl.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4127,15 +4127,11 @@ GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const {
41274127
return DD;
41284128
}
41294129

4130-
41314130
bool ClassDecl::hasMissingDesignatedInitializers() const {
4132-
if (!Bits.ClassDecl.ComputedHasMissingDesignatedInitializers) {
4133-
auto *mutableThis = const_cast<ClassDecl *>(this);
4134-
mutableThis->Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = 1;
4135-
(void)mutableThis->lookupDirect(DeclBaseName::createConstructor());
4136-
}
4137-
4138-
return Bits.ClassDecl.HasMissingDesignatedInitializers;
4131+
return evaluateOrDefault(
4132+
getASTContext().evaluator,
4133+
HasMissingDesignatedInitializersRequest{const_cast<ClassDecl *>(this)},
4134+
false);
41394135
}
41404136

41414137
bool ClassDecl::hasMissingVTableEntries() const {
@@ -4158,7 +4154,7 @@ bool ClassDecl::isIncompatibleWithWeakReferences() const {
41584154
return false;
41594155
}
41604156

4161-
bool ClassDecl::inheritsSuperclassInitializers() {
4157+
bool ClassDecl::inheritsSuperclassInitializers() const {
41624158
// If there's no superclass, there's nothing to inherit.
41634159
if (!getSuperclass())
41644160
return false;

lib/AST/NameLookupRequests.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,47 @@ void SuperclassDeclRequest::cacheResult(ClassDecl *value) const {
6767
protocolDecl->LazySemanticInfo.SuperclassDecl.setPointerAndInt(value, true);
6868
}
6969

70+
//----------------------------------------------------------------------------//
71+
// Missing designated initializers computation
72+
//----------------------------------------------------------------------------//
73+
74+
Optional<bool> HasMissingDesignatedInitializersRequest::getCachedResult() const {
75+
auto classDecl = std::get<0>(getStorage());
76+
return classDecl->getCachedHasMissingDesignatedInitializers();
77+
}
78+
79+
void HasMissingDesignatedInitializersRequest::cacheResult(bool result) const {
80+
auto classDecl = std::get<0>(getStorage());
81+
classDecl->setHasMissingDesignatedInitializers(result);
82+
}
83+
84+
llvm::Expected<bool>
85+
HasMissingDesignatedInitializersRequest::evaluate(Evaluator &evaluator,
86+
ClassDecl *subject) const {
87+
// Short-circuit and check for the attribute here.
88+
if (subject->getAttrs().hasAttribute<HasMissingDesignatedInitializersAttr>())
89+
return true;
90+
91+
AccessScope scope =
92+
subject->getFormalAccessScope(/*useDC*/nullptr,
93+
/*treatUsableFromInlineAsPublic*/true);
94+
// This flag only makes sense for public types that will be written in the
95+
// module.
96+
if (!scope.isPublic())
97+
return false;
98+
99+
auto constructors = subject->lookupDirect(DeclBaseName::createConstructor());
100+
return llvm::any_of(constructors, [&](ValueDecl *decl) {
101+
auto init = cast<ConstructorDecl>(decl);
102+
if (!init->isDesignatedInit())
103+
return false;
104+
AccessScope scope =
105+
init->getFormalAccessScope(/*useDC*/nullptr,
106+
/*treatUsableFromInlineAsPublic*/true);
107+
return !scope.isPublic();
108+
});
109+
}
110+
70111
//----------------------------------------------------------------------------//
71112
// Extended nominal computation.
72113
//----------------------------------------------------------------------------//

lib/ClangImporter/ImportDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7695,7 +7695,8 @@ ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl,
76957695
if (getClangModuleForDecl(theClass) == getClangModuleForDecl(method)) {
76967696
if (auto swiftClass = castIgnoringCompatibilityAlias<ClassDecl>(
76977697
importDecl(theClass, CurrentVersion))) {
7698-
swiftClass->setHasMissingDesignatedInitializers();
7698+
SwiftContext.evaluator.cacheOutput(
7699+
HasMissingDesignatedInitializersRequest{swiftClass}, true);
76997700
}
77007701
}
77017702
}

lib/Sema/CodeSynthesis.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1002,13 +1002,18 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) {
10021002
llvm::Expected<bool>
10031003
InheritsSuperclassInitializersRequest::evaluate(Evaluator &eval,
10041004
ClassDecl *decl) const {
1005+
// Check if we parsed the @_inheritsConvenienceInitializers attribute.
1006+
if (decl->getAttrs().hasAttribute<InheritsConvenienceInitializersAttr>())
1007+
return true;
1008+
10051009
auto superclass = decl->getSuperclass();
10061010
assert(superclass);
10071011

10081012
// If the superclass has known-missing designated initializers, inheriting
10091013
// is unsafe.
10101014
auto *superclassDecl = superclass->getClassOrBoundGenericClass();
1011-
if (superclassDecl->hasMissingDesignatedInitializers())
1015+
if (superclassDecl->getModuleContext() != decl->getParentModule() &&
1016+
superclassDecl->hasMissingDesignatedInitializers())
10121017
return false;
10131018

10141019
// If we're allowed to inherit designated initializers, then we can inherit

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ static void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
11031103

11041104
auto *superclassDecl = classDecl->getSuperclassDecl();
11051105
if (superclassDecl &&
1106+
superclassDecl->getModuleContext() != classDecl->getModuleContext() &&
11061107
superclassDecl->hasMissingDesignatedInitializers())
11071108
return;
11081109

0 commit comments

Comments
 (0)