Skip to content

Commit ee197ae

Browse files
authored
Merge pull request #72078 from simanerush/redundant-nonisolated-unsafe
[Concurrency] Diagnose a redundant `nonisolated(unsafe)`
2 parents 0547323 + a5eff6b commit ee197ae

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5696,6 +5696,18 @@ NOTE(nonisolated_mutable_storage_note,none,
56965696
"convert %0 to a 'let' constant or consider declaring it "
56975697
"'nonisolated(unsafe)' if manually managing concurrency safety",
56985698
(const VarDecl *))
5699+
WARNING(nonisolated_unsafe_sendable_constant,none,
5700+
"'nonisolated(unsafe)' is unnecessary for a constant with 'Sendable' type "
5701+
"%0, consider removing it",
5702+
(Type))
5703+
WARNING(unsafe_sendable_actor_constant,none,
5704+
"'(unsafe)' is unnecessary for a constant public actor property with "
5705+
"'Sendable' type %0, consider removing it",
5706+
(Type))
5707+
WARNING(nonisolated_unsafe_sendable_actor_constant,none,
5708+
"'nonisolated(unsafe)' is unnecessary for a constant actor-isolated "
5709+
"property with 'Sendable' type %0, consider removing it",
5710+
(Type))
56995711
ERROR(nonisolated_non_sendable,none,
57005712
"'nonisolated' can not be applied to variable with non-'Sendable' "
57015713
"type %0",

lib/Sema/TypeCheckAttr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6921,6 +6921,40 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
69216921
return;
69226922
}
69236923
}
6924+
6925+
// 'nonisolated(unsafe)' is redundant for 'Sendable' immutables.
6926+
if (attr->isUnsafe() &&
6927+
type->isSendableType() &&
6928+
var->isLet()) {
6929+
6930+
// '(unsafe)' is redundant for a public actor-isolated 'Sendable'
6931+
// immutable.
6932+
auto nominal = dyn_cast<NominalTypeDecl>(dc);
6933+
if (nominal && nominal->isActor()) {
6934+
auto access = nominal->getFormalAccessScope(
6935+
/*useDC=*/nullptr,
6936+
/*treatUsableFromInlineAsPublic=*/true);
6937+
if (access.isPublic()) {
6938+
// Get the location where '(unsafe)' starts.
6939+
SourceLoc unsafeStart = Lexer::getLocForEndOfToken(
6940+
Ctx.SourceMgr, attr->getRange().Start);
6941+
diagnose(unsafeStart, diag::unsafe_sendable_actor_constant, type)
6942+
.fixItRemoveChars(unsafeStart,
6943+
attr->getRange().End.getAdvancedLoc(1));
6944+
} else {
6945+
// This actor is not public, so suggest to remove
6946+
// 'nonisolated(unsafe)'.
6947+
diagnose(attr->getLocation(),
6948+
diag::nonisolated_unsafe_sendable_actor_constant, type)
6949+
.fixItRemove(attr->getRange());
6950+
}
6951+
6952+
} else {
6953+
diagnose(attr->getLocation(),
6954+
diag::nonisolated_unsafe_sendable_constant, type)
6955+
.fixItRemove(attr->getRange());
6956+
}
6957+
}
69246958
}
69256959

69266960
// Using 'nonisolated' with wrapped properties is unsupported, because

test/Concurrency/global_variables.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ public struct TestWrapper {
3737
}
3838
}
3939

40+
// https://github.com/apple/swift/issues/71546
41+
actor TestActor {
42+
nonisolated(unsafe) let immutableActorIsolated = TestSendable()
43+
// expected-warning@-1 {{'nonisolated(unsafe)' is unnecessary for a constant actor-isolated property with 'Sendable' type 'TestSendable', consider removing it}} {{3-23=}}
44+
}
45+
4046
struct TestStatics {
4147
static let immutableExplicitSendable = TestSendable()
4248
static let immutableNonsendable = TestNonsendable() // expected-error{{static property 'immutableNonsendable' is not concurrency-safe because non-'Sendable' type 'TestNonsendable' may have shared mutable state}}
@@ -45,6 +51,8 @@ struct TestStatics {
4551
static nonisolated let immutableNonisolated = TestNonsendable() // expected-error{{static property 'immutableNonisolated' is not concurrency-safe because non-'Sendable' type 'TestNonsendable' may have shared mutable state}}
4652
// expected-note@-1 {{isolate 'immutableNonisolated' to a global actor, or conform 'TestNonsendable' to 'Sendable'}}
4753
// expected-error@-2 {{'nonisolated' can not be applied to variable with non-'Sendable' type 'TestNonsendable'}}
54+
static nonisolated(unsafe) let immutableNonisolatedUnsafeSendable = TestSendable()
55+
// expected-warning@-1 {{'nonisolated(unsafe)' is unnecessary for a constant with 'Sendable' type 'TestSendable', consider removing it}} {{10-30=}}
4856
static let immutableInferredSendable = 0
4957
static var mutable = 0 // expected-error{{static property 'mutable' is not concurrency-safe because it is non-isolated global shared mutable state}}
5058
// expected-note@-1{{isolate 'mutable' to a global actor, or convert it to a 'let' constant and conform it to 'Sendable'}}
@@ -54,6 +62,11 @@ struct TestStatics {
5462
// expected-note@-1{{isolate 'wrapped' to a global actor, or convert it to a 'let' constant and conform it to 'Sendable'}}
5563
}
5664

65+
public actor TestPublicActor {
66+
nonisolated(unsafe) let immutableNonisolatedUnsafeSendable = TestSendable()
67+
// expected-warning@-1 {{'(unsafe)' is unnecessary for a constant public actor property with 'Sendable' type 'TestSendable', consider removing it}} {{14-22=}}
68+
}
69+
5770
@TestGlobalActor
5871
func f() {
5972
print(TestStatics.immutableExplicitSendable)
@@ -63,6 +76,9 @@ func f() {
6376
}
6477

6578
func testLocalNonisolatedUnsafe() async {
79+
nonisolated(unsafe) let immutable = 1
80+
// expected-warning@-1{{'nonisolated(unsafe)' is unnecessary for a constant with 'Sendable' type 'Int', consider removing it}} {{3-23=}}
81+
// expected-warning@-2{{initialization of immutable value 'immutable' was never used; consider replacing with assignment to '_' or removing it}}
6682
nonisolated(unsafe) var value = 1
6783
let task = Task {
6884
value = 2

0 commit comments

Comments
 (0)