Skip to content

Commit 0a627bc

Browse files
authored
Merge pull request #72324 from hborla/extract-function-isolation-expr
[Concurrency] Add a `.isolation` member on dynamically isolated function values.
2 parents 9fa0028 + f5e407e commit 0a627bc

18 files changed

+160
-0
lines changed

include/swift/AST/Expr.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3518,6 +3518,43 @@ class ActorIsolationErasureExpr : public ImplicitConversionExpr {
35183518
}
35193519
};
35203520

3521+
/// Extracts the isolation of a dynamically isolated function value.
3522+
class ExtractFunctionIsolationExpr : public Expr {
3523+
/// The function value expression from which to extract the
3524+
/// isolation. The type of `fnExpr` must be an ``@isolated(any)`
3525+
/// funciton.
3526+
Expr *fnExpr;
3527+
3528+
/// The source location of `.isolation`
3529+
SourceLoc isolationLoc;
3530+
3531+
public:
3532+
ExtractFunctionIsolationExpr(Expr *fnExpr, SourceLoc isolationLoc,
3533+
Type type, bool implicit = false)
3534+
: Expr(ExprKind::ExtractFunctionIsolation, implicit, type),
3535+
fnExpr(fnExpr), isolationLoc(isolationLoc) {}
3536+
3537+
Expr *getFunctionExpr() const {
3538+
return fnExpr;
3539+
}
3540+
3541+
void setFunctionExpr(Expr *fnExpr) {
3542+
this->fnExpr = fnExpr;
3543+
}
3544+
3545+
SourceLoc getStartLoc() const {
3546+
return fnExpr->getStartLoc();
3547+
}
3548+
3549+
SourceLoc getEndLoc() const {
3550+
return isolationLoc;
3551+
}
3552+
3553+
static bool classof(const Expr *E) {
3554+
return E->getKind() == ExprKind::ExtractFunctionIsolation;
3555+
}
3556+
};
3557+
35213558
/// UnresolvedSpecializeExpr - Represents an explicit specialization using
35223559
/// a type parameter list (e.g. "Vector<Int>") that has not been resolved.
35233560
class UnresolvedSpecializeExpr final : public Expr,

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ EXPR(VarargExpansion, Expr)
134134
EXPR(PackExpansion, Expr)
135135
EXPR(PackElement, Expr)
136136
EXPR(MaterializePack, Expr)
137+
EXPR(ExtractFunctionIsolation, Expr)
137138
EXPR(DynamicType, Expr)
138139
EXPR(RebindSelfInConstructor, Expr)
139140
EXPR(OpaqueValue, Expr)

include/swift/Sema/OverloadChoice.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ enum class OverloadChoiceKind : int {
5656
DeclViaUnwrappedOptional,
5757
/// The overload choice materializes a pack from a tuple.
5858
MaterializePack,
59+
/// The overload choice extracts the isolation of a dynamically isolated
60+
/// function value.
61+
ExtractFunctionIsolation,
5962
/// The overload choice indexes into a tuple. Index zero will
6063
/// have the value of this enumerator, index one will have the value of this
6164
/// enumerator + 1, and so on. Thus, this enumerator must always be last.

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,13 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
26992699
printFoot();
27002700
}
27012701

2702+
void visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E,
2703+
StringRef label) {
2704+
printCommon(E, "extract_function_isolation", label);
2705+
printRec(E->getFunctionExpr());
2706+
printFoot();
2707+
}
2708+
27022709
void visitInOutExpr(InOutExpr *E, StringRef label) {
27032710
printCommon(E, "inout_expr", label);
27042711
printRec(E->getSubExpr());

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5290,6 +5290,11 @@ void PrintAST::visitLinearToDifferentiableFunctionExpr(swift::LinearToDifferenti
52905290
void PrintAST::visitActorIsolationErasureExpr(ActorIsolationErasureExpr *expr) {
52915291
}
52925292

5293+
void PrintAST::visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *expr) {
5294+
visit(expr->getFunctionExpr());
5295+
Printer << ".isolation";
5296+
}
5297+
52935298
void PrintAST::visitPropertyWrapperValuePlaceholderExpr(swift::PropertyWrapperValuePlaceholderExpr *expr) {
52945299
}
52955300

lib/AST/ASTWalker.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,17 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
13261326
return E;
13271327
}
13281328

