Skip to content

Commit 74df113

Browse files
authored
Merge pull request #29027 from CodaFi/a-designation-with-a-difference
[ModuleInterface][5.2] Add Support for @_hasMissingDesignatedInitializers
2 parents 277d771 + bcec86e commit 74df113

33 files changed

+429
-52
lines changed

include/swift/AST/Decl.h

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

529529
/// \see ClassDecl::getEmittedMembers()
530-
HasForcedEmittedMembers : 1,
530+
HasForcedEmittedMembers : 1,
531531

532532
HasMissingDesignatedInitializers : 1,
533533
ComputedHasMissingDesignatedInitializers : 1,
@@ -3806,6 +3806,25 @@ class ClassDecl final : public NominalTypeDecl {
38063806
return None;
38073807
}
38083808

3809+
Optional<bool> getCachedHasMissingDesignatedInitializers() const {
3810+
if (!Bits.ClassDecl.ComputedHasMissingDesignatedInitializers) {
3811+
// Force loading all the members, which will add this attribute if any of
3812+
// members are determined to be missing while loading.
3813+
auto mutableThis = const_cast<ClassDecl *>(this);
3814+
(void)mutableThis->lookupDirect(DeclBaseName::createConstructor());
3815+
}
3816+
3817+
if (Bits.ClassDecl.ComputedHasMissingDesignatedInitializers)
3818+
return Bits.ClassDecl.HasMissingDesignatedInitializers;
3819+
3820+
return None;
3821+
}
3822+
3823+
void setHasMissingDesignatedInitializers(bool value) {
3824+
Bits.ClassDecl.HasMissingDesignatedInitializers = value;
3825+
Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = true;
3826+
}
3827+
38093828
/// Marks that this class inherits convenience initializers from its
38103829
/// superclass.
38113830
void setInheritsSuperclassInitializers(bool value) {
@@ -3816,6 +3835,7 @@ class ClassDecl final : public NominalTypeDecl {
38163835
friend class SuperclassDeclRequest;
38173836
friend class SuperclassTypeRequest;
38183837
friend class EmittedMembersRequest;
3838+
friend class HasMissingDesignatedInitializersRequest;
38193839
friend class InheritsSuperclassInitializersRequest;
38203840
friend class TypeChecker;
38213841

@@ -3922,11 +3942,6 @@ class ClassDecl final : public NominalTypeDecl {
39223942
/// initializers that cannot be represented in Swift.
39233943
bool hasMissingDesignatedInitializers() const;
39243944

3925-
void setHasMissingDesignatedInitializers(bool newValue = true) {
3926-
Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = 1;
3927-
Bits.ClassDecl.HasMissingDesignatedInitializers = newValue;
3928-
}
3929-
39303945
/// Returns true if the class has missing members that require vtable entries.
39313946
///
39323947
/// In this case, the class cannot be subclassed, because we cannot construct
@@ -3965,7 +3980,7 @@ class ClassDecl final : public NominalTypeDecl {
39653980

39663981
/// Determine whether this class inherits the convenience initializers
39673982
/// from its superclass.
3968-
bool inheritsSuperclassInitializers();
3983+
bool inheritsSuperclassInitializers() const;
39693984

39703985
/// Walks the class hierarchy starting from this class, checking various
39713986
/// conditions.

include/swift/AST/DiagnosticsModuleDiffer.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ ERROR(objc_name_change,none,"%0 has ObjC name change from %1 to %2", (StringRef,
9898

9999
ERROR(desig_init_added,none,"%0 has been added as a designated initializer to an open class", (StringRef))
100100

101+
ERROR(added_invisible_designated_init,none,"%0 has new designated initializers that are not visible to clients", (StringRef))
102+
103+
ERROR(not_inheriting_convenience_inits,none,"%0 no longer inherits convenience inits from its superclass", (StringRef))
104+
101105
#ifndef DIAG_NO_UNDEF
102106
# if defined(DIAG)
103107
# undef DIAG

include/swift/AST/NameLookupRequests.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,29 @@ class SuperclassDeclRequest :
156156
void cacheResult(ClassDecl *value) const;
157157
};
158158

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

include/swift/AST/NameLookupTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ SWIFT_REQUEST(NameLookup, SelfBoundsFromWhereClauseRequest,
3939
Uncached, NoLocationInfo)
4040
SWIFT_REQUEST(NameLookup, SuperclassDeclRequest, ClassDecl *(NominalTypeDecl *),
4141
SeparatelyCached, NoLocationInfo)
42+
SWIFT_REQUEST(NameLookup, HasMissingDesignatedInitializersRequest,
43+
bool(ClassDecl *),
44+
SeparatelyCached, NoLocationInfo)
4245
SWIFT_REQUEST(NameLookup, TypeDeclsFromWhereClauseRequest,
4346
DirectlyReferencedTypeDecls(ExtensionDecl *), Uncached,
4447
NoLocationInfo)

include/swift/IDE/DigesterEnums.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ KEY_BOOL(HasStorage, hasStorage)
132132
KEY_BOOL(ReqNewWitnessTableEntry, reqNewWitnessTableEntry)
133133
KEY_BOOL(IsABIPlaceholder, isABIPlaceholder)
134134
KEY_BOOL(IsExternal, isExternal)
135+
KEY_BOOL(HasMissingDesignatedInitializers, hasMissingDesignatedInitializers)
136+
KEY_BOOL(InheritsConvenienceInitializers, inheritsConvenienceInitializers)
135137

136138
KEY(kind)
137139

lib/AST/ASTPrinter.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,22 @@ void PrintAST::printAttributes(const Decl *D) {
974974
Printer << " ";
975975
}
976976
}
977+
978+
// If the declaration has designated inits that won't be visible to
979+
// clients, or if it inherits superclass convenience initializers,
980+
// then print those attributes specially.
981+
if (auto CD = dyn_cast<ClassDecl>(D)) {
982+
if (Options.PrintImplicitAttrs) {
983+
if (CD->inheritsSuperclassInitializers()) {
984+
Printer.printAttrName("@_inheritsConvenienceInitializers");
985+
Printer << " ";
986+
}
987+
if (CD->hasMissingDesignatedInitializers()) {
988+
Printer.printAttrName("@_hasMissingDesignatedInitializers");
989+
Printer << " ";
990+
}
991+
}
992+
}
977993
}
978994

979995
D->getAttrs().print(Printer, Options, D);

lib/AST/Decl.cpp

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

4114-
41154114
bool ClassDecl::hasMissingDesignatedInitializers() const {
4116-
if (!Bits.ClassDecl.ComputedHasMissingDesignatedInitializers) {
4117-
auto *mutableThis = const_cast<ClassDecl *>(this);
4118-
mutableThis->Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = 1;
4119-
(void)mutableThis->lookupDirect(DeclBaseName::createConstructor());
4120-
}
4121-
4122-
return Bits.ClassDecl.HasMissingDesignatedInitializers;
4115+
return evaluateOrDefault(
4116+
getASTContext().evaluator,
4117+
HasMissingDesignatedInitializersRequest{const_cast<ClassDecl *>(this)},
4118+
false);
41234119
}
41244120

41254121
bool ClassDecl::hasMissingVTableEntries() const {
@@ -4142,7 +4138,7 @@ bool ClassDecl::isIncompatibleWithWeakReferences() const {
41424138
return false;
41434139
}
41444140

4145-
bool ClassDecl::inheritsSuperclassInitializers() {
4141+
bool ClassDecl::inheritsSuperclassInitializers() const {
41464142
// If there's no superclass, there's nothing to inherit.
41474143
if (!getSuperclass())
41484144
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
@@ -7646,7 +7646,8 @@ ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl,
76467646
if (getClangModuleForDecl(theClass) == getClangModuleForDecl(method)) {
76477647
if (auto swiftClass = castIgnoringCompatibilityAlias<ClassDecl>(
76487648
importDecl(theClass, CurrentVersion))) {
7649-
swiftClass->setHasMissingDesignatedInitializers();
7649+
SwiftContext.evaluator.cacheOutput(
7650+
HasMissingDesignatedInitializersRequest{swiftClass}, true);
76507651
}
76517652
}
76527653
}

lib/Sema/CodeSynthesis.cpp

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

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

10131018
// 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
@@ -1096,6 +1096,7 @@ static void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
10961096

10971097
auto *superclassDecl = classDecl->getSuperclassDecl();
10981098
if (superclassDecl &&
1099+
superclassDecl->getModuleContext() != classDecl->getModuleContext() &&
10991100
superclassDecl->hasMissingDesignatedInitializers())
11001101
return;
11011102

lib/Serialization/Deserialization.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3400,6 +3400,7 @@ class swift::DeclDeserializer {
34003400
DeclContextID contextID;
34013401
bool isImplicit, isObjC;
34023402
bool inheritsSuperclassInitializers;
3403+
bool hasMissingDesignatedInits;
34033404
GenericSignatureID genericSigID;
34043405
TypeID superclassID;
34053406
uint8_t rawAccessLevel;
@@ -3408,6 +3409,7 @@ class swift::DeclDeserializer {
34083409
decls_block::ClassLayout::readRecord(scratch, nameID, contextID,
34093410
isImplicit, isObjC,
34103411
inheritsSuperclassInitializers,
3412+
hasMissingDesignatedInits,
34113413
genericSigID, superclassID,
34123414
rawAccessLevel, numConformances,
34133415
numInheritedTypes,
@@ -3450,6 +3452,8 @@ class swift::DeclDeserializer {
34503452
theClass->setSuperclass(MF.getType(superclassID));
34513453
ctx.evaluator.cacheOutput(InheritsSuperclassInitializersRequest{theClass},
34523454
std::move(inheritsSuperclassInitializers));
3455+
ctx.evaluator.cacheOutput(HasMissingDesignatedInitializersRequest{theClass},
3456+
std::move(hasMissingDesignatedInits));
34533457

34543458
handleInherited(theClass,
34553459
rawInheritedAndDependencyIDs.slice(0, numInheritedTypes));
@@ -5328,7 +5332,8 @@ Decl *handleErrorAndSupplyMissingClassMember(ASTContext &context,
53285332
Decl *suppliedMissingMember = nullptr;
53295333
auto handleMissingClassMember = [&](const DeclDeserializationError &error) {
53305334
if (error.isDesignatedInitializer())
5331-
containingClass->setHasMissingDesignatedInitializers();
5335+
context.evaluator.cacheOutput(
5336+
HasMissingDesignatedInitializersRequest{containingClass}, true);
53325337
if (error.getNumberOfVTableEntries() > 0)
53335338
containingClass->setHasMissingVTableEntries();
53345339

lib/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t SWIFTMODULE_VERSION_MINOR = 527; // #filePath
58+
const uint16_t SWIFTMODULE_VERSION_MINOR = 528; // @_hasMissingDesignatedInitializers
5959

6060
/// A standard hash seed used for all string hashes in a serialized module.
6161
///
@@ -1102,6 +1102,7 @@ namespace decls_block {
11021102
BCFixed<1>, // implicit?
11031103
BCFixed<1>, // explicitly objc?
11041104
BCFixed<1>, // inherits convenience initializers from its superclass?
1105+
BCFixed<1>, // has missing designated initializers?
11051106
GenericSignatureIDField, // generic environment
11061107
TypeIDField, // superclass
11071108
AccessLevelField, // access level

lib/Serialization/Serialization.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3071,17 +3071,16 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
30713071
uint8_t rawAccessLevel =
30723072
getRawStableAccessLevel(theClass->getFormalAccess());
30733073

3074-
bool inheritsSuperclassInitializers =
3075-
const_cast<ClassDecl *>(theClass)->
3076-
inheritsSuperclassInitializers();
3074+
auto mutableClass = const_cast<ClassDecl *>(theClass);
30773075

30783076
unsigned abbrCode = S.DeclTypeAbbrCodes[ClassLayout::Code];
30793077
ClassLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
30803078
S.addDeclBaseNameRef(theClass->getName()),
30813079
contextID.getOpaqueValue(),
30823080
theClass->isImplicit(),
30833081
theClass->isObjC(),
3084-
inheritsSuperclassInitializers,
3082+
mutableClass->inheritsSuperclassInitializers(),
3083+
mutableClass->hasMissingDesignatedInitializers(),
30853084
S.addGenericSignatureRef(
30863085
theClass->getGenericSignature()),
30873086
S.addTypeRef(theClass->getSuperclass()),

test/IDE/print_ast_tc_decls.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ class d0120_TestClassBase {
452452
}
453453

454454
class d0121_TestClassDerived : d0120_TestClassBase {
455-
// PASS_COMMON-LABEL: {{^}}class d0121_TestClassDerived : d0120_TestClassBase {{{$}}
455+
// PASS_COMMON-LABEL: {{^}}@_inheritsConvenienceInitializers {{()?}}class d0121_TestClassDerived : d0120_TestClassBase {{{$}}
456456

457457
required init() { super.init() }
458458
// PASS_COMMON-NEXT: {{^}} required init(){{$}}
@@ -611,8 +611,8 @@ struct d0200_EscapedIdentifiers {
611611
// PASS_ONE_LINE_TYPEREPR-DAG: {{^}} typealias `protocol` = `class`{{$}}
612612

613613
class `extension` : `class` {}
614-
// PASS_ONE_LINE_TYPE-DAG: {{^}} class `extension` : d0200_EscapedIdentifiers.`class` {{{$}}
615-
// PASS_ONE_LINE_TYPEREPR-DAG: {{^}} class `extension` : `class` {{{$}}
614+
// PASS_ONE_LINE_TYPE-DAG: {{^}} @_inheritsConvenienceInitializers class `extension` : d0200_EscapedIdentifiers.`class` {{{$}}
615+
// PASS_ONE_LINE_TYPEREPR-DAG: {{^}} @_inheritsConvenienceInitializers class `extension` : `class` {{{$}}
616616
// PASS_COMMON: {{^}} @objc deinit{{$}}
617617
// PASS_COMMON-NEXT: {{^}} {{(override )?}}init(){{$}}
618618
// PASS_COMMON-NEXT: {{^}} }{{$}}
@@ -748,7 +748,7 @@ class d0260_ExplodePattern_TestClassBase {
748748
}
749749

750750
class d0261_ExplodePattern_TestClassDerived : d0260_ExplodePattern_TestClassBase {
751-
// PASS_EXPLODE_PATTERN-LABEL: {{^}}class d0261_ExplodePattern_TestClassDerived : d0260_ExplodePattern_TestClassBase {{{$}}
751+
// PASS_EXPLODE_PATTERN-LABEL: {{^}}@_inheritsConvenienceInitializers class d0261_ExplodePattern_TestClassDerived : d0260_ExplodePattern_TestClassBase {{{$}}
752752

753753
override final var baseProp2: Int {
754754
get {
@@ -791,13 +791,13 @@ class ClassWithInheritance2 : FooProtocol, BarProtocol {}
791791
// PASS_ONE_LINE-DAG: {{^}}class ClassWithInheritance2 : FooProtocol, BarProtocol {{{$}}
792792

793793
class ClassWithInheritance3 : FooClass {}
794-
// PASS_ONE_LINE-DAG: {{^}}class ClassWithInheritance3 : FooClass {{{$}}
794+
// PASS_ONE_LINE-DAG: {{^}}@_inheritsConvenienceInitializers class ClassWithInheritance3 : FooClass {{{$}}
795795

796796
class ClassWithInheritance4 : FooClass, FooProtocol {}
797-
// PASS_ONE_LINE-DAG: {{^}}class ClassWithInheritance4 : FooClass, FooProtocol {{{$}}
797+
// PASS_ONE_LINE-DAG: {{^}}@_inheritsConvenienceInitializers class ClassWithInheritance4 : FooClass, FooProtocol {{{$}}
798798

799799
class ClassWithInheritance5 : FooClass, FooProtocol, BarProtocol {}
800-
// PASS_ONE_LINE-DAG: {{^}}class ClassWithInheritance5 : FooClass, FooProtocol, BarProtocol {{{$}}
800+
// PASS_ONE_LINE-DAG: {{^}}@_inheritsConvenienceInitializers class ClassWithInheritance5 : FooClass, FooProtocol, BarProtocol {{{$}}
801801

802802
class ClassWithInheritance6 : QuxProtocol, SubFooProtocol {
803803
typealias Qux = Int

0 commit comments

Comments
 (0)