mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Sema] Exclude private initialized vars from memberwise initializer
Exclude properties with initial values from the memberwise initializer if they are less accessible than the most accessible property, up to `internal`. Introduce a compatibility overload that continues to include the same properties as before until the next language mode. This is gated behind the `ExcludePrivateFromMemberwiseInit` feature. rdar://122416579
This commit is contained in:
@@ -273,6 +273,15 @@ static_assert(uint8_t(SelfAccessKind::LastSelfAccessKind) <
|
||||
"Self Access Kind is too small to fit in SelfAccess kind bits. "
|
||||
"Please expand ");
|
||||
|
||||
enum class MemberwiseInitKind {
|
||||
/// The regular memberwise initializer.
|
||||
Regular,
|
||||
/// A compatibility memberwise initializer that includes all private
|
||||
/// initialized variables. This only exists for migration purposes, and will
|
||||
/// be removed in a future language mode.
|
||||
Compatibility
|
||||
};
|
||||
|
||||
enum class UsingSpecifier : uint8_t {
|
||||
MainActor,
|
||||
Nonisolated,
|
||||
@@ -4634,9 +4643,10 @@ public:
|
||||
ArrayRef<VarDecl *> getInitAccessorProperties() const;
|
||||
|
||||
/// Return a collection of all properties that will be part of the memberwise
|
||||
/// initializer.
|
||||
ArrayRef<VarDecl *> getMemberwiseInitProperties() const;
|
||||
|
||||
/// initializer.
|
||||
ArrayRef<VarDecl *>
|
||||
getMemberwiseInitProperties(MemberwiseInitKind initKind) const;
|
||||
|
||||
/// Establish a mapping between properties that could be iniitalized
|
||||
/// via other properties by means of init accessors. This mapping is
|
||||
/// one-to-many because we allow intersecting `initializes(...)`.
|
||||
@@ -4679,11 +4689,11 @@ public:
|
||||
}
|
||||
|
||||
/// Whether this declaration has a synthesized memberwise initializer.
|
||||
bool hasMemberwiseInitializer() const;
|
||||
bool hasMemberwiseInitializer(MemberwiseInitKind initKind) const;
|
||||
|
||||
/// Retrieves the synthesized memberwise initializer for this declaration,
|
||||
/// or \c nullptr if it does not have one.
|
||||
ConstructorDecl *getMemberwiseInitializer() const;
|
||||
ConstructorDecl *getMemberwiseInitializer(MemberwiseInitKind initKind) const;
|
||||
|
||||
/// Retrieves the effective memberwise initializer for this declaration, or
|
||||
/// \c nullptr if it does not have one.
|
||||
@@ -6967,7 +6977,9 @@ public:
|
||||
/// actual declared property (which may or may not be considered "stored"
|
||||
/// as the moment) to the backing storage property. Otherwise, the stored
|
||||
/// backing property will be treated as the member-initialized property.
|
||||
bool isMemberwiseInitialized(bool preferDeclaredProperties) const;
|
||||
bool isMemberwiseInitialized(
|
||||
MemberwiseInitKind initKind, bool preferDeclaredProperties,
|
||||
std::optional<AccessLevel> minAccess = std::nullopt) const;
|
||||
|
||||
/// Return the range of semantics attributes attached to this VarDecl.
|
||||
auto getSemanticsAttrs() const
|
||||
@@ -7728,6 +7740,7 @@ public:
|
||||
enum class SILSynthesizeKind {
|
||||
None,
|
||||
MemberwiseInitializer,
|
||||
CompatibilityMemberwiseInitializer,
|
||||
DistributedActorFactory
|
||||
|
||||
// This enum currently needs to fit in a 2-bit bitfield.
|
||||
@@ -8100,11 +8113,19 @@ public:
|
||||
|
||||
/// Note that this is a memberwise initializer and thus the body will be
|
||||
/// generated by SILGen.
|
||||
void setIsMemberwiseInitializer() {
|
||||
void setIsMemberwiseInitializer(MemberwiseInitKind initKind) {
|
||||
assert(getBodyKind() == BodyKind::None);
|
||||
assert(isa<ConstructorDecl>(this));
|
||||
setBodyKind(BodyKind::SILSynthesize);
|
||||
setSILSynthesizeKind(SILSynthesizeKind::MemberwiseInitializer);
|
||||
switch (initKind) {
|
||||
case MemberwiseInitKind::Regular:
|
||||
setSILSynthesizeKind(SILSynthesizeKind::MemberwiseInitializer);
|
||||
break;
|
||||
case MemberwiseInitKind::Compatibility:
|
||||
setSILSynthesizeKind(
|
||||
SILSynthesizeKind::CompatibilityMemberwiseInitializer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark that the body should be filled in to be a factory method for creating
|
||||
@@ -8140,9 +8161,20 @@ public:
|
||||
/// typechecking.
|
||||
bool isBodySkipped() const;
|
||||
|
||||
bool isMemberwiseInitializer() const {
|
||||
return getBodyKind() == BodyKind::SILSynthesize
|
||||
&& getSILSynthesizeKind() == SILSynthesizeKind::MemberwiseInitializer;
|
||||
/// Checks whether this is a memberwise initializer decl, and if so the kind,
|
||||
/// otherwise \c std::nullopt.
|
||||
std::optional<MemberwiseInitKind> isMemberwiseInitializer() const {
|
||||
if (getBodyKind() != BodyKind::SILSynthesize)
|
||||
return std::nullopt;
|
||||
|
||||
switch (getSILSynthesizeKind()) {
|
||||
case SILSynthesizeKind::MemberwiseInitializer:
|
||||
return MemberwiseInitKind::Regular;
|
||||
case SILSynthesizeKind::CompatibilityMemberwiseInitializer:
|
||||
return MemberwiseInitKind::Compatibility;
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines whether this function represents a distributed actor
|
||||
@@ -10196,9 +10228,22 @@ getAccessorNameForDiagnostic(AccessorDecl *accessor, bool article,
|
||||
StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind, bool article,
|
||||
bool underscored);
|
||||
|
||||
/// Retrieve a textual representation for a memberwise initializer in a given
|
||||
/// nominal decl.
|
||||
void printMemberwiseInit(NominalTypeDecl *nominal, llvm::raw_ostream &out);
|
||||
inline void simple_display(llvm::raw_ostream &out,
|
||||
MemberwiseInitKind initKind) {
|
||||
switch (initKind) {
|
||||
case MemberwiseInitKind::Regular:
|
||||
out << "regular";
|
||||
break;
|
||||
case MemberwiseInitKind::Compatibility:
|
||||
out << "compatibility";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve a textual representation for a particular kind of memberwise
|
||||
/// initializer in a given nominal decl.
|
||||
void printMemberwiseInit(NominalTypeDecl *nominal, MemberwiseInitKind initKind,
|
||||
llvm::raw_ostream &out);
|
||||
|
||||
void simple_display(llvm::raw_ostream &out,
|
||||
OptionSet<NominalTypeDecl::LookupDirectFlags> options);
|
||||
|
||||
@@ -2706,6 +2706,15 @@ ERROR(spi_only_imports_not_enabled, none,
|
||||
"'@_spiOnly' requires setting the frontend flag '-experimental-spi-only-imports'",
|
||||
())
|
||||
|
||||
WARNING(warn_use_of_compat_memberwise_init,Deprecation,
|
||||
"synthesized memberwise initializer no longer includes "
|
||||
"%select{private properties with initial values|%1}0; uses of it "
|
||||
"will be an error in a future Swift language mode", (bool, StringRef))
|
||||
NOTE(insert_compat_memberwise_init,none,
|
||||
"insert an explicit implementation of the memberwise initializer",())
|
||||
NOTE(compat_memberwise_init_used_here,none,
|
||||
"memberwise initializer used here",())
|
||||
|
||||
// Access level on imports
|
||||
ERROR(access_level_on_import_unsupported, none,
|
||||
"The access level %0 is unsupported on imports: "
|
||||
|
||||
@@ -23,6 +23,9 @@ class Decl;
|
||||
/// Extra information associated with a source file that is lazily created and
|
||||
/// stored in a separately-allocated side structure.
|
||||
struct SourceFileExtras {
|
||||
/// Set of compatibility memberwise initializers that we have emitted a
|
||||
/// warning for.
|
||||
llvm::DenseSet<const ConstructorDecl *> DiagnosedCompatMemberwiseInits;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1990,10 +1990,11 @@ public:
|
||||
|
||||
/// Request to obtain a list of properties that will be reflected in the parameters of a
|
||||
/// memberwise initializer.
|
||||
class MemberwiseInitPropertiesRequest :
|
||||
public SimpleRequest<MemberwiseInitPropertiesRequest,
|
||||
ArrayRef<VarDecl *>(NominalTypeDecl *),
|
||||
RequestFlags::Cached> {
|
||||
class MemberwiseInitPropertiesRequest
|
||||
: public SimpleRequest<MemberwiseInitPropertiesRequest,
|
||||
ArrayRef<VarDecl *>(NominalTypeDecl *,
|
||||
MemberwiseInitKind),
|
||||
RequestFlags::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
|
||||
@@ -2001,8 +2002,27 @@ private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
ArrayRef<VarDecl *>
|
||||
evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
|
||||
ArrayRef<VarDecl *> evaluate(Evaluator &evaluator, NominalTypeDecl *decl,
|
||||
MemberwiseInitKind initKind) const;
|
||||
|
||||
public:
|
||||
bool isCached() const { return true; }
|
||||
};
|
||||
|
||||
/// The maximum access level the memberwise initializer can be for a given
|
||||
/// nominal decl.
|
||||
class MemberwiseInitMaxAccessLevel
|
||||
: public SimpleRequest<MemberwiseInitMaxAccessLevel,
|
||||
AccessLevel(NominalTypeDecl *),
|
||||
RequestFlags::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
|
||||
private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
AccessLevel evaluate(Evaluator &evaluator, NominalTypeDecl *nominal) const;
|
||||
|
||||
public:
|
||||
bool isCached() const { return true; }
|
||||
@@ -2843,7 +2863,8 @@ public:
|
||||
|
||||
/// Checks whether this type has a synthesized memberwise initializer.
|
||||
class HasMemberwiseInitRequest
|
||||
: public SimpleRequest<HasMemberwiseInitRequest, bool(StructDecl *),
|
||||
: public SimpleRequest<HasMemberwiseInitRequest,
|
||||
bool(StructDecl *, MemberwiseInitKind),
|
||||
RequestFlags::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
@@ -2852,7 +2873,8 @@ private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
bool evaluate(Evaluator &evaluator, StructDecl *decl) const;
|
||||
bool evaluate(Evaluator &evaluator, StructDecl *decl,
|
||||
MemberwiseInitKind initKind) const;
|
||||
|
||||
public:
|
||||
// Caching.
|
||||
@@ -2862,7 +2884,8 @@ public:
|
||||
/// Synthesizes a memberwise initializer for a given type.
|
||||
class SynthesizeMemberwiseInitRequest
|
||||
: public SimpleRequest<SynthesizeMemberwiseInitRequest,
|
||||
ConstructorDecl *(NominalTypeDecl *),
|
||||
ConstructorDecl *(NominalTypeDecl *,
|
||||
MemberwiseInitKind),
|
||||
RequestFlags::Cached> {
|
||||
public:
|
||||
using SimpleRequest::SimpleRequest;
|
||||
@@ -2871,7 +2894,8 @@ private:
|
||||
friend SimpleRequest;
|
||||
|
||||
// Evaluation.
|
||||
ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
|
||||
ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *decl,
|
||||
MemberwiseInitKind initKind) const;
|
||||
|
||||
public:
|
||||
// Caching.
|
||||
|
||||
@@ -342,7 +342,10 @@ SWIFT_REQUEST(TypeChecker, InitAccessorPropertiesRequest,
|
||||
ArrayRef<VarDecl *>(NominalTypeDecl *),
|
||||
Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, MemberwiseInitPropertiesRequest,
|
||||
ArrayRef<VarDecl *>(NominalTypeDecl *),
|
||||
ArrayRef<VarDecl *>(NominalTypeDecl *, MemberwiseInitKind),
|
||||
Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, MemberwiseInitMaxAccessLevel,
|
||||
AccessLevel(NominalTypeDecl *),
|
||||
Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, StructuralTypeRequest, Type(TypeAliasDecl *), Cached,
|
||||
NoLocationInfo)
|
||||
@@ -394,7 +397,7 @@ SWIFT_REQUEST(TypeChecker, AreAllStoredPropertiesDefaultInitableRequest,
|
||||
SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
|
||||
bool(NominalTypeDecl *), Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
|
||||
bool(StructDecl *), Cached, NoLocationInfo)
|
||||
bool(StructDecl *, MemberwiseInitKind), Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, BraceHasExplicitReturnStmtRequest,
|
||||
bool(const BraceStmt *),
|
||||
Cached, NoLocationInfo)
|
||||
@@ -434,7 +437,8 @@ SWIFT_REQUEST(TypeChecker, SPIGroupsRequest,
|
||||
llvm::ArrayRef<Identifier>(Decl *),
|
||||
SeparatelyCached | SplitCached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, SynthesizeMemberwiseInitRequest,
|
||||
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
|
||||
ConstructorDecl *(NominalTypeDecl *, MemberwiseInitKind),
|
||||
Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, ResolveEffectiveMemberwiseInitRequest,
|
||||
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
|
||||
SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,
|
||||
|
||||
@@ -533,6 +533,10 @@ EXPERIMENTAL_FEATURE(DefaultIsolationPerFile, false)
|
||||
/// Enable @_lifetime attribute
|
||||
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(Lifetimes, true)
|
||||
|
||||
/// Excludes '(file)private' properties with initial values from the memberwise
|
||||
/// initializer if there is a more accessible initializable property.
|
||||
EXPERIMENTAL_FEATURE(ExcludePrivateFromMemberwiseInit, true)
|
||||
|
||||
/// Allow macro based aliases to be imported into Swift
|
||||
EXPERIMENTAL_FEATURE(ImportMacroAliases, true)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user