Centralize the definition of isMemberwiseInitialized()

This utility was defined in Sema, used in Sema and Index, declared in
two headers, and semi- copy-pasted into SILGen. Pull it into
VarDecl::isMemberwiseInitialized() and use it consistently.
This commit is contained in:
Doug Gregor
2019-04-29 10:30:38 -07:00
parent 209e7fcd83
commit 1a169b91bd
8 changed files with 43 additions and 39 deletions

View File

@@ -5142,7 +5142,11 @@ public:
/// Returns true if the name is the self identifier and is implicit. /// Returns true if the name is the self identifier and is implicit.
bool isSelfParameter() const; bool isSelfParameter() const;
/// Determine whether this property will be part of the implicit memberwise
/// initializer.
bool isMemberwiseInitialized() const;
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { static bool classof(const Decl *D) {
return D->getKind() == DeclKind::Var || D->getKind() == DeclKind::Param; return D->getKind() == DeclKind::Var || D->getKind() == DeclKind::Param;

View File

@@ -239,10 +239,6 @@ namespace swift {
/// \param DC The DeclContext from which the subscript is being referenced. /// \param DC The DeclContext from which the subscript is being referenced.
Optional<Type> getRootTypeOfKeypathDynamicMember(SubscriptDecl *subscript, Optional<Type> getRootTypeOfKeypathDynamicMember(SubscriptDecl *subscript,
const DeclContext *DC); const DeclContext *DC);
/// Determine whether the given property is part of the memberwise initializer
/// for a struct.
bool isMemberwiseInitialized(VarDecl *var);
} }
#endif #endif

View File

@@ -5254,6 +5254,30 @@ bool VarDecl::isSelfParameter() const {
return false; return false;
} }
bool VarDecl::isMemberwiseInitialized() const {
if (!getDeclContext()->isTypeContext())
return false;
// Implicit, computed, and static properties are not initialized.
// The exception is lazy properties, which due to batch mode we may or
// may not have yet finalized, so they may currently be "stored" or
// "computed" in the current AST state.
if (isImplicit() || isStatic())
return false;
if (!hasStorage() && !getAttrs().hasAttribute<LazyAttr>() &&
!getAttachedPropertyDelegate())
return false;
// Initialized 'let' properties have storage, but don't get an argument
// to the memberwise initializer since they already have an initial
// value that cannot be overridden.
if (isLet() && isParentInitialized())
return false;
return true;
}
void VarDecl::setSpecifier(Specifier specifier) { void VarDecl::setSpecifier(Specifier specifier) {
Bits.VarDecl.Specifier = static_cast<unsigned>(specifier); Bits.VarDecl.Specifier = static_cast<unsigned>(specifier);
setSupportsMutationIfStillStored( setSupportsMutationIfStillStored(

View File

@@ -364,7 +364,7 @@ private:
if (auto Original = Prop->getOriginalDelegatedProperty()) if (auto Original = Prop->getOriginalDelegatedProperty())
Prop = Original; Prop = Original;
if (!isMemberwiseInitialized(Prop)) if (!Prop->isMemberwiseInitialized())
continue; continue;
if (CurLabel == LabelLocs.size()) if (CurLabel == LabelLocs.size())

View File

@@ -217,14 +217,8 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
auto fieldTy = selfTy.getFieldType(field, SGF.SGM.M); auto fieldTy = selfTy.getFieldType(field, SGF.SGM.M);
SILValue v; SILValue v;
// An initialized 'let' property has a single value specified by the // If it's memberwise initialized, do so now.
// initializer - it doesn't come from an argument. if (field->isMemberwiseInitialized()) {
if (!field->isStatic() && field->isLet() && field->getParentInitializer()) {
// Cleanup after this initialization.
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
v = SGF.emitRValue(field->getParentInitializer())
.forwardAsSingleStorageValue(SGF, fieldTy, Loc);
} else {
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding()); FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
assert(elti != eltEnd && "number of args does not match number of fields"); assert(elti != eltEnd && "number of args does not match number of fields");
(void)eltEnd; (void)eltEnd;
@@ -237,6 +231,14 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
v = std::move(*elti).forwardAsSingleStorageValue(SGF, fieldTy, Loc); v = std::move(*elti).forwardAsSingleStorageValue(SGF, fieldTy, Loc);
} }
++elti; ++elti;
} else {
// Otherwise, use its initializer.
assert(field->isParentInitialized());
// Cleanup after this initialization.
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
v = SGF.emitRValue(field->getParentInitializer())
.forwardAsSingleStorageValue(SGF, fieldTy, Loc);
} }
eltValues.push_back(v); eltValues.push_back(v);

View File

@@ -2050,26 +2050,6 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
arg->setDefaultArgumentKind(DefaultArgumentKind::StoredProperty); arg->setDefaultArgumentKind(DefaultArgumentKind::StoredProperty);
} }
bool swift::isMemberwiseInitialized(VarDecl *var) {
// Implicit, computed, and static properties are not initialized.
// The exception is lazy properties, which due to batch mode we may or
// may not have yet finalized, so they may currently be "stored" or
// "computed" in the current AST state.
if (var->isImplicit() || var->isStatic())
return false;
if (!var->hasStorage() && !var->getAttrs().hasAttribute<LazyAttr>() &&
!var->getAttachedPropertyDelegate())
return false;
// Initialized 'let' properties have storage, but don't get an argument
// to the memberwise initializer since they already have an initial
// value that cannot be overridden.
if (var->isLet() && var->isParentInitialized())
return false;
return true;
}
/// Create an implicit struct or class constructor. /// Create an implicit struct or class constructor.
/// ///
/// \param decl The struct or class for which a constructor will be created. /// \param decl The struct or class for which a constructor will be created.
@@ -2097,7 +2077,7 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
if (!var) if (!var)
continue; continue;
if (!isMemberwiseInitialized(var)) if (!var->isMemberwiseInitialized())
continue; continue;
accessLevel = std::min(accessLevel, var->getFormalAccess()); accessLevel = std::min(accessLevel, var->getFormalAccess());

View File

@@ -69,8 +69,6 @@ enum class ImplicitConstructorKind {
Memberwise Memberwise
}; };
bool isMemberwiseInitialized(VarDecl *var);
/// Create an implicit struct or class constructor. /// Create an implicit struct or class constructor.
/// ///
/// \param decl The struct or class for which a constructor will be created. /// \param decl The struct or class for which a constructor will be created.

View File

@@ -5230,7 +5230,7 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
if (isa<StructDecl>(decl)) { if (isa<StructDecl>(decl)) {
for (auto member : decl->getMembers()) { for (auto member : decl->getMembers()) {
if (auto var = dyn_cast<VarDecl>(member)) { if (auto var = dyn_cast<VarDecl>(member)) {
if (!isMemberwiseInitialized(var)) if (!var->isMemberwiseInitialized())
continue; continue;
validateDecl(var); validateDecl(var);
@@ -5303,7 +5303,7 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
if (backingStorageVars.count(var) > 0) if (backingStorageVars.count(var) > 0)
continue; continue;
if (isMemberwiseInitialized(var)) { if (var->isMemberwiseInitialized()) {
// Initialized 'let' properties have storage, but don't get an argument // Initialized 'let' properties have storage, but don't get an argument
// to the memberwise initializer since they already have an initial // to the memberwise initializer since they already have an initial
// value that cannot be overridden. // value that cannot be overridden.