1329+
Expr *visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E) {
1330+
if (auto fn = E->getFunctionExpr()) {
1331+
if (auto newFn = doIt(fn))
1332+
E->setFunctionExpr(newFn);
1333+
else
1334+
return nullptr;
1335+
}
1336+
1337+
return E;
1338+
}
1339+
13291340
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) { return E; }
13301341

13311342
Expr *visitSingleValueStmtExpr(SingleValueStmtExpr *E) {

lib/AST/Expr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
378378
PASS_THROUGH_REFERENCE(Try, getSubExpr);
379379
PASS_THROUGH_REFERENCE(ForceTry, getSubExpr);
380380
PASS_THROUGH_REFERENCE(OptionalTry, getSubExpr);
381+
PASS_THROUGH_REFERENCE(ExtractFunctionIsolation, getFunctionExpr);
381382

382383
NO_REFERENCE(Tuple);
383384
SIMPLE_REFERENCE(Array, getInitializer);
@@ -723,6 +724,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
723724
case ExprKind::UnresolvedSpecialize:
724725
case ExprKind::UnresolvedMember:
725726
case ExprKind::UnresolvedDot:
727+
case ExprKind::ExtractFunctionIsolation:
726728
return true;
727729

728730
case ExprKind::Sequence:
@@ -1032,6 +1034,7 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
10321034
case ExprKind::MacroExpansion:
10331035
case ExprKind::CurrentContextIsolation:
10341036
case ExprKind::ActorIsolationErasure:
1037+
case ExprKind::ExtractFunctionIsolation:
10351038
return false;
10361039
}
10371040

lib/IDE/SelectedOverloadInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ swift::ide::getSelectedOverloadInfo(const Solution &S,
8989
case OverloadChoiceKind::DynamicMemberLookup:
9090
case OverloadChoiceKind::TupleIndex:
9191
case OverloadChoiceKind::MaterializePack:
92+
case OverloadChoiceKind::ExtractFunctionIsolation:
9293
// If it's DynamicMemberLookup, we don't know which function is being
9394
// called, so we can't extract any information from it.
9495
// TupleIndex isn't a function call and is not relevant for argument

lib/SILGen/SILGenExpr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ namespace {
486486
SGFContext C);
487487
RValue visitActorIsolationErasureExpr(ActorIsolationErasureExpr *E,
488488
SGFContext C);
489+
RValue visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E,
490+
SGFContext C);
489491
RValue visitCovariantFunctionConversionExpr(
490492
CovariantFunctionConversionExpr *E,
491493
SGFContext C);
@@ -2107,6 +2109,14 @@ RValue RValueEmitter::visitActorIsolationErasureExpr(ActorIsolationErasureExpr *
21072109
nonIsolatedType));
21082110
}
21092111

2112+
RValue RValueEmitter::visitExtractFunctionIsolationExpr(
2113+
ExtractFunctionIsolationExpr *E, SGFContext C) {
2114+
auto arg = SGF.emitRValue(E->getFunctionExpr());
2115+
auto result = SGF.emitExtractFunctionIsolation(
2116+
E, ArgumentSource(E, std::move(arg)), C);
2117+
return RValue(SGF, E, result);
2118+
}
2119+
21102120
RValue RValueEmitter::visitErasureExpr(ErasureExpr *E, SGFContext C) {
21112121
if (auto result = tryEmitAsBridgingConversion(SGF, E, false, C)) {
21122122
return RValue(SGF, E, *result);

lib/Sema/CSApply.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3423,6 +3423,15 @@ namespace {
34233423
packType));
34243424
}
34253425

3426+
case OverloadChoiceKind::ExtractFunctionIsolation: {
3427+
auto isolationType = solution.getResolvedType(expr);
3428+
auto *extractExpr = new (cs.getASTContext())
3429+
ExtractFunctionIsolationExpr(base,
3430+
expr->getEndLoc(),
3431+
isolationType);
3432+
return cs.cacheType(extractExpr);
3433+
}
3434+
34263435
case OverloadChoiceKind::KeyPathApplication:
34273436
llvm_unreachable("should only happen in a subscript");
34283437

@@ -5372,6 +5381,10 @@ namespace {
53725381
return E;
53735382
}
53745383

5384+
Expr *visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E) {
5385+
llvm_unreachable("found ExtractFunctionIsolationExpr in CSApply");
5386+
}
5387+
53755388
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) {
53765389
llvm_unreachable("found KeyPathDotExpr in CSApply");
53775390
}

