Skip to content

Commit 8b561ad

Browse files
authored
Merge pull request #18750 from rjmccall/misc-cleanups-for-coroutines
2 parents 5753e12 + af1fbee commit 8b561ad

17 files changed

+207
-73
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -83,29 +83,14 @@ class AnyFunctionRef {
8383
return TheFunction.get<AbstractClosureExpr *>()->getResultType();
8484
}
8585

86-
struct YieldResult {
87-
Type Ty;
88-
VarDecl::Specifier Specifier;
89-
};
86+
ArrayRef<AnyFunctionType::Yield>
87+
getYieldResults(SmallVectorImpl<AnyFunctionType::Yield> &buffer) const {
88+
return getYieldResultsImpl(buffer, /*mapIntoContext*/ false);
89+
}
9090

91-
ArrayRef<YieldResult>
92-
getBodyYieldResults(SmallVectorImpl<YieldResult> &buffer) const {
93-
assert(buffer.empty());
94-
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
95-
if (auto *AD = dyn_cast<AccessorDecl>(AFD)) {
96-
if (AD->isCoroutine()) {
97-
auto valueTy = AD->getStorage()->getValueInterfaceType();
98-
valueTy = AD->mapTypeIntoContext(valueTy);
99-
auto specifier =
100-
AD->getAccessorKind() == AccessorKind::Modify
101-
? VarDecl::Specifier::InOut
102-
: VarDecl::Specifier::Shared;
103-
buffer.push_back({valueTy, specifier});
104-
return buffer;
105-
}
106-
}
107-
}
108-
return {};
91+
ArrayRef<AnyFunctionType::Yield>
92+
getBodyYieldResults(SmallVectorImpl<AnyFunctionType::Yield> &buffer) const {
93+
return getYieldResultsImpl(buffer, /*mapIntoContext*/ true);
10994
}
11095

11196
BraceStmt *getBody() const {
@@ -196,6 +181,28 @@ class AnyFunctionRef {
196181
}
197182
llvm_unreachable("unexpected AnyFunctionRef representation");
198183
}
184+
185+
private:
186+
ArrayRef<AnyFunctionType::Yield>
187+
getYieldResultsImpl(SmallVectorImpl<AnyFunctionType::Yield> &buffer,
188+
bool mapIntoContext) const {
189+
assert(buffer.empty());
190+
if (auto *AFD = TheFunction.dyn_cast<AbstractFunctionDecl *>()) {
191+
if (auto *AD = dyn_cast<AccessorDecl>(AFD)) {
192+
if (AD->isCoroutine()) {
193+
auto valueTy = AD->getStorage()->getValueInterfaceType();
194+
if (mapIntoContext)
195+
valueTy = AD->mapTypeIntoContext(valueTy);
196+
YieldTypeFlags flags(AD->getAccessorKind() == AccessorKind::Modify
197+
? ValueOwnership::InOut
198+
: ValueOwnership::Shared);
199+
buffer.push_back(AnyFunctionType::Yield(valueTy, flags));
200+
return buffer;
201+
}
202+
}
203+
}
204+
return {};
205+
}
199206
};
200207
#if SWIFT_COMPILER_IS_MSVC
201208
#pragma warning(pop)

include/swift/AST/Decl.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4143,15 +4143,15 @@ class AbstractStorageDecl : public ValueDecl {
41434143

41444144
protected:
41454145
AbstractStorageDecl(DeclKind Kind, DeclContext *DC, DeclName Name,
4146-
SourceLoc NameLoc, bool supportsMutation)
4146+
SourceLoc NameLoc, StorageIsMutable_t supportsMutation)
41474147
: ValueDecl(Kind, DC, Name, NameLoc) {
41484148
Bits.AbstractStorageDecl.HasStorage = true;
41494149
Bits.AbstractStorageDecl.SupportsMutation = supportsMutation;
41504150
Bits.AbstractStorageDecl.IsGetterMutating = false;
41514151
Bits.AbstractStorageDecl.IsSetterMutating = true;
41524152
}
41534153

