Skip to content

Commit 709efbc

Browse files
committed
Sema: implement getInitKind using a request evaluator.
Add the request `InitKind` to lazily compute the kind of an initializer declaration.
1 parent 76272d3 commit 709efbc

File tree

11 files changed

+118
-72
lines changed

11 files changed

+118
-72
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ SWIFT_TYPEID_NAMED(Decl *, Decl)
2222
SWIFT_TYPEID(Type)
2323
SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo)
2424
SWIFT_TYPEID(PropertyWrapperTypeInfo)
25+
SWIFT_TYPEID(CtorInitializerKind)
2526
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
2627
SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl)

include/swift/AST/ASTTypeIDs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class CustomAttr;
2424
class NominalTypeDecl;
2525
struct PropertyWrapperBackingPropertyInfo;
2626
struct PropertyWrapperTypeInfo;
27+
enum class CtorInitializerKind;
2728
class Type;
2829
class VarDecl;
2930
class TypeAliasDecl;

include/swift/AST/Decl.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -449,17 +449,14 @@ class alignas(1 << DeclAlignInBits) Decl {
449449
AccessorKind : 4
450450
);
451451

452-
SWIFT_INLINE_BITFIELD(ConstructorDecl, AbstractFunctionDecl, 3+2+2+1,
452+
SWIFT_INLINE_BITFIELD(ConstructorDecl, AbstractFunctionDecl, 3+2+1,
453453
/// The body initialization kind (+1), or zero if not yet computed.
454454
///
455455
/// This value is cached but is not serialized, because it is a property
456456
/// of the definition of the constructor that is useful only to semantic
457457
/// analysis and SIL generation.
458458
ComputedBodyInitKind : 3,
459459

460-
/// The kind of initializer we have.
461-
InitKind : 2,
462-
463460
/// The failability of this initializer, which is an OptionalTypeKind.
464461
Failability : 2,
465462

@@ -6519,14 +6516,7 @@ class ConstructorDecl : public AbstractFunctionDecl {
65196516
}
65206517

65216518
/// Determine the kind of initializer this is.
6522-
CtorInitializerKind getInitKind() const {
6523-
return static_cast<CtorInitializerKind>(Bits.ConstructorDecl.InitKind);
6524-
}
6525-
6526-
/// Set whether this is a convenience initializer.
6527-
void setInitKind(CtorInitializerKind kind) {
6528-
Bits.ConstructorDecl.InitKind = static_cast<unsigned>(kind);
6529-
}
6519+
CtorInitializerKind getInitKind() const;
65306520

65316521
/// Whether this is a designated initializer.
65326522
bool isDesignatedInit() const {

include/swift/AST/TypeCheckRequests.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,28 @@ class IsObjCRequest :
177177
void cacheResult(bool value) const;
178178
};
179179

180+
void simple_display(llvm::raw_ostream &out, CtorInitializerKind initKind);
181+
182+
/// Computes the kind of initializer for a given \c ConstructorDecl
183+
class InitKindRequest:
184+
public SimpleRequest<InitKindRequest,
185+
CtorInitializerKind(ConstructorDecl *),
186+
CacheKind::Cached> {
187+
public:
188+
using SimpleRequest::SimpleRequest;
189+
190+
private:
191+
friend SimpleRequest;
192+
193+
// Evaluation.
194+
llvm::Expected<CtorInitializerKind>
195+
evaluate(Evaluator &evaluator, ConstructorDecl *decl) const;
196+
197+
public:
198+
// Caching.
199+
bool isCached() const { return true; }
200+
};
201+
180202
/// Determine whether the given protocol declaration is class-bounded.
181203
class ProtocolRequiresClassRequest:
182204
public SimpleRequest<ProtocolRequiresClassRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ SWIFT_TYPEID(SuperclassTypeRequest)
1919
SWIFT_TYPEID(EnumRawTypeRequest)
2020
SWIFT_TYPEID(OverriddenDeclsRequest)
2121
SWIFT_TYPEID(IsObjCRequest)
22+
SWIFT_TYPEID(InitKindRequest)
2223
SWIFT_TYPEID(ProtocolRequiresClassRequest)
2324
SWIFT_TYPEID(ExistentialConformsToSelfRequest)
2425
SWIFT_TYPEID(ExistentialTypeSupportedRequest)

lib/AST/Decl.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6915,7 +6915,6 @@ ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
69156915

69166916
Bits.ConstructorDecl.ComputedBodyInitKind = 0;
69176917
Bits.ConstructorDecl.HasStubImplementation = 0;
6918-
Bits.ConstructorDecl.InitKind = static_cast<unsigned>(CtorInitializerKind::Designated);
69196918
Bits.ConstructorDecl.Failability = static_cast<unsigned>(Failability);
69206919

69216920
assert(Name.getBaseName() == DeclBaseName::createConstructor());
@@ -7107,6 +7106,12 @@ Type ConstructorDecl::getInitializerInterfaceType() {
71077106
return InitializerInterfaceType;
71087107
}
71097108

7109+
CtorInitializerKind ConstructorDecl::getInitKind() const {
7110+
return evaluateOrDefault(getASTContext().evaluator,
7111+
InitKindRequest{const_cast<ConstructorDecl *>(this)},
7112+
CtorInitializerKind::Designated);
7113+
}
7114+
71107115
ConstructorDecl::BodyInitKind
71117116
ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags,
71127117
ApplyExpr **init) const {

lib/AST/TypeCheckRequests.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,22 @@ void swift::simple_display(
587587
out << " }";
588588
}
589589

590+
void swift::simple_display(
591+
llvm::raw_ostream &out, const CtorInitializerKind initKind) {
592+
out << "{ ";
593+
switch (initKind) {
594+
case CtorInitializerKind::Designated:
595+
out << "designated"; break;
596+
case CtorInitializerKind::Convenience:
597+
out << "convenience"; break;
598+
case CtorInitializerKind::ConvenienceFactory:
599+
out << "convenience_factory"; break;
600+
case CtorInitializerKind::Factory:
601+
out << "factory"; break;
602+
}
603+
out << " }";
604+
}
605+
590606
//----------------------------------------------------------------------------//
591607
// FunctionBuilder-related requests.
592608
//----------------------------------------------------------------------------//

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "swift/AST/ProtocolConformance.h"
3737
#include "swift/AST/Stmt.h"
3838
#include "swift/AST/Types.h"
39+
#include "swift/AST/TypeCheckRequests.h"
3940
#include "swift/Basic/Defer.h"
4041
#include "swift/Basic/PrettyStackTrace.h"
4142
#include "swift/ClangImporter/ClangModule.h"
@@ -5695,7 +5696,8 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer(
56955696
initOptionality, /*FailabilityLoc=*/SourceLoc(),
56965697
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), parameterList,
56975698
/*GenericParams=*/nullptr, dc);
5698-
result->setInitKind(initKind);
5699+
result->getASTContext().evaluator.cacheOutput(InitKindRequest{result},
5700+
std::move(initKind));
56995701
result->setImportAsStaticMember();
57005702

57015703
// Set the constructor's type.
@@ -6324,7 +6326,8 @@ ConstructorDecl *SwiftDeclConverter::importConstructor(
63246326
result->setImplicit();
63256327

63266328
// Set the kind of initializer.
6327-
result->setInitKind(kind);
6329+
result->getASTContext().evaluator.cacheOutput(InitKindRequest{result},
6330+
std::move(kind));
63286331

63296332
// Consult API notes to determine whether this initializer is required.
63306333
if (!required && isRequiredInitializer(objcMethod))

lib/Parse/ParseDecl.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6530,11 +6530,6 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
65306530

65316531
CD->setGenericParams(GenericParams);
65326532

6533-
CtorInitializerKind initKind = CtorInitializerKind::Designated;
6534-
if (Attributes.hasAttribute<ConvenienceAttr>())
6535-
initKind = CtorInitializerKind::Convenience;
6536-
CD->setInitKind(initKind);
6537-
65386533
// No need to setLocalDiscriminator.
65396534

65406535
DefaultArgs.setFunctionContext(CD, CD->getParameters());

lib/Sema/TypeCheckDecl.cpp

Lines changed: 62 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,65 @@ static bool doesAccessorNeedDynamicAttribute(AccessorDecl *accessor) {
12281228
llvm_unreachable("covered switch");
12291229
}
12301230

1231+
llvm::Expected<CtorInitializerKind>
1232+
InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const {
1233+
auto &diags = decl->getASTContext().Diags;
1234+
1235+
// Convenience inits are only allowed on classes and in extensions thereof.
1236+
if (decl->getAttrs().hasAttribute<ConvenienceAttr>()) {
1237+
if (auto extType = decl->getDeclContext()->getDeclaredInterfaceType()) {
1238+
auto extClass = extType->getClassOrBoundGenericClass();
1239+
1240+
// Forbid convenience inits on Foreign CF types, as Swift does not yet
1241+
// support user-defined factory inits.
1242+
if (extClass &&
1243+
extClass->getForeignClassKind() == ClassDecl::ForeignKind::CFType) {
1244+
diags.diagnose(decl->getLoc(), diag::cfclass_convenience_init);
1245+
}
1246+
1247+
if (!extClass && !extType->hasError()) {
1248+
auto ConvenienceLoc =
1249+
decl->getAttrs().getAttribute<ConvenienceAttr>()->getLocation();
1250+
1251+
// Produce a tailored diagnostic for structs and enums.
1252+
bool isStruct = extType->getStructOrBoundGenericStruct() != nullptr;
1253+
if (isStruct || extType->getEnumOrBoundGenericEnum()) {
1254+
diags.diagnose(decl->getLoc(), diag::enumstruct_convenience_init,
1255+
isStruct ? "structs" : "enums")
1256+
.fixItRemove(ConvenienceLoc);
1257+
} else {
1258+
diags.diagnose(decl->getLoc(), diag::nonclass_convenience_init, extType)
1259+
.fixItRemove(ConvenienceLoc);
1260+
}
1261+
return CtorInitializerKind::Designated;
1262+
}
1263+
}
1264+
1265+
return CtorInitializerKind::Convenience;
1266+
1267+
} else if (auto extType = decl->getDeclContext()->getDeclaredInterfaceType()) {
1268+
// A designated init for a class must be written within the class itself.
1269+
//
1270+
// This is because designated initializers of classes get a vtable entry,
1271+
// and extensions cannot add vtable entries to the extended type.
1272+
//
1273+
// If we implement the ability for extensions defined in the same module
1274+
// (or the same file) to add vtable entries, we can re-evaluate this
1275+
// restriction.
1276+
if (extType->getClassOrBoundGenericClass() &&
1277+
!decl->isSynthesized() && isa<ExtensionDecl>(decl->getDeclContext()) &&
1278+
!(decl->getAttrs().hasAttribute<DynamicReplacementAttr>())) {
1279+
diags.diagnose(decl->getLoc(), diag::designated_init_in_extension, extType)
1280+
.fixItInsert(decl->getLoc(), "convenience ");
1281+
return CtorInitializerKind::Convenience;
1282+
} else if (decl->getDeclContext()->getExtendedProtocolDecl()) {
1283+
return CtorInitializerKind::Convenience;
1284+
}
1285+
}
1286+
1287+
return CtorInitializerKind::Designated;
1288+
}
1289+
12311290
llvm::Expected<bool>
12321291
ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator,
12331292
ProtocolDecl *decl) const {
@@ -3494,6 +3553,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
34943553
void visitConstructorDecl(ConstructorDecl *CD) {
34953554
TC.validateDecl(CD);
34963555

3556+
// Compute these requests in case they emit diagnostics.
3557+
(void) CD->getInitKind();
3558+
34973559
if (!CD->isInvalid()) {
34983560
checkGenericParams(CD->getGenericParams(), CD, TC);
34993561
TC.checkReferencedGenericParams(CD);
@@ -4320,57 +4382,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
43204382

43214383
checkDeclAttributesEarly(CD);
43224384

4323-
// convenience initializers are only allowed on classes and in
4324-
// extensions thereof.
4325-
if (CD->isConvenienceInit()) {
4326-
if (auto extType = CD->getDeclContext()->getDeclaredInterfaceType()) {
4327-
auto extClass = extType->getClassOrBoundGenericClass();
4328-
4329-
// Forbid convenience inits on Foreign CF types, as Swift does not yet
4330-
// support user-defined factory inits.
4331-
if (extClass &&
4332-
extClass->getForeignClassKind() == ClassDecl::ForeignKind::CFType) {
4333-
diagnose(CD->getLoc(), diag::cfclass_convenience_init);
4334-
}
4335-
4336-
if (!extClass && !extType->hasError()) {
4337-
auto ConvenienceLoc =
4338-
CD->getAttrs().getAttribute<ConvenienceAttr>()->getLocation();
4339-
4340-
// Produce a tailored diagnostic for structs and enums.
4341-
bool isStruct = extType->getStructOrBoundGenericStruct() != nullptr;
4342-
if (isStruct || extType->getEnumOrBoundGenericEnum()) {
4343-
diagnose(CD->getLoc(), diag::enumstruct_convenience_init,
4344-
isStruct ? "structs" : "enums")
4345-
.fixItRemove(ConvenienceLoc);
4346-
} else {
4347-
diagnose(CD->getLoc(), diag::nonclass_convenience_init, extType)
4348-
.fixItRemove(ConvenienceLoc);
4349-
}
4350-
CD->setInitKind(CtorInitializerKind::Designated);
4351-
}
4352-
}
4353-
} else if (auto extType = CD->getDeclContext()->getDeclaredInterfaceType()) {
4354-
// A designated initializer for a class must be written within the class
4355-
// itself.
4356-
//
4357-
// This is because designated initializers of classes get a vtable entry,
4358-
// and extensions cannot add vtable entries to the extended type.
4359-
//
4360-
// If we implement the ability for extensions defined in the same module
4361-
// (or the same file) to add vtable entries, we can re-evaluate this
4362-
// restriction.
4363-
if (extType->getClassOrBoundGenericClass() &&
4364-
isa<ExtensionDecl>(CD->getDeclContext()) &&
4365-
!(CD->getAttrs().hasAttribute<DynamicReplacementAttr>())) {
4366-
diagnose(CD->getLoc(), diag::designated_init_in_extension, extType)
4367-
.fixItInsert(CD->getLoc(), "convenience ");
4368-
CD->setInitKind(CtorInitializerKind::Convenience);
4369-
} else if (CD->getDeclContext()->getExtendedProtocolDecl()) {
4370-
CD->setInitKind(CtorInitializerKind::Convenience);
4371-
}
4372-
}
4373-
43744385
validateGenericFuncOrSubscriptSignature(CD, CD, CD);
43754386

43764387
// We want the constructor to be available for name lookup as soon

lib/Serialization/Deserialization.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2707,7 +2707,8 @@ class swift::DeclDeserializer {
27072707
if (hasStubImplementation)
27082708
ctor->setStubImplementation(true);
27092709
if (initKind.hasValue())
2710-
ctor->setInitKind(initKind.getValue());
2710+
ctx.evaluator.cacheOutput(InitKindRequest{ctor},
2711+
std::move(initKind.getValue()));
27112712
ctor->setNeedsNewVTableEntry(needsNewVTableEntry);
27122713

27132714
ctor->setOverriddenDecl(cast_or_null<ConstructorDecl>(overridden.get()));

0 commit comments

Comments
 (0)