Skip to content

Commit e9886f4

Browse files
committed
Create stub stored properties in main objcImpl
Further modify objcImpl missing requirement diagnostics so the stubs create stored properties in the main body, or computed properties otherwise. Also tweak printing so we use `let` where appropriate.
1 parent 0f351e7 commit e9886f4

File tree

7 files changed

+36
-10
lines changed

7 files changed

+36
-10
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ struct PrintOptions {
143143
/// Whether to print *any* accessors on properties.
144144
bool PrintPropertyAccessors = true;
145145

146+
/// Use \c let for a read-only computed property.
147+
bool InferPropertyIntroducerFromAccessors = false;
148+
146149
/// Whether to print *any* accessors on subscript.
147150
bool PrintSubscriptAccessors = true;
148151

lib/AST/ASTPrinter.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3939,11 +3939,18 @@ void PrintAST::visitVarDecl(VarDecl *decl) {
39393939
if (decl->isStatic() && Options.PrintStaticKeyword)
39403940
printStaticKeyword(decl->getCorrectStaticSpelling());
39413941
if (decl->getKind() == DeclKind::Var || Options.PrintParameterSpecifiers) {
3942+
// If InferPropertyIntroducerFromAccessors is set, turn all read-only
3943+
// properties to `let`.
3944+
auto introducer = decl->getIntroducer();
3945+
if (Options.InferPropertyIntroducerFromAccessors &&
3946+
!cast<VarDecl>(decl)->isSettable(nullptr))
3947+
introducer = VarDecl::Introducer::Let;
3948+
39423949
// Map all non-let specifiers to 'var'. This is not correct, but
39433950
// SourceKit relies on this for info about parameter decls.
39443951

39453952
Printer.printIntroducerKeyword(
3946-
decl->getIntroducer() == VarDecl::Introducer::Let ? "let" : "var",
3953+
introducer == VarDecl::Introducer::Let ? "let" : "var",
39473954
Options, " ");
39483955
}
39493956
printContextIfNeeded(decl);

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3696,7 +3696,10 @@ bool swift::
36963696
printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
36973697
Type AdopterTy, SourceLoc TypeLoc, raw_ostream &OS,
36983698
bool withExplicitObjCAttr) {
3699-
if (isa<ConstructorDecl>(Requirement)) {
3699+
// We sometimes use this for @implementation extensions too.
3700+
bool forProtocol = isa<ProtocolDecl>(Requirement->getDeclContext());
3701+
3702+
if (isa<ConstructorDecl>(Requirement) && forProtocol) {
37003703
if (auto CD = Adopter->getSelfClassDecl()) {
37013704
if (!CD->isSemanticallyFinal() && isa<ExtensionDecl>(Adopter)) {
37023705
// In this case, user should mark class as 'final' or define
@@ -3764,7 +3767,7 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
37643767

37653768
Printer << "\n";
37663769
} else {
3767-
if (isa<ConstructorDecl>(Requirement)) {
3770+
if (isa<ConstructorDecl>(Requirement) && forProtocol) {
37683771
if (auto CD = Adopter->getSelfClassDecl()) {
37693772
if (!CD->isFinal()) {
37703773
Printer << "required ";
@@ -3799,9 +3802,9 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
37993802
};
38003803
Options.setBaseType(AdopterTy);
38013804
Options.CurrentModule = Adopter->getParentModule();
3802-
if (isa<NominalTypeDecl>(Adopter)) {
3805+
if (isa<NominalTypeDecl>(Adopter->getImplementedObjCContext())) {
38033806
// Create a variable declaration instead of a computed property in
3804-
// nominal types...
3807+
// nominal types (or implementations thereof)...
38053808
Options.PrintPropertyAccessors = false;
38063809

38073810
// ...but a non-mutating setter requirement will force us into a
@@ -3812,6 +3815,11 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
38123815
if (const auto Set = VD->getOpaqueAccessor(AccessorKind::Set))
38133816
if (Set->getAttrs().hasAttribute<NonMutatingAttr>())
38143817
Options.PrintPropertyAccessors = true;
3818+
3819+
// If we're not printing the accessors, make them affect the introducer
3820+
// instead.
3821+
Options.InferPropertyIntroducerFromAccessors =
3822+
!Options.PrintPropertyAccessors;
38153823
}
38163824
Requirement->print(Printer, Options);
38173825
Printer << "\n";

test/decl/ext/Inputs/objc_implementation.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@
8585
@property int categoryPropertyFromHeader2;
8686
@property int categoryPropertyFromHeader3;
8787
@property int categoryPropertyFromHeader4;
88+
@property int categoryPropertyFromHeader5;
89+
90+
@property (readonly) int categoryReadonlyPropertyFromHeader1;
91+
8892

8993
@end
9094

test/decl/ext/objc_implementation.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protocol EmptySwiftProto {}
1717
// FIXME: give better diagnostic expected-note@-8 {{missing instance method 'method(fromHeader3:)'}} {{none}}
1818
// expected-note@-9 {{missing instance method 'extensionMethod(fromHeader2:)'}} {{none}}
1919
// expected-note@-10 {{missing property 'readonlyPropertyFromHeader7'}}
20-
// expected-note@-11 {{add stubs for missing '@implementation' requirements}} {{77-77=\n @objc(methodFromHeader3:)\n open func method(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(methodFromHeader4:)\n open func method(fromHeader4 param: Int32) {\n <#code#>\n \}\n\n @objc(propertyFromHeader7)\n open var propertyFromHeader7: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(propertyFromHeader8)\n open var propertyFromHeader8: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(propertyFromHeader9)\n open var propertyFromHeader9: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(readonlyPropertyFromHeader7)\n open var readonlyPropertyFromHeader7: Int32 {\n <#code#>\n \}\n\n @objc(extensionMethodFromHeader2:)\n open func extensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n}}
20+
// expected-note@-11 {{add stubs for missing '@implementation' requirements}} {{77-77=\n @objc(methodFromHeader3:)\n open func method(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(methodFromHeader4:)\n open func method(fromHeader4 param: Int32) {\n <#code#>\n \}\n\n @objc(propertyFromHeader7)\n open var propertyFromHeader7: Int32\n\n @objc(propertyFromHeader8)\n open var propertyFromHeader8: Int32\n\n @objc(propertyFromHeader9)\n open var propertyFromHeader9: Int32\n\n @objc(readonlyPropertyFromHeader7)\n open let readonlyPropertyFromHeader7: Int32\n\n @objc(extensionMethodFromHeader2:)\n open func extensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n}}
2121

2222
func method(fromHeader1: CInt) {
2323
// OK, provides an implementation for the header's method.
@@ -241,7 +241,9 @@ protocol EmptySwiftProto {}
241241
// expected-error@-1 {{extension for category 'PresentAdditions' does not provide all required implementations}}
242242
// expected-note@-2 {{missing instance method 'categoryMethod(fromHeader4:)'}} {{none}}
243243
// FIXME: give better diagnostic expected-note@-3 {{missing instance method 'categoryMethod(fromHeader3:)'}} {{none}}
244-
// expected-note@-4 {{add stubs for missing '@implementation' requirements}} {{62-62=\n @objc(categoryMethodFromHeader3:)\n open func categoryMethod(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(categoryMethodFromHeader4:)\n open func categoryMethod(fromHeader4 param: Int32) {\n <#code#>\n \}\n}}
244+
// expected-note@-4 {{missing property 'categoryPropertyFromHeader5'}} {{none}}
245+
// expected-note@-5 {{missing property 'categoryReadonlyPropertyFromHeader1'}} {{none}}
246+
// expected-note@-6 {{add stubs for missing '@implementation' requirements}} {{62-62=\n @objc(categoryMethodFromHeader3:)\n open func categoryMethod(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(categoryMethodFromHeader4:)\n open func categoryMethod(fromHeader4 param: Int32) {\n <#code#>\n \}\n\n @objc(categoryPropertyFromHeader5)\n open var categoryPropertyFromHeader5: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(categoryReadonlyPropertyFromHeader1)\n open var categoryReadonlyPropertyFromHeader1: Int32 {\n <#code#>\n \}\n}}
245247

246248
func method(fromHeader3: CInt) {
247249
// FIXME: should emit expected-DISABLED-error@-1 {{instance method 'method(fromHeader3:)' should be implemented in extension for main class interface, not category 'PresentAdditions'}}

test/decl/ext/objc_implementation_class_extension.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
// expected-note@-5 {{missing property 'otherModuleExtensionPropertyFromHeader2'}} {{none}}
1212
// expected-note@-6 {{missing instance method 'extensionMethod(fromHeader2:)'}} {{none}}
1313
// expected-note@-7 {{missing property 'extensionPropertyFromHeader2'}} {{none}}
14-
// expected-note@-8 {{add stubs for missing '@implementation' requirements}} {{43-43=\n @objc(methodFromHeader2:)\n open func method(fromHeader2 param: Int32) {\n <#code#>\n \}\n\n @objc(propertyFromHeader2)\n open var propertyFromHeader2: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(otherModuleExtensionMethodFromHeader2:)\n open func otherModuleExtensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n\n @objc(otherModuleExtensionPropertyFromHeader2)\n open var otherModuleExtensionPropertyFromHeader2: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(extensionMethodFromHeader2:)\n open func extensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n\n @objc(extensionPropertyFromHeader2)\n open var extensionPropertyFromHeader2: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n}}
14+
// expected-note@-8 {{add stubs for missing '@implementation' requirements}} {{43-43=\n @objc(methodFromHeader2:)\n open func method(fromHeader2 param: Int32) {\n <#code#>\n \}\n\n @objc(propertyFromHeader2)\n open var propertyFromHeader2: Int32\n\n @objc(otherModuleExtensionMethodFromHeader2:)\n open func otherModuleExtensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n\n @objc(otherModuleExtensionPropertyFromHeader2)\n open var otherModuleExtensionPropertyFromHeader2: Int32\n\n @objc(extensionMethodFromHeader2:)\n open func extensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n\n @objc(extensionPropertyFromHeader2)\n open var extensionPropertyFromHeader2: Int32\n}}
1515

1616
@objc func method(fromHeader1: CInt) {}
1717
@objc private func method(fromHeader2: CInt) {}

test/decl/ext/objc_implementation_early_adopter.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protocol EmptySwiftProto {}
1717
// FIXME: give better diagnostic expected-note@-8 {{missing instance method 'method(fromHeader3:)'}} {{none}}
1818
// expected-note@-9 {{missing instance method 'extensionMethod(fromHeader2:)'}} {{none}}
1919
// expected-note@-10 {{missing property 'readonlyPropertyFromHeader7'}}
20-
// expected-note@-11 {{add stubs for missing '@implementation' requirements}} {{76-76=\n @objc(methodFromHeader3:)\n open func method(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(methodFromHeader4:)\n open func method(fromHeader4 param: Int32) {\n <#code#>\n \}\n\n @objc(propertyFromHeader7)\n open var propertyFromHeader7: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(propertyFromHeader8)\n open var propertyFromHeader8: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(propertyFromHeader9)\n open var propertyFromHeader9: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(readonlyPropertyFromHeader7)\n open var readonlyPropertyFromHeader7: Int32 {\n <#code#>\n \}\n\n @objc(extensionMethodFromHeader2:)\n open func extensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n}}
20+
// expected-note@-11 {{add stubs for missing '@implementation' requirements}} {{76-76=\n @objc(methodFromHeader3:)\n open func method(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(methodFromHeader4:)\n open func method(fromHeader4 param: Int32) {\n <#code#>\n \}\n\n @objc(propertyFromHeader7)\n open var propertyFromHeader7: Int32\n\n @objc(propertyFromHeader8)\n open var propertyFromHeader8: Int32\n\n @objc(propertyFromHeader9)\n open var propertyFromHeader9: Int32\n\n @objc(readonlyPropertyFromHeader7)\n open let readonlyPropertyFromHeader7: Int32\n\n @objc(extensionMethodFromHeader2:)\n open func extensionMethod(fromHeader2 param: Int32) {\n <#code#>\n \}\n}}
2121

2222
func method(fromHeader1: CInt) {
2323
// OK, provides an implementation for the header's method.
@@ -241,7 +241,9 @@ protocol EmptySwiftProto {}
241241
// expected-warning@-1 {{extension for category 'PresentAdditions' does not provide all required implementations; this will become an error after adopting '@implementation'}}
242242
// expected-note@-2 {{missing instance method 'categoryMethod(fromHeader4:)'}} {{none}}
243243
// FIXME: give better diagnostic expected-note@-3 {{missing instance method 'categoryMethod(fromHeader3:)'}} {{none}}
244-
// expected-note@-4 {{add stubs for missing '@implementation' requirements}} {{61-61=\n @objc(categoryMethodFromHeader3:)\n open func categoryMethod(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(categoryMethodFromHeader4:)\n open func categoryMethod(fromHeader4 param: Int32) {\n <#code#>\n \}\n}}
244+
// expected-note@-4 {{missing property 'categoryPropertyFromHeader5'}} {{none}}
245+
// expected-note@-5 {{missing property 'categoryReadonlyPropertyFromHeader1'}} {{none}}
246+
// expected-note@-6 {{add stubs for missing '@implementation' requirements}} {{61-61=\n @objc(categoryMethodFromHeader3:)\n open func categoryMethod(fromHeader3 param: Int32) {\n <#code#>\n \}\n\n @objc(categoryMethodFromHeader4:)\n open func categoryMethod(fromHeader4 param: Int32) {\n <#code#>\n \}\n\n @objc(categoryPropertyFromHeader5)\n open var categoryPropertyFromHeader5: Int32 {\n get {\n <#code#>\n \}\n set {\n <#code#>\n \}\n \}\n\n @objc(categoryReadonlyPropertyFromHeader1)\n open var categoryReadonlyPropertyFromHeader1: Int32 {\n <#code#>\n \}\n}}
245247

246248
func method(fromHeader3: CInt) {
247249
// FIXME: should emit expected-DISABLED-error@-1 {{instance method 'method(fromHeader3:)' should be implemented in extension for main class interface, not category 'PresentAdditions'}}

0 commit comments

Comments
 (0)