Skip to content

Commit 88f32b3

Browse files
authored
Merge pull request #83434 from xedin/rdar-157061896-6.2
[6.2][Concurrency] Downgrade errors when isolated member is referenced fro…
2 parents eba3593 + c04eb7c commit 88f32b3

9 files changed

+96
-29
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "swift/Strings.h"
4242

4343
using namespace swift;
44+
using namespace swift::version;
4445

4546
static ActorIsolation getOverriddenIsolationFor(const ValueDecl *value);
4647

@@ -569,7 +570,7 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule, VarDecl *var,
569570
if (var->isGlobalStorage() && var->isLazilyInitializedGlobal()) {
570571
// Compiler versions <= 5.9 accepted this code, so downgrade to a
571572
// warning prior to Swift 6.
572-
options = ActorReferenceResult::Flags::Preconcurrency;
573+
options = ActorReferenceResult::Flags::CompatibilityDowngrade;
573574
return false;
574575
}
575576

@@ -590,7 +591,7 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule, VarDecl *var,
590591
// so downgrade async access errors in the effects checker to
591592
// warnings prior to Swift 6.
592593
if (accessWithinModule)
593-
options = ActorReferenceResult::Flags::Preconcurrency;
594+
options = ActorReferenceResult::Flags::CompatibilityDowngrade;
594595

