Skip to content

Commit 1fc04bf

Browse files
authored
Merge pull request #84514 from hamishknight/not-privy
[Sema] Exclude private initialized vars from memberwise initializer
2 parents b27c90b + 45683f6 commit 1fc04bf

28 files changed

+1114
-280
lines changed

include/swift/AST/Decl.h

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,15 @@ static_assert(uint8_t(SelfAccessKind::LastSelfAccessKind) <
273273
"Self Access Kind is too small to fit in SelfAccess kind bits. "
274274
"Please expand ");
275275

276+
enum class MemberwiseInitKind {
277+
/// The regular memberwise initializer.
278+
Regular,
279+
/// A compatibility memberwise initializer that includes all private
280+
/// initialized variables. This only exists for migration purposes, and will
281+
/// be removed in a future language mode.
282+
Compatibility
283+
};
284+
276285
enum class UsingSpecifier : uint8_t {
277286
MainActor,
278287
Nonisolated,
@@ -4634,9 +4643,10 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
46344643
ArrayRef<VarDecl *> getInitAccessorProperties() const;
46354644

46364645
/// Return a collection of all properties that will be part of the memberwise
4637-
/// initializer.
4638-
ArrayRef<VarDecl *> getMemberwiseInitProperties() const;
4639-
4646+
/// initializer.
4647+
ArrayRef<VarDecl *>
4648+
getMemberwiseInitProperties(MemberwiseInitKind initKind) const;
4649+
46404650
/// Establish a mapping between properties that could be iniitalized
46414651
/// via other properties by means of init accessors. This mapping is
46424652
/// one-to-many because we allow intersecting `initializes(...)`.
@@ -4679,11 +4689,11 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
46794689
}
46804690

46814691
/// Whether this declaration has a synthesized memberwise initializer.
4682-
bool hasMemberwiseInitializer() const;
4692+
bool hasMemberwiseInitializer(MemberwiseInitKind initKind) const;
46834693

46844694
/// Retrieves the synthesized memberwise initializer for this declaration,
46854695
/// or \c nullptr if it does not have one.
4686-
ConstructorDecl *getMemberwiseInitializer() const;
4696+
ConstructorDecl *getMemberwiseInitializer(MemberwiseInitKind initKind) const;
46874697

