Skip to content

Commit ed78d00

Browse files
authored
Merge pull request #59964 from DougGregor/constraint-system-preconcurrency-5.7
[5.7] [Constraint solver] Track "isolated by preconcurrency" in the solver.
2 parents 3ab722e + d703e5a commit ed78d00

File tree

9 files changed

+112
-31
lines changed

9 files changed

+112
-31
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,10 @@ class Solution {
12761276
/// The set of parameters that have been inferred to be 'isolated'.
12771277
llvm::SmallVector<ParamDecl *, 2> isolatedParams;
12781278

1279+
/// The set of closures that have been inferred to be "isolated by
1280+
/// preconcurrency".
1281+
llvm::SmallVector<const ClosureExpr *, 2> preconcurrencyClosures;
1282+
12791283
/// The set of functions that have been transformed by a result builder.
12801284
llvm::MapVector<AnyFunctionRef, AppliedBuilderTransform>
12811285
resultBuilderTransformed;
@@ -2479,6 +2483,13 @@ struct GetClosureType {
24792483
Type operator()(const AbstractClosureExpr *expr) const;
24802484
};
24812485

2486+
/// Retrieve the closure type from the constraint system.
2487+
struct ClosureIsolatedByPreconcurrency {
2488+
ConstraintSystem &cs;
2489+
2490+
bool operator()(const ClosureExpr *expr) const;
2491+
};
2492+
24822493
/// Describes the type produced when referencing a declaration.
24832494
struct DeclReferenceType {
24842495
/// The "opened" type, which is the type of the declaration where any
@@ -2533,6 +2544,7 @@ class ConstraintSystem {
25332544
friend class ConjunctionElement;
25342545
friend class RequirementFailure;
25352546
friend class MissingMemberFailure;
2547+
friend struct ClosureIsolatedByPreconcurrency;
25362548

25372549
class SolverScope;
25382550

@@ -2663,6 +2675,10 @@ class ConstraintSystem {
26632675
/// The set of parameters that have been inferred to be 'isolated'.
26642676
llvm::SmallSetVector<ParamDecl *, 2> isolatedParams;
26652677

2678+
/// The set of closures that have been inferred to be "isolated by
2679+
/// preconcurrency".
2680+
llvm::SmallSetVector<const ClosureExpr *, 2> preconcurrencyClosures;
2681+
26662682
/// Maps closure parameters to type variables.
26672683
llvm::DenseMap<const ParamDecl *, TypeVariableType *>
26682684
OpenedParameterTypes;
@@ -3233,6 +3249,9 @@ class ConstraintSystem {
32333249
/// The length of \c isolatedParams.
32343250
unsigned numIsolatedParams;
32353251

3252+
/// The length of \c PreconcurrencyClosures.
3253+
unsigned numPreconcurrencyClosures;
3254+
32363255
/// The length of \c ImplicitValueConversions.
32373256
unsigned numImplicitValueConversions;
32383257

@@ -4511,6 +4530,10 @@ class ConstraintSystem {
45114530
llvm::function_ref<Type(const AbstractClosureExpr *)> getClosureType =
45124531
[](const AbstractClosureExpr *) {
45134532
return Type();
4533+
},
4534+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency =
4535+
[](const ClosureExpr *closure) {
4536+
return closure->isIsolatedByPreconcurrency();
45144537
});
45154538

45164539
/// Given the opened type and a pile of information about a member reference,

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5638,25 +5638,22 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
56385638

56395639
/// Apply the contextually Sendable flag to the given expression,
56405640
static void applyContextualClosureFlags(
5641-
Expr *expr, bool implicitSelfCapture, bool inheritActorContext,
5642-
bool isolatedByPreconcurrency) {
5641+
Expr *expr, bool implicitSelfCapture, bool inheritActorContext) {
56435642
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
56445643
closure->setAllowsImplicitSelfCapture(implicitSelfCapture);
56455644
closure->setInheritsActorContext(inheritActorContext);
5646-
closure->setIsolatedByPreconcurrency(isolatedByPreconcurrency);
56475645
return;
56485646
}
56495647

56505648
if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
56515649
applyContextualClosureFlags(
56525650
captureList->getClosureBody(), implicitSelfCapture,
5653-
inheritActorContext, isolatedByPreconcurrency);
5651+
inheritActorContext);
56545652
}
56555653

56565654
if (auto identity = dyn_cast<IdentityExpr>(expr)) {
56575655
applyContextualClosureFlags(
5658-
identity->getSubExpr(), implicitSelfCapture, inheritActorContext,
5659-
isolatedByPreconcurrency);
5656+
identity->getSubExpr(), implicitSelfCapture, inheritActorContext);
56605657
}
56615658
}
56625659

@@ -5683,8 +5680,6 @@ ArgumentList *ExprRewriter::coerceCallArguments(
56835680
// Determine the parameter bindings.
56845681
ParameterListInfo paramInfo(params, callee.getDecl(), skipCurriedSelf);
56855682

5686-
bool preconcurrency = callee && callee.getDecl()->preconcurrency();
5687-
56885683
// If this application is an init(wrappedValue:) call that needs an injected
56895684
// wrapped value placeholder, the first non-defaulted argument must be
56905685
// wrapped in an OpaqueValueExpr.
@@ -5707,14 +5702,6 @@ ArgumentList *ExprRewriter::coerceCallArguments(
57075702
auto matches = args->matches(params, [&](Expr *E) { return cs.getType(E); });
57085703
if (matches && !shouldInjectWrappedValuePlaceholder &&
57095704
!paramInfo.anyContextualInfo()) {
5710-
// Propagate preconcurrency to any closure arguments.
5711-
if (preconcurrency) {
5712-
for (const auto &arg : *args) {
5713-
Expr *argExpr = arg.getExpr();
5714-
applyContextualClosureFlags(argExpr, false, false, preconcurrency);
5715-
}
5716-
}
5717-
57185705
return args;
57195706
}
57205707

@@ -5865,7 +5852,7 @@ ArgumentList *ExprRewriter::coerceCallArguments(
58655852
bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx);
58665853
bool inheritsActorContext = paramInfo.inheritsActorContext(paramIdx);
58675854
applyContextualClosureFlags(
5868-
argExpr, isImplicitSelfCapture, inheritsActorContext, preconcurrency);
5855+
argExpr, isImplicitSelfCapture, inheritsActorContext);
58695856

58705857
// If the types exactly match, this is easy.
58715858
auto paramType = param.getOldType();

lib/Sema/CSClosure.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,9 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
16561656
param->setIsolated(true);
16571657
}
16581658

1659+
if (llvm::is_contained(solution.preconcurrencyClosures, closure))
1660+
closure->setIsolatedByPreconcurrency();
1661+
16591662
// Coerce the result type, if it was written explicitly.
16601663
if (closure->hasExplicitResultType()) {
16611664
closure->setExplicitResultType(closureFnType->getResult());

lib/Sema/CSSimplify.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2738,7 +2738,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
27382738
// For a @preconcurrency callee outside of a strict concurrency
27392739
// context, ignore.
27402740
if (hasPreconcurrencyCallee(this, locator) &&
2741-
!contextRequiresStrictConcurrencyChecking(DC, GetClosureType{*this}))
2741+
!contextRequiresStrictConcurrencyChecking(DC, GetClosureType{*this}, ClosureIsolatedByPreconcurrency{*this}))
27422742
return FixBehavior::Suppress;
27432743

27442744
// Otherwise, warn until Swift 6.
@@ -9841,6 +9841,10 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
98419841
auto *closure = castToExpr<ClosureExpr>(closureLocator->getAnchor());
98429842
auto *inferredClosureType = getClosureType(closure);
98439843

9844+
// Note if this closure is isolated by preconcurrency.
9845+
if (hasPreconcurrencyCallee(this, locator))
9846+
preconcurrencyClosures.insert(closure);
9847+
98449848
// Let's look through all optionals associated with contextual
98459849
// type to make it possible to infer parameter/result type of
98469850
// the closure faster e.g.:

lib/Sema/CSSolver.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ Solution ConstraintSystem::finalize() {
182182
solution.solutionApplicationTargets = solutionApplicationTargets;
183183
solution.caseLabelItems = caseLabelItems;
184184
solution.isolatedParams.append(isolatedParams.begin(), isolatedParams.end());
185+
solution.preconcurrencyClosures.append(preconcurrencyClosures.begin(),
186+
preconcurrencyClosures.end());
185187

186188
for (const auto &transformed : resultBuilderTransformed) {
187189
solution.resultBuilderTransformed.insert(transformed);
@@ -295,6 +297,10 @@ void ConstraintSystem::applySolution(const Solution &solution) {
295297
isolatedParams.insert(param);
296298
}
297299

300+
for (auto closure : solution.preconcurrencyClosures) {
301+
preconcurrencyClosures.insert(closure);
302+
}
303+
298304
for (const auto &transformed : solution.resultBuilderTransformed) {
299305
resultBuilderTransformed.insert(transformed);
300306
}
@@ -535,6 +541,7 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
535541
numSolutionApplicationTargets = cs.solutionApplicationTargets.size();
536542
numCaseLabelItems = cs.caseLabelItems.size();
537543
numIsolatedParams = cs.isolatedParams.size();
544+
numPreconcurrencyClosures = cs.preconcurrencyClosures.size();
538545
numImplicitValueConversions = cs.ImplicitValueConversions.size();
539546
numArgumentLists = cs.ArgumentLists.size();
540547
numImplicitCallAsFunctionRoots = cs.ImplicitCallAsFunctionRoots.size();
@@ -646,6 +653,9 @@ ConstraintSystem::SolverScope::~SolverScope() {
646653
// Remove any isolated parameters.
647654
truncate(cs.isolatedParams, numIsolatedParams);
648655

656+
// Remove any preconcurrency closures.
657+
truncate(cs.preconcurrencyClosures, numPreconcurrencyClosures);
658+
649659
// Remove any implicit value conversions.
650660
truncate(cs.ImplicitValueConversions, numImplicitValueConversions);
651661

lib/Sema/ConstraintSystem.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,12 @@ Type GetClosureType::operator()(const AbstractClosureExpr *expr) const {
12021202
return Type();
12031203
}
12041204

1205+
bool
1206+
ClosureIsolatedByPreconcurrency::operator()(const ClosureExpr *expr) const {
1207+
return expr->isIsolatedByPreconcurrency() ||
1208+
cs.preconcurrencyClosures.count(expr);
1209+
}
1210+
12051211
Type ConstraintSystem::getUnopenedTypeOfReference(
12061212
VarDecl *value, Type baseType, DeclContext *UseDC,
12071213
ConstraintLocator *memberLocator, bool wantInterfaceType) {
@@ -1217,20 +1223,22 @@ Type ConstraintSystem::getUnopenedTypeOfReference(
12171223

12181224
return wantInterfaceType ? var->getInterfaceType() : var->getType();
12191225
},
1220-
memberLocator, wantInterfaceType, GetClosureType{*this});
1226+
memberLocator, wantInterfaceType, GetClosureType{*this},
1227+
ClosureIsolatedByPreconcurrency{*this});
12211228
}
12221229

12231230
Type ConstraintSystem::getUnopenedTypeOfReference(
12241231
VarDecl *value, Type baseType, DeclContext *UseDC,
12251232
llvm::function_ref<Type(VarDecl *)> getType,
12261233
ConstraintLocator *memberLocator, bool wantInterfaceType,
1227-
llvm::function_ref<Type(const AbstractClosureExpr *)> getClosureType) {
1234+
llvm::function_ref<Type(const AbstractClosureExpr *)> getClosureType,
1235+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency) {
12281236
Type requestedType =
12291237
getType(value)->getWithoutSpecifierType()->getReferenceStorageReferent();
12301238

12311239
// Adjust the type for concurrency.
12321240
requestedType = adjustVarTypeForConcurrency(
1233-
requestedType, value, UseDC, getClosureType);
1241+
requestedType, value, UseDC, getClosureType, isolatedByPreconcurrency);
12341242

12351243
// If we're dealing with contextual types, and we referenced this type from
12361244
// a different context, map the type.
@@ -1409,7 +1417,8 @@ AnyFunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
14091417
unsigned numApplies, bool isMainDispatchQueue,
14101418
OpenedTypeMap &replacements) {
14111419
return swift::adjustFunctionTypeForConcurrency(
1412-
fnType, decl, dc, numApplies, isMainDispatchQueue, GetClosureType{*this},
1420+
fnType, decl, dc, numApplies, isMainDispatchQueue,
1421+
GetClosureType{*this}, ClosureIsolatedByPreconcurrency{*this},
14131422
[&](Type type) {
14141423
if (replacements.empty())
14151424
return type;
@@ -2500,7 +2509,8 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
25002509
type = withDynamicSelfResultReplaced(type, /*uncurryLevel=*/0);
25012510
}
25022511
type = adjustVarTypeForConcurrency(
2503-
type, var, useDC, GetClosureType{*this});
2512+
type, var, useDC, GetClosureType{*this},
2513+
ClosureIsolatedByPreconcurrency{*this});
25042514
} else if (isa<AbstractFunctionDecl>(decl) || isa<EnumElementDecl>(decl)) {
25052515
if (decl->isInstanceMember() &&
25062516
(!overload.getBaseType() ||

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,9 @@ static void addSendableFixIt(
600600
static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
601601
return contextRequiresStrictConcurrencyChecking(dc, [](const AbstractClosureExpr *) {
602602
return Type();
603+
},
604+
[](const ClosureExpr *closure) {
605+
return closure->isIsolatedByPreconcurrency();
603606
});
604607
}
605608

@@ -3972,7 +3975,8 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
39723975

39733976
bool swift::contextRequiresStrictConcurrencyChecking(
39743977
const DeclContext *dc,
3975-
llvm::function_ref<Type(const AbstractClosureExpr *)> getType) {
3978+
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
3979+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency) {
39763980
switch (dc->getASTContext().LangOpts.StrictConcurrencyLevel) {
39773981
case StrictConcurrency::Complete:
39783982
return true;
@@ -3993,7 +3997,7 @@ bool swift::contextRequiresStrictConcurrencyChecking(
39933997

39943998
// Don't take any more cues if this only got its type information by
39953999
// being provided to a `@preconcurrency` operation.
3996-
if (explicitClosure->isIsolatedByPreconcurrency()) {
4000+
if (isolatedByPreconcurrency(explicitClosure)) {
39974001
dc = dc->getParent();
39984002
continue;
39994003
}
@@ -4551,11 +4555,13 @@ static bool hasKnownUnsafeSendableFunctionParams(AbstractFunctionDecl *func) {
45514555

45524556
Type swift::adjustVarTypeForConcurrency(
45534557
Type type, VarDecl *var, DeclContext *dc,
4554-
llvm::function_ref<Type(const AbstractClosureExpr *)> getType) {
4558+
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
4559+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency) {
45554560
if (!var->preconcurrency())
45564561
return type;
45574562

4558-
if (contextRequiresStrictConcurrencyChecking(dc, getType))
4563+
if (contextRequiresStrictConcurrencyChecking(
4564+
dc, getType, isolatedByPreconcurrency))
45594565
return type;
45604566

45614567
bool isLValue = false;
@@ -4676,9 +4682,11 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
46764682
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
46774683
unsigned numApplies, bool isMainDispatchQueue,
46784684
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
4685+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency,
46794686
llvm::function_ref<Type(Type)> openType) {
46804687
// Apply unsafe concurrency features to the given function type.
4681-
bool strictChecking = contextRequiresStrictConcurrencyChecking(dc, getType);
4688+
bool strictChecking = contextRequiresStrictConcurrencyChecking(
4689+
dc, getType, isolatedByPreconcurrency);
46824690
fnType = applyUnsafeConcurrencyToFunctionType(
46834691
fnType, decl, strictChecking, numApplies, isMainDispatchQueue);
46844692

@@ -4738,7 +4746,10 @@ bool swift::completionContextUsesConcurrencyFeatures(const DeclContext *dc) {
47384746
return contextRequiresStrictConcurrencyChecking(
47394747
dc, [](const AbstractClosureExpr *) {
47404748
return Type();
4741-
});
4749+
},
4750+
[](const ClosureExpr *closure) {
4751+
return closure->isIsolatedByPreconcurrency();
4752+
});
47424753
}
47434754

47444755
AbstractFunctionDecl const *swift::isActorInitOrDeInitContext(
@@ -4847,6 +4858,9 @@ static ActorIsolation getActorIsolationForReference(
48474858
fromDC,
48484859
[](const AbstractClosureExpr *closure) {
48494860
return closure->getType();
4861+
},
4862+
[](const ClosureExpr *closure) {
4863+
return closure->isIsolatedByPreconcurrency();
48504864
})) {
48514865
declIsolation = ActorIsolation::forGlobalActor(
48524866
declIsolation.getGlobalActor(), /*unsafe=*/false);

lib/Sema/TypeCheckConcurrency.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ void checkOverrideActorIsolation(ValueDecl *value);
102102
/// code where strict checking has been enabled.
103103
bool contextRequiresStrictConcurrencyChecking(
104104
const DeclContext *dc,
105-
llvm::function_ref<Type(const AbstractClosureExpr *)> getType);
105+
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
106+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency);
106107

107108
/// Describes a referenced actor variable and whether it is isolated.
108109
struct ReferencedActor {
@@ -417,7 +418,8 @@ Type getExplicitGlobalActor(ClosureExpr *closure);
417418
/// Adjust the type of the variable for concurrency.
418419
Type adjustVarTypeForConcurrency(
419420
Type type, VarDecl *var, DeclContext *dc,
420-
llvm::function_ref<Type(const AbstractClosureExpr *)> getType);
421+
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
422+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency);
421423

422424
/// Adjust the given function type to account for concurrency-specific
423425
/// attributes whose affect on the type might differ based on context.
@@ -428,6 +430,7 @@ AnyFunctionType *adjustFunctionTypeForConcurrency(
428430
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
429431
unsigned numApplies, bool isMainDispatchQueue,
430432
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
433+
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency,
431434
llvm::function_ref<Type(Type)> openType);
432435

433436
/// Determine whether the given name is that of a DispatchQueue operation that

test/Concurrency/predates_concurrency.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,30 @@ func testStringPlacement() {
152152
let fn2 = StringPlacement.position(before:)
153153
let _: Int = fn2 // expected-error{{cannot convert value of type '(String) -> ([String]) -> Int' to specified type 'Int'}}
154154
}
155+
156+
// @preconcurrency in an outer closure
157+
// (https://github.com/apple/swift/issues/59910)
158+
struct Scheduled<T> { }
159+
160+
@preconcurrency
161+
func doPreconcurrency(_: @Sendable () -> Void) { }
162+
163+
class EventLoop {
164+
@discardableResult
165+
@preconcurrency
166+
func scheduleTask<T>(deadline: Int, _ task: @escaping @Sendable () throws -> T) -> Scheduled<T> { fatalError("") }
167+
}
168+
169+
class C {
170+
var ev: EventLoop? = nil
171+
172+
func test(i: Int) {
173+
func doNext() {
174+
doPreconcurrency {
175+
self.ev?.scheduleTask(deadline: i, doNext)
176+
return
177+
}
178+
}
179+
}
180+
}
181+

0 commit comments

Comments
 (0)