Skip to content

Commit ffd5a9c

Browse files
committed
[Sema] Requestify memberwise init synthesis
This commit adds two requests, one to compute whether or not a decl should have a memberwise initializer, and another to synthesize it.
1 parent d8477d5 commit ffd5a9c

File tree

7 files changed

+112
-24
lines changed

7 files changed

+112
-24
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ SWIFT_TYPEID(Requirement)
2525
SWIFT_TYPEID(ResilienceExpansion)
2626
SWIFT_TYPEID(Type)
2727
SWIFT_TYPEID(TypePair)
28+
SWIFT_TYPEID_NAMED(ConstructorDecl *, ConstructorDecl)
2829
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
2930
SWIFT_TYPEID_NAMED(Decl *, Decl)
3031
SWIFT_TYPEID_NAMED(EnumDecl *, EnumDecl)

include/swift/AST/ASTTypeIDs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace swift {
2323

2424
class AbstractFunctionDecl;
2525
class BraceStmt;
26+
class ConstructorDecl;
2627
class CustomAttr;
2728
class Decl;
2829
class EnumDecl;

include/swift/AST/Decl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3464,6 +3464,13 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
34643464
});
34653465
}
34663466

3467+
/// Whether this declaration has a synthesized memberwise initializer.
3468+
bool hasMemberwiseInitializer() const;
3469+
3470+
/// Retrieves the synthesized memberwise initializer for this declaration,
3471+
/// or \c nullptr if it does not have one.
3472+
ConstructorDecl *getMemberwiseInitializer() const;
3473+
34673474
// Implement isa/cast/dyncast/etc.
34683475
static bool classof(const Decl *D) {
34693476
return D->getKind() >= DeclKind::First_NominalTypeDecl &&

include/swift/AST/TypeCheckRequests.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,44 @@ class HasUserDefinedDesignatedInitRequest
15491549
bool isCached() const { return true; }
15501550
};
15511551

1552+
/// Checks whether this type has a synthesized memberwise initializer.
1553+
class HasMemberwiseInitRequest
1554+
: public SimpleRequest<HasMemberwiseInitRequest, bool(StructDecl *),
1555+
CacheKind::Cached> {
1556+
public:
1557+
using SimpleRequest::SimpleRequest;
1558+
1559+
private:
1560+
friend SimpleRequest;
1561+
1562+
// Evaluation.
1563+
llvm::Expected<bool> evaluate(Evaluator &evaluator, StructDecl *decl) const;
1564+
1565+
public:
1566+
// Caching.
1567+
bool isCached() const { return true; }
1568+
};
1569+
1570+
/// Synthesizes a memberwise initializer for a given type.
1571+
class SynthesizeMemberwiseInitRequest
1572+
: public SimpleRequest<SynthesizeMemberwiseInitRequest,
1573+
ConstructorDecl *(NominalTypeDecl *),
1574+
CacheKind::Cached> {
1575+
public:
1576+
using SimpleRequest::SimpleRequest;
1577+
1578+
private:
1579+
friend SimpleRequest;
1580+
1581+
// Evaluation.
1582+
llvm::Expected<ConstructorDecl *> evaluate(Evaluator &evaluator,
1583+
NominalTypeDecl *decl) const;
1584+
1585+
public:
1586+
// Caching.
1587+
bool isCached() const { return true; }
1588+
};
1589+
15521590
// Allow AnyValue to compare two Type values, even though Type doesn't
15531591
// support ==.
15541592
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,7 @@ SWIFT_REQUEST(TypeChecker, AreAllStoredPropertiesDefaultInitableRequest,
169169
bool(NominalTypeDecl *), Cached, NoLocationInfo)
170170
SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
171171
bool(NominalTypeDecl *), Cached, NoLocationInfo)
172+
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
173+
bool(StructDecl *), Cached, NoLocationInfo)
174+
SWIFT_REQUEST(TypeChecker, SynthesizeMemberwiseInitRequest,
175+
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)

lib/AST/Decl.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3834,6 +3834,28 @@ StructDecl::StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
38343834
Bits.StructDecl.HasUnreferenceableStorage = false;
38353835
}
38363836

