Skip to content

Commit bfe0ebb

Browse files
committed
Parse: Split off StorageImplInfo computation from accessor parsing
Soon this will be performed lazily as part of a request.
1 parent 56f8f05 commit bfe0ebb

File tree

1 file changed

+89
-94
lines changed

1 file changed

+89
-94
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 89 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -4470,16 +4470,12 @@ struct Parser::ParsedAccessors {
44704470
#include "swift/AST/AccessorKinds.def"
44714471

44724472
void record(Parser &P, AbstractStorageDecl *storage, bool invalid,
4473-
ParseDeclOptions flags, SourceLoc staticLoc,
44744473
const DeclAttributes &attrs,
4475-
TypeLoc elementTy, ParameterList *indices,
44764474
SmallVectorImpl<Decl *> &decls);
44774475

44784476
StorageImplInfo
44794477
classify(Parser &P, AbstractStorageDecl *storage, bool invalid,
4480-
ParseDeclOptions flags, SourceLoc staticLoc,
4481-
const DeclAttributes &attrs,
4482-
TypeLoc elementTy, ParameterList *indices);
4478+
const DeclAttributes &attrs);
44834479

44844480
/// Add an accessor. If there's an existing accessor of this kind,
44854481
/// return it. The new accessor is still remembered but will be
@@ -4912,8 +4908,7 @@ Parser::parseDeclVarGetSet(Pattern *pattern, ParseDeclOptions Flags,
49124908
accessors.Set->setInvalid();
49134909
}
49144910

4915-
accessors.record(*this, PrimaryVar, Invalid, Flags, StaticLoc,
4916-
Attributes, TyLoc, /*indices*/ nullptr, Decls);
4911+
accessors.record(*this, PrimaryVar, Invalid, Attributes, Decls);
49174912

49184913
return makeParserResult(PrimaryVar);
49194914
}
@@ -4940,13 +4935,10 @@ AccessorDecl *Parser::ParsedAccessors::add(AccessorDecl *accessor) {
49404935

49414936
/// Record a bunch of parsed accessors into the given abstract storage decl.
49424937
void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage,
4943-
bool invalid, ParseDeclOptions flags,
4944-
SourceLoc staticLoc,
4938+
bool invalid,
49454939
const DeclAttributes &attrs,
4946-
TypeLoc elementTy, ParameterList *indices,
49474940
SmallVectorImpl<Decl *> &decls) {
4948-
auto storageKind = classify(P, storage, invalid, flags, staticLoc, attrs,
4949-
elementTy, indices);
4941+
auto storageKind = classify(P, storage, invalid, attrs);
49504942
storage->setImplInfo(storageKind);
49514943

49524944
decls.append(Accessors.begin(), Accessors.end());
@@ -4959,13 +4951,6 @@ static void flagInvalidAccessor(AccessorDecl *func) {
49594951
}
49604952
}
49614953