46884698
/// Retrieves the effective memberwise initializer for this declaration, or
46894699
/// \c nullptr if it does not have one.
@@ -6781,9 +6791,14 @@ class VarDecl : public AbstractStorageDecl {
67816791
bool isLazyStorageProperty() const {
67826792
return Bits.VarDecl.IsLazyStorageProperty;
67836793
}
6784-
void setLazyStorageProperty(bool IsLazyStorage) {
6785-
Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage;
6786-
}
6794+
6795+
/// Mark this VarDecl as backing storage for a the lazy variable `VD`.
6796+
void setLazyStorageFor(VarDecl *VD);
6797+
6798+
/// For a backing storage variable for either a property wrapper or `lazy`
6799+
/// variable, retrieves the original declared variable. Otherwise returns
6800+
/// \c nullptr.
6801+
VarDecl *getOriginalVarForBackingStorage() const;
67876802

67886803
/// Retrieve the backing storage property for a lazy property.
67896804
VarDecl *getLazyStorageProperty() const;
@@ -6962,7 +6977,9 @@ class VarDecl : public AbstractStorageDecl {
69626977
/// actual declared property (which may or may not be considered "stored"
69636978
/// as the moment) to the backing storage property. Otherwise, the stored
69646979
/// backing property will be treated as the member-initialized property.
6965-
bool isMemberwiseInitialized(bool preferDeclaredProperties) const;
6980+
bool isMemberwiseInitialized(
6981+
MemberwiseInitKind initKind, bool preferDeclaredProperties,
6982+
std::optional<AccessLevel> minAccess = std::nullopt) const;
69666983

69676984
/// Return the range of semantics attributes attached to this VarDecl.
69686985
auto getSemanticsAttrs() const
@@ -7723,6 +7740,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
77237740
enum class SILSynthesizeKind {
77247741
None,
77257742
MemberwiseInitializer,
7743+
CompatibilityMemberwiseInitializer,
77267744
DistributedActorFactory
77277745

77287746
// This enum currently needs to fit in a 2-bit bitfield.
@@ -8095,11 +8113,19 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
80958113

80968114
/// Note that this is a memberwise initializer and thus the body will be
80978115
/// generated by SILGen.
8098-
void setIsMemberwiseInitializer() {
8116+
void setIsMemberwiseInitializer(MemberwiseInitKind initKind) {
80998117
assert(getBodyKind() == BodyKind::None);
81008118
assert(isa<ConstructorDecl>(this));
81018119
setBodyKind(BodyKind::SILSynthesize);
8102-
setSILSynthesizeKind(SILSynthesizeKind::MemberwiseInitializer);
8120+
switch (initKind) {
8121+
case MemberwiseInitKind::Regular:
8122+
setSILSynthesizeKind(SILSynthesizeKind::MemberwiseInitializer);
8123+
break;
8124+
case MemberwiseInitKind::Compatibility:
8125+
setSILSynthesizeKind(
8126+
SILSynthesizeKind::CompatibilityMemberwiseInitializer);
8127+
break;
8128+
}
81038129
}
81048130

81058131
/// Mark that the body should be filled in to be a factory method for creating
@@ -8135,9 +8161,20 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
81358161
/// typechecking.
81368162
bool isBodySkipped() const;
81378163

8138-
bool isMemberwiseInitializer() const {
8139-
return getBodyKind() == BodyKind::SILSynthesize
8140-
&& getSILSynthesizeKind() == SILSynthesizeKind::MemberwiseInitializer;
8164+
/// Checks whether this is a memberwise initializer decl, and if so the kind,
8165+
/// otherwise \c std::nullopt.
8166+
std::optional<MemberwiseInitKind> isMemberwiseInitializer() const {
8167+
if (getBodyKind() != BodyKind::SILSynthesize)
8168+
return std::nullopt;
8169+
8170+
switch (getSILSynthesizeKind()) {
8171+
case SILSynthesizeKind::MemberwiseInitializer:
8172+
return MemberwiseInitKind::Regular;
8173+
case SILSynthesizeKind::CompatibilityMemberwiseInitializer:
8174+
return MemberwiseInitKind::Compatibility;
8175+
default:
8176+
return std::nullopt;
8177+
}
81418178
}
81428179

81438180
/// Determines whether this function represents a distributed actor
@@ -10191,6 +10228,23 @@ getAccessorNameForDiagnostic(AccessorDecl *accessor, bool article,
1019110228
StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind, bool article,
1019210229
bool underscored);
1019310230

10231+
inline void simple_display(llvm::raw_ostream &out,
10232+
MemberwiseInitKind initKind) {
10233+
switch (initKind) {
10234+
case MemberwiseInitKind::Regular:
10235+
out << "regular";
10236+
break;
10237+
case MemberwiseInitKind::Compatibility:
10238+
out << "compatibility";
10239+
break;
10240+
}
10241+
}
10242+
10243+
/// Retrieve a textual representation for a particular kind of memberwise
10244+
/// initializer in a given nominal decl.
10245+
void printMemberwiseInit(NominalTypeDecl *nominal, MemberwiseInitKind initKind,
10246+
llvm::raw_ostream &out);
10247+
1019410248
void simple_display(llvm::raw_ostream &out,
1019510249
OptionSet<NominalTypeDecl::LookupDirectFlags> options);
1019610250

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,6 +2706,15 @@ ERROR(spi_only_imports_not_enabled, none,
27062706
"'@_spiOnly' requires setting the frontend flag '-experimental-spi-only-imports'",
27072707
())
27082708

2709+
WARNING(warn_use_of_compat_memberwise_init,Deprecation,
2710+
"synthesized memberwise initializer no longer includes "
2711+
"%select{private properties with initial values|%1}0; uses of it "
2712+
"will be an error in a future Swift language mode", (bool, StringRef))
2713+
NOTE(insert_compat_memberwise_init,none,
2714+
"insert an explicit implementation of the memberwise initializer",())
2715+
NOTE(compat_memberwise_init_used_here,none,
2716+
"memberwise initializer used here",())
2717+
27092718
// Access level on imports
27102719
ERROR(access_level_on_import_unsupported, none,
27112720
"The access level %0 is unsupported on imports: "

include/swift/AST/SourceFileExtras.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ class Decl;
2323
/// Extra information associated with a source file that is lazily created and
2424
/// stored in a separately-allocated side structure.
2525
struct SourceFileExtras {
26+
/// Set of compatibility memberwise initializers that we have emitted a
27+
/// warning for.
28+
llvm::DenseSet<const ConstructorDecl *> DiagnosedCompatMemberwiseInits;
2629
};
2730

2831
}

include/swift/AST/TypeCheckRequests.h

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,25 @@ class StoredPropertiesAndMissingMembersRequest :
19491949
bool isCached() const { return true; }
19501950
};
19511951

1952+
/// Request to obtain a list of properties that can be initalized.
1953+
class InitializablePropertiesRequest
1954+
: public SimpleRequest<InitializablePropertiesRequest,
1955+
ArrayRef<VarDecl *>(NominalTypeDecl *),
1956+
RequestFlags::Cached> {
1957+
public:
1958+
using SimpleRequest::SimpleRequest;
1959+
1960+
private:
1961+
friend SimpleRequest;
1962+
1963+
// Evaluation.
1964+
ArrayRef<VarDecl *> evaluate(Evaluator &evaluator,
1965+
NominalTypeDecl *decl) const;
1966+
1967+
public:
1968+
bool isCached() const { return true; }
1969+
};
1970+
19521971
/// Request to obtain a list of computed properties with init accesors
19531972
/// in the given nominal type.
19541973
class InitAccessorPropertiesRequest :
@@ -1961,33 +1980,49 @@ class InitAccessorPropertiesRequest :
19611980
private:
19621981
friend SimpleRequest;
19631982

1983+
// Evaluation.
19641984
ArrayRef<VarDecl *>
19651985
evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
19661986

1967-
// Evaluation.
1968-
bool evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const;
1969-
19701987
public:
19711988
bool isCached() const { return true; }
19721989
};
19731990

19741991
/// Request to obtain a list of properties that will be reflected in the parameters of a
19751992
/// memberwise initializer.
1976-
class MemberwiseInitPropertiesRequest :
1977-
public SimpleRequest<MemberwiseInitPropertiesRequest,
1978-
ArrayRef<VarDecl *>(NominalTypeDecl *),
1979-
RequestFlags::Cached> {
1993+
class MemberwiseInitPropertiesRequest
1994+
: public SimpleRequest<MemberwiseInitPropertiesRequest,
1995+
ArrayRef<VarDecl *>(NominalTypeDecl *,
1996+
MemberwiseInitKind),
1997+
RequestFlags::Cached> {
19801998
public:
19811999
using SimpleRequest::SimpleRequest;
19822000

19832001
private:
19842002
friend SimpleRequest;
19852003

1986-
ArrayRef<VarDecl *>
1987-
evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
2004+
// Evaluation.
2005+
ArrayRef<VarDecl *> evaluate(Evaluator &evaluator, NominalTypeDecl *decl,
2006+
MemberwiseInitKind initKind) const;
2007+
2008+
public:
2009+
bool isCached() const { return true; }
2010+
};
2011+
2012+
/// The maximum access level the memberwise initializer can be for a given
2013+
/// nominal decl.
2014+
class MemberwiseInitMaxAccessLevel
2015+
: public SimpleRequest<MemberwiseInitMaxAccessLevel,
2016+
AccessLevel(NominalTypeDecl *),
2017+
RequestFlags::Cached> {
2018+
public:
2019+
using SimpleRequest::SimpleRequest;
2020+
2021+
private:
2022+
friend SimpleRequest;
19882023

19892024
// Evaluation.
1990-
bool evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const;
2025+
AccessLevel evaluate(Evaluator &evaluator, NominalTypeDecl *nominal) const;
19912026

19922027
public:
19932028
bool isCached() const { return true; }
@@ -2828,7 +2863,8 @@ class HasUserDefinedDesignatedInitRequest
28282863

28292864
/// Checks whether this type has a synthesized memberwise initializer.
28302865
class HasMemberwiseInitRequest
2831-
: public SimpleRequest<HasMemberwiseInitRequest, bool(StructDecl *),
2866+
: public SimpleRequest<HasMemberwiseInitRequest,
2867+
bool(StructDecl *, MemberwiseInitKind),
28322868
RequestFlags::Cached> {
28332869
public:
28342870
using SimpleRequest::SimpleRequest;
@@ -2837,7 +2873,8 @@ class HasMemberwiseInitRequest
28372873
friend SimpleRequest;
28382874

28392875
// Evaluation.
2840-
bool evaluate(Evaluator &evaluator, StructDecl *decl) const;
2876+
bool evaluate(Evaluator &evaluator, StructDecl *decl,
2877+
MemberwiseInitKind initKind) const;
28412878

28422879
public:
28432880
// Caching.
@@ -2847,7 +2884,8 @@ class HasMemberwiseInitRequest
28472884
/// Synthesizes a memberwise initializer for a given type.
28482885
class SynthesizeMemberwiseInitRequest
28492886
: public SimpleRequest<SynthesizeMemberwiseInitRequest,
2850-
ConstructorDecl *(NominalTypeDecl *),
2887+
ConstructorDecl *(NominalTypeDecl *,
2888+
MemberwiseInitKind),
28512889
RequestFlags::Cached> {
28522890
public:
28532891
using SimpleRequest::SimpleRequest;
@@ -2856,7 +2894,8 @@ class SynthesizeMemberwiseInitRequest
28562894
friend SimpleRequest;
28572895

28582896
// Evaluation.
2859-
ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
2897+
ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *decl,
2898+
MemberwiseInitKind initKind) const;
28602899

28612900
public:
28622901
// Caching.

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,11 +336,16 @@ SWIFT_REQUEST(TypeChecker, StoredPropertiesAndMissingMembersRequest,
336336
ArrayRef<Decl *>(NominalTypeDecl *), Cached, NoLocationInfo)
337337
SWIFT_REQUEST(TypeChecker, StoredPropertiesRequest,
338338
ArrayRef<VarDecl *>(NominalTypeDecl *), Cached, NoLocationInfo)
339+
SWIFT_REQUEST(TypeChecker, InitializablePropertiesRequest,
340+
ArrayRef<VarDecl *>(NominalTypeDecl *), Cached, NoLocationInfo)
339341
SWIFT_REQUEST(TypeChecker, InitAccessorPropertiesRequest,
340342
ArrayRef<VarDecl *>(NominalTypeDecl *),
341343
Cached, NoLocationInfo)
342344
SWIFT_REQUEST(TypeChecker, MemberwiseInitPropertiesRequest,
343-
ArrayRef<VarDecl *>(NominalTypeDecl *),
345+
ArrayRef<VarDecl *>(NominalTypeDecl *, MemberwiseInitKind),
346+
Cached, NoLocationInfo)
347+
SWIFT_REQUEST(TypeChecker, MemberwiseInitMaxAccessLevel,
348+
AccessLevel(NominalTypeDecl *),
344349
Cached, NoLocationInfo)
345350
SWIFT_REQUEST(TypeChecker, StructuralTypeRequest, Type(TypeAliasDecl *), Cached,
346351
NoLocationInfo)
@@ -392,7 +397,7 @@ SWIFT_REQUEST(TypeChecker, AreAllStoredPropertiesDefaultInitableRequest,
392397
SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
393398
bool(NominalTypeDecl *), Cached, NoLocationInfo)
394399
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
395-
bool(StructDecl *), Cached, NoLocationInfo)
400+
bool(StructDecl *, MemberwiseInitKind), Cached, NoLocationInfo)
396401
SWIFT_REQUEST(TypeChecker, BraceHasExplicitReturnStmtRequest,
397402
bool(const BraceStmt *),
398403
Cached, NoLocationInfo)
@@ -432,7 +437,8 @@ SWIFT_REQUEST(TypeChecker, SPIGroupsRequest,
432437
llvm::ArrayRef<Identifier>(Decl *),
433438
SeparatelyCached | SplitCached, NoLocationInfo)
434439
SWIFT_REQUEST(TypeChecker, SynthesizeMemberwiseInitRequest,
435-
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
440+
ConstructorDecl *(NominalTypeDecl *, MemberwiseInitKind),
441+
Cached, NoLocationInfo)
436442
SWIFT_REQUEST(TypeChecker, ResolveEffectiveMemberwiseInitRequest,
437443
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
438444
SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest,

include/swift/Basic/Features.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,10 @@ EXPERIMENTAL_FEATURE(DefaultIsolationPerFile, false)
533533
/// Enable @_lifetime attribute
534534
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(Lifetimes, true)
535535

536+
/// Excludes '(file)private' properties with initial values from the memberwise
537+
/// initializer if there is a more accessible initializable property.
538+
EXPERIMENTAL_FEATURE(ExcludePrivateFromMemberwiseInit, true)
539+
536540
/// Allow macro based aliases to be imported into Swift
537541
EXPERIMENTAL_FEATURE(ImportMacroAliases, true)
538542

0 commit comments

Comments
 (0)