Skip to content

Commit 43cdee3

Browse files
authored
Merge pull request #71904 from rjmccall/isolated-any-closures
Properly erase closure isolation to `@isolated(any)`
2 parents 76252f8 + cecf041 commit 43cdee3

13 files changed

+683
-135
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,16 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
19001900
TypeExpansionContext expansion,
19011901
SmallVectorImpl<SILParameterInfo> &inputs) {
19021902

1903+
// If the function is a closure being converted to an @isolated(any) type,
1904+
// add the implicit isolation parameter.
1905+
if (auto closureInfo = TC.getClosureTypeInfo(function)) {
1906+
if (closureInfo->ExpectedLoweredType->hasErasedIsolation()) {
1907+
auto isolationTy = SILType::getOpaqueIsolationType(TC.Context);
1908+
inputs.push_back({isolationTy.getASTType(),
1909+
ParameterConvention::Direct_Guaranteed});
1910+
}
1911+
}
1912+
19031913
// NB: The generic signature may be elided from the lowered function type
19041914
// if the function is in a fully-specialized context, but we still need to
19051915
// canonicalize references to the generic parameters that may appear in

lib/SILGen/Cleanup.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ class LLVM_LIBRARY_VISIBILITY CleanupManager {
176176
/// we can only reap the cleanup stack up to the innermost depth
177177
/// that we've handed out as a Scope.
178178
Scope *innermostScope = nullptr;
179-
FormalEvaluationScope *innermostFormalScope = nullptr;
180179

181180
void popTopDeadCleanups();
182181
void emitCleanups(CleanupsDepth depth, CleanupLocation l,

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 149 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ SILValue SILGenFunction::emitGenericExecutor(SILLocation loc) {
235235
return B.createOptionalNone(loc, ty);
236236
}
237237

238+
ManagedValue SILGenFunction::emitNonIsolatedIsolation(SILLocation loc) {
239+
return B.createManagedOptionalNone(loc,
240+
SILType::getOpaqueIsolationType(getASTContext()));
241+
}
242+
238243
SILValue SILGenFunction::emitLoadGlobalActorExecutor(Type globalActor) {
239244
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
240245
auto actor = emitLoadOfGlobalActorShared(loc, globalActor->getCanonicalType());
@@ -268,8 +273,71 @@ SILGenFunction::emitLoadOfGlobalActorShared(SILLocation loc, CanType actorType)
268273
return actorInstance;
269274
}
270275

276+
ManagedValue
277+
SILGenFunction::emitGlobalActorIsolation(SILLocation loc,
278+
CanType globalActorType) {
279+
// GlobalActor.shared returns Self, so this should be a value of
280+
// GlobalActor type.
281+
auto actor = emitLoadOfGlobalActorShared(loc, globalActorType);
282+
283+
// Since it's just a normal actor instance, we can use the normal path.
284+
return emitActorInstanceIsolation(loc, actor, globalActorType);
285+
}
286+
287+
/// Given a value of some non-optional actor type, convert it to
288+
/// non-optional `any Actor` type.
289+
static ManagedValue
290+
emitNonOptionalActorInstanceIsolation(SILGenFunction &SGF, SILLocation loc,
291+
ManagedValue actor, CanType actorType,
292+
SILType anyActorTy) {
293+
// If we have an `any Actor` already, we're done.
294+
if (actor.getType() == anyActorTy)
295+
return actor;
296+
297+
CanType anyActorType = anyActorTy.getASTType();
298+
return SGF.emitTransformExistential(loc, actor, actorType, anyActorType);
299+
}
300+
301+
ManagedValue
302+
SILGenFunction::emitActorInstanceIsolation(SILLocation loc, ManagedValue actor,
303+
CanType actorType) {
304+
// $Optional<any Actor>
305+
auto optionalAnyActorTy = SILType::getOpaqueIsolationType(getASTContext());
306+
// Optional<any Actor> as a formal type (it's invariant to lowering)
307+
auto optionalAnyActorType = optionalAnyActorTy.getASTType();
308+
309+
// If we started with an Optional<any Actor>, we're done.
310+
if (actorType == optionalAnyActorType) {
311+
return actor;
312+
}
313+
314+
// Otherwise, if we have an optional value, we need to transform the payload.
315+
auto actorObjectType = actorType.getOptionalObjectType();
316+
if (actorObjectType) {
317+
return emitOptionalToOptional(loc, actor, optionalAnyActorTy,
318+
[&](SILGenFunction &SGF, SILLocation loc, ManagedValue actorObject,
319+
SILType anyActorTy, SGFContext C) {
320+
return emitNonOptionalActorInstanceIsolation(*this, loc, actorObject,
321+
actorObjectType, anyActorTy);
322+
});
323+
}
324+
325+
// Otherwise, transform the non-optional value we have, then inject that
326+
// into Optional.
327+
SILType anyActorTy = optionalAnyActorTy.getOptionalObjectType();
328+
ManagedValue anyActor =
329+
emitNonOptionalActorInstanceIsolation(*this, loc, actor, actorType,
330+
anyActorTy);
331+
332+
// Inject into `Optional`.
333+
auto result = B.createOptionalSome(loc, anyActor);
334+
return result;
335+
}
336+
271337
SILValue SILGenFunction::emitLoadActorExecutor(SILLocation loc,
272338
ManagedValue actor) {
339+
// FIXME: Checking for whether we're in a formal evaluation scope
340+
// like this doesn't seem like a good pattern.
273341
SILValue actorV;
274342
if (isInFormalEvaluationScope())
275343
actorV = actor.formalAccessBorrow(*this, loc).getValue();
@@ -291,23 +359,18 @@ SILValue SILGenFunction::emitLoadErasedExecutor(SILLocation loc,
291359
ManagedValue
292360
SILGenFunction::emitLoadErasedIsolation(SILLocation loc,
293361
ManagedValue fn) {
294-
if (isInFormalEvaluationScope())
295-
fn = fn.formalAccessBorrow(*this, loc);
296-
else
297-
fn = fn.borrow(*this, loc);
362+
fn = fn.borrow(*this, loc);
298363

299364
// This expects a borrowed function and returns a borrowed (any Actor)?.
300365
auto actor = B.createFunctionExtractIsolation(loc, fn.getValue());
301366

302367
return ManagedValue::forBorrowedObjectRValue(actor);
303368
}
304369

305-
/// The ownership of the value returned here is mixed; callers that need
306-
/// an owned value must call ensurePlusOne.
307370
ManagedValue
308-
SILGenFunction::emitLoadOfFunctionIsolation(SILLocation loc,
309-
FunctionTypeIsolation isolation,
310-
ManagedValue fn) {
371+
SILGenFunction::emitFunctionTypeIsolation(SILLocation loc,
372+
FunctionTypeIsolation isolation,
373+
ManagedValue fn) {
311374
switch (isolation.getKind()) {
312375

313376
// Parameter-isolated functions don't have a specific actor they're isolated
@@ -318,50 +381,96 @@ SILGenFunction::emitLoadOfFunctionIsolation(SILLocation loc,
318381

319382
// Emit nonisolated by simply emitting Optional.none in the result type.
320383
case FunctionTypeIsolation::Kind::NonIsolated:
321-
return B.createManagedOptionalNone(loc,
322-
SILType::getOpaqueIsolationType(getASTContext()));
384+
return emitNonIsolatedIsolation(loc);
323385

324386
// Emit global actor isolation by loading .shared from the global actor,
325387
// erasing it into `any Actor`, and injecting that into Optional.
326-
case FunctionTypeIsolation::Kind::GlobalActor: {
327-
auto concreteActorType =
328-
isolation.getGlobalActorType()->getCanonicalType();
388+
case FunctionTypeIsolation::Kind::GlobalActor:
389+
return emitGlobalActorIsolation(loc,
390+
isolation.getGlobalActorType()->getCanonicalType());
329391

330-
// GlobalActor.shared returns Self, so this should be a value of the
331-
// actor type.
332-
auto actor = emitLoadOfGlobalActorShared(loc, concreteActorType);
392+
// Emit @isolated(any) isolation by loading the actor reference from the
393+
// function.
394+
case FunctionTypeIsolation::Kind::Erased: {
395+
Scope scope(*this, CleanupLocation(loc));
396+
auto value = emitLoadErasedIsolation(loc, fn).copy(*this, loc);
397+
return scope.popPreservingValue(value);
398+
}
399+
}
333400

334-
auto optionalAnyActorTy = SILType::getOpaqueIsolationType(getASTContext());
335-
auto anyActorTy = optionalAnyActorTy.getOptionalObjectType();
336-
assert(anyActorTy);
401+
llvm_unreachable("bad kind");
402+
}
337403

404+
static ActorIsolation getClosureIsolationInfo(SILDeclRef constant) {
405+
if (auto closure = constant.getAbstractClosureExpr()) {
406+
return closure->getActorIsolation();
407+
}
408+
auto func = constant.getAbstractFunctionDecl();
409+
assert(func && "unexpected closure constant");
410+
return getActorIsolation(func);
411+
}
338412

339-
ArrayRef<ProtocolConformanceRef> conformances =
340-
SGM.SwiftModule->collectExistentialConformances(concreteActorType,
341-
anyActorTy.getASTType());
413+
static ManagedValue emitLoadOfCaptureIsolation(SILGenFunction &SGF,
414+
SILLocation loc,
415+
VarDecl *isolatedCapture,
416+
SILDeclRef constant,
417+
ArrayRef<ManagedValue> captureArgs) {
418+
auto &TC = SGF.SGM.Types;
419+
auto captureInfo = TC.getLoweredLocalCaptures(constant);
420+
421+
auto isolatedVarType =
422+
isolatedCapture->getInterfaceType()->getCanonicalType();
423+
424+
// Capture arguments are 1-1 with the lowered capture info.
425+
auto captures = captureInfo.getCaptures();
426+
for (auto i : indices(captures)) {
427+
const auto &capture = captures[i];
428+
if (capture.isDynamicSelfMetadata()) continue;
429+
auto capturedVar = capture.getDecl();
430+
if (capturedVar != isolatedCapture) continue;
431+
432+
// Captured actor references should always be captured as constants.
433+
assert(TC.getDeclCaptureKind(capture,
434+
TC.getCaptureTypeExpansionContext(constant))
435+
== CaptureKind::Constant);
436+
437+
auto value = captureArgs[i].copy(SGF, loc);
438+
return SGF.emitActorInstanceIsolation(loc, value, isolatedVarType);
439+
}
342440

343-
for (auto conf: conformances)
344-
SGM.useConformance(conf);
441+
// The capture not being a lowered capture can happen in global code.
442+
auto value = SGF.emitRValueForDecl(loc, isolatedCapture, isolatedVarType,
443+
AccessSemantics::Ordinary)
444+
.getAsSingleValue(SGF, loc);
445+
return SGF.emitActorInstanceIsolation(loc, value, isolatedVarType);
446+
}
345447

346-
// Erase to `any Actor`.
347-
assert(anyActorTy.getPreferredExistentialRepresentation(concreteActorType)
348-
== ExistentialRepresentation::Class);
349-
auto erasedActor = B.createInitExistentialRef(loc, anyActorTy,
350-
concreteActorType,
351-
actor, conformances);
448+
ManagedValue
449+
SILGenFunction::emitClosureIsolation(SILLocation loc, SILDeclRef constant,
450+
ArrayRef<ManagedValue> captures) {
451+
auto isolation = getClosureIsolationInfo(constant);
452+
switch (isolation) {
453+
case ActorIsolation::Unspecified:
454+
case ActorIsolation::Nonisolated:
455+
case ActorIsolation::NonisolatedUnsafe:
456+
return emitNonIsolatedIsolation(loc);
352457

353-
// Inject into `Optional`.
354-
auto result = B.createOptionalSome(loc, erasedActor);
458+
case ActorIsolation::Erased:
459+
llvm_unreachable("closures cannot directly have erased isolation");
355460

356-
return result;
357-
}
461+
case ActorIsolation::GlobalActor:
462+
return emitGlobalActorIsolation(loc,
463+
isolation.getGlobalActor()->getCanonicalType());
358464

359-
// Emit @isolated(any) isolation by loading the actor reference from the
360-
// function.
361-
case FunctionTypeIsolation::Kind::Erased:
362-
return emitLoadErasedIsolation(loc, fn);
465+
case ActorIsolation::ActorInstance: {
466+
// This should always be a capture. That's not expressed super-cleanly
467+
// in ActorIsolation, unfortunately.
468+
assert(isolation.getActorInstanceParameter() == 0);
469+
auto capture = isolation.getActorInstance();
470+
assert(capture);
471+
return emitLoadOfCaptureIsolation(*this, loc, capture, constant, captures);
472+
}
363473
}
364-
365474
llvm_unreachable("bad kind");
366475
}
367476

lib/SILGen/SILGenEpilog.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ using namespace Lowering;
2222

2323
void SILGenFunction::prepareEpilog(
2424
DeclContext *DC, std::optional<Type> directResultType,
25-
std::optional<Type> errorType, CleanupLocation CleanupL,
26-
std::optional<AbstractionPattern> origClosureType) {
25+
std::optional<Type> errorType, CleanupLocation CleanupL) {
2726
auto *epilogBB = createBasicBlock();
2827

2928
// If we have any direct results, receive them via BB arguments.
@@ -66,8 +65,8 @@ void SILGenFunction::prepareEpilog(
6665

6766
if (errorType) {
6867
auto genericSig = DC->getGenericSignatureOfContext();
69-
AbstractionPattern origErrorType = origClosureType
70-
? *origClosureType->getFunctionThrownErrorType()
68+
AbstractionPattern origErrorType = TypeContext
69+
? *TypeContext->OrigType.getFunctionThrownErrorType()
7170
: AbstractionPattern(genericSig.getCanonicalSignature(),
7271
(*errorType)->getCanonicalType());
7372

0 commit comments

Comments
 (0)