Skip to content

Commit cc60f2c

Browse files
authored
Merge pull request #27896 from AnthonyLatsis/proto-stubs-nonmutating-set
Sema: Print property accessors for non-mutating setter requirements
2 parents b92beb4 + 9b77ae5 commit cc60f2c

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2627,13 +2627,13 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
26272627
Options.FunctionDefinitions = true;
26282628
Options.PrintAccessorBodiesInProtocols = true;
26292629

2630+
bool AdopterIsClass = Adopter->getSelfClassDecl() != nullptr;
26302631
// Skip 'mutating' only inside classes: mutating methods usually
26312632
// don't have a sensible non-mutating implementation.
2632-
bool isClass = Adopter->getSelfClassDecl() != nullptr;
2633-
if (isClass)
2633+
if (AdopterIsClass)
26342634
Options.ExcludeAttrList.push_back(DAK_Mutating);
26352635
// 'nonmutating' is only meaningful on value type member accessors.
2636-
if (isClass || !isa<AbstractStorageDecl>(Requirement))
2636+
if (AdopterIsClass || !isa<AbstractStorageDecl>(Requirement))
26372637
Options.ExcludeAttrList.push_back(DAK_NonMutating);
26382638

26392639
// FIXME: Once we support move-only types, remove this if the
@@ -2650,10 +2650,19 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
26502650
};
26512651
Options.setBaseType(AdopterTy);
26522652
Options.CurrentModule = Adopter->getParentModule();
2653-
if (!isa<ExtensionDecl>(Adopter)) {
2653+
if (isa<NominalTypeDecl>(Adopter)) {
26542654
// Create a variable declaration instead of a computed property in
2655-
// nominal types
2655+
// nominal types...
26562656
Options.PrintPropertyAccessors = false;
2657+
2658+
// ...but a non-mutating setter requirement will force us into a
2659+
// computed property in non-class adopters; don't leave the user
2660+
// wondering why a conformance fails.
2661+
if (!AdopterIsClass)
2662+
if (const auto VD = dyn_cast<VarDecl>(Requirement))
2663+
if (const auto Set = VD->getAccessor(AccessorKind::Set))
2664+
if (Set->getAttrs().hasAttribute<NonMutatingAttr>())
2665+
Options.PrintPropertyAccessors = true;
26572666
}
26582667
Requirement->print(Printer, Options);
26592668
Printer << "\n";

test/decl/protocol/conforms/fixit_stub_editor.swift

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ class C2 : P4 {} // expected-error{{type 'C2' does not conform to protocol 'P4'}
3939
// in structs.
4040
// =============================================================================
4141

42-
protocol LocalMutabilityProto {
43-
mutating func foo()
44-
subscript() -> Int { get nonmutating set }
42+
protocol MutabilityProto {
43+
mutating func foo()
44+
subscript() -> Int { get nonmutating set }
4545
}
4646

47-
class Class1: LocalMutabilityProto { // expected-error{{type 'Class1' does not conform to protocol 'LocalMutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{37-37=\n func foo() {\n <#code#>\n \}\n\n subscript() -> Int {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n}}
47+
class Class1: MutabilityProto { // expected-error{{type 'Class1' does not conform to protocol 'MutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{32-32=\n func foo() {\n <#code#>\n \}\n\n subscript() -> Int {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n}}
4848
}
4949

50-
struct Struct1: LocalMutabilityProto { // expected-error{{type 'Struct1' does not conform to protocol 'LocalMutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{39-39=\n mutating func foo() {\n <#code#>\n \}\n\n subscript() -> Int {\n get {\n <#code#>\n \}\n nonmutating set {\n <#code#>\n \}\n \}\n}}
50+
struct Struct1: MutabilityProto { // expected-error{{type 'Struct1' does not conform to protocol 'MutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{34-34=\n mutating func foo() {\n <#code#>\n \}\n\n subscript() -> Int {\n get {\n <#code#>\n \}\n nonmutating set {\n <#code#>\n \}\n \}\n}}
5151
}
5252

5353
import fixit_stub_mutability_proto_module
@@ -57,3 +57,18 @@ class Class2: ExternalMutabilityProto { // expected-error{{type 'Class2' does no
5757

5858
struct Struct2: ExternalMutabilityProto { // expected-error{{type 'Struct2' does not conform to protocol 'ExternalMutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{42-42=\n mutating func foo() {\n <#code#>\n \}\n\n subscript() -> Int {\n mutating get {\n <#code#>\n \}\n nonmutating set(newValue) {\n <#code#>\n \}\n \}\n}}
5959
}
60+
61+
protocol PropertyMutabilityProto {
62+
var computed: Int { mutating get nonmutating set }
63+
var stored: Int { mutating get set }
64+
}
65+
66+
class Class3: PropertyMutabilityProto { // expected-error{{type 'Class3' does not conform to protocol 'PropertyMutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{40-40=\n var computed: Int\n\n var stored: Int\n}}
67+
}
68+
69+
struct Struct3: PropertyMutabilityProto { // expected-error{{type 'Struct3' does not conform to protocol 'PropertyMutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{42-42=\n var computed: Int {\n mutating get {\n <#code#>\n \}\n nonmutating set {\n <#code#>\n \}\n \}\n\n var stored: Int\n}}
70+
}
71+
72+
class Class4 {}
73+
extension Class4: PropertyMutabilityProto { // expected-error{{type 'Class4' does not conform to protocol 'PropertyMutabilityProto'}} expected-note{{do you want to add protocol stubs?}} {{44-44=\n var computed: Int {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n var stored: Int {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n}}
74+
}

0 commit comments

Comments
 (0)