4962-
static void ignoreInvalidAccessor(AccessorDecl *&func) {
4963-
if (func) {
4964-
flagInvalidAccessor(func);
4965-
func = nullptr;
4966-
}
4967-
}
4968-
49694954
static void diagnoseConflictingAccessors(Parser &P, AccessorDecl *first,
49704955
AccessorDecl *&second) {
49714956
if (!second) return;
@@ -4976,7 +4961,7 @@ static void diagnoseConflictingAccessors(Parser &P, AccessorDecl *first,
49764961
P.diagnose(first->getLoc(), diag::previous_accessor,
49774962
getAccessorNameForDiagnostic(first, /*article*/ false),
49784963
/*already*/ false);
4979-
ignoreInvalidAccessor(second);
4964+
flagInvalidAccessor(second);
49804965
}
49814966

49824967
template <class... DiagArgs>
@@ -4986,11 +4971,11 @@ static void diagnoseAndIgnoreObservers(Parser &P,
49864971
typename std::enable_if<true, DiagArgs>::type... args) {
49874972
if (auto &accessor = accessors.WillSet) {
49884973
P.diagnose(accessor->getLoc(), diagnostic, /*willSet*/ 0, args...);
4989-
ignoreInvalidAccessor(accessor);
4974+
flagInvalidAccessor(accessor);
49904975
}
49914976
if (auto &accessor = accessors.DidSet) {
49924977
P.diagnose(accessor->getLoc(), diagnostic, /*didSet*/ 1, args...);
4993-
ignoreInvalidAccessor(accessor);
4978+
flagInvalidAccessor(accessor);
49944979
}
49954980
}
49964981

@@ -5013,20 +4998,10 @@ static void diagnoseAndIgnoreObservers(Parser &P,
50134998
/// - MaterializeToTemporary, if the decl has a setter.
50144999
static StorageImplInfo classifyWithHasStorageAttr(
50155000
Parser::ParsedAccessors &accessors, ASTContext &ctx,
5016-
AbstractStorageDecl *storage, const DeclAttributes &attrs) {
5017-
5018-
// Determines if the storage is immutable, either by declaring itself as a
5019-
// `let` or by omitting a setter.
5020-
auto isImmutable = [&]() {
5021-
if (auto varDecl = dyn_cast<VarDecl>(storage))
5022-
return varDecl->isLet();
5023-
if (accessors.Set == nullptr) return true;
5024-
return false;
5025-
};
5001+
VarDecl *var, const DeclAttributes &attrs) {
50265002

5027-
// Default to stored writes.
5028-
WriteImplKind writeImpl = WriteImplKind::Stored;
5029-
ReadWriteImplKind readWriteImpl = ReadWriteImplKind::Stored;
5003+
WriteImplKind writeImpl;
5004+
ReadWriteImplKind readWriteImpl;
50305005

50315006
if (accessors.Get && accessors.Set) {
50325007
// If we see `@_hasStorage var x: T { get set }`, then our property has
@@ -5035,9 +5010,13 @@ static StorageImplInfo classifyWithHasStorageAttr(
50355010
WriteImplKind::InheritedWithObservers :
50365011
WriteImplKind::StoredWithObservers;
50375012
readWriteImpl = ReadWriteImplKind::MaterializeToTemporary;
5038-
} else if (isImmutable()) {
5013+
} else if (var->isLet()) {
50395014
writeImpl = WriteImplKind::Immutable;
50405015
readWriteImpl = ReadWriteImplKind::Immutable;
5016+
} else {
5017+
// Default to stored writes.
5018+
writeImpl = WriteImplKind::Stored;
5019+
readWriteImpl = ReadWriteImplKind::Stored;
50415020
}
50425021

50435022
// Always force Stored reads if @_hasStorage is present.
@@ -5046,14 +5025,7 @@ static StorageImplInfo classifyWithHasStorageAttr(
50465025

50475026
StorageImplInfo
50485027
Parser::ParsedAccessors::classify(Parser &P, AbstractStorageDecl *storage,
5049-
bool invalid, ParseDeclOptions flags,
5050-
SourceLoc staticLoc,
5051-
const DeclAttributes &attrs,
5052-
TypeLoc elementTy, ParameterList *indices) {
5053-
GenericParamList *genericParams = nullptr;
5054-
if (auto *subscript = dyn_cast<SubscriptDecl>(storage))
5055-
genericParams = subscript->getGenericParams();
5056-
5028+
bool invalid, const DeclAttributes &attrs) {
50575029
// If there was a problem parsing accessors, mark all parsed accessors
50585030
// as invalid to avoid tripping up later invariants.
50595031
// We also want to avoid diagnose missing accessors if something
@@ -5077,35 +5049,19 @@ Parser::ParsedAccessors::classify(Parser &P, AbstractStorageDecl *storage,
50775049
diagnoseAndIgnoreObservers(P, *this,
50785050
diag::observing_accessor_conflicts_with_accessor,
50795051
getAccessorNameForDiagnostic(nonObserver, /*article*/ true));
5080-
5081-
// Otherwise, we have either a stored or inherited observing property.
5082-
} else {
5083-
if (attrs.hasAttribute<OverrideAttr>()) {
5084-
return StorageImplInfo(ReadImplKind::Inherited,
5085-
WriteImplKind::InheritedWithObservers,
5086-
ReadWriteImplKind::MaterializeToTemporary);
5087-
} else {
5088-
return StorageImplInfo(ReadImplKind::Stored,
5089-
WriteImplKind::StoredWithObservers,
5090-
ReadWriteImplKind::MaterializeToTemporary);
5091-
}
50925052
}
50935053
}
50945054

50955055
// Okay, observers are out of the way.
5096-
assert(!WillSet && !DidSet);
50975056

50985057
// 'get', 'read', and a non-mutable addressor are all exclusive.
5099-
ReadImplKind readImpl;
51005058
if (Get) {
51015059
diagnoseConflictingAccessors(P, Get, Read);
51025060
diagnoseConflictingAccessors(P, Get, Address);
5103-
readImpl = ReadImplKind::Get;
51045061
} else if (Read) {
51055062
diagnoseConflictingAccessors(P, Read, Address);
5106-
readImpl = ReadImplKind::Read;
51075063
} else if (Address) {
5108-
readImpl = ReadImplKind::Address;
5064+
// Nothing can go wrong.
51095065

51105066
// If there's a writing accessor of any sort, there must also be a
51115067
// reading accessor.
@@ -5121,76 +5077,116 @@ Parser::ParsedAccessors::classify(Parser &P, AbstractStorageDecl *storage,
51215077
getAccessorNameForDiagnostic(mutator, /*article*/ true));
51225078
}
51235079

5124-
readImpl = ReadImplKind::Get;
5125-
51265080
// Subscripts always have to have some sort of accessor; they can't be
51275081
// purely stored.
51285082
} else if (isa<SubscriptDecl>(storage)) {
51295083
if (!invalid) {
51305084
P.diagnose(LBLoc, diag::subscript_without_get);
51315085
}
5086+
}
5087+
5088+
// A mutable addressor is exclusive with 'set' and 'modify', but
5089+
// 'set' and 'modify' can appear together.
5090+
if (Set) {
5091+
diagnoseConflictingAccessors(P, Set, MutableAddress);
5092+
} else if (Modify) {
5093+
diagnoseConflictingAccessors(P, Modify, MutableAddress);
5094+
}
5095+
5096+
if (auto *var = dyn_cast<VarDecl>(storage)) {
5097+
// Allow the @_hasStorage attribute to override all the accessors we parsed
5098+
// when making the final classification.
5099+
if (attrs.hasAttribute<HasStorageAttr>()) {
5100+
// The SIL rules for @_hasStorage are slightly different from the non-SIL
5101+
// rules. In SIL mode, @_hasStorage marks that the type is simply stored,
5102+
// and the only thing that determines mutability is the existence of the
5103+
// setter.
5104+
//
5105+
// FIXME: SIL should not be special cased here. The behavior should be
5106+
// consistent between SIL and non-SIL.
5107+
// The strategy here should be to keep track of all opaque accessors
5108+
// along with enough information to access the storage trivially
5109+
// if allowed. This could be a representational change to
5110+
// StorageImplInfo such that it keeps a bitset of listed accessors
5111+
// and dynamically determines the access strategy from that.
5112+
if (P.isInSILMode())
5113+
return StorageImplInfo::getSimpleStored(
5114+
StorageIsMutable_t(Set != nullptr));
5115+
5116+
return classifyWithHasStorageAttr(*this, P.Context, var, attrs);
5117+
}
5118+
}
51325119

5120+
// 'get', 'read', and a non-mutable addressor are all exclusive.
5121+
ReadImplKind readImpl;
5122+
if (Get) {
5123+
readImpl = ReadImplKind::Get;
5124+
} else if (Read) {
5125+
readImpl = ReadImplKind::Read;
5126+
} else if (Address) {
5127+
readImpl = ReadImplKind::Address;
5128+
5129+
// If there's a writing accessor of any sort, there must also be a
5130+
// reading accessor.
5131+
} else if (auto mutator = findFirstMutator()) {
51335132
readImpl = ReadImplKind::Get;
51345133

5134+
// Subscripts always have to have some sort of accessor; they can't be
5135+
// purely stored.
5136+
} else if (isa<SubscriptDecl>(storage)) {
5137+
readImpl = ReadImplKind::Get;
5138+
5139+
// Check if we have observers.
5140+
} else if (WillSet || DidSet) {
5141+
if (attrs.hasAttribute<OverrideAttr>()) {
5142+
readImpl = ReadImplKind::Inherited;
5143+
} else {
5144+
readImpl = ReadImplKind::Stored;
5145+
}
5146+
51355147
// Otherwise, it's stored.
51365148
} else {
51375149
readImpl = ReadImplKind::Stored;
51385150
}
51395151

5140-
// A mutable addressor is exclusive with 'set' and 'modify', but
5141-
// 'set' and 'modify' can appear together.
51425152
// Prefer using 'set' and 'modify' over a mutable addressor.
51435153
WriteImplKind writeImpl;
51445154
ReadWriteImplKind readWriteImpl;
51455155
if (Set) {
5146-
diagnoseConflictingAccessors(P, Set, MutableAddress);
51475156
writeImpl = WriteImplKind::Set;
51485157
if (Modify) {
51495158
readWriteImpl = ReadWriteImplKind::Modify;
51505159
} else {
51515160
readWriteImpl = ReadWriteImplKind::MaterializeToTemporary;
51525161
}
51535162
} else if (Modify) {
5154-
diagnoseConflictingAccessors(P, Modify, MutableAddress);
51555163
writeImpl = WriteImplKind::Modify;
51565164
readWriteImpl = ReadWriteImplKind::Modify;
51575165
} else if (MutableAddress) {
51585166
writeImpl = WriteImplKind::MutableAddress;
51595167
readWriteImpl = ReadWriteImplKind::MutableAddress;
51605168

5161-
// Otherwise, it's stored if there was no specific reading accessor.
5169+
// Check if we have observers.
5170+
} else if (readImpl == ReadImplKind::Inherited) {
5171+
writeImpl = WriteImplKind::InheritedWithObservers;
5172+
readWriteImpl = ReadWriteImplKind::MaterializeToTemporary;
5173+
5174+
// Otherwise, it's stored.
51625175
} else if (readImpl == ReadImplKind::Stored) {
5163-
writeImpl = WriteImplKind::Stored;
5164-
readWriteImpl = ReadWriteImplKind::Stored;
5176+
if (WillSet || DidSet) {
5177+
writeImpl = WriteImplKind::StoredWithObservers;
5178+
readWriteImpl = ReadWriteImplKind::MaterializeToTemporary;
5179+
} else {
5180+
writeImpl = WriteImplKind::Stored;
5181+
readWriteImpl = ReadWriteImplKind::Stored;
5182+
}
51655183

51665184
// Otherwise, it's immutable.
51675185
} else {
51685186
writeImpl = WriteImplKind::Immutable;
51695187
readWriteImpl = ReadWriteImplKind::Immutable;
51705188
}
51715189

5172-
// Allow the @_hasStorage attribute to override all the accessors we parsed
5173-
// when making the final classification.
5174-
if (attrs.hasAttribute<HasStorageAttr>()) {
5175-
// The SIL rules for @_hasStorage are slightly different from the non-SIL
5176-
// rules. In SIL mode, @_hasStorage marks that the type is simply stored,
5177-
// and the only thing that determines mutability is the existence of the
5178-
// setter.
5179-
//
5180-
// FIXME: SIL should not be special cased here. The behavior should be
5181-
// consistent between SIL and non-SIL.
5182-
// The strategy here should be to keep track of all opaque accessors
5183-
// along with enough information to access the storage trivially
5184-
// if allowed. This could be a representational change to
5185-
// StorageImplInfo such that it keeps a bitset of listed accessors
5186-
// and dynamically determines the access strategy from that.
5187-
if (P.isInSILMode())
5188-
return StorageImplInfo::getSimpleStored(
5189-
StorageIsMutable_t(Set != nullptr));
5190-
5191-
return classifyWithHasStorageAttr(*this, P.Context, storage, attrs);
5192-
}
5193-
51945190
return StorageImplInfo(readImpl, writeImpl, readWriteImpl);
51955191
}
51965192

@@ -6603,8 +6599,7 @@ Parser::parseDeclSubscript(SourceLoc StaticLoc,
66036599
}
66046600

66056601
accessors.record(*this, Subscript, (Invalid || !Status.isSuccess()),
6606-
Flags, StaticLoc, Attributes,
6607-
ElementTy.get(), Indices.get(), Decls);
6602+
Attributes, Decls);
66086603

66096604
// No need to setLocalDiscriminator because subscripts cannot
66106605
// validly appear outside of type decls.

0 commit comments

Comments
 (0)