3837+
bool NominalTypeDecl::hasMemberwiseInitializer() const {
3838+
// Currently only structs can have memberwise initializers.
3839+
auto *sd = dyn_cast<StructDecl>(this);
3840+
if (!sd)
3841+
return false;
3842+
3843+
auto &ctx = getASTContext();
3844+
auto *mutableThis = const_cast<StructDecl *>(sd);
3845+
return evaluateOrDefault(ctx.evaluator, HasMemberwiseInitRequest{mutableThis},
3846+
false);
3847+
}
3848+
3849+
ConstructorDecl *NominalTypeDecl::getMemberwiseInitializer() const {
3850+
if (!hasMemberwiseInitializer())
3851+
return nullptr;
3852+
3853+
auto &ctx = getASTContext();
3854+
auto *mutableThis = const_cast<NominalTypeDecl *>(this);
3855+
return evaluateOrDefault(
3856+
ctx.evaluator, SynthesizeMemberwiseInitRequest{mutableThis}, nullptr);
3857+
}
3858+
38373859
ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
38383860
MutableArrayRef<TypeLoc> Inherited,
38393861
GenericParamList *GenericParams, DeclContext *Parent)

lib/Sema/CodeSynthesis.cpp

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -871,36 +871,14 @@ static void addImplicitConstructorsToStruct(StructDecl *decl) {
871871
"User-defined structs cannot have unreferenceable storage");
872872

873873
decl->setAddedImplicitInitializers();
874-
875-
// Check whether there is a user-declared constructor or an instance
876-
// variable.
877-
bool FoundMemberwiseInitializedProperty = false;
874+
(void)decl->getMemberwiseInitializer();
878875

879876
// If the user has already defined a designated initializer, then don't
880-
// synthesize an initializer.
877+
// synthesize a default initializer.
881878
auto &ctx = decl->getASTContext();
882879
if (hasUserDefinedDesignatedInit(ctx.evaluator, decl))
883880
return;
884881

885-
for (auto member : decl->getMembers()) {
886-
if (auto var = dyn_cast<VarDecl>(member)) {
887-
// If this is a backing storage property for a property wrapper,
888-
// skip it.
889-
if (var->getOriginalWrappedProperty())
890-
continue;
891-
892-
if (var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
893-
FoundMemberwiseInitializedProperty = true;
894-
}
895-
}
896-
897-
if (FoundMemberwiseInitializedProperty) {
898-
// Create the implicit memberwise constructor.
899-
auto ctor = createImplicitConstructor(
900-
decl, ImplicitConstructorKind::Memberwise, ctx);
901-
decl->addMember(ctor);
902-
}
903-
904882
if (areAllStoredPropertiesDefaultInitializable(ctx.evaluator, decl))
905883
TypeChecker::defineDefaultConstructor(decl);
906884
}
@@ -1203,6 +1181,43 @@ void TypeChecker::synthesizeMemberForLookup(NominalTypeDecl *target,
12031181
}
12041182
}
12051183

1184+
llvm::Expected<bool>
1185+
HasMemberwiseInitRequest::evaluate(Evaluator &evaluator,
1186+
StructDecl *decl) const {
1187+
// Don't synthesize a memberwise init for imported decls.
1188+
if (decl->hasClangNode())
1189+
return false;
1190+
1191+
// If the user has already defined a designated initializer, then don't
1192+
// synthesize a memberwise init.
1193+
if (hasUserDefinedDesignatedInit(evaluator, decl))
1194+
return false;
1195+
1196+
for (auto *member : decl->getMembers()) {
1197+
if (auto *var = dyn_cast<VarDecl>(member)) {
1198+
// If this is a backing storage property for a property wrapper,
1199+
// skip it.
1200+
if (var->getOriginalWrappedProperty())
1201+
continue;
1202+
1203+
if (var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
1204+
return true;
1205+
}
1206+
}
1207+
return false;
1208+
}
1209+
1210+
llvm::Expected<ConstructorDecl *>
1211+
SynthesizeMemberwiseInitRequest::evaluate(Evaluator &evaluator,
1212+
NominalTypeDecl *decl) const {
1213+
// Create the implicit memberwise constructor.
1214+
auto &ctx = decl->getASTContext();
1215+
auto ctor =
1216+
createImplicitConstructor(decl, ImplicitConstructorKind::Memberwise, ctx);
1217+
decl->addMember(ctor);
1218+
return ctor;
1219+
}
1220+
12061221
/// Synthesizer callback for a function body consisting of "return".
12071222
static std::pair<BraceStmt *, bool>
12081223
synthesizeSingleReturnFunctionBody(AbstractFunctionDecl *afd, void *) {

0 commit comments

Comments
 (0)