Skip to content

Commit 51ef44a

Browse files
committed
Don’t serialize objcImpl members
Avoids failures where an imported member implementation is mistaken for a regular member, creating new ambiguities. Fixes rdar://134736899.
1 parent 96b14a7 commit 51ef44a

File tree

6 files changed

+110
-2
lines changed

6 files changed

+110
-2
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,6 +2535,10 @@ class PatternBindingDecl final : public Decl,
25352535
/// Does this binding declare something that requires storage?
25362536
bool hasStorage() const;
25372537

2538+
/// Does this binding have at least one VarDecl that's an ObjC member
2539+
/// implementation?
2540+
bool hasAnyObjCMemberImplementations() const;
2541+
25382542
/// Determines whether this binding either has an initializer expression, or is
25392543
/// default initialized, without performing any type checking on it.
25402544
bool isDefaultInitializable() const {

lib/AST/Decl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4620,6 +4620,16 @@ bool ValueDecl::isObjCMemberImplementation() const {
46204620
this, [&]() { return this->getFormalAccess(); });
46214621
}
46224622

4623+
bool PatternBindingDecl::hasAnyObjCMemberImplementations() const {
4624+
bool foundAny = false;
4625+
for (auto i : range(getNumPatternEntries())) {
4626+
getPattern(i)->forEachVariable([&](VarDecl *VD) {
4627+
foundAny |= VD->isObjCMemberImplementation();
4628+
});
4629+
}
4630+
return foundAny;
4631+
}
4632+
46234633
/// Checks if \p VD may be used from \p useDC, taking \@testable and \@_spi
46244634
/// imports into account.
46254635
///

lib/Serialization/Serialization.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,7 +2024,6 @@ static bool shouldSerializeMember(Decl *D) {
20242024
case DeclKind::Protocol:
20252025
case DeclKind::Constructor:
20262026
case DeclKind::Destructor:
2027-
case DeclKind::PatternBinding:
20282027
case DeclKind::Subscript:
20292028
case DeclKind::TypeAlias:
20302029
case DeclKind::GenericTypeParam:
@@ -2036,7 +2035,10 @@ static bool shouldSerializeMember(Decl *D) {
20362035
case DeclKind::Param:
20372036
case DeclKind::Func:
20382037
case DeclKind::Accessor:
2039-
return true;
2038+
return !cast<ValueDecl>(D)->isObjCMemberImplementation();
2039+
2040+
case DeclKind::PatternBinding:
2041+
return !cast<PatternBindingDecl>(D)->hasAnyObjCMemberImplementations();
20402042
}
20412043

20422044
llvm_unreachable("Unhandled DeclKind in switch.");

test/Serialization/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ module CLibrary {
66
module RawLayoutCXX {
77
header "raw_layout_cxx.h"
88
}
9+
10+
module objc_implementation {
11+
header "objc_implementation.h"
12+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#import <Foundation/Foundation.h>
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
@interface ObjCImpl : NSObject
6+
7+
- (instancetype)initWithNonSerialized:(int)value NS_SWIFT_NAME(init(nonSerialized:));
8+
- (void)nonSerializedMethod;
9+
@property (assign) int nonSerializedProperty;
10+
11+
@end
12+
13+
@interface ObjCImpl (CategoryMembers)
14+
15+
- (void)nonSerializedCategoryMethod;
16+
@property (assign) int nonSerializedCategoryProperty;
17+
18+
@end
19+
20+
NS_ASSUME_NONNULL_END
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -module-name main -o %t -I %S/Inputs %s
3+
// RUN: llvm-bcanalyzer %t/main.swiftmodule > %t/main.swiftmodule.txt
4+
// RUN: %target-swift-ide-test -print-module -module-to-print=main -I %t -source-filename=%s >%t/main.txt
5+
// RUN: %FileCheck %s --check-prefixes POSITIVE,CHECK --input-file=%t/main.txt
6+
// RUN: %FileCheck %s --check-prefixes NEGATIVE,CHECK --input-file=%t/main.txt
7+
8+
// REQUIRES: objc_interop
9+
10+
import Foundation
11+
import objc_implementation
12+
13+
// CHECK-LABEL: @objc @implementation extension ObjCImpl
14+
@objc @implementation extension ObjCImpl {
15+
// These should not appear in the serialized output.
16+
17+
// NEGATIVE-NOT: init(nonSerialized value
18+
@objc(initWithNonSerialized:)
19+
public init(nonSerialized value: Int32) {
20+
super.init()
21+
}
22+
23+
// NEGATIVE-NOT: func nonSerializedMethod
24+
@objc public func nonSerializedMethod() {}
25+
26+
// NEGATIVE-NOT: var nonSerializedProperty
27+
@objc public var nonSerializedProperty: Int32 = 0
28+
29+
// NEGATIVE-NOT: deinit
30+
deinit {}
31+
32+
// These should appear in the serialized output.
33+
34+
// POSITIVE: func serializedMethod
35+
final public func serializedMethod() {}
36+
// POSITIVE: var serializedProperty
37+
final public var serializedProperty: Int32 = 0
38+
39+
// POSITIVE: init(serialized value
40+
@nonobjc public convenience init(serialized value: Int32) {
41+
self.init(nonSerialized: value)
42+
}
43+
}
44+
45+
// CHECK-LABEL: @objc(CategoryMembers) @implementation extension ObjCImpl
46+
@objc(CategoryMembers) @implementation extension ObjCImpl {
47+
// These should not appear in the serialized output.
48+
49+
// NEGATIVE-NOT: func nonSerializedCategoryMethod
50+
@objc public func nonSerializedCategoryMethod() {}
51+
52+
// NEGATIVE-NOT: var nonSerializedCategoryProperty
53+
@objc public var nonSerializedCategoryProperty: Int32 {
54+
get { nonSerializedProperty }
55+
set { nonSerializedProperty = newValue }
56+
}
57+
58+
// These should appear in the serialized output.
59+
60+
// POSITIVE: func serializedCategoryMethod()
61+
final public func serializedCategoryMethod() {}
62+
63+
// POSITIVE: var serializedCategoryProperty
64+
final public var serializedCategoryProperty: Int32 {
65+
get { serializedProperty }
66+
set { serializedProperty = newValue }
67+
}
68+
}

0 commit comments

Comments
 (0)