mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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.
This commit is contained in:
@@ -25,6 +25,7 @@ SWIFT_TYPEID(Requirement)
|
||||
SWIFT_TYPEID(ResilienceExpansion)
|
||||
SWIFT_TYPEID(Type)
|
||||
SWIFT_TYPEID(TypePair)
|
||||
SWIFT_TYPEID_NAMED(ConstructorDecl *, ConstructorDecl)
|
||||
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
|
||||
SWIFT_TYPEID_NAMED(Decl *, Decl)
|
||||
SWIFT_TYPEID_NAMED(EnumDecl *, EnumDecl)
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace swift {
|
||||
|
||||
class AbstractFunctionDecl;
|
||||
class BraceStmt;
|
||||
class ConstructorDecl;
|
||||
class CustomAttr;
|
||||
class Decl;
|
||||
class EnumDecl;
|
||||
|
||||
@@ -3464,6 +3464,13 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
/// Whether this declaration has a synthesized memberwise initializer.
|
||||
bool hasMemberwiseInitializer() const;
|
||||
|
||||
/// Retrieves the synthesized memberwise initializer for this declaration,
|
||||
/// or \c nullptr if it does not have one.
|
||||
ConstructorDecl *getMemberwiseInitializer() const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
|
||||
|
||||
@@ -1549,6 +1549,44 @@ public:
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
/// Checks whether this type has a synthesized memberwise initializer.
|
||||
class HasMemberwiseInitRequest
|
||||
: public SimpleRequest<HasMemberwiseInitRequest, bool(StructDecl *),
|
||||
CacheKind::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
|
||||
private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
llvm::Expected<bool> evaluate(Evaluator &evaluator, StructDecl *decl) const;
|
||||
|
||||
public:
|
||||
// Caching.
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
/// Synthesizes a memberwise initializer for a given type.
|
||||
class SynthesizeMemberwiseInitRequest
|
||||
: public SimpleRequest<SynthesizeMemberwiseInitRequest,
|
||||
ConstructorDecl *(NominalTypeDecl *),
|
||||
CacheKind::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
|
||||
private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
llvm::Expected<ConstructorDecl *> evaluate(Evaluator &evaluator,
|
||||
NominalTypeDecl *decl) const;
|
||||
|
||||
public:
|
||||
// Caching.
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
// Allow AnyValue to compare two Type values, even though Type doesn't
|
||||
// support ==.
|
||||
template<>
|
||||
|
||||
@@ -169,3 +169,7 @@ SWIFT_REQUEST(TypeChecker, AreAllStoredPropertiesDefaultInitableRequest,
|
||||
bool(NominalTypeDecl *), Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
|
||||
bool(NominalTypeDecl *), Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
|
||||
bool(StructDecl *), Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, SynthesizeMemberwiseInitRequest,
|
||||
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
|
||||
|
||||
@@ -3834,6 +3834,28 @@ StructDecl::StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
|
||||
Bits.StructDecl.HasUnreferenceableStorage = false;
|
||||
}
|
||||
|
||||
bool NominalTypeDecl::hasMemberwiseInitializer() const {
|
||||
// Currently only structs can have memberwise initializers.
|
||||
auto *sd = dyn_cast<StructDecl>(this);
|
||||
if (!sd)
|
||||
return false;
|
||||
|
||||
auto &ctx = getASTContext();
|
||||
auto *mutableThis = const_cast<StructDecl *>(sd);
|
||||
return evaluateOrDefault(ctx.evaluator, HasMemberwiseInitRequest{mutableThis},
|
||||
false);
|
||||
}
|
||||
|
||||
ConstructorDecl *NominalTypeDecl::getMemberwiseInitializer() const {
|
||||
if (!hasMemberwiseInitializer())
|
||||
return nullptr;
|
||||
|
||||
auto &ctx = getASTContext();
|
||||
auto *mutableThis = const_cast<NominalTypeDecl *>(this);
|
||||
return evaluateOrDefault(
|
||||
ctx.evaluator, SynthesizeMemberwiseInitRequest{mutableThis}, nullptr);
|
||||
}
|
||||
|
||||
ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
|
||||
MutableArrayRef<TypeLoc> Inherited,
|
||||
GenericParamList *GenericParams, DeclContext *Parent)
|
||||
|
||||
@@ -871,36 +871,14 @@ static void addImplicitConstructorsToStruct(StructDecl *decl) {
|
||||
"User-defined structs cannot have unreferenceable storage");
|
||||
|
||||
decl->setAddedImplicitInitializers();
|
||||
|
||||
// Check whether there is a user-declared constructor or an instance
|
||||
// variable.
|
||||
bool FoundMemberwiseInitializedProperty = false;
|
||||
(void)decl->getMemberwiseInitializer();
|
||||
|
||||
// If the user has already defined a designated initializer, then don't
|
||||
// synthesize an initializer.
|
||||
// synthesize a default initializer.
|
||||
auto &ctx = decl->getASTContext();
|
||||
if (hasUserDefinedDesignatedInit(ctx.evaluator, decl))
|
||||
return;
|
||||
|
||||
for (auto member : decl->getMembers()) {
|
||||
if (auto var = dyn_cast<VarDecl>(member)) {
|
||||
// If this is a backing storage property for a property wrapper,
|
||||
// skip it.
|
||||
if (var->getOriginalWrappedProperty())
|
||||
continue;
|
||||
|
||||
if (var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
|
||||
FoundMemberwiseInitializedProperty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (FoundMemberwiseInitializedProperty) {
|
||||
// Create the implicit memberwise constructor.
|
||||
auto ctor = createImplicitConstructor(
|
||||
decl, ImplicitConstructorKind::Memberwise, ctx);
|
||||
decl->addMember(ctor);
|
||||
}
|
||||
|
||||
if (areAllStoredPropertiesDefaultInitializable(ctx.evaluator, decl))
|
||||
TypeChecker::defineDefaultConstructor(decl);
|
||||
}
|
||||
@@ -1203,6 +1181,43 @@ void TypeChecker::synthesizeMemberForLookup(NominalTypeDecl *target,
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Expected<bool>
|
||||
HasMemberwiseInitRequest::evaluate(Evaluator &evaluator,
|
||||
StructDecl *decl) const {
|
||||
// Don't synthesize a memberwise init for imported decls.
|
||||
if (decl->hasClangNode())
|
||||
return false;
|
||||
|
||||
// If the user has already defined a designated initializer, then don't
|
||||
// synthesize a memberwise init.
|
||||
if (hasUserDefinedDesignatedInit(evaluator, decl))
|
||||
return false;
|
||||
|
||||
for (auto *member : decl->getMembers()) {
|
||||
if (auto *var = dyn_cast<VarDecl>(member)) {
|
||||
// If this is a backing storage property for a property wrapper,
|
||||
// skip it.
|
||||
if (var->getOriginalWrappedProperty())
|
||||
continue;
|
||||
|
||||
if (var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Expected<ConstructorDecl *>
|
||||
SynthesizeMemberwiseInitRequest::evaluate(Evaluator &evaluator,
|
||||
NominalTypeDecl *decl) const {
|
||||
// Create the implicit memberwise constructor.
|
||||
auto &ctx = decl->getASTContext();
|
||||
auto ctor =
|
||||
createImplicitConstructor(decl, ImplicitConstructorKind::Memberwise, ctx);
|
||||
decl->addMember(ctor);
|
||||
return ctor;
|
||||
}
|
||||
|
||||
/// Synthesizer callback for a function body consisting of "return".
|
||||
static std::pair<BraceStmt *, bool>
|
||||
synthesizeSingleReturnFunctionBody(AbstractFunctionDecl *afd, void *) {
|
||||
|
||||
Reference in New Issue
Block a user