Skip to content

Commit 1b863d6

Browse files
committed
Allow final on dynamic members
Dynamic is about dynamically replacing a method implementiation not overriding. rdar://49535048
1 parent 0205150 commit 1b863d6

File tree

5 files changed

+28
-3
lines changed

5 files changed

+28
-3
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,10 @@ void AttributeEarlyChecker::visitMutationAttr(DeclAttribute *attr) {
324324

325325
void AttributeEarlyChecker::visitDynamicAttr(DynamicAttr *attr) {
326326
// Members cannot be both dynamic and final.
327-
if (D->getAttrs().hasAttribute<FinalAttr>())
327+
// We do allow dynamic final members for dynamic replacement in
328+
// swift-version 5.
329+
if (D->getAttrs().hasAttribute<FinalAttr>() &&
330+
!D->getASTContext().LangOpts.isSwiftVersionAtLeast(5))
328331
diagnoseAndRemoveAttr(attr, diag::dynamic_with_final);
329332

330333
// Members cannot be both dynamic and @nonobjc.
@@ -2590,8 +2593,12 @@ void TypeChecker::addImplicitDynamicAttribute(Decl *D) {
25902593
isa<AccessorDecl>(D))
25912594
return;
25922595

2593-
if (D->getAttrs().hasAttribute<FinalAttr>() ||
2594-
D->getAttrs().hasAttribute<NonObjCAttr>() ||
2596+
// Don't add implicit dynamic to final functions before swift-version 5.
2597+
if (D->getAttrs().hasAttribute<FinalAttr>() &&
2598+
!D->getASTContext().LangOpts.isSwiftVersionAtLeast(5))
2599+
return;
2600+
2601+
if (D->getAttrs().hasAttribute<NonObjCAttr>() ||
25952602
D->getAttrs().hasAttribute<TransparentAttr>() ||
25962603
D->getAttrs().hasAttribute<InlinableAttr>())
25972604
return;

test/Interpreter/Inputs/dynamic_replacement_module.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public class PublicClass {
1717
public dynamic func function() -> String {
1818
return "public_class_func"
1919
}
20+
public dynamic final func finalFunction() -> String {
21+
return "public_class_final_func"
22+
}
2023
public dynamic func genericFunction<T>(_ t: T.Type) -> String {
2124
return "public_class_generic_func"
2225
}
@@ -84,6 +87,11 @@ public class PublicClass {
8487
public func function() -> String {
8588
return "public_class_func"
8689
}
90+
91+
public final func finalFunction() -> String {
92+
return "public_class_final_func"
93+
}
94+
8795
public func genericFunction<T>(_ t: T.Type) -> String {
8896
return "public_class_generic_func"
8997
}
@@ -163,6 +171,10 @@ extension PublicClass {
163171
public func replacement_function() -> String {
164172
return "replacement of " + function()
165173
}
174+
@_dynamicReplacement(for: finalFunction())
175+
public func replacement_finalFunction() -> String {
176+
return "replacement of " + finalFunction()
177+
}
166178
@_dynamicReplacement(for: genericFunction(_:))
167179
public func replacement_genericFunction<T>(_ t: T.Type) -> String {
168180
return "replacement of " + genericFunction(t)

test/Interpreter/dynamic_replacement.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ func checkExpectedResults(forOriginalLibrary useOrig: Bool) {
8484

8585
expectTrue(PublicClass().function() ==
8686
expectedResult(useOrig, "public_class_func"))
87+
expectTrue(PublicClass().finalFunction() ==
88+
expectedResult(useOrig, "public_class_final_func"))
8789
expectTrue(PublicClass().genericFunction(Int.self) ==
8890
expectedResult(useOrig, "public_class_generic_func"))
8991

test/attr/Inputs/dynamicReplacementC.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ public extension TheReplaceables {
1111
public class K {
1212
public init(i: Int) {}
1313
public convenience init(c : Int) { self.init(i : c) }
14+
public final func finalFunction() {}
1415
}

test/attr/dynamicReplacement.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ extension K {
4545

4646
@_dynamicReplacement(for: init(c:)) // expected-error{{replaced constructor 'init(c:)' is marked as convenience}})
4747
init(rc: Int) { }
48+
49+
@_dynamicReplacement(for:finalFunction())
50+
func replacement_finalFunction() {}
4851
}
4952

5053
extension undeclared { // expected-error{{use of undeclared type 'undeclared'}}

0 commit comments

Comments
 (0)