Skip to content

Commit d5e000f

Browse files
committed
[Sema] Fix inconsistent mutatingness diagnostic.
Refer to the correct problematic accessor or accessors.
1 parent d06e6a3 commit d5e000f

File tree

4 files changed

+86
-43
lines changed

4 files changed

+86
-43
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,9 +1710,10 @@ ERROR(functions_mutating_and_not,none,
17101710
ERROR(static_functions_not_mutating,none,
17111711
"static functions must not be declared mutating", ())
17121712

1713-
ERROR(modify_mutatingness_differs_from_setter,none,
1714-
"'modify' accessor cannot be %0 when the setter is %1",
1715-
(SelfAccessKind, SelfAccessKind))
1713+
ERROR(readwriter_mutatingness_differs_from_reader_or_writer_mutatingness,none,
1714+
"%0 cannot be %1 when "
1715+
"%select{both the %3 is %4 and the %5 is not %6|either the %3 is not %4 or the %5 is %6|the %3 is not %4|the %5 is %6}2",
1716+
(StringRef, SelfAccessKind, unsigned, StringRef, SelfAccessKind, StringRef, SelfAccessKind))
17161717

17171718
ERROR(transparent_in_protocols_not_supported,none,
17181719
"'@_transparent' attribute is not supported on declarations within protocols", ())

lib/Sema/TypeCheckStorage.cpp

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -697,28 +697,70 @@ IsGetterMutatingRequest::evaluate(Evaluator &evaluator,
697697
/// the implied value.
698698
static void diagnoseReadWriteMutatingnessMismatch(
699699
AbstractStorageDecl *storage, bool isWriterMutating, WriteImplKind write,
700-
AccessorKind writeAccesor, ReadWriteImplKind readWrite,
701-
AccessorKind readWriteAccessor) {
700+
AccessorKind writerAccesor, ReadWriteImplKind readWrite,
701+
AccessorKind readWriterAccessor) {
702702
if (storage->getImplInfo().getReadWriteImpl() != readWrite)
703703
return;
704-
auto modifyAccessor = storage->getParsedAccessor(readWriteAccessor);
704+
auto modifyAccessor = storage->getParsedAccessor(readWriterAccessor);
705705
if (!modifyAccessor)
706706
return;
707707

708708
auto isModifierMutating = modifyAccessor->isMutating();
709-
auto isReaderOrWriterMutating =
710-
isWriterMutating || storage->isGetterMutating();
709+
auto isReaderMutating = storage->isGetterMutating();
710+
auto isReaderOrWriterMutating = isWriterMutating || isReaderMutating;
711711
if (isReaderOrWriterMutating == isModifierMutating)
712712
return;
713713

714-
modifyAccessor->diagnose(diag::modify_mutatingness_differs_from_setter,
715-
isModifierMutating ? SelfAccessKind::Mutating
716-
: SelfAccessKind::NonMutating,
717-
isModifierMutating ? SelfAccessKind::NonMutating
718-
: SelfAccessKind::Mutating);
719-
auto *setter = storage->getParsedAccessor(writeAccesor);
720-
if (setter)
721-
setter->diagnose(diag::previous_accessor, "setter", 0);
714+
auto disagreesWithReader = (isReaderMutating != isModifierMutating);
715+
auto disagreesWithWriter = (isWriterMutating != isModifierMutating);
716+
auto disagreesWithBoth = disagreesWithReader && disagreesWithWriter;
717+
718+
auto readerAccessor = directAccessorKindForReadImpl(storage->getReadImpl());
719+
StringRef readerAccessorName =
720+
readerAccessor.has_value()
721+
? getAccessorNameForDiagnostic(*readerAccessor, /*article=*/false)
722+
: "the inherited accessor";
723+
StringRef writerAccessorName =
724+
getAccessorNameForDiagnostic(writerAccesor, /*article=*/false);
725+
unsigned diagnosticForm;
726+
if (isModifierMutating) {
727+
// modifier can't be mutating when both the setter is nonmutating and the
728+
// getter isn't mutating
729+
assert(disagreesWithBoth);
730+
diagnosticForm = 0;
731+
} else if (disagreesWithBoth) {
732+
// modify can't be nonmutating when either the setter isn't nonmutating or
733+
// the getter is mutating
734+
diagnosticForm = 1;
735+
} else if (disagreesWithWriter) {
736+
// modify can't be nonmutating when the setter isn't nonmutating
737+
diagnosticForm = 2;
738+
} else {
739+
// modify can't be nonmutating when the getter is mutating
740+
assert(disagreesWithReader);
741+
diagnosticForm = 3;
742+
}
743+
744+
modifyAccessor->diagnose(
745+
diag::readwriter_mutatingness_differs_from_reader_or_writer_mutatingness,
746+
getAccessorNameForDiagnostic(readWriterAccessor, /*article=*/false),
747+
isModifierMutating ? SelfAccessKind::Mutating
748+
: SelfAccessKind::NonMutating,
749+
diagnosticForm, writerAccessorName, SelfAccessKind::NonMutating,
750+
readerAccessorName, SelfAccessKind::Mutating);
751+
auto *writer = storage->getParsedAccessor(writerAccesor);
752+
if (disagreesWithWriter && writer) {
753+
writer->diagnose(
754+
diag::previous_accessor,
755+
getAccessorNameForDiagnostic(writerAccesor, /*article=*/false), 0);
756+
}
757+
AccessorDecl *reader = nullptr;
758+
if (disagreesWithReader && readerAccessor.has_value() &&
759+
(reader = storage->getParsedAccessor(*readerAccessor))) {
760+
StringRef readerAccessorName =
761+
getAccessorNameForDiagnostic(reader, /*article=*/false);
762+
reader->diagnose(diag::previous_accessor, readerAccessorName, 0);
763+
}
722764
modifyAccessor->setInvalid();
723765
}
724766

test/Sema/coroutine_accessors.swift

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,16 @@ var ingnsn_m: Int {
3333
var ignsn_m: Int {
3434
mutating get { 0 }
3535
nonmutating set {}
36-
// FIXME: Bad diagnostic! The writer is non-mutating--the reader is mutating.
37-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
38-
// expected-note@-3{{setter defined here}}
36+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the getter is 'mutating'}}
37+
// expected-note@-3{{getter defined here}}
3938
var fake: Int
4039
yield &fake
4140
}
4241
}
4342
var ingsn_m: Int {
4443
get { 0 }
4544
set {}
46-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
45+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is not 'nonmutating'}}
4746
// expected-note@-2{{setter defined here}}
4847
var fake: Int
4948
yield &fake
@@ -52,18 +51,19 @@ var ingsn_m: Int {
5251
var igsn_m: Int {
5352
mutating get { 0 }
5453
set {}
55-
// TODO: Incomplete diagnostic! Both the writer AND the reader are mutating.
56-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
57-
// expected-note@-3{{setter defined here}}
54+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when either the setter is not 'nonmutating' or the getter is 'mutating'}}
55+
// expected-note@-2{{setter defined here}}
56+
// expected-note@-4{{getter defined here}}
5857
var fake: Int
5958
yield &fake
6059
}
6160
}
6261
var ingns_m: Int {
6362
get { 0 }
6463
nonmutating set {}
65-
_modify { // expected-error{{'modify' accessor cannot be 'mutating' when the setter is 'nonmutating'}}
64+
_modify { // expected-error{{'modify' accessor cannot be 'mutating' when both the setter is 'nonmutating' and the getter is not 'mutating'}}
6665
// expected-note@-2{{setter defined here}}
66+
// expected-note@-4{{getter defined here}}
6767
yield &i
6868
}
6969
}
@@ -115,17 +115,16 @@ var in_rnsn_m: Int {
115115
var i_rnsn_m: Int {
116116
mutating _read { yield i }
117117
nonmutating set {}
118-
// FIXME: Bad diagnostic! The writer is non-mutating--the reader is mutating.
119-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
120-
// expected-note@-3{{setter defined here}}
118+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the 'read' accessor is 'mutating'}}
119+
// expected-note@-3{{'read' accessor defined here}}
121120
var fake: Int
122121
yield &fake
123122
}
124123
}
125124
var in_rsn_m: Int {
126125
_read { yield i }
127126
set {}
128-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
127+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is not 'nonmutating'}}
129128
// expected-note@-2{{setter defined here}}
130129
var fake: Int
131130
yield &fake
@@ -134,18 +133,19 @@ var in_rsn_m: Int {
134133
var i_rsn_m: Int {
135134
mutating _read { yield i }
136135
set {}
137-
// TODO: Incomplete diagnostic! Both the writer AND the reader are mutating.
138-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
139-
// expected-note@-3{{setter defined here}}
136+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when either the setter is not 'nonmutating' or the 'read' accessor is 'mutating'}}
137+
// expected-note@-2{{setter defined here}}
138+
// expected-note@-4{{'read' accessor defined here}}
140139
var fake: Int
141140
yield &fake
142141
}
143142
}
144143
var in_rns_m: Int {
145144
_read { yield i }
146145
nonmutating set {}
147-
_modify { // expected-error{{'modify' accessor cannot be 'mutating' when the setter is 'nonmutating'}}
146+
_modify { // expected-error{{'modify' accessor cannot be 'mutating' when both the setter is 'nonmutating' and the 'read' accessor is not 'mutating'}}
148147
// expected-note@-2{{setter defined here}}
148+
// expected-note@-4{{'read' accessor defined here}}
149149
yield &i
150150
}
151151
}
@@ -197,17 +197,16 @@ var inuansn_m: Int {
197197
var iuansn_m: Int {
198198
mutating unsafeAddress { UnsafePointer(bitPattern: 0x0)! }
199199
nonmutating set {}
200-
// FIXME: Bad diagnostic! The writer is non-mutating--the reader is mutating.
201-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
202-
// expected-note@-3{{setter defined here}}
200+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the addressor is 'mutating'}}
201+
// expected-note@-3{{addressor defined here}}
203202
var fake: Int
204203
yield &fake
205204
}
206205
}
207206
var inuasn_m: Int {
208207
unsafeAddress { UnsafePointer(bitPattern: 0x0)! }
209208
set {}
210-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
209+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is not 'nonmutating'}}
211210
// expected-note@-2{{setter defined here}}
212211
var fake: Int
213212
yield &fake
@@ -216,18 +215,19 @@ var inuasn_m: Int {
216215
var iuasn_m: Int {
217216
mutating unsafeAddress { UnsafePointer(bitPattern: 0x0)! }
218217
set {}
219-
// TODO: Incomplete diagnostic! Both the writer AND the reader are mutating.
220-
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
221-
// expected-note@-3{{setter defined here}}
218+
nonmutating _modify { // expected-error{{'modify' accessor cannot be 'nonmutating' when either the setter is not 'nonmutating' or the addressor is 'mutating'}}
219+
// expected-note@-2{{setter defined here}}
220+
// expected-note@-4{{addressor defined here}}
222221
var fake: Int
223222
yield &fake
224223
}
225224
}
226225
var inuans_m: Int {
227226
unsafeAddress { UnsafePointer(bitPattern: 0x0)! }
228227
nonmutating set {}
229-
_modify { // expected-error{{'modify' accessor cannot be 'mutating' when the setter is 'nonmutating'}}
228+
_modify { // expected-error{{'modify' accessor cannot be 'mutating' when both the setter is 'nonmutating' and the addressor is not 'mutating'}}
230229
// expected-note@-2{{setter defined here}}
230+
// expected-note@-4{{addressor defined here}}
231231
yield &i
232232
}
233233
}

test/Sema/generalized_accessors.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,13 @@ struct Modify {
9494

9595
var getAndNonMutatingModifyAndSet: Int {
9696
get {}
97-
nonmutating _modify {} // expected-error {{'modify' accessor cannot be 'nonmutating' when the setter is 'mutating'}}
97+
nonmutating _modify {} // expected-error {{'modify' accessor cannot be 'nonmutating' when the setter is not 'nonmutating'}}
9898
set {} // expected-note {{setter defined here}}
9999
}
100100

101101
var getAndModifyAndNonMutatingSet: Int {
102-
get {}
103-
_modify {}// expected-error {{'modify' accessor cannot be 'mutating' when the setter is 'nonmutating'}}
102+
get {} // expected-note{{getter defined here}}
103+
_modify {}// expected-error {{'modify' accessor cannot be 'mutating' when both the setter is 'nonmutating' and the getter is not 'mutating'}}
104104
nonmutating set {} // expected-note {{setter defined here}}
105105
}
106106
}

0 commit comments

Comments
 (0)