595596
return false;
596597
}
@@ -4259,11 +4260,10 @@ namespace {
42594260

42604261
applyErrors[key].push_back(mismatch);
42614262
} else {
4262-
ctx.Diags.diagnose(
4263-
apply->getLoc(),
4264-
diagnostic.getID(),
4265-
diagnostic.getArgs())
4266-
.warnUntilSwiftVersionIf(preconcurrency, 6);
4263+
ctx.Diags
4264+
.diagnose(apply->getLoc(), diagnostic.getID(),
4265+
diagnostic.getArgs())
4266+
.limitBehaviorIf(preconcurrency, DiagnosticBehavior::Warning);
42674267

42684268
if (calleeDecl) {
42694269
auto calleeIsolation = getInferredActorIsolation(calleeDecl);
@@ -4607,9 +4607,10 @@ namespace {
46074607
break;
46084608
}
46094609

4610-
bool downgrade = isolation.isGlobalActor() ||
4611-
options.contains(
4612-
ActorReferenceResult::Flags::Preconcurrency);
4610+
bool downgrade =
4611+
isolation.isGlobalActor() ||
4612+
options.contains(
4613+
ActorReferenceResult::Flags::CompatibilityDowngrade);
46134614

46144615
ctx.Diags.diagnose(
46154616
component.getLoc(), diag::actor_isolated_keypath_component,
@@ -4799,6 +4800,10 @@ namespace {
47994800
// Does the reference originate from a @preconcurrency context?
48004801
bool preconcurrencyContext =
48014802
result.options.contains(ActorReferenceResult::Flags::Preconcurrency);
4803+
bool shouldDowngradeToWarning =
4804+
preconcurrencyContext ||
4805+
result.options.contains(
4806+
ActorReferenceResult::Flags::CompatibilityDowngrade);
48024807

48034808
Type derivedConformanceType;
48044809
DeclName requirementName;
@@ -4833,14 +4838,21 @@ namespace {
48334838
refErrors.insert(std::make_pair(keyPair, list));
48344839
}
48354840
} else {
4836-
ctx.Diags.diagnose(
4837-
loc, diag::actor_isolated_non_self_reference,
4838-
decl, useKind,
4839-
refKind + 1, refGlobalActor,
4840-
result.isolation)
4841-
.warnUntilSwiftVersionIf(preconcurrencyContext, 6);
4842-
maybeNoteMutatingMethodSuggestion(ctx, decl, loc, getDeclContext(), result.isolation,
4843-
kindOfUsage(decl, context).value_or(VarRefUseEnv::Read));
4841+
{
4842+
auto diagnostic = ctx.Diags.diagnose(
4843+
loc, diag::actor_isolated_non_self_reference, decl, useKind,
4844+
refKind + 1, refGlobalActor, result.isolation);
4845+
4846+
// For compatibility downgrades - the error is downgraded until
4847+
// Swift 6, for preconcurrency - always.
4848+
if (shouldDowngradeToWarning)
4849+
diagnostic.limitBehaviorWithPreconcurrency(
4850+
DiagnosticBehavior::Warning, preconcurrencyContext);
4851+
}
4852+
4853+
maybeNoteMutatingMethodSuggestion(
4854+
ctx, decl, loc, getDeclContext(), result.isolation,
4855+
kindOfUsage(decl, context).value_or(VarRefUseEnv::Read));
48444856

48454857
if (derivedConformanceType) {
48464858
auto *decl = dyn_cast<ValueDecl>(getDeclContext()->getAsDecl());
@@ -8337,7 +8349,7 @@ ActorReferenceResult ActorReferenceResult::forReference(
83378349
// Treat the decl isolation as 'preconcurrency' to downgrade violations
83388350
// to warnings, because violating Sendable here is accepted by the
83398351
// Swift 5.9 compiler.
8340-
options |= Flags::Preconcurrency;
8352+
options |= Flags::CompatibilityDowngrade;
83418353
return forEntersActor(declIsolation, options);
83428354
}
83438355
}
@@ -8376,8 +8388,10 @@ ActorReferenceResult ActorReferenceResult::forReference(
83768388
// This is a cross-actor reference.
83778389

83788390
// Note if the reference originates from a @preconcurrency-isolated context.
8379-
if (contextIsolation.preconcurrency() || declIsolation.preconcurrency())
8391+
if (contextIsolation.preconcurrency() || declIsolation.preconcurrency()) {
83808392
options |= Flags::Preconcurrency;
8393+
options |= Flags::CompatibilityDowngrade;
8394+
}
83818395

83828396
// If the declaration isn't asynchronous, promote to async.
83838397
if (!decl->isAsync())

lib/Sema/TypeCheckConcurrency.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,20 @@ struct ActorReferenceResult {
207207
/// potentially from a different node, so it must be marked 'distributed'.
208208
Distributed = 1 << 2,
209209

210-
/// The declaration is being accessed from a @preconcurrency context.
210+
/// The declaration is marked as `@preconcurrency` or being accessed
211+
/// from a @preconcurrency context.
211212
Preconcurrency = 1 << 3,
212213

213214
/// Only arguments cross an isolation boundary, e.g. because they
214215
/// escape into an actor in a nonisolated actor initializer.
215216
OnlyArgsCrossIsolation = 1 << 4,
217+
218+
/// The reference to the declaration is invalid but has to be downgraded
219+
/// to a warning because it was accepted by the older compilers or because
220+
/// the declaration predates concurrency and is marked as such.
221+
///
222+
/// NOTE: This flag is set for `Preconcurrency` declarations.
223+
CompatibilityDowngrade = 1 << 5,
216224
};
217225

218226
using Options = OptionSet<Flags>;

lib/Sema/TypeCheckEffects.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,8 @@ class ApplyClassifier {
14871487
module = var->getDeclContext()->getParentModule();
14881488
}
14891489
if (!isLetAccessibleAnywhere(module, var, options)) {
1490-
return options.contains(ActorReferenceResult::Flags::Preconcurrency);
1490+
return options.contains(
1491+
ActorReferenceResult::Flags::CompatibilityDowngrade);
14911492
}
14921493
}
14931494

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3583,7 +3583,7 @@ ConformanceChecker::checkActorIsolation(ValueDecl *requirement,
35833583
isLetAccessibleAnywhere(
35843584
witness->getDeclContext()->getParentModule(),
35853585
var, options);
3586-
if (options.contains(ActorReferenceResult::Flags::Preconcurrency)) {
3586+
if (options.contains(ActorReferenceResult::Flags::CompatibilityDowngrade)) {
35873587
behavior = DiagnosticBehavior::Warning;
35883588
}
35893589
}

test/ClangImporter/objc_async.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ extension SomeWrapper: Sendable where T: Sendable {}
392392
func makeCall(slowServer: SlowServer) {
393393
slowServer.doSomethingSlow("churn butter") { (_ : Int) in
394394
let _ = self.isolatedThing
395-
// expected-warning@-1 {{main actor-isolated property 'isolatedThing' can not be referenced from a Sendable closure; this is an error in the Swift 6 language mode}}
395+
// expected-warning@-1 {{main actor-isolated property 'isolatedThing' can not be referenced from a Sendable closure}}
396396
}
397397
}
398398
}

test/Concurrency/assume_mainactor_typechecker_errors.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class SendableData : @unchecked Sendable {}
1111
// expected-swift5-note@-1 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}}
1212

1313
nonisolated func getDataFromSocket() -> SendableData { SendableData() }
14-
// expected-swift5-warning@-1 {{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context; this is an error in the Swift 6 language mode}}
14+
// expected-swift5-warning@-1 {{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context}}
1515

1616
class Klass { // expected-swift5-note 3 {{}} expected-swift6-note 3 {{}}
1717
let s = SendableData()

test/Concurrency/objc_async_overload.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ extension Delegate {
5858
func handle(_ req: Request, with delegate: Delegate) {
5959
delegate.makeRequest1(req) {
6060
self.finish()
61-
// expected-warning@-1 {{call to main actor-isolated instance method 'finish()' in a synchronous nonisolated context; this is an error in the Swift 6 language mode}}
61+
// expected-warning@-1 {{call to main actor-isolated instance method 'finish()' in a synchronous nonisolated context}}
6262
}
6363
}
6464
}

test/Concurrency/predates_concurrency.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ do {
386386
func run() async {
387387
await test {
388388
if let value {
389-
// expected-warning@-1 {{main actor-isolated property 'value' can not be referenced from a Sendable closure; this is an error in the Swift 6 language mode}}
389+
// expected-warning@-1 {{main actor-isolated property 'value' can not be referenced from a Sendable closure}}
390390
print(value)
391391
}
392392
}

test/Concurrency/predates_concurrency_swift6.swift

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ func testElsewhere(x: X) {
6363

6464
func testCalls(x: X) {
6565
// expected-note@-1 2{{add '@MainActor' to make global function 'testCalls(x:)' part of global actor 'MainActor'}}
66-
onMainActorAlways() // expected-error{{call to main actor-isolated global function 'onMainActorAlways()' in a synchronous nonisolated context}}
66+
onMainActorAlways() // expected-warning{{call to main actor-isolated global function 'onMainActorAlways()' in a synchronous nonisolated context}}
6767

6868
let _: () -> Void = onMainActorAlways // expected-error{{converting function value of type '@MainActor @Sendable () -> ()' to '() -> Void' loses global actor 'MainActor'}}
6969

7070
let c = MyModelClass() // okay, synthesized init() is 'nonisolated'
7171

72-
c.f() // expected-error{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
72+
c.f() // expected-warning{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
7373
}
7474

7575
func testCallsWithAsync() async {
@@ -338,3 +338,47 @@ func testSendableMetatypeDowngrades() {
338338
acceptsSendableMetatype(t) // Ok (because P is `Sendable`
339339
}
340340
}
341+
342+
// Test that Sendable issues are downgraded to warnings in `@preconcurrency` context.
343+
do {
344+
@preconcurrency nonisolated func f(callback: @Sendable () -> Void) {}
345+
346+
@MainActor
347+
struct Env {
348+
var v: Int = 0
349+
}
350+
351+
@MainActor
352+
class IsolatedTest {
353+
var env = Env()
354+
// expected-note@-1 {{property declared here}}
355+
356+
func onMain() {}
357+
// expected-note@-1 {{calls to instance method 'onMain()' from outside of its actor context are implicitly asynchronous}}
358+
359+
func testProperty() {
360+
f {
361+
_ = self.env.v
362+
// expected-warning@-1 {{main actor-isolated property 'env' can not be referenced from a Sendable closure}}
363+
}
364+
}
365+
366+
func testMethod() {
367+
f {
368+
self.onMain()
369+
// expected-warning@-1 {{call to main actor-isolated instance method 'onMain()' in a synchronous nonisolated context}}
370+
}
371+
}
372+
}
373+
374+
class Test { // expected-note {{class 'Test' does not conform to the 'Sendable' protocol}}
375+
var env = Env()
376+
377+
func testProperty() async {
378+
f {
379+
_ = self.env.v
380+
// expected-warning@-1 {{capture of 'self' with non-Sendable type 'Test' in a '@Sendable' closure}}
381+
}
382+
}
383+
}
384+
}

0 commit comments

Comments
 (0)