Skip to content

Commit 737665c

Browse files
committed
[Sema] Group isolation errors in checkApply
1 parent 4d2b01b commit 737665c

File tree

3 files changed

+152
-30
lines changed

3 files changed

+152
-30
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 75 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,11 +2003,15 @@ namespace {
20032003
/// an expression or function.
20042004
llvm::SmallDenseMap<const DeclContext *, ActorIsolation> requiredIsolation;
20052005

2006-
using IsolationPair = std::pair<ReferencedActor::Kind, ActorIsolation>;
2006+
using ActorRefKindPair = std::pair<ReferencedActor::Kind, ActorIsolation>;
2007+
2008+
using IsolationPair = std::pair<ActorIsolation, ActorIsolation>;
20072009

20082010
using DiagnosticList = std::vector<IsolationError>;
20092011

2010-
llvm::DenseMap<IsolationPair, DiagnosticList> isoErrors;
2012+
llvm::DenseMap<ActorRefKindPair, DiagnosticList> refErrors;
2013+
2014+
llvm::DenseMap<IsolationPair, DiagnosticList> applyErrors;
20112015

20122016
/// Keeps track of the capture context of variables that have been
20132017
/// explicitly captured in closures.
@@ -2065,8 +2069,8 @@ namespace {
20652069
bool diagnoseIsolationErrors() {
20662070
bool diagnosedError = false;
20672071

2068-
for (auto list : isoErrors) {
2069-
IsolationPair key = list.getFirst();
2072+
for (auto list : refErrors) {
2073+
ActorRefKindPair key = list.getFirst();
20702074
DiagnosticList errors = list.getSecond();
20712075
ActorIsolation isolation = key.second;
20722076

@@ -2087,6 +2091,30 @@ namespace {
20872091
.limitBehavior(behavior);
20882092
}
20892093
}
2094+
2095+
for (auto list : applyErrors) {
2096+
IsolationPair key = list.getFirst();
2097+
DiagnosticList errors = list.getSecond();
2098+
ActorIsolation isolation = key.first;
2099+
2100+
auto behavior = DiagnosticBehavior::Error;
2101+
2102+
// Add Fix-it for missing @SomeActor annotation
2103+
if (isolation.isGlobalActor()) {
2104+
if (missingGlobalActorOnContext(
2105+
const_cast<DeclContext*>(getDeclContext()), isolation.getGlobalActor())) {
2106+
behavior= DiagnosticBehavior::Note;
2107+
}
2108+
}
2109+
2110+
for (IsolationError error : errors) {
2111+
// Diagnose actor_isolated_non_self_reference as note
2112+
// if we provide fix-it in missingGlobalActorOnContext
2113+
ctx.Diags.diagnose(error.loc, error.diag)
2114+
.limitBehavior(behavior);
2115+
}
2116+
}
2117+
20902118
return diagnosedError;
20912119
}
20922120

@@ -2422,8 +2450,6 @@ namespace {
24222450
requiredIsolationLoc = expr->getLoc();
24232451

24242452
expr->walk(*this);
2425-
// print all diagnostics here :)
2426-
//diagnoseIsolationErrors(getDeclContext(), isoErrors);
24272453
requiredIsolationLoc = SourceLoc();
24282454
return requiredIsolation[getDeclContext()];
24292455
}
@@ -3225,28 +3251,49 @@ namespace {
32253251
// If we need to mark the call as implicitly asynchronous, make sure
32263252
// we're in an asynchronous context.
32273253
if (requiresAsync && !getDeclContext()->isAsyncContext()) {
3228-
if (calleeDecl) {
3229-
auto preconcurrency = getContextIsolation().preconcurrency() ||
3230-
calleeDecl->preconcurrency();
3231-
ctx.Diags.diagnose(
3232-
apply->getLoc(), diag::actor_isolated_call_decl,
3233-
*unsatisfiedIsolation,
3234-
calleeDecl,
3235-
getContextIsolation())
3236-
.warnUntilSwiftVersionIf(preconcurrency, 6);
3237-
calleeDecl->diagnose(diag::actor_isolated_sync_func, calleeDecl);
3254+
3255+
if (ctx.LangOpts.hasFeature(Feature::GroupActorErrors)) {
3256+
IsolationError isoMismatch =
3257+
IsolationError(
3258+
apply->getLoc(),
3259+
Diagnostic(diag::actor_isolated_call_decl,
3260+
*unsatisfiedIsolation,
3261+
calleeDecl,
3262+
getContextIsolation()));
3263+
3264+
auto iter = applyErrors.find(std::make_pair(*unsatisfiedIsolation, getContextIsolation()));
3265+
if (iter != applyErrors.end()){
3266+
iter->second.push_back(isoMismatch);
3267+
} else {
3268+
DiagnosticList list;
3269+
list.push_back(isoMismatch);
3270+
auto keyPair = std::make_pair(*unsatisfiedIsolation, getContextIsolation());
3271+
applyErrors.insert(std::make_pair(keyPair, list));
3272+
}
32383273
} else {
3239-
ctx.Diags.diagnose(
3240-
apply->getLoc(), diag::actor_isolated_call, *unsatisfiedIsolation,
3241-
getContextIsolation())
3274+
if (calleeDecl) {
3275+
auto preconcurrency = getContextIsolation().preconcurrency() ||
3276+
calleeDecl->preconcurrency();
3277+
ctx.Diags.diagnose(
3278+
apply->getLoc(), diag::actor_isolated_call_decl,
3279+
*unsatisfiedIsolation,
3280+
calleeDecl,
3281+
getContextIsolation())
3282+
.warnUntilSwiftVersionIf(preconcurrency, 6);
3283+
calleeDecl->diagnose(diag::actor_isolated_sync_func, calleeDecl);
3284+
} else {
3285+
ctx.Diags.diagnose(
3286+
apply->getLoc(), diag::actor_isolated_call, *unsatisfiedIsolation,
3287+
getContextIsolation())
32423288
.warnUntilSwiftVersionIf(getContextIsolation().preconcurrency(), 6);
3243-
}
3289+
}
32443290

3245-
// if (unsatisfiedIsolation->isGlobalActor()) {
3246-
// noteGlobalActorOnContext(
3247-
// const_cast<DeclContext *>(getDeclContext()),
3248-
// unsatisfiedIsolation->getGlobalActor());
3249-
// }
3291+
if (unsatisfiedIsolation->isGlobalActor()) {
3292+
missingGlobalActorOnContext(
3293+
const_cast<DeclContext *>(getDeclContext()),
3294+
unsatisfiedIsolation->getGlobalActor());
3295+
}
3296+
}
32503297

32513298
return true;
32523299
}
@@ -3622,14 +3669,14 @@ namespace {
36223669
refKind + 1, refGlobalActor,
36233670
result.isolation));
36243671

3625-
auto iter = isoErrors.find(std::make_pair(refKind,result.isolation));
3626-
if (iter != isoErrors.end()){
3672+
auto iter = refErrors.find(std::make_pair(refKind,result.isolation));
3673+
if (iter != refErrors.end()){
36273674
iter->second.push_back(isoMismatch);
36283675
} else {
36293676
DiagnosticList list;
36303677
list.push_back(isoMismatch);
36313678
auto keyPair = std::make_pair(refKind,result.isolation);
3632-
isoErrors.insert(std::make_pair(keyPair, list));
3679+
refErrors.insert(std::make_pair(keyPair, list));
36333680
}
36343681
} else {
36353682
ctx.Diags.diagnose(

lib/Sema/TypeCheckConcurrency.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,6 @@ struct IsolationError {
259259

260260
};
261261

262-
static bool diagnoseIsolationErrors(DeclContext *dc, ArrayRef<IsolationError> errors);
263-
264262
/// Individual options used with \c FunctionCheckOptions
265263
enum class FunctionCheckKind {
266264
/// Check params
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature GroupActorErrors
2+
// REQUIRES: concurrency
3+
4+
5+
@MainActor
6+
protocol P {
7+
func f()
8+
nonisolated func g()
9+
}
10+
11+
struct S_P: P {
12+
func f() { }
13+
// expected-complete-sns-note @-1 {{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}}
14+
func g() { }
15+
}
16+
17+
func testP2(x: S_P, p: P) { // expected-error{{add '@MainActor' to make global function 'testP2(x:p:)' part of global actor 'MainActor'}}
18+
p.f() // expected-note{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
19+
p.f() // expected-note{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
20+
p.f() // expected-note{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
21+
p.g() // OKAY
22+
x.f() // expected-note{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
23+
x.f() // expected-note{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
24+
x.f() // expected-note{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
25+
x.g() // OKAY
26+
}
27+
28+
actor SomeActor { }
29+
30+
@globalActor
31+
struct SomeGlobalActor {
32+
static let shared = SomeActor()
33+
}
34+
35+
@propertyWrapper
36+
struct WrapperOnActor<Wrapped: Sendable> {
37+
private var stored: Wrapped
38+
39+
nonisolated init(wrappedValue: Wrapped) {
40+
stored = wrappedValue
41+
}
42+
43+
@MainActor var wrappedValue: Wrapped {
44+
get { }
45+
set { }
46+
}
47+
48+
@SomeGlobalActor var projectedValue: Wrapped {
49+
get { }
50+
set { }
51+
}
52+
}
53+
54+
struct HasWrapperOnActor {
55+
@WrapperOnActor var x: Int = 0
56+
@WrapperOnActor var y: String = ""
57+
@WrapperOnActor var z: (Double, Double) = (1.0,2.0)
58+
59+
func testWrapped() { // expected-error{{add '@MainActor' to make instance method 'testWrapped()' part of global actor 'MainActor'}}
60+
_ = x // expected-note{{main actor-isolated property 'x' can not be referenced from a non-isolated context}}
61+
_ = y // expected-note{{main actor-isolated property 'y' can not be referenced from a non-isolated context}}
62+
_ = z // expected-note{{main actor-isolated property 'z' can not be referenced from a non-isolated context}}
63+
}
64+
func testProjected(){ // expected-error{{add '@SomeGlobalActor' to make instance method 'testProjected()' part of global actor 'SomeGlobalActor'}}
65+
_ = $x // expected-note{{global actor 'SomeGlobalActor'-isolated property '$x' can not be referenced from a non-isolated context}}
66+
_ = $y // expected-note{{global actor 'SomeGlobalActor'-isolated property '$y' can not be referenced from a non-isolated context}}
67+
_ = $z // expected-note{{global actor 'SomeGlobalActor'-isolated property '$z' can not be referenced from a non-isolated context}}
68+
}
69+
70+
@MainActor
71+
func testMA(){ }
72+
73+
func testErrors() { // expected-error{{add '@MainActor' to make instance method 'testErrors()' part of global actor 'MainActor'}}
74+
testMA() // expected-note{{call to main actor-isolated instance method 'testMA()' in a synchronous nonisolated context}}
75+
testMA() // expected-note{{call to main actor-isolated instance method 'testMA()' in a synchronous nonisolated context}}
76+
}
77+
}

0 commit comments

Comments
 (0)