@@ -2920,6 +2920,68 @@ bool ConstraintSystem::hasPreconcurrencyCallee(
29202920 return calleeOverload->choice.getDecl()->preconcurrency();
29212921}
29222922
2923+ /// Determines whether a DeclContext is preconcurrency, using information
2924+ /// tracked by the solver to aid in answering that.
2925+ static bool isPreconcurrency(ConstraintSystem &cs, DeclContext *dc) {
2926+ if (auto *decl = dc->getAsDecl())
2927+ return decl->preconcurrency();
2928+
2929+ if (auto *ce = dyn_cast<ClosureExpr>(dc)) {
2930+ return ClosureIsolatedByPreconcurrency{cs}(ce);
2931+ }
2932+
2933+ if (auto *autoClos = dyn_cast<AutoClosureExpr>(dc)) {
2934+ return isPreconcurrency(cs, autoClos->getParent());
2935+ }
2936+
2937+ llvm_unreachable("unhandled DeclContext kind in isPreconcurrency");
2938+ }
2939+
2940+ /// A thin wrapper around \c swift::safeToDropGlobalActor that provides the
2941+ /// ability to infer the isolation of a closure. Not perfect but mostly works.
2942+ static bool okToRemoveGlobalActor(ConstraintSystem &cs,
2943+ DeclContext *dc,
2944+ Type globalActor, Type ty) {
2945+ auto findGlobalActorForClosure = [&](AbstractClosureExpr *ace) -> ClosureActorIsolation {
2946+ // FIXME: Because the actor isolation checking happens after constraint
2947+ // solving, the closure expression does not yet have its actor isolation
2948+ // set, i.e., the code that would call
2949+ // `AbstractClosureExpr::setActorIsolation` hasn't run yet.
2950+ // So, I expect the existing isolation to always be set to the default.
2951+ // If the assertion below starts tripping, then this ad-hoc inference
2952+ // is no longer needed!
2953+ auto existingIso = ace->getActorIsolation();
2954+ if (existingIso != ClosureActorIsolation()) {
2955+ assert(false && "somebody set the closure's isolation already?");
2956+ return existingIso;
2957+ }
2958+
2959+ // Otherwise, do an ad-hoc inference of the closure's isolation.
2960+
2961+ // see if the closure's type has isolation.
2962+ if (auto closType = GetClosureType{cs}(ace)) {
2963+ if (auto fnTy = closType->getAs<AnyFunctionType>()) {
2964+ if (auto globActor = fnTy->getGlobalActor()) {
2965+ return ClosureActorIsolation::forGlobalActor(globActor,
2966+ isPreconcurrency(cs, ace));
2967+ }
2968+ }
2969+ }
2970+
2971+ // otherwise, check for an explicit annotation
2972+ if (auto *ce = dyn_cast<ClosureExpr>(ace)) {
2973+ if (auto globActor = getExplicitGlobalActor(ce)) {
2974+ return ClosureActorIsolation::forGlobalActor(globActor,
2975+ isPreconcurrency(cs, ce));
2976+ }
2977+ }
2978+
2979+ return existingIso;
2980+ };
2981+
2982+ return safeToDropGlobalActor(dc, globalActor, ty, findGlobalActorForClosure);
2983+ }
2984+
29232985ConstraintSystem::TypeMatchResult
29242986ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
29252987 ConstraintKind kind, TypeMatchOptions flags,
@@ -2999,10 +3061,30 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
29993061 ConstraintKind::Equal, subflags, locator);
30003062 if (result == SolutionKind::Error)
30013063 return getTypeMatchFailure(locator);
3064+
30023065 } else if (func1->getGlobalActor() && !func2->isAsync()) {
3003- // Cannot remove a global actor from a synchronous function.
3004- if (MarkGlobalActorFunction::attempt(*this, kind, func1, func2, locator))
3066+ // Cannot remove a global actor from a synchronous function in mismatched
3067+ // DeclContext.
3068+ //
3069+ // FIXME: the ConstraintSystem's DeclContext is not always precise enough
3070+ // to give an accurate answer. We want the innermost DeclContext that
3071+ // contains the expression associated with the constraint locator.
3072+ // Sometimes the ConstraintSystem only has the enclosing function, and not
3073+ // the inner closure containing the expression. To workaround this,
3074+ // `ActorIsolationChecker::checkFunctionConversion`, has extra checking of
3075+ // function conversions specifically to account for this false positive.
3076+ // This means we may have duplicate diagnostics emitted.
3077+ if (okToRemoveGlobalActor(*this, DC, func1->getGlobalActor(), func2)) {
3078+ // FIXME: this is a bit of a hack to workaround multiple solutions
3079+ // because in these contexts it's valid to both add or remove the actor
3080+ // from these function types. At least with the score increases, we
3081+ // can bias the solver to pick the solution with fewer conversions.
3082+ increaseScore(SK_FunctionConversion);
3083+
3084+ } else if (MarkGlobalActorFunction::attempt(*this, kind, func1, func2, locator)) {
30053085 return getTypeMatchFailure(locator);
3086+ }
3087+
30063088 } else if (kind < ConstraintKind::Subtype) {
30073089 return getTypeMatchFailure(locator);
30083090 } else {
@@ -3011,6 +3093,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
30113093 // is a function conversion going on here, let's increase the score to
30123094 // avoid ambiguity when solver can also match a global actor matching
30133095 // function type.
3096+ // FIXME: there may be a better way. see https://github.com/apple/swift/pull/62514
30143097 increaseScore(SK_FunctionConversion);
30153098 }
30163099 }
0 commit comments