Skip to content

Commit eff0845

Browse files
authored
Merge pull request #82613 from rjmccall/local-function-isolation-fixes-6.2
[6.2] Local function isolation fixes
2 parents 7606a69 + 06dec05 commit eff0845

13 files changed

+331
-158
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 84 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,75 @@ class ActorIsolation {
8888
/// Set to true if this was parsed from SIL.
8989
unsigned silParsed : 1;
9090

91-
unsigned parameterIndex : 27;
91+
/// The opaque value of an EncodedParameterIndex.
92+
/// Only meaningful for ActorInstance.
93+
unsigned encodedParameterIndex : 27;
94+
95+
class EncodedParameterIndex {
96+
enum : unsigned {
97+
SpecialIndex_Capture,
98+
SpecialIndex_Self,
99+
NumSpecialIndexes
100+
};
101+
102+
/// Either a special index or (parameter index + NumSpecialIndexes).
103+
unsigned value;
104+
105+
constexpr EncodedParameterIndex(unsigned value) : value(value) {}
106+
107+
public:
108+
static constexpr EncodedParameterIndex parameter(unsigned index) {
109+
return EncodedParameterIndex(NumSpecialIndexes + index);
110+
}
111+
static constexpr EncodedParameterIndex self() {
112+
return EncodedParameterIndex(SpecialIndex_Self);
113+
}
114+
static constexpr EncodedParameterIndex capture() {
115+
return EncodedParameterIndex(SpecialIndex_Capture);
116+
}
117+
118+
unsigned getParameterIndex() const {
119+
assert(value >= NumSpecialIndexes);
120+
return value - NumSpecialIndexes;
121+
}
122+
bool isSelf() const {
123+
return value == SpecialIndex_Self;
124+
}
125+
bool isCapture() const {
126+
return value == SpecialIndex_Capture;
127+
}
92128

93-
ActorIsolation(Kind kind, NominalTypeDecl *actor, unsigned parameterIndex);
129+
static EncodedParameterIndex fromOpaqueValue(unsigned value) {
130+
return EncodedParameterIndex(value);
131+
}
132+
unsigned getOpaqueValue() const {
133+
return value;
134+
}
135+
};
94136

95-
ActorIsolation(Kind kind, VarDecl *actor, unsigned parameterIndex);
137+
ActorIsolation(Kind kind, NominalTypeDecl *actor,
138+
EncodedParameterIndex parameterIndex);
96139

97-
ActorIsolation(Kind kind, Expr *actor, unsigned parameterIndex);
140+
ActorIsolation(Kind kind, VarDecl *actor,
141+
EncodedParameterIndex parameterIndex);
142+
143+
ActorIsolation(Kind kind, Expr *actor,
144+
EncodedParameterIndex parameterIndex);
98145

99146
ActorIsolation(Kind kind, Type globalActor);
100147

148+
EncodedParameterIndex getEncodedParameterIndex() const {
149+
return EncodedParameterIndex::fromOpaqueValue(encodedParameterIndex);
150+
}
151+
101152
public:
102153
// No-argument constructor needed for DenseMap use in PostfixCompletion.cpp
103154
explicit ActorIsolation(Kind kind = Unspecified, bool isSILParsed = false)
104155
: pointer(nullptr), kind(kind), isolatedByPreconcurrency(false),
105-
silParsed(isSILParsed), parameterIndex(0) {}
156+
silParsed(isSILParsed), encodedParameterIndex(0) {
157+
// SIL's use of this has weaker invariants for now.
158+
assert(kind != ActorInstance || isSILParsed);
159+
}
106160

107161
static ActorIsolation forUnspecified() {
108162
return ActorIsolation(Unspecified);
@@ -125,19 +179,22 @@ class ActorIsolation {
125179

126180
static ActorIsolation forActorInstanceParameter(NominalTypeDecl *actor,
127181
unsigned parameterIndex) {
128-
return ActorIsolation(ActorInstance, actor, parameterIndex + 1);
182+
return ActorIsolation(ActorInstance, actor,
183+
EncodedParameterIndex::parameter(parameterIndex));
129184
}
130185

131186
static ActorIsolation forActorInstanceParameter(VarDecl *actor,
132187
unsigned parameterIndex) {
133-
return ActorIsolation(ActorInstance, actor, parameterIndex + 1);
188+
return ActorIsolation(ActorInstance, actor,
189+
EncodedParameterIndex::parameter(parameterIndex));
134190
}
135191

136192
static ActorIsolation forActorInstanceParameter(Expr *actor,
137193
unsigned parameterIndex);
138194

139195
static ActorIsolation forActorInstanceCapture(VarDecl *capturedActor) {
140-
return ActorIsolation(ActorInstance, capturedActor, 0);
196+
return ActorIsolation(ActorInstance, capturedActor,
197+
EncodedParameterIndex::capture());
141198
}
142199

143200
static ActorIsolation forGlobalActor(Type globalActor) {
@@ -153,21 +210,14 @@ class ActorIsolation {
153210
static std::optional<ActorIsolation> forSILString(StringRef string) {
154211
auto kind =
155212
llvm::StringSwitch<std::optional<ActorIsolation::Kind>>(string)
156-
.Case("unspecified",
157-
std::optional<ActorIsolation>(ActorIsolation::Unspecified))
158-
.Case("actor_instance",
159-
std::optional<ActorIsolation>(ActorIsolation::ActorInstance))
160-
.Case("nonisolated",
161-
std::optional<ActorIsolation>(ActorIsolation::Nonisolated))
162-
.Case("nonisolated_unsafe", std::optional<ActorIsolation>(
163-
ActorIsolation::NonisolatedUnsafe))
164-
.Case("global_actor",
165-
std::optional<ActorIsolation>(ActorIsolation::GlobalActor))
166-
.Case("global_actor_unsafe",
167-
std::optional<ActorIsolation>(ActorIsolation::GlobalActor))
213+
.Case("unspecified", ActorIsolation::Unspecified)
214+
.Case("actor_instance", ActorIsolation::ActorInstance)
215+
.Case("nonisolated", ActorIsolation::Nonisolated)
216+
.Case("nonisolated_unsafe", ActorIsolation::NonisolatedUnsafe)
217+
.Case("global_actor", ActorIsolation::GlobalActor)
218+
.Case("global_actor_unsafe", ActorIsolation::GlobalActor)
168219
.Case("caller_isolation_inheriting",
169-
std::optional<ActorIsolation>(
170-
ActorIsolation::CallerIsolationInheriting))
220+
ActorIsolation::CallerIsolationInheriting)
171221
.Default(std::nullopt);
172222
if (kind == std::nullopt)
173223
return std::nullopt;
@@ -187,17 +237,22 @@ class ActorIsolation {
187237
bool isNonisolatedUnsafe() const { return kind == NonisolatedUnsafe; }
188238

189239
/// Retrieve the parameter to which actor-instance isolation applies.
190-
///
191-
/// Parameter 0 is `self`.
192-
unsigned getActorInstanceParameter() const {
240+
unsigned getActorInstanceParameterIndex() const {
193241
assert(getKind() == ActorInstance);
194-
return parameterIndex;
242+
return getEncodedParameterIndex().getParameterIndex();
243+
}
244+
245+
/// Given that this is actor instance isolation, is it a capture?
246+
bool isActorInstanceForCapture() const {
247+
assert(getKind() == ActorInstance);
248+
return getEncodedParameterIndex().isCapture();
195249
}
196250

197251
/// Returns true if this is an actor-instance isolation that additionally
198252
/// applies to the self parameter of a method.
199253
bool isActorInstanceForSelfParameter() const {
200-
return getActorInstanceParameter() == 0;
254+
assert(getKind() == ActorInstance);
255+
return getEncodedParameterIndex().isSelf();
201256
}
202257

203258
bool isSILParsed() const { return silParsed; }
@@ -285,13 +340,13 @@ class ActorIsolation {
285340
id.AddPointer(pointer);
286341
id.AddBoolean(isolatedByPreconcurrency);
287342
id.AddBoolean(silParsed);
288-
id.AddInteger(parameterIndex);
343+
id.AddInteger(encodedParameterIndex);
289344
}
290345

291346
friend llvm::hash_code hash_value(const ActorIsolation &state) {
292347
return llvm::hash_combine(state.kind, state.pointer,
293348
state.isolatedByPreconcurrency, state.silParsed,
294-
state.parameterIndex);
349+
state.encodedParameterIndex);
295350
}
296351

297352
void print(llvm::raw_ostream &os) const;

lib/AST/ActorIsolation.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,27 @@ ActorIsolation ActorIsolation::forMainActor(ASTContext &ctx) {
2323
ctx.getMainActorType()->mapTypeOutOfContext());
2424
}
2525

26+
// These constructors are defined out-of-line so that including ActorIsolation.h
27+
// doesn't require a bunch of other headers to be included.
28+
2629
ActorIsolation::ActorIsolation(Kind kind, NominalTypeDecl *actor,
27-
unsigned parameterIndex)
30+
EncodedParameterIndex parameterIndex)
2831
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
29-
silParsed(false), parameterIndex(parameterIndex) {}
32+
silParsed(false), encodedParameterIndex(parameterIndex.getOpaqueValue()) {}
3033

3134
ActorIsolation::ActorIsolation(Kind kind, VarDecl *actor,
32-
unsigned parameterIndex)
35+
EncodedParameterIndex parameterIndex)
3336
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
34-
silParsed(false), parameterIndex(parameterIndex) {}
37+
silParsed(false), encodedParameterIndex(parameterIndex.getOpaqueValue()) {}
3538

36-
ActorIsolation::ActorIsolation(Kind kind, Expr *actor, unsigned parameterIndex)
39+
ActorIsolation::ActorIsolation(Kind kind, Expr *actor,
40+
EncodedParameterIndex parameterIndex)
3741
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false),
38-
silParsed(false), parameterIndex(parameterIndex) {}
42+
silParsed(false), encodedParameterIndex(parameterIndex.getOpaqueValue()) {}
3943

4044
ActorIsolation::ActorIsolation(Kind kind, Type globalActor)
4145
: globalActor(globalActor), kind(kind), isolatedByPreconcurrency(false),
42-
silParsed(false), parameterIndex(0) {}
46+
silParsed(false), encodedParameterIndex(0) {}
4347

4448
ActorIsolation
4549
ActorIsolation::forActorInstanceParameter(Expr *actor,
@@ -67,25 +71,29 @@ ActorIsolation::forActorInstanceParameter(Expr *actor,
6771
}
6872
}
6973

70-
return ActorIsolation(ActorInstance, actor, parameterIndex + 1);
74+
return ActorIsolation(ActorInstance, actor,
75+
EncodedParameterIndex::parameter(parameterIndex));
7176
}
7277

7378
ActorIsolation ActorIsolation::forActorInstanceSelf(ValueDecl *decl) {
7479
if (auto *fn = dyn_cast<AbstractFunctionDecl>(decl))
75-
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(), 0);
80+
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(),
81+
EncodedParameterIndex::self());
7682

