Skip to content

Commit 78edeea

Browse files
authored
Merge pull request #26377 from hborla/init-kind-request
Sema: implement `getInitKind` using a request evaluator.
2 parents fa38b01 + fd03db4 commit 78edeea

File tree

16 files changed

+130
-91
lines changed

16 files changed

+130
-91
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ 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(Optional<PropertyWrapperMutability>, PropertyWrapperMutability)
2627
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
2728
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
struct PropertyWrapperMutability;
2829
class Type;
2930
class VarDecl;

include/swift/AST/Decl.h

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

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

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

@@ -6525,14 +6522,7 @@ class ConstructorDecl : public AbstractFunctionDecl {
65256522
}
65266523

65276524
/// Determine the kind of initializer this is.
6528-
CtorInitializerKind getInitKind() const {
6529-
return static_cast<CtorInitializerKind>(Bits.ConstructorDecl.InitKind);
6530-
}
6531-
6532-
/// Set whether this is a convenience initializer.
6533-
void setInitKind(CtorInitializerKind kind) {
6534-
Bits.ConstructorDecl.InitKind = static_cast<unsigned>(kind);
6535-
}
6525+
CtorInitializerKind getInitKind() const;
65366526

65376527
/// Whether this is a designated initializer.
65386528
bool isDesignatedInit() const {

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,13 +2813,13 @@ NOTE(convenience_init_here,none,
28132813
ERROR(designated_init_in_extension,none,
28142814
"designated initializer cannot be declared in an extension of %0; "
28152815
"did you mean this to be a convenience initializer?",
2816-
(Type))
2816+
(DeclName))
28172817
ERROR(enumstruct_convenience_init,none,
28182818
"delegating initializers in %0 are not marked with 'convenience'",
28192819
(StringRef))
28202820
ERROR(nonclass_convenience_init,none,
28212821
"convenience initializer not allowed in non-class type %0",
2822-
(Type))
2822+
(DeclName))
28232823
ERROR(cfclass_convenience_init,none,
28242824
"convenience initializers are not supported in extensions of CF types",
28252825
())

include/swift/AST/TypeCheckRequests.h

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

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

69266926
Bits.ConstructorDecl.ComputedBodyInitKind = 0;
69276927
Bits.ConstructorDecl.HasStubImplementation = 0;
6928-
Bits.ConstructorDecl.InitKind = static_cast<unsigned>(CtorInitializerKind::Designated);
69296928
Bits.ConstructorDecl.Failability = static_cast<unsigned>(Failability);
69306929

69316930
assert(Name.getBaseName() == DeclBaseName::createConstructor());
@@ -7117,6 +7116,12 @@ Type ConstructorDecl::getInitializerInterfaceType() {
71177116
return InitializerInterfaceType;
71187117
}
71197118

7119+
CtorInitializerKind ConstructorDecl::getInitKind() const {
7120+
return evaluateOrDefault(getASTContext().evaluator,
7121+
InitKindRequest{const_cast<ConstructorDecl *>(this)},
7122+
CtorInitializerKind::Designated);
7123+
}
7124+
71207125
ConstructorDecl::BodyInitKind
71217126
ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags,
71227127
ApplyExpr **init) const {

lib/AST/TypeCheckRequests.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,14 +592,29 @@ void swift::simple_display(
592592
out << " }";
593593
}
594594

595+
void swift::simple_display(
596+
llvm::raw_ostream &out, const CtorInitializerKind initKind) {
597+
out << "{ ";
598+
switch (initKind) {
599+
case CtorInitializerKind::Designated:
600+
out << "designated"; break;
601+
case CtorInitializerKind::Convenience:
602+
out << "convenience"; break;
603+
case CtorInitializerKind::ConvenienceFactory:
604+
out << "convenience_factory"; break;
605+
case CtorInitializerKind::Factory:
606+
out << "factory"; break;
607+
}
608+
out << " }";
609+
}
610+
595611
void swift::simple_display(llvm::raw_ostream &os, PropertyWrapperMutability m) {
596612
static const char *names[] =
597613
{"is nonmutating", "is mutating", "doesn't exist"};
598614

599615
os << "getter " << names[m.Getter] << ", setter " << names[m.Setter];
600616
}
601617

602-
603618
//----------------------------------------------------------------------------//
604619
// FunctionBuilder-related requests.
605620
//----------------------------------------------------------------------------//

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: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6514,6 +6514,7 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
65146514
throwsLoc.isValid(), throwsLoc,
65156515
Params.get(), nullptr,
65166516
CurDeclContext);
6517+
CD->getAttrs() = Attributes;
65176518

65186519
// Parse a 'where' clause if present, adding it to our GenericParamList.
65196520
if (Tok.is(tok::kw_where)) {
@@ -6529,11 +6530,6 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
65296530

65306531
CD->setGenericParams(GenericParams);
65316532

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

65396535
DefaultArgs.setFunctionContext(CD, CD->getParameters());
@@ -6556,8 +6552,6 @@ Parser::parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
65566552
parseAbstractFunctionBody(CD);
65576553
}
65586554

6559-
CD->getAttrs() = Attributes;
6560-
65616555
return makeParserResult(CD);
65626556
}
65636557

