Skip to content

Commit 940ab81

Browse files
authored
Merge pull request #68685 from hborla/minimize-constraint-system-isolation-checking
2 parents 2f7b42c + 2e9c64d commit 940ab81

File tree

6 files changed

+61
-121
lines changed

6 files changed

+61
-121
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 9 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2955,51 +2955,6 @@ static bool isPreconcurrency(ConstraintSystem &cs, DeclContext *dc) {
29552955
llvm_unreachable("unhandled DeclContext kind in isPreconcurrency");
29562956
}
29572957

2958-
/// A thin wrapper around \c swift::safeToDropGlobalActor that provides the
2959-
/// ability to infer the isolation of a closure. Not perfect but mostly works.
2960-
static bool okToRemoveGlobalActor(ConstraintSystem &cs,
2961-
DeclContext *dc,
2962-
Type globalActor, Type ty) {
2963-
auto findGlobalActorForClosure = [&](AbstractClosureExpr *ace) -> ActorIsolation {
2964-
// FIXME: Because the actor isolation checking happens after constraint
2965-
// solving, the closure expression does not yet have its actor isolation
2966-
// set, i.e., the code that would call
2967-
// `AbstractClosureExpr::setActorIsolation` hasn't run yet.
2968-
// So, I expect the existing isolation to always be set to the default.
2969-
// If the assertion below starts tripping, then this ad-hoc inference
2970-
// is no longer needed!
2971-
auto existingIso = ace->getActorIsolation();
2972-
if (existingIso != ActorIsolation::forUnspecified()) {
2973-
assert(false && "somebody set the closure's isolation already?");
2974-
return existingIso;
2975-
}
2976-
2977-
// Otherwise, do an ad-hoc inference of the closure's isolation.
2978-
2979-
// see if the closure's type has isolation.
2980-
if (auto closType = GetClosureType{cs}(ace)) {
2981-
if (auto fnTy = closType->getAs<AnyFunctionType>()) {
2982-
if (auto globActor = fnTy->getGlobalActor()) {
2983-
return ActorIsolation::forGlobalActor(globActor, /*unsafe=*/false)
2984-
.withPreconcurrency(isPreconcurrency(cs, ace));
2985-
}
2986-
}
2987-
}
2988-
2989-
// otherwise, check for an explicit annotation
2990-
if (auto *ce = dyn_cast<ClosureExpr>(ace)) {
2991-
if (auto globActor = getExplicitGlobalActor(ce)) {
2992-
return ActorIsolation::forGlobalActor(globActor, /*unsafe=*/false)
2993-
.withPreconcurrency(isPreconcurrency(cs, ace));
2994-
}
2995-
}
2996-
2997-
return existingIso;
2998-
};
2999-
3000-
return safeToDropGlobalActor(dc, globalActor, ty, findGlobalActorForClosure);
3001-
}
3002-
30032958
ConstraintSystem::TypeMatchResult
30042959
ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
30052960
ConstraintKind kind, TypeMatchOptions flags,
@@ -3067,7 +3022,15 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
30673022
return getTypeMatchFailure(locator);
30683023
}
30693024

3070-
// A global actor can be added or can match, but cannot be removed.
3025+
// Check the global-actor isolation on each of the function types. Two
3026+
// different global-actor attributes never match, but function conversions
3027+
// that add or remove global-actor attributes are okay.
3028+
//
3029+
// Some function conversions that erase global-actor isolation can admit
3030+
// data races; such violations are diagnosed by the actor isolation checker.
3031+
// We deliberately do not allow actor isolation violations to influence
3032+
// overload resolution to preserve the property that an expression can be
3033+
// re-checked against a different isolation context for isolation violations.
30713034
if (func1->getGlobalActor() || func2->getGlobalActor()) {
30723035
if (func1->getGlobalActor() && func2->getGlobalActor()) {
30733036
// If both have a global actor, match them.
@@ -3079,29 +3042,6 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
30793042
if (result == SolutionKind::Error)
30803043
return getTypeMatchFailure(locator);
30813044

3082-
} else if (func1->getGlobalActor() && !func2->isAsync()) {
3083-
// Cannot remove a global actor from a synchronous function in mismatched
3084-
// DeclContext.
3085-
//
3086-
// FIXME: the ConstraintSystem's DeclContext is not always precise enough
3087-
// to give an accurate answer. We want the innermost DeclContext that
3088-
// contains the expression associated with the constraint locator.
3089-
// Sometimes the ConstraintSystem only has the enclosing function, and not
3090-
// the inner closure containing the expression. To workaround this,
3091-
// `ActorIsolationChecker::checkFunctionConversion`, has extra checking of
3092-
// function conversions specifically to account for this false positive.
3093-
// This means we may have duplicate diagnostics emitted.
3094-
if (okToRemoveGlobalActor(*this, DC, func1->getGlobalActor(), func2)) {
3095-
// FIXME: this is a bit of a hack to workaround multiple solutions
3096-
// because in these contexts it's valid to both add or remove the actor
3097-
// from these function types. At least with the score increases, we
3098-
// can bias the solver to pick the solution with fewer conversions.
3099-
increaseScore(SK_FunctionConversion, locator);
3100-
3101-
} else if (MarkGlobalActorFunction::attempt(*this, kind, func1, func2, locator)) {
3102-
return getTypeMatchFailure(locator);
3103-
}
3104-
31053045
} else if (kind < ConstraintKind::Subtype) {
31063046
return getTypeMatchFailure(locator);
31073047
} else {

test/Concurrency/actor_call_implicitly_async.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ func blender(_ peeler : () -> Void) {
299299
await (((wisk)))((wisk)((wisk)(1)))
300300

301301
blender((peelBanana))
302-
// expected-warning@-1 2{{converting function value of type '@BananaActor () -> ()' to '() -> Void' loses global actor 'BananaActor'}}
302+
// expected-warning@-1 {{converting function value of type '@BananaActor () -> ()' to '() -> Void' loses global actor 'BananaActor'}}
303303

304304
await wisk(peelBanana)
305305
// expected-complete-warning@-1{{passing argument of non-sendable type '() -> ()' into global actor 'BananaActor'-isolated context may introduce data races}}
@@ -314,7 +314,12 @@ func blender(_ peeler : () -> Void) {
314314

315315
await {wisk}()(1)
316316

317+
// FIXME: Poor diagnostic. The issue is that the invalid function conversion
318+
// to remove '@BananaActor' on 'wisk' cannot influence which solution is chosen.
319+
// So, the constraint system cannot determine whether the type of this expression
320+
// is '(Any) -> Void' or '@BananaActor (Any) -> Void'.
317321
await (true ? wisk : {n in return})(1)
322+
// expected-error@-1 {{type of expression is ambiguous without a type annotation}}
318323
}
319324

320325
actor Chain {

test/Concurrency/actor_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ func testGlobalActorClosures() {
472472
return 17
473473
}
474474

475-
acceptConcurrentClosure { @SomeGlobalActor in 5 } // expected-warning 2{{converting function value of type '@SomeGlobalActor @Sendable () -> Int' to '@Sendable () -> Int' loses global actor 'SomeGlobalActor'}}
475+
acceptConcurrentClosure { @SomeGlobalActor in 5 } // expected-warning {{converting function value of type '@SomeGlobalActor @Sendable () -> Int' to '@Sendable () -> Int' loses global actor 'SomeGlobalActor'}}
476476
}
477477

478478
@available(SwiftStdlib 5.1, *)

0 commit comments

Comments
 (0)