lib/Sema/CSGen.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3935,6 +3935,10 @@ namespace {
39353935
return OptionalType::get(actorProto->getDeclaredExistentialType());
39363936
}
39373937

3938+
Type visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E) {
3939+
llvm_unreachable("found ExtractFunctionIsolationExpr in CSGen");
3940+
}
3941+
39383942
Type visitKeyPathDotExpr(KeyPathDotExpr *E) {
39393943
llvm_unreachable("found KeyPathDotExpr in CSGen");
39403944
}

lib/Sema/CSRanking.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ static bool sameOverloadChoice(const OverloadChoice &x,
205205
return x.getTupleIndex() == y.getTupleIndex();
206206

207207
case OverloadChoiceKind::MaterializePack:
208+
case OverloadChoiceKind::ExtractFunctionIsolation:
208209
return true;
209210
}
210211

@@ -1121,6 +1122,7 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
11211122
switch (choice1.getKind()) {
11221123
case OverloadChoiceKind::TupleIndex:
11231124
case OverloadChoiceKind::MaterializePack:
1125+
case OverloadChoiceKind::ExtractFunctionIsolation:
11241126
continue;
11251127

11261128
case OverloadChoiceKind::KeyPathApplication:

lib/Sema/CSSimplify.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ static bool areConservativelyCompatibleArgumentLabels(
205205
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
206206
case OverloadChoiceKind::TupleIndex:
207207
case OverloadChoiceKind::MaterializePack:
208+
case OverloadChoiceKind::ExtractFunctionIsolation:
208209
return true;
209210
}
210211

@@ -9763,6 +9764,16 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
97639764
if (auto *selfTy = instanceTy->getAs<DynamicSelfType>())
97649765
instanceTy = selfTy->getSelfType();
97659766

9767+
// Dynamically isolated function types have a magic '.isolation'
9768+
// member that extracts the isolation value.
9769+
if (auto *fn = dyn_cast<FunctionType>(instanceTy)) {
9770+
if (fn->getIsolation().isErased() &&
9771+
memberName.getBaseIdentifier().str() == "isolation") {
9772+
result.ViableCandidates.push_back(
9773+
OverloadChoice(baseTy, OverloadChoiceKind::ExtractFunctionIsolation));
9774+
}
9775+
}
9776+
97669777
if (!instanceTy->mayHaveMembers())
97679778
return result;
97689779

lib/Sema/Constraint.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,9 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm,
534534
case OverloadChoiceKind::MaterializePack:
535535
Out << "materialize pack";
536536
break;
537+
case OverloadChoiceKind::ExtractFunctionIsolation:
538+
Out << "extract function islation";
539+
break;
537540
case OverloadChoiceKind::KeyPathApplication:
538541
Out << "key path application";
539542
break;

lib/Sema/ConstraintSystem.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2890,6 +2890,7 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
28902890
case OverloadChoiceKind::KeyPathApplication:
28912891
case OverloadChoiceKind::TupleIndex:
28922892
case OverloadChoiceKind::MaterializePack:
2893+
case OverloadChoiceKind::ExtractFunctionIsolation:
28932894
return Type();
28942895
}
28952896

@@ -3569,6 +3570,7 @@ void ConstraintSystem::bindOverloadType(
35693570
case OverloadChoiceKind::DeclViaUnwrappedOptional:
35703571
case OverloadChoiceKind::TupleIndex:
35713572
case OverloadChoiceKind::MaterializePack:
3573+
case OverloadChoiceKind::ExtractFunctionIsolation:
35723574
case OverloadChoiceKind::KeyPathApplication:
35733575
bindTypeOrIUO(openedType);
35743576
return;
@@ -3829,6 +3831,15 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
38293831
break;
38303832
}
38313833

