Skip to content

Commit 20a023b

Browse files
authored
Merge pull request #6419 from jrose-apple/keep-properties-and-accessors-on-the-same-page
Don't infer 'dynamic' on accessors in extensions of ObjC classes.
2 parents 6a34ba5 + 2660cfc commit 20a023b

File tree

2 files changed

+41
-11
lines changed

2 files changed

+41
-11
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,6 +2275,12 @@ static void inferDynamic(ASTContext &ctx, ValueDecl *D) {
22752275
if (VD->isLet() && !isNSManaged) return;
22762276
}
22772277

2278+
// Accessors should not infer 'dynamic' on their own; they can get it from
2279+
// their storage decls.
2280+
if (auto FD = dyn_cast<FuncDecl>(D))
2281+
if (FD->isAccessor())
2282+
return;
2283+
22782284
// The presence of 'final' on a class prevents 'dynamic'.
22792285
auto classDecl = D->getDeclContext()->getAsClassOrClassExtensionContext();
22802286
if (!classDecl) return;
@@ -3859,6 +3865,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
38593865
if (isObjC && !TC.isRepresentableInObjC(SD, *isObjC))
38603866
isObjC = None;
38613867
markAsObjC(TC, SD, isObjC);
3868+
3869+
// Infer 'dynamic' before touching accessors.
3870+
inferDynamic(TC.Context, SD);
38623871
}
38633872

38643873
if (SD->hasAccessorFunctions())
@@ -3887,8 +3896,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
38873896
synthesizeSetterForMutableAddressedStorage(SD, TC);
38883897
}
38893898

3890-
inferDynamic(TC.Context, SD);
3891-
38923899
TC.checkDeclAttributes(SD);
38933900
}
38943901

@@ -4819,21 +4826,18 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
48194826
// The only additional condition we need to check is if the var decl
48204827
// had an @objc or @iboutlet property.
48214828

4822-
ValueDecl *prop = cast<ValueDecl>(FD->getAccessorStorageDecl());
4829+
AbstractStorageDecl *storage = FD->getAccessorStorageDecl();
48234830
// Validate the subscript or property because it might not be type
48244831
// checked yet.
4825-
if (isa<SubscriptDecl>(prop))
4826-
TC.validateDecl(prop);
4827-
else if (isa<VarDecl>(prop))
4828-
TC.validateDecl(prop);
4832+
TC.validateDecl(storage);
48294833

4830-
if (prop->getAttrs().hasAttribute<NonObjCAttr>())
4834+
if (storage->getAttrs().hasAttribute<NonObjCAttr>())
48314835
isObjC = None;
4832-
else if (!isObjC && prop->isObjC())
4836+
else if (!isObjC && storage->isObjC())
48334837
isObjC = ObjCReason::DoNotDiagnose;
48344838

4835-
// If the property is dynamic, propagate to this accessor.
4836-
if (isObjC && prop->isDynamic() && !FD->isDynamic())
4839+
// If the storage is dynamic, propagate to this accessor.
4840+
if (isObjC && storage->isDynamic() && !FD->isDynamic())
48374841
FD->getAttrs().add(new (TC.Context) DynamicAttr(/*implicit*/ true));
48384842
}
48394843

@@ -7065,6 +7069,7 @@ void TypeChecker::validateDecl(ValueDecl *D) {
70657069

70667070
markAsObjC(*this, VD, isObjC);
70677071

7072+
// Infer 'dynamic' before touching accessors.
70687073
inferDynamic(Context, VD);
70697074

70707075
// If this variable is a class member, mark it final if the

test/attr/attr_dynamic_infer.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,28 @@ extension Sub {
5454
override func baseFoo() {
5555
}
5656
}
57+
58+
59+
@objc class FinalTests {}
60+
61+
extension FinalTests {
62+
// CHECK: @objc final func foo
63+
final func foo() { }
64+
65+
// CHECK: @objc final var prop: Super
66+
final var prop: Super {
67+
// CHECK: @objc final get
68+
get { return Super() }
69+
// CHECK: @objc final set
70+
set { }
71+
}
72+
73+
// CHECK: @objc final subscript(sup: Super) -> Super
74+
final subscript(sup: Super) -> Super {
75+
// CHECK: @objc final get
76+
get { return sup }
77+
// CHECK: @objc final set
78+
set { }
79+
}
80+
}
81+

0 commit comments

Comments
 (0)