4154-
void setSupportsMutationIfStillStored(bool supportsMutation) {
4154+
void setSupportsMutationIfStillStored(StorageIsMutable_t supportsMutation) {
41554155
if (auto ptr = Accessors.getPointer()) {
41564156
auto impl = ptr->getImplInfo();
41574157
if (!impl.isSimpleStored()) return;
@@ -4210,8 +4210,8 @@ class AbstractStorageDecl : public ValueDecl {
42104210
/// don't support mutation (e.g. to initialize them), and sometimes we
42114211
/// can't mutate things that do support mutation (e.g. because their
42124212
/// setter is private).
4213-
bool supportsMutation() const {
4214-
return Bits.AbstractStorageDecl.SupportsMutation;
4213+
StorageIsMutable_t supportsMutation() const {
4214+
return StorageIsMutable_t(Bits.AbstractStorageDecl.SupportsMutation);
42154215
}
42164216

42174217
/// Are there any accessors for this declaration, including implicit ones?
@@ -4452,7 +4452,8 @@ class VarDecl : public AbstractStorageDecl {
44524452

44534453
VarDecl(DeclKind Kind, bool IsStatic, Specifier Sp, bool IsCaptureList,
44544454
SourceLoc NameLoc, Identifier Name, DeclContext *DC)
4455-
: AbstractStorageDecl(Kind, DC, Name, NameLoc, !isImmutableSpecifier(Sp))
4455+
: AbstractStorageDecl(Kind, DC, Name, NameLoc,
4456+
StorageIsMutable_t(!isImmutableSpecifier(Sp)))
44564457
{
44574458
Bits.VarDecl.IsStatic = IsStatic;
44584459
Bits.VarDecl.Specifier = static_cast<unsigned>(Sp);
@@ -4853,7 +4854,7 @@ class SubscriptDecl : public GenericContext, public AbstractStorageDecl {
48534854
GenericParamList *GenericParams)
48544855
: GenericContext(DeclContextKind::SubscriptDecl, Parent),
48554856
AbstractStorageDecl(DeclKind::Subscript, Parent, Name, SubscriptLoc,
4856-
/*supports mutation (will be overwritten)*/ true),
4857+
/*will be overwritten*/ StorageIsNotMutable),
48574858
ArrowLoc(ArrowLoc), Indices(nullptr), ElementTy(ElementTy) {
48584859
setIndices(Indices);
48594860
setGenericParams(GenericParams);

include/swift/AST/StorageImpl.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222

2323
namespace swift {
2424

25+
enum StorageIsMutable_t : bool {
26+
StorageIsNotMutable = false,
27+
StorageIsMutable = true
28+
};
29+
2530
// Note that the values of these enums line up with %select values in
2631
// diagnostics.
2732
enum class AccessorKind {
@@ -309,16 +314,17 @@ class StorageImplInfo {
309314
#endif
310315
}
311316

312-
static StorageImplInfo getSimpleStored(bool supportsMutation) {
317+
static StorageImplInfo getSimpleStored(StorageIsMutable_t isMutable) {
313318
return { ReadImplKind::Stored,
314-
supportsMutation ? WriteImplKind::Stored
315-
: WriteImplKind::Immutable,
316-
supportsMutation ? ReadWriteImplKind::Stored
317-
: ReadWriteImplKind::Immutable };
319+
isMutable ? WriteImplKind::Stored
320+
: WriteImplKind::Immutable,
321+
isMutable ? ReadWriteImplKind::Stored
322+
: ReadWriteImplKind::Immutable };
318323
}
319324

320-
static StorageImplInfo getOpaque(bool supportsMutation) {
321-
return (supportsMutation ? getMutableOpaque() : getImmutableOpaque());
325+
static StorageImplInfo getOpaque(StorageIsMutable_t isMutable) {
326+
return (isMutable ? getMutableOpaque()
327+
: getImmutableOpaque());
322328
}
323329

324330
/// Describe the implementation of a immutable property implemented opaquely.
@@ -332,8 +338,9 @@ class StorageImplInfo {
332338
ReadWriteImplKind::MaterializeForSet };
333339
}
334340

335-
static StorageImplInfo getComputed(bool supportsMutation) {
336-
return (supportsMutation ? getMutableComputed() : getImmutableComputed());
341+
static StorageImplInfo getComputed(StorageIsMutable_t isMutable) {
342+
return (isMutable ? getMutableComputed()
343+
: getImmutableComputed());
337344
}
338345

339346
/// Describe the implementation of an immutable property implemented
@@ -362,8 +369,8 @@ class StorageImplInfo {
362369
}
363370

364371
/// Does this describe storage that supports mutation?
365-
bool supportsMutation() const {
366-
return getWriteImpl() != WriteImplKind::Immutable;
372+
StorageIsMutable_t supportsMutation() const {
373+
return StorageIsMutable_t(getWriteImpl() != WriteImplKind::Immutable);
367374
}
368375

369376
ReadImplKind getReadImpl() const {

include/swift/AST/Types.h

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,70 @@ class ParameterTypeFlags {
17451745
uint8_t toRaw() const { return value.toRaw(); }
17461746
};
17471747

1748+
class YieldTypeFlags {
1749+
enum YieldFlags : uint8_t {
1750+
None = 0,
1751+
InOut = 1 << 1,
1752+
Shared = 1 << 2,
1753+
Owned = 1 << 3,
1754+
1755+
NumBits = 3
1756+
};
1757+
OptionSet<YieldFlags> value;
1758+
1759+
static_assert(NumBits < 8 * sizeof(OptionSet<YieldFlags>), "overflowed");
1760+
1761+
YieldTypeFlags(OptionSet<YieldFlags, uint8_t> val) : value(val) {}
1762+
1763+
public:
1764+
YieldTypeFlags() = default;
1765+
static YieldTypeFlags fromRaw(uint8_t raw) {
1766+
return YieldTypeFlags(OptionSet<YieldFlags>(raw));
1767+
}
1768+
1769+
YieldTypeFlags(ValueOwnership ownership)
1770+
: value((ownership == ValueOwnership::InOut ? InOut : 0) |
1771+
(ownership == ValueOwnership::Shared ? Shared : 0) |
1772+
(ownership == ValueOwnership::Owned ? Owned : 0)) {}
1773+
1774+
bool isInOut() const { return value.contains(InOut); }
1775+
bool isShared() const { return value.contains(Shared); }
1776+
bool isOwned() const { return value.contains(Owned); }
1777+
1778+
ValueOwnership getValueOwnership() const {
1779+
if (isInOut())
1780+
return ValueOwnership::InOut;
1781+
else if (isShared())
1782+
return ValueOwnership::Shared;
1783+
else if (isOwned())
1784+
return ValueOwnership::Owned;
1785+
1786+
return ValueOwnership::Default;
1787+
}
1788+
1789+
YieldTypeFlags withInOut(bool isInout) const {
1790+
return YieldTypeFlags(isInout ? value | InOut : value - InOut);
1791+
}
1792+
1793+
YieldTypeFlags withShared(bool isShared) const {
1794+
return YieldTypeFlags(isShared ? value | Shared : value - Shared);
1795+
}
1796+
1797+
YieldTypeFlags withOwned(bool isOwned) const {
1798+
return YieldTypeFlags(isOwned ? value | Owned : value - Owned);
1799+
}
1800+
1801+
bool operator ==(const YieldTypeFlags &other) const {
1802+
return value.toRaw() == other.value.toRaw();
1803+
}
1804+
1805+
bool operator!=(const YieldTypeFlags &other) const {
1806+
return value.toRaw() != other.value.toRaw();
1807+
}
1808+
1809+
uint8_t toRaw() const { return value.toRaw(); }
1810+
};
1811+
17481812
/// ParenType - A paren type is a type that's been written in parentheses.
17491813
class ParenType : public SugarType {
17501814
friend class ASTContext;
@@ -2560,7 +2624,7 @@ class AnyFunctionType : public TypeBase {
25602624

25612625
public:
25622626
using Representation = FunctionTypeRepresentation;
2563-
2627+
25642628
class Param {
25652629
public:
25662630
explicit Param(const TupleTypeElt &tte);
@@ -2635,6 +2699,50 @@ class AnyFunctionType : public TypeBase {
26352699
using CanParamArrayRef =
26362700
ArrayRefView<Param,CanParam,CanParam::getFromParam,/*AccessOriginal*/true>;
26372701

2702+
class CanYield;
2703+
class Yield {
2704+
Type Ty;
2705+
YieldTypeFlags Flags;
2706+
public:
2707+
explicit Yield(Type type, YieldTypeFlags flags)
2708+
: Ty(type), Flags(flags) {}
2709+
2710+
Type getType() const { return Ty; }
2711+
2712+
YieldTypeFlags getFlags() const { return Flags; }
2713+
ValueOwnership getValueOwnership() const {
2714+
return getFlags().getValueOwnership();
2715+
}
2716+
bool isInOut() const { return getFlags().isInOut(); }
2717+
2718+
CanYield getCanonical() const;
2719+
2720+
Yield subst(SubstitutionMap subs, SubstOptions options = None) const {
2721+
return Yield(getType().subst(subs, options), getFlags());
2722+
}
2723+
2724+
bool operator==(const Yield &other) const {
2725+
return getType()->isEqual(other.getType()) &&
2726+
getFlags() == other.getFlags();
2727+
}
2728+
bool operator!=(const Yield &other) const {
2729+
return !operator==(other);
2730+
}
2731+
};
2732+
2733+
class CanYield : public Yield {
2734+
public:
2735+
explicit CanYield(CanType type, YieldTypeFlags flags)
2736+
: Yield(type, flags) {}
2737+
2738+
CanType getType() const { return CanType(Yield::getType()); }
2739+
2740+
CanYield subst(SubstitutionMap subs, SubstOptions options = None) const {
2741+
return CanYield(getType().subst(subs, options)->getCanonicalType(),
2742+
getFlags());
2743+
}
2744+
};
2745+
26382746
/// \brief A class which abstracts out some details necessary for
26392747
/// making a call.
26402748
class ExtInfo {
@@ -2896,6 +3004,10 @@ BEGIN_CAN_TYPE_WRAPPER(AnyFunctionType, Type)
28963004
}
28973005
END_CAN_TYPE_WRAPPER(AnyFunctionType, Type)
28983006

3007+
inline AnyFunctionType::CanYield AnyFunctionType::Yield::getCanonical() const {
3008+
return CanYield(getType()->getCanonicalType(), getFlags());
3009+
}
3010+
28993011
/// FunctionType - A monomorphic function type, specified with an arrow.
29003012
///
29013013
/// For example:

lib/AST/Decl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4577,7 +4577,8 @@ bool VarDecl::isSelfParameter() const {
45774577

45784578
void VarDecl::setSpecifier(Specifier specifier) {
45794579
Bits.VarDecl.Specifier = static_cast<unsigned>(specifier);
4580-
setSupportsMutationIfStillStored(!isImmutableSpecifier(specifier));
4580+
setSupportsMutationIfStillStored(
4581+
StorageIsMutable_t(!isImmutableSpecifier(specifier)));
45814582
}
45824583

45834584
bool VarDecl::isAnonClosureParam() const {

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4768,7 +4768,7 @@ Parser::ParsedAccessors::classify(Parser &P, AbstractStorageDecl *storage,
47684768
// Allow the sil_stored attribute to override all the accessors we parsed
47694769
// when making the final classification.
47704770
if (attrs.hasAttribute<SILStoredAttr>()) {
4771-
return StorageImplInfo::getSimpleStored(Set != nullptr);
4771+
return StorageImplInfo::getSimpleStored(StorageIsMutable_t(Set != nullptr));
47724772
}
47734773

47744774
return StorageImplInfo(readImpl, writeImpl, readWriteImpl);

lib/SILGen/Cleanup.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,12 @@ void CleanupManager::emitBranchAndCleanups(JumpDest dest, SILLocation branchLoc,
138138
builder.createBranch(branchLoc, dest.getBlock(), args);
139139
}
140140

141-
void CleanupManager::emitCleanupsForReturn(CleanupLocation loc) {
141+
void CleanupManager::emitCleanupsForReturn(CleanupLocation loc,
142+
ForUnwind_t forUnwind) {
142143
SILGenBuilder &builder = SGF.getBuilder();
143144
assert(builder.hasValidInsertionPoint() && "Emitting return in invalid spot");
144145
(void)builder;
145-
emitCleanups(stack.stable_end(), loc, NotForUnwind, /*popCleanups=*/false);
146+
emitCleanups(stack.stable_end(), loc, forUnwind, /*popCleanups=*/false);
146147
}
147148

148149
/// Emit a new block that jumps to the specified location and runs necessary

lib/SILGen/Cleanup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ class LLVM_LIBRARY_VISIBILITY CleanupManager {
173173

174174
/// emitCleanupsForReturn - Emit the top-level cleanups needed prior to a
175175
/// return from the function.
176-
void emitCleanupsForReturn(CleanupLocation loc);
176+
void emitCleanupsForReturn(CleanupLocation loc, ForUnwind_t forUnwind);
177177

178178
/// Emit a new block that jumps to the specified location and runs necessary
179179
/// cleanups based on its level. If there are no cleanups to run, this just

lib/SILGen/FormalEvaluation.h

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -148,23 +148,25 @@ class FormalEvaluationContext {
148148
void dump(SILGenFunction &SGF);
149149
};
150150

151-
/// A scope associated with the beginning of the formal evaluation of an lvalue.
151+
/// A scope associated with the beginning of the evaluation of an lvalue.
152152
///
153-
/// A formal evaluation of an lvalue occurs when emitting:
153+
/// The evaluation of an l-value is split into two stages: its formal
154+
/// evaluation, which evaluates any independent r-values embedded in the l-value
155+
/// expression (e.g. class references and subscript indices), and its formal
156+
/// access duration, which delimits the span of time for which the referenced
157+
/// storage is actually accessed.
154158
///
155-
/// 1. accessors.
156-
/// 2. getters.
157-
/// 3. materializeForSets.
159+
/// Note that other evaluations can be interleaved between the formal evaluation
160+
/// and the beginning of the formal access. For example, in a simple assignment
161+
/// statement, the left-hand side of the assignment is first formally evaluated
162+
/// as an l-value, then the right-hand side is evaluated as an r-value, and only
163+
/// then does the write access begin to the l-value.
158164
///
159-
/// for lvalues. The general form of such an evaluation is:
160-
///
161-
/// formally evaluate the lvalue "x" into memory
162-
/// begin formal access to "x"
163-
/// end formal access to "x"
164-
/// ... *more formal access*
165-
/// begin formal access to "x"
166-
/// end formal access to "x"
167-
/// end formal evaluation of lvalue into memory
165+
/// Note also that the formal evaluation of an l-value will sometimes require
166+
/// its component l-values to be formally accessed. For example, the formal
167+
/// access of the l-value `x?.prop` will initiate an access to `x` immediately
168+
/// because the downstream evaluation must be skipped if `x` has no value, which
169+
/// cannot be determined without beginning the access.
168170
///
169171
/// *NOTE* All formal access contain a pointer to a cleanup in the normal
170172
/// cleanup stack. This is to ensure that when SILGen calls

0 commit comments

Comments
 (0)