7783
if (auto *storage = dyn_cast<AbstractStorageDecl>(decl)) {
7884
if (auto *fn = storage->getAccessor(AccessorKind::Get)) {
79-
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(), 0);
85+
return ActorIsolation(ActorInstance, fn->getImplicitSelfDecl(),
86+
EncodedParameterIndex::self());
8087
}
8188
}
8289

8390
auto *dc = decl->getDeclContext();
84-
return ActorIsolation(ActorInstance, dc->getSelfNominalTypeDecl(), 0);
91+
return ActorIsolation(ActorInstance, dc->getSelfNominalTypeDecl(),
92+
EncodedParameterIndex::self());
8593
}
8694

8795
ActorIsolation ActorIsolation::forActorInstanceSelf(NominalTypeDecl *selfDecl) {
88-
return ActorIsolation(ActorInstance, selfDecl, 0);
96+
return ActorIsolation(ActorInstance, selfDecl, EncodedParameterIndex::self());
8997
}
9098

9199
NominalTypeDecl *ActorIsolation::getActor() const {
@@ -183,6 +191,9 @@ bool ActorIsolation::isEqual(const ActorIsolation &lhs,
183191
auto *lhsActor = lhs.getActorInstance();
184192
auto *rhsActor = rhs.getActorInstance();
185193
if (lhsActor && rhsActor) {
194+
if (lhsActor == rhsActor)
195+
return true;
196+
186197
// FIXME: This won't work for arbitrary isolated parameter captures.
187198
if ((lhsActor->isSelfParameter() && rhsActor->isSelfParamCapture()) ||
188199
(lhsActor->isSelfParamCapture() && rhsActor->isSelfParameter())) {

lib/AST/ConformanceLookup.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,13 @@ static ProtocolConformanceRef getBuiltinTupleTypeConformance(
269269
return ProtocolConformanceRef::forMissingOrInvalid(type, protocol);
270270
}
271271

272+
// We can end up checking builtin conformances for generic function types
273+
// when e.g. we're checking whether a captured local func declaration is
274+
// sendable. That's fine, we can answer that question in the abstract
275+
// without needing to generally support conformances on generic function
276+
// types.
272277
using EitherFunctionType =
273-
llvm::PointerUnion<const SILFunctionType *, const FunctionType *>;
278+
llvm::PointerUnion<const SILFunctionType *, const AnyFunctionType *>;
274279

275280
/// Whether the given function type conforms to Sendable.
276281
static bool isSendableFunctionType(EitherFunctionType eitherFnTy) {
@@ -288,7 +293,7 @@ static bool isSendableFunctionType(EitherFunctionType eitherFnTy) {
288293
representation = *converted;
289294

290295
} else {
291-
auto functionType = eitherFnTy.get<const FunctionType *>();
296+
auto functionType = eitherFnTy.get<const AnyFunctionType *>();
292297

293298
if (functionType->isSendable())
294299
return true;
@@ -332,7 +337,7 @@ static bool isBitwiseCopyableFunctionType(EitherFunctionType eitherFnTy) {
332337
if (auto silFnTy = eitherFnTy.dyn_cast<const SILFunctionType *>()) {
333338
representation = silFnTy->getRepresentation();
334339
} else {
335-
auto fnTy = eitherFnTy.get<const FunctionType *>();
340+
auto fnTy = eitherFnTy.get<const AnyFunctionType *>();
336341
representation = convertRepresentation(fnTy->getRepresentation());
337342
}
338343

@@ -621,7 +626,7 @@ LookupConformanceInModuleRequest::evaluate(
621626
}
622627

623628
// Function types can conform to protocols.
624-
if (auto functionType = type->getAs<FunctionType>()) {
629+
if (auto functionType = type->getAs<AnyFunctionType>()) {
625630
return getBuiltinFunctionTypeConformance(type, functionType, protocol);
626631
}
627632

lib/SILGen/SILGenApply.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6123,13 +6123,15 @@ RValue SILGenFunction::emitApply(
61236123
SILValue executor;
61246124
switch (*implicitActorHopTarget) {
61256125
case ActorIsolation::ActorInstance:
6126-
if (unsigned paramIndex =
6127-
implicitActorHopTarget->getActorInstanceParameter()) {
6126+
assert(!implicitActorHopTarget->isActorInstanceForCapture());
6127+
if (implicitActorHopTarget->isActorInstanceForSelfParameter()) {
6128+
executor = emitLoadActorExecutor(loc, args.back());
6129+
} else {
6130+
unsigned paramIndex =
6131+
implicitActorHopTarget->getActorInstanceParameterIndex();
61286132
auto isolatedIndex = calleeTypeInfo.origFormalType
6129-
->getLoweredParamIndex(paramIndex - 1);
6133+
->getLoweredParamIndex(paramIndex);
61306134
executor = emitLoadActorExecutor(loc, args[isolatedIndex]);
6131-
} else {
6132-
executor = emitLoadActorExecutor(loc, args.back());
61336135
}
61346136
break;
61356137

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ void SILGenFunction::emitExpectedExecutorProlog() {
195195

196196
case ActorIsolation::GlobalActor:
197197
if (F.isAsync() || wantDataRaceChecks) {
198-
setExpectedExecutorForGlobalActor(*this, actorIsolation.getGlobalActor());
198+
auto globalActorType = F.mapTypeIntoContext(actorIsolation.getGlobalActor());
199+
setExpectedExecutorForGlobalActor(*this, globalActorType);
199200
}
200201
break;
201202
}
@@ -226,7 +227,8 @@ void SILGenFunction::emitExpectedExecutorProlog() {
226227

227228
case ActorIsolation::GlobalActor:
228229
if (wantExecutor) {
229-
setExpectedExecutorForGlobalActor(*this, actorIsolation.getGlobalActor());
230+
auto globalActorType = F.mapTypeIntoContext(actorIsolation.getGlobalActor());
231+
setExpectedExecutorForGlobalActor(*this, globalActorType);
230232
break;
231233
}
232234
}
@@ -573,9 +575,10 @@ SILGenFunction::emitFunctionTypeIsolation(SILLocation loc,
573575

574576
// Emit global actor isolation by loading .shared from the global actor,
575577
// erasing it into `any Actor`, and injecting that into Optional.
576-
case FunctionTypeIsolation::Kind::GlobalActor:
578+
case FunctionTypeIsolation::Kind::GlobalActor: {
577579
return emitGlobalActorIsolation(loc,
578580
isolation.getGlobalActorType()->getCanonicalType());
581+
}
579582

580583
// Emit @isolated(any) isolation by loading the actor reference from the
581584
// function.
@@ -646,14 +649,14 @@ SILGenFunction::emitClosureIsolation(SILLocation loc, SILDeclRef constant,
646649
case ActorIsolation::Erased:
647650
llvm_unreachable("closures cannot directly have erased isolation");
648651

649-
case ActorIsolation::GlobalActor:
650-
return emitGlobalActorIsolation(loc,
651-
isolation.getGlobalActor()->getCanonicalType());
652+
case ActorIsolation::GlobalActor: {
653+
auto globalActorType = F.mapTypeIntoContext(isolation.getGlobalActor())
654+
->getCanonicalType();
655+
return emitGlobalActorIsolation(loc, globalActorType);
656+
}
652657

653658
case ActorIsolation::ActorInstance: {
654-
// This should always be a capture. That's not expressed super-cleanly
655-
// in ActorIsolation, unfortunately.
656-
assert(isolation.getActorInstanceParameter() == 0);
659+
assert(isolation.isActorInstanceForCapture());
657660
auto capture = isolation.getActorInstance();
658661
assert(capture);
659662
return emitLoadOfCaptureIsolation(*this, loc, capture, constant, captures);
@@ -705,8 +708,10 @@ SILGenFunction::emitExecutor(SILLocation loc, ActorIsolation isolation,
705708
return emitLoadActorExecutor(loc, self);
706709
}
707710

708-
case ActorIsolation::GlobalActor:
709-
return emitLoadGlobalActorExecutor(isolation.getGlobalActor());
711+
case ActorIsolation::GlobalActor: {
712+
auto globalActorType = F.mapTypeIntoContext(isolation.getGlobalActor());
713+
return emitLoadGlobalActorExecutor(globalActorType);
714+
}
710715
}
711716
llvm_unreachable("covered switch");
712717
}

lib/SILGen/SILGenConstructor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ static bool ctorHopsInjectedByDefiniteInit(ConstructorDecl *ctor,
595595
// must be self-isolated
596596
switch (isolation) {
597597
case ActorIsolation::ActorInstance:
598-
return isolation.getActorInstanceParameter() == 0;
598+
return isolation.isActorInstanceForSelfParameter();
599599

600600
case ActorIsolation::Erased:
601601
llvm_unreachable("constructor cannot have erased isolation");

0 commit comments

Comments
 (0)