Skip to content

Commit c58481f

Browse files
authored
Merge pull request #25538 from jrose-apple/override-the-train-electric-boogaloo
[Serialization] If an override is dynamic, missing the base decl is OK
2 parents 83f86f5 + 2d3872a commit c58481f

File tree

6 files changed

+206
-6
lines changed

6 files changed

+206
-6
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,7 +1628,12 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
16281628
return nullptr;
16291629
}
16301630
values.front() = storage->getAccessor(*actualKind);
1631-
assert(values.front() && "missing accessor");
1631+
if (!values.front()) {
1632+
return llvm::make_error<XRefError>("missing accessor",
1633+
pathTrace,
1634+
getXRefDeclNameForError());
1635+
1636+
}
16321637
}
16331638
break;
16341639
}
@@ -2996,10 +3001,27 @@ class swift::DeclDeserializer {
29963001
}
29973002
}
29983003

2999-
Expected<Decl *> overridden = MF.getDeclChecked(overriddenID);
3000-
if (!overridden) {
3001-
llvm::consumeError(overridden.takeError());
3002-
return llvm::make_error<OverrideError>(name, errorFlags);
3004+
Expected<Decl *> overriddenOrError = MF.getDeclChecked(overriddenID);
3005+
Decl *overridden;
3006+
if (overriddenOrError) {
3007+
overridden = overriddenOrError.get();
3008+
} else {
3009+
llvm::consumeError(overriddenOrError.takeError());
3010+
// There's one case where we know it's safe to ignore a missing override:
3011+
// if this declaration is '@objc' and 'dynamic'.
3012+
bool canIgnoreMissingOverriddenDecl = false;
3013+
if (isObjC && ctx.LangOpts.EnableDeserializationRecovery) {
3014+
canIgnoreMissingOverriddenDecl =
3015+
std::any_of(DeclAttributes::iterator(DAttrs),
3016+
DeclAttributes::iterator(nullptr),
3017+
[](const DeclAttribute *attr) -> bool {
3018+
return isa<DynamicAttr>(attr);
3019+
});
3020+
}
3021+
if (!canIgnoreMissingOverriddenDecl)
3022+
return llvm::make_error<OverrideError>(name, errorFlags);
3023+
3024+
overridden = nullptr;
30033025
}
30043026

30053027
for (TypeID dependencyID : dependencyIDs) {
@@ -3090,7 +3112,7 @@ class swift::DeclDeserializer {
30903112
if (auto bodyText = MF.maybeReadInlinableBodyText())
30913113
fn->setBodyStringRepresentation(*bodyText);
30923114

3093-
fn->setOverriddenDecl(cast_or_null<FuncDecl>(overridden.get()));
3115+
fn->setOverriddenDecl(cast_or_null<FuncDecl>(overridden));
30943116
if (fn->getOverriddenDecl())
30953117
AddAttribute(new (ctx) OverrideAttr(SourceLoc()));
30963118

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@interface Base
2+
@end
3+
4+
@interface Parent : Base
5+
- (nonnull instancetype)init __attribute__((objc_designated_initializer));
6+
7+
// The SECRET is on a non-secret property here because we need to enforce that
8+
// it's not printed.
9+
@property (readonly, strong, nullable) Parent *redefinedPropSECRET;
10+
@end
11+
12+
@interface GenericParent<T: Base *> : Base
13+
- (nonnull instancetype)init __attribute__((objc_designated_initializer));
14+
@end
15+
16+
@interface SubscriptParent : Base
17+
- (nullable Parent *)objectAtIndexedSubscript:(int)index;
18+
@end
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#import <FooKit.h>
2+
3+
@interface Parent ()
4+
- (nonnull instancetype)initWithSECRET:(int)secret __attribute__((objc_designated_initializer, swift_name("init(SECRET:)")));
5+
6+
- (void)methodSECRET;
7+
8+
@property (readonly, strong, nullable) Parent *roPropSECRET;
9+
@property (readwrite, strong, nullable) Parent *rwPropSECRET;
10+
11+
- (nullable Parent *)objectAtIndexedSubscript:(int)index;
12+
13+
@property (readwrite, strong, nullable) Parent *redefinedPropSECRET;
14+
@end
15+
16+
@protocol MandatorySecrets
17+
- (nonnull instancetype)initWithRequiredSECRET:(int)secret;
18+
@end
19+
20+
@interface Parent () <MandatorySecrets>
21+
- (nonnull instancetype)initWithRequiredSECRET:(int)secret __attribute__((objc_designated_initializer));
22+
@end
23+
24+
@interface GenericParent<T: Base *> ()
25+
@property (readonly, strong, nullable) T roPropSECRET;
26+
- (nullable Parent *)objectAtIndexedSubscript:(int)index;
27+
@end
28+
29+
@interface SubscriptParent ()
30+
- (void)setObject:(nullable Parent *)object atIndexedSubscript:(int)index;
31+
@end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module FooKit {
2+
header "FooKit.h"
3+
export *
4+
}
5+
6+
module FooKit_SECRET {
7+
header "FooKit_SECRET.h"
8+
export *
9+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module-path %t/Library.swiftmodule -I %S/Inputs/implementation-only-override -enable-library-evolution -enable-objc-interop -module-name Library %s
3+
// RUN: %target-swift-ide-test -print-module -module-to-print=Library -I %t -I %S/Inputs/implementation-only-override -source-filename=x -access-filter-public -enable-objc-interop > %t/Library.txt
4+
// RUN: %FileCheck %s < %t/Library.txt
5+
6+
// CHECK: import FooKit
7+
// CHECK: import FooKit_SECRET
8+
9+
import FooKit
10+
@_implementationOnly import FooKit_SECRET
11+
12+
// CHECK-LABEL: class GoodChild : Parent {
13+
// CHECK-NEXT: override init()
14+
// CHECK-NEXT: /* placeholder for init(SECRET:) */
15+
// CHECK-NEXT: /* placeholder for init(requiredSECRET:) */
16+
// CHECK-NEXT: @_implementationOnly func methodSECRET()
17+
// CHECK-NEXT: @_implementationOnly override var redefinedPropSECRET: Parent?
18+
// CHECK-NEXT: }
19+
public class GoodChild: Parent {
20+
public override init() { super.init() }
21+
// FIXME: @_implementationOnly on an initializer doesn't exactly make sense,
22+
// since they're not inherited.
23+
@_implementationOnly public override init(SECRET: Int32) { super.init() }
24+
@_implementationOnly public required init(requiredSECRET: Int32) { super.init() }
25+
26+
@_implementationOnly public override func methodSECRET() {}
27+
@_implementationOnly public override var roPropSECRET: Parent? { nil }
28+
@_implementationOnly public override var rwPropSECRET: Parent? {
29+
get { nil }
30+
set {}
31+
}
32+
@_implementationOnly public override subscript(_ index: Int32) -> Parent? { nil }
33+
@_implementationOnly public override var redefinedPropSECRET: Parent? {
34+
get { nil }
35+
set {}
36+
}
37+
}
38+
39+
// CHECK-LABEL: class GoodGenericChild<Toy> : Parent {
40+
// CHECK-NEXT: override init()
41+
// CHECK-NEXT: /* placeholder for init(SECRET:) */
42+
// CHECK-NEXT: /* placeholder for init(requiredSECRET:) */
43+
// CHECK-NEXT: @_implementationOnly func methodSECRET()
44+
// CHECK-NEXT: @_implementationOnly override var redefinedPropSECRET: Parent?
45+
// CHECK-NEXT: }
46+
public class GoodGenericChild<Toy>: Parent {
47+
public override init() { super.init() }
48+
// FIXME: @_implementationOnly on an initializer doesn't exactly make sense,
49+
// since they're not inherited.
50+
@_implementationOnly public override init(SECRET: Int32) { super.init() }
51+
@_implementationOnly public required init(requiredSECRET: Int32) { super.init() }
52+
53+
@_implementationOnly public override func methodSECRET() {}
54+
@_implementationOnly public override var roPropSECRET: Parent? { nil }
55+
@_implementationOnly public override var rwPropSECRET: Parent? {
56+
get { nil }
57+
set {}
58+
}
59+
@_implementationOnly public override subscript(_ index: Int32) -> Parent? { nil }
60+
@_implementationOnly public override var redefinedPropSECRET: Parent? {
61+
get { nil }
62+
set {}
63+
}
64+
}
65+
66+
// CHECK-LABEL: class QuietChild : Parent {
67+
// CHECK-NEXT: /* placeholder for init(SECRET:) */
68+
// CHECK-NEXT: /* placeholder for init(requiredSECRET:) */
69+
// CHECK-NEXT: }
70+
public class QuietChild: Parent {
71+
internal override init() { super.init() }
72+
internal override init(SECRET: Int32) { super.init() }
73+
internal required init(requiredSECRET: Int32) { super.init() }
74+
}
75+
76+
internal class PrivateChild: Parent {
77+
override func methodSECRET() {}
78+
override var roPropSECRET: Parent? { nil }
79+
override var rwPropSECRET: Parent? {
80+
get { nil }
81+
set {}
82+
}
83+
override subscript(_ index: Int32) -> Parent? { nil }
84+
override var redefinedPropSECRET: Parent? {
85+
get { nil }
86+
set {}
87+
}
88+
}
89+
90+
internal class PrivateGrandchild: GoodChild {
91+
override func methodSECRET() {}
92+
override var roPropSECRET: Parent? { nil }
93+
override var rwPropSECRET: Parent? {
94+
get { nil }
95+
set {}
96+
}
97+
override subscript(_ index: Int32) -> Parent? { nil }
98+
override var redefinedPropSECRET: Parent? {
99+
get { nil }
100+
set {}
101+
}
102+
}
103+
104+
// CHECK-LABEL: class SubscriptChild : SubscriptParent {
105+
// CHECK-NEXT: @_implementationOnly override subscript(index: Int32) -> Parent?
106+
// CHECK-NEXT: }
107+
public class SubscriptChild: SubscriptParent {
108+
@_implementationOnly public override subscript(_ index: Int32) -> Parent? {
109+
get { nil }
110+
set {}
111+
}
112+
}

test/Serialization/Recovery/overrides.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,15 @@ public class A_Sub2: A_Sub {
9494
// CHECK-NEXT: {{^}$}}
9595

9696
// CHECK-RECOVERY-LABEL: class A_Sub : Base {
97+
// CHECK-RECOVERY-NEXT: func disappearingMethod()
98+
// CHECK-RECOVERY-NEXT: func nullabilityChangeMethod() -> Any?
99+
// CHECK-RECOVERY-NEXT: func typeChangeMethod() -> Any
100+
// CHECK-RECOVERY-NEXT: func disappearingMethodWithOverload()
97101
// CHECK-RECOVERY-NEXT: init()
98102
// CHECK-RECOVERY-NEXT: {{^}$}}
99103

100104
// CHECK-RECOVERY-LABEL: class A_Sub2 : A_Sub {
105+
// CHECK-RECOVERY-NEXT: func disappearingMethod()
101106
// CHECK-RECOVERY-NEXT: init()
102107
// CHECK-RECOVERY-NEXT: {{^}$}}
103108

@@ -119,6 +124,9 @@ public class B_GenericSub : GenericBase<Base> {
119124
// CHECK-NEXT: {{^}$}}
120125

121126
// CHECK-RECOVERY-LABEL: class B_GenericSub : GenericBase<Base> {
127+
// CHECK-RECOVERY-NEXT: func disappearingMethod()
128+
// CHECK-RECOVERY-NEXT: func nullabilityChangeMethod() -> Base?
129+
// CHECK-RECOVERY-NEXT: func typeChangeMethod() -> Any
122130
// CHECK-RECOVERY-NEXT: init()
123131
// CHECK-RECOVERY-NEXT: {{^}$}}
124132

0 commit comments

Comments
 (0)