lib/Parse/ParseStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,8 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
468468
SourceLoc StartLoc = Tok.getLoc();
469469
auto CD = cast<ConstructorDecl>(CurDeclContext);
470470
// Hint at missing 'self.' or 'super.' then skip this statement.
471-
bool isSelf = !CD->isDesignatedInit() || !isa<ClassDecl>(CD->getParent());
471+
bool isSelf = CD->getAttrs().hasAttribute<ConvenienceAttr>() ||
472+
!isa<ClassDecl>(CD->getParent());
472473
diagnose(StartLoc, diag::invalid_nested_init, isSelf)
473474
.fixItInsert(StartLoc, isSelf ? "self." : "super.");
474475
NeedParseErrorRecovery = true;

lib/Sema/TypeCheckDecl.cpp

Lines changed: 66 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,69 @@ 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 nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) {
1238+
auto classDecl = dyn_cast<ClassDecl>(nominal);
1239+
1240+
// Forbid convenience inits on Foreign CF types, as Swift does not yet
1241+
// support user-defined factory inits.
1242+
if (classDecl &&
1243+
classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType) {
1244+
diags.diagnose(decl->getLoc(), diag::cfclass_convenience_init);
1245+
}
1246+
1247+
if (!classDecl) {
1248+
auto ConvenienceLoc =
1249+
decl->getAttrs().getAttribute<ConvenienceAttr>()->getLocation();
1250+
1251+
// Produce a tailored diagnostic for structs and enums.
1252+
bool isStruct = dyn_cast<StructDecl>(nominal) != nullptr;
1253+
if (isStruct || dyn_cast<EnumDecl>(nominal)) {
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,
1259+
nominal->getName())
1260+
.fixItRemove(ConvenienceLoc);
1261+
}
1262+
return CtorInitializerKind::Designated;
1263+
}
1264+
}
1265+
1266+
return CtorInitializerKind::Convenience;
1267+
1268+
} else if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) {
1269+
// A designated init for a class must be written within the class itself.
1270+
//
1271+
// This is because designated initializers of classes get a vtable entry,
1272+
// and extensions cannot add vtable entries to the extended type.
1273+
//
1274+
// If we implement the ability for extensions defined in the same module
1275+
// (or the same file) to add vtable entries, we can re-evaluate this
1276+
// restriction.
1277+
if (dyn_cast<ClassDecl>(nominal) &&
1278+
!decl->isSynthesized() && isa<ExtensionDecl>(decl->getDeclContext()) &&
1279+
!(decl->getAttrs().hasAttribute<DynamicReplacementAttr>())) {
1280+
diags.diagnose(decl->getLoc(), diag::designated_init_in_extension,
1281+
nominal->getName())
1282+
.fixItInsert(decl->getLoc(), "convenience ");
1283+
return CtorInitializerKind::Convenience;
1284+
}
1285+
1286+
if (decl->getDeclContext()->getExtendedProtocolDecl()) {
1287+
return CtorInitializerKind::Convenience;
1288+
}
1289+
}
1290+
1291+
return CtorInitializerKind::Designated;
1292+
}
1293+
12311294
llvm::Expected<bool>
12321295
ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator,
12331296
ProtocolDecl *decl) const {
@@ -3488,6 +3551,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
34883551
void visitConstructorDecl(ConstructorDecl *CD) {
34893552
TC.validateDecl(CD);
34903553

3554+
// Compute these requests in case they emit diagnostics.
3555+
(void) CD->getInitKind();
3556+
34913557
if (!CD->isInvalid()) {
34923558
checkGenericParams(CD->getGenericParams(), CD, TC);
34933559
TC.checkReferencedGenericParams(CD);
@@ -4314,57 +4380,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
43144380

43154381
checkDeclAttributesEarly(CD);
43164382

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

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

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4351,17 +4351,8 @@ canSuppressPotentialWitnessWarningWithMovement(ValueDecl *requirement,
43514351
// If the witness is a designated or required initializer, we can't move it
43524352
// to an extension.
43534353
if (auto ctor = dyn_cast<ConstructorDecl>(witness)) {
4354-
switch (ctor->getInitKind()) {
4355-
case CtorInitializerKind::Designated:
4354+
if (ctor->isDesignatedInit() || ctor->isRequired())
43564355
return None;
4357-
4358-
case CtorInitializerKind::Convenience:
4359-
case CtorInitializerKind::ConvenienceFactory:
4360-
case CtorInitializerKind::Factory:
4361-
break;
4362-
}
4363-
4364-
if (ctor->isRequired()) return None;
43654356
}
43664357

43674358
// We can move this entity to an extension.

lib/Sema/TypeCheckStmt.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2068,7 +2068,6 @@ static void checkClassConstructorBody(ClassDecl *classDecl,
20682068
ctor->getDeclContext()->getDeclaredInterfaceType())
20692069
.fixItInsert(ctor->getLoc(), "convenience ");
20702070
ctx.Diags.diagnose(initExpr->getLoc(), diag::delegation_here);
2071-
ctor->setInitKind(CtorInitializerKind::Convenience);
20722071
}
20732072

20742073
// An inlinable constructor in a class must always be delegating,

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)