3834+
case OverloadChoiceKind::ExtractFunctionIsolation: {
3835+
// The type of `.isolation` is `(any Actor)?`
3836+
auto actor = getASTContext().getProtocol(KnownProtocolKind::Actor);
3837+
adjustedRefType =
3838+
OptionalType::get(actor->getDeclaredExistentialType());
3839+
refType = adjustedRefType;
3840+
break;
3841+
}
3842+
38323843
case OverloadChoiceKind::KeyPathApplication: {
38333844
// Key path application looks like a subscript(keyPath: KeyPath<Base, T>).
38343845
// The element type is T or @lvalue T based on the key path subtype and
@@ -4466,6 +4477,7 @@ DeclName OverloadChoice::getName() const {
44664477

44674478
case OverloadChoiceKind::MaterializePack:
44684479
case OverloadChoiceKind::TupleIndex:
4480+
case OverloadChoiceKind::ExtractFunctionIsolation:
44694481
llvm_unreachable("no name!");
44704482
}
44714483

@@ -5830,6 +5842,7 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef<Solution> solutions) {
58305842

58315843
case OverloadChoiceKind::TupleIndex:
58325844
case OverloadChoiceKind::MaterializePack:
5845+
case OverloadChoiceKind::ExtractFunctionIsolation:
58335846
// FIXME: Actually diagnose something here.
58345847
break;
58355848
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,10 @@ void OverloadChoice::dump(Type adjustedOpenedType, SourceManager *sm,
13041304
case OverloadChoiceKind::MaterializePack:
13051305
out << "materialize pack from tuple " << getBaseType()->getString(PO);
13061306
break;
1307+
1308+
case OverloadChoiceKind::ExtractFunctionIsolation:
1309+
out << "extract isolation from " << getBaseType()->getString(PO);
1310+
break;
13071311
}
13081312
}
13091313

@@ -1610,6 +1614,11 @@ void ConstraintSystem::print(raw_ostream &out) const {
16101614
out << "materialize pack from tuple "
16111615
<< choice.getBaseType()->getString(PO);
16121616
break;
1617+
1618+
case OverloadChoiceKind::ExtractFunctionIsolation:
1619+
out << "extract isolation from "
1620+
<< choice.getBaseType()->getString(PO);
1621+
break;
16131622
}
16141623
out << " for ";
16151624
elt.first->dump(&getASTContext().SourceMgr, out);

test/Concurrency/isolated_any.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,16 @@ func extractFunctionIsolation(_ fn: @isolated(any) @escaping () async -> Void) {
8383
let _: (any Actor)? = extractIsolation(myActor.asyncThrowsActorFunction)
8484
let _: (any Actor)? = extractIsolation(myActor.actorFunctionWithArgs(value:))
8585
}
86+
87+
func extractFunctionIsolationExpr(
88+
_ fn1: @isolated(any) @escaping () async -> Void,
89+
_ fn2: @isolated(any) @escaping (Int, String) -> Bool
90+
) {
91+
let _: (any Actor)? = fn1.isolation
92+
let _: (any Actor)? = fn2.isolation
93+
94+
// Only `@isolated(any)` functions have `.isolation`
95+
let myActor = A()
96+
let _: (any Actor)? = myActor.asyncActorFunction.isolation // expected-error {{value of type '@Sendable () async -> ()' has no member 'isolation'}}
97+
let _: (any Actor)? = globalNonisolatedFunction.isolation // expected-error {{value of type '@Sendable () -> ()' has no member 'isolation'}}
98+
}

test/SILGen/isolated_any.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,3 +452,17 @@ extension MyActor {
452452
func testEraseAsyncActorIsolatedPartialApplication(a: MyActor) {
453453
takeAsyncIsolatedAny(fn: a.asyncAction)
454454
}
455+
456+
/*-- Isolation extraction --*/
457+
458+
// CHECK-LABEL: sil hidden [ossa] @$s4test16extractIsolation2fnScA_pSgyyYAc_tF
459+
// CHECK: [[FN:%.*]] = copy_value %0 : $@isolated(any) @callee_guaranteed () -> ()
460+
// CHECK-NEXT: [[FN_BORROW:%.*]] = begin_borrow [[FN]] : $@isolated(any) @callee_guaranteed () -> ()
461+
// CHECK-NEXT: [[ISOLATION:%.*]] = function_extract_isolation [[FN_BORROW]] : $@isolated(any) @callee_guaranteed () -> ()
462+
// CHECK-NEXT: [[RESULT:%.*]] = copy_value [[ISOLATION]] : $Optional<any Actor>
463+
// CHECK-NEXT: end_borrow [[FN_BORROW]] : $@isolated(any) @callee_guaranteed () -> ()
464+
// CHECK-NEXT: destroy_value [[FN]] : $@isolated(any) @callee_guaranteed () -> ()
465+
// CHECK-NEXT: return [[RESULT]] : $Optional<any Actor>
466+
func extractIsolation(fn: @escaping @isolated(any) () -> Void) -> (any Actor)? {
467+
fn.isolation
468+
}

0 commit comments

Comments
 (0)