From 29c1fc472b62913d5b95a5b7655061483f340634 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 9 Mar 2017 14:18:39 -0500 Subject: [PATCH 1/3] Generate an error message on protocol extensions with the final attribute. --- include/swift/AST/DiagnosticsSema.def | 3 + lib/Sema/TypeCheckAttr.cpp | 30 ++-- stdlib/public/SDK/Foundation/NSError.swift | 12 +- .../final_protocol_extension.swift | 8 ++ test/Generics/existential_restrictions.swift | 2 +- test/IRGen/protocol_extensions.sil | 4 +- .../IRGen/protocol_extensions_constrain.swift | 2 +- test/Interpreter/protocol_extensions.swift | 20 +-- test/NameBinding/reference-dependencies.swift | 4 +- test/NameBinding/scope_map_lookup.swift | 4 +- test/SILGen/boxed_existentials.swift | 2 +- test/SILGen/guaranteed_self.swift | 2 +- test/SILGen/protocol_extensions.swift | 20 +-- test/SILGen/witnesses_canonical.swift | 2 +- test/SILOptimizer/devirt_extension.swift | 2 +- test/Serialization/Inputs/def_class.swift | 4 +- test/SourceKit/DocSupport/Inputs/cake.swift | 2 +- test/attr/attr_final.swift | 37 ++--- test/attr/attr_objc.swift | 14 +- test/decl/ext/protocol.swift | 134 +++++++++--------- test/decl/ext/protocol_objc.swift | 2 +- .../req/associated_type_inference.swift | 8 +- test/decl/var/properties.swift | 4 +- 23 files changed, 171 insertions(+), 151 deletions(-) create mode 100644 test/Compatibility/final_protocol_extension.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 39302b03ce153..eb39d6b0b6f42 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1988,6 +1988,9 @@ ERROR(override_static,none, ERROR(member_cannot_be_final,none, "only classes and class members may be marked with 'final'", ()) +WARNING(protocol_extension_cannot_be_final,none, + "functions in a protocol extension do not need to be marked with 'final'", + ()) ERROR(final_not_allowed_here,none, "'final' may only be applied to classes, properties, methods, and " diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index d8169a2b41ce2..90e94bf48deb6 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -182,15 +182,21 @@ class AttributeEarlyChecker : public AttributeVisitor { if (isa(D)) return; - // 'final' only makes sense in the context of a class - // declaration or a protocol extension. Reject it on global functions, - // structs, enums, etc. - if (D->getDeclContext()->getAsProtocolExtensionContext()) { - // Accept and remove the 'final' attribute from members of protocol - // extensions. - D->getAttrs().removeAttribute(attr); - } else if (!D->getDeclContext()->getAsClassOrClassExtensionContext()) { - diagnoseAndRemoveAttr(attr, diag::member_cannot_be_final); + // 'final' only makes sense in the context of a class declaration. + // Reject it on global functions, protocols, structs, enums, etc. + if (!D->getDeclContext()->getAsClassOrClassExtensionContext()) { + if (TC.Context.isSwiftVersion3() && + D->getDeclContext()->getAsProtocolExtensionContext()) + TC.diagnose(attr->getLocation(), + diag::protocol_extension_cannot_be_final) + .fixItRemove(attr->getRange()); + else + TC.diagnose(attr->getLocation(), diag::member_cannot_be_final) + .fixItRemove(attr->getRange()); + + // Invalidate the attribute so child declarations are not flagged as final + // and duplicate the error message. + attr->setInvalid(); return; } } @@ -1008,7 +1014,8 @@ void AttributeChecker::visitFinalAttr(FinalAttr *attr) { // We currently only support final on var/let, func and subscript // declarations. if (!isa(D) && !isa(D) && !isa(D)) { - TC.diagnose(attr->getLocation(), diag::final_not_allowed_here); + TC.diagnose(attr->getLocation(), diag::final_not_allowed_here) + .fixItRemove(attr->getRange()); return; } @@ -1017,7 +1024,8 @@ void AttributeChecker::visitFinalAttr(FinalAttr *attr) { unsigned Kind = 2; if (auto *VD = dyn_cast(FD->getAccessorStorageDecl())) Kind = VD->isLet() ? 1 : 0; - TC.diagnose(attr->getLocation(), diag::final_not_on_accessors, Kind); + TC.diagnose(attr->getLocation(), diag::final_not_on_accessors, Kind) + .fixItRemove(attr->getRange()); return; } } diff --git a/stdlib/public/SDK/Foundation/NSError.swift b/stdlib/public/SDK/Foundation/NSError.swift index 4fb745c140e54..7f6dbc94c29af 100644 --- a/stdlib/public/SDK/Foundation/NSError.swift +++ b/stdlib/public/SDK/Foundation/NSError.swift @@ -380,8 +380,8 @@ extension __BridgedNSError public extension __BridgedNSError where Self: RawRepresentable, Self.RawValue: SignedInteger { - public final var _domain: String { return Self._nsErrorDomain } - public final var _code: Int { return Int(rawValue.toIntMax()) } + public var _domain: String { return Self._nsErrorDomain } + public var _code: Int { return Int(rawValue.toIntMax()) } public init?(rawValue: RawValue) { self = unsafeBitCast(rawValue, to: Self.self) @@ -395,7 +395,7 @@ public extension __BridgedNSError self.init(rawValue: RawValue(IntMax(_bridgedNSError.code))) } - public final var hashValue: Int { return _code } + public var hashValue: Int { return _code } } // Allow two bridged NSError types to be compared. @@ -408,8 +408,8 @@ extension __BridgedNSError public extension __BridgedNSError where Self: RawRepresentable, Self.RawValue: UnsignedInteger { - public final var _domain: String { return Self._nsErrorDomain } - public final var _code: Int { + public var _domain: String { return Self._nsErrorDomain } + public var _code: Int { return Int(bitPattern: UInt(rawValue.toUIntMax())) } @@ -425,7 +425,7 @@ public extension __BridgedNSError self.init(rawValue: RawValue(UIntMax(UInt(_bridgedNSError.code)))) } - public final var hashValue: Int { return _code } + public var hashValue: Int { return _code } } /// Describes a raw representable type that is bridged to a particular diff --git a/test/Compatibility/final_protocol_extension.swift b/test/Compatibility/final_protocol_extension.swift new file mode 100644 index 0000000000000..00e116446c158 --- /dev/null +++ b/test/Compatibility/final_protocol_extension.swift @@ -0,0 +1,8 @@ +// RUN: %target-typecheck-verify-swift -swift-version 3 +// Generate a swift 3 compatible warning if final is specified in an extension + +protocol P {} + +extension P { + final func inExtension() {} // expected-warning{{functions in a protocol extension do not need to be marked with 'final'}} {{3-9=}} +} diff --git a/test/Generics/existential_restrictions.swift b/test/Generics/existential_restrictions.swift index e054d06065f8c..0e9e1c38169ef 100644 --- a/test/Generics/existential_restrictions.swift +++ b/test/Generics/existential_restrictions.swift @@ -73,7 +73,7 @@ protocol Mine {} class M1: Mine {} class M2: Mine {} extension Collection where Iterator.Element : Mine { - final func takeAll() {} + func takeAll() {} } func foo() { diff --git a/test/IRGen/protocol_extensions.sil b/test/IRGen/protocol_extensions.sil index 2bd52c19a4405..d196ca6a7c0f7 100644 --- a/test/IRGen/protocol_extensions.sil +++ b/test/IRGen/protocol_extensions.sil @@ -9,8 +9,8 @@ public protocol P1 { } extension P1 { - final func extP1a() - public final func extP1b() + func extP1a() + public func extP1b() } // CHECK-LABEL: define hidden swiftcc void @_TFP19protocol_extensions2P16extP1aUS0___fQPS0_FT_T_ diff --git a/test/IRGen/protocol_extensions_constrain.swift b/test/IRGen/protocol_extensions_constrain.swift index 9d9305975bbba..da4351012b5bf 100644 --- a/test/IRGen/protocol_extensions_constrain.swift +++ b/test/IRGen/protocol_extensions_constrain.swift @@ -27,7 +27,7 @@ public struct C2 : P2 { } extension P2 where Self.Index : P3 { - final public var bar: Bool { + public var bar: Bool { let i = startIndex return i.foo(i) } diff --git a/test/Interpreter/protocol_extensions.swift b/test/Interpreter/protocol_extensions.swift index c21a17c26ef5d..f31b55f566ed7 100644 --- a/test/Interpreter/protocol_extensions.swift +++ b/test/Interpreter/protocol_extensions.swift @@ -3,7 +3,7 @@ // Extend a protocol with a property. extension Sequence { - final var myCount: Int { + var myCount: Int { var result = 0 for _ in self { result += 1 @@ -17,7 +17,7 @@ print(["a", "b", "c", "d"].myCount) // Extend a protocol with a function. extension Collection { - final var myIndices: Range { + var myIndices: Range { return startIndex.. EnumeratedSequence { + public func myEnumerated() -> EnumeratedSequence { return self.enumerated() } } @@ -43,7 +43,7 @@ for (index, element) in ["a", "b", "c"].myEnumerated() { } extension Sequence { - final public func myReduce( + public func myReduce( _ initial: T, combine: (T, Self.Iterator.Element) -> T ) -> T { var result = initial @@ -59,7 +59,7 @@ print([1, 2, 3, 4, 5].myReduce(0, combine: +)) extension Sequence { - final public func myZip(_ s: S) -> Zip2Sequence { + public func myZip(_ s: S) -> Zip2Sequence { return Zip2Sequence(_sequence1: self, _sequence2: s) } } @@ -75,14 +75,14 @@ for (a, b) in [1, 2, 3].myZip(["a", "b", "c"]) { extension MutableCollection where Self: RandomAccessCollection, Self.Iterator.Element : Comparable { - public final mutating func myPartition() -> Index { + public mutating func myPartition() -> Index { let first = self.first return self.partition(by: { $0 >= first! }) } } extension RangeReplaceableCollection { - public final func myJoin( + public func myJoin( _ elements: S ) -> Self { var result = Self() @@ -107,7 +107,7 @@ print( // Constrained extensions for specific types. extension Collection where Self.Iterator.Element == String { - final var myCommaSeparatedList: String { + var myCommaSeparatedList: String { if startIndex == endIndex { return "" } var result = "" @@ -133,7 +133,7 @@ protocol ExistP1 { } extension ExistP1 { - final func runExistP1() { + func runExistP1() { print("runExistP1") self.existP1() } @@ -167,7 +167,7 @@ protocol P { } extension P { - final var extValue: Bool { + var extValue: Bool { get { return getValue() } set(newValue) { setValue(newValue) } } diff --git a/test/NameBinding/reference-dependencies.swift b/test/NameBinding/reference-dependencies.swift index d652c10223f12..63407c857e8f5 100644 --- a/test/NameBinding/reference-dependencies.swift +++ b/test/NameBinding/reference-dependencies.swift @@ -107,12 +107,12 @@ typealias MyArray = Array // CHECK-DAG: "ExpressibleByArrayLiteral" extension ExpressibleByArrayLiteral { - final func useless() {} + func useless() {} } // CHECK-DAG: OtherFileElementType extension ExpressibleByArrayLiteral where Element == OtherFileElementType { - final func useless2() {} + func useless2() {} } // CHECK-DAG: "IntegerLiteralType" diff --git a/test/NameBinding/scope_map_lookup.swift b/test/NameBinding/scope_map_lookup.swift index e932fd0e1fcf3..102ff1f860d7f 100644 --- a/test/NameBinding/scope_map_lookup.swift +++ b/test/NameBinding/scope_map_lookup.swift @@ -73,14 +73,14 @@ class Superclass { protocol PConstrained4 { } extension PConstrained4 where Self : Superclass { - final func testFoo() -> Foo { + func testFoo() -> Foo { foo() self.foo() return Foo(5) } - final static func testBar() { + static func testBar() { bar() self.bar() } diff --git a/test/SILGen/boxed_existentials.swift b/test/SILGen/boxed_existentials.swift index 1a600bf886cb7..d94652cfc4f76 100644 --- a/test/SILGen/boxed_existentials.swift +++ b/test/SILGen/boxed_existentials.swift @@ -98,7 +98,7 @@ func test_property_of_lvalue(_ x: Error) -> String { // CHECK: return [[RESULT]] // CHECK: } // end sil function '_T018boxed_existentials23test_property_of_lvalueSSs5Error_pF' extension Error { - final func extensionMethod() { } + func extensionMethod() { } } // CHECK-LABEL: sil hidden @_T018boxed_existentials21test_extension_methodys5Error_pF diff --git a/test/SILGen/guaranteed_self.swift b/test/SILGen/guaranteed_self.swift index 0e6a54c79ebc7..a04374dd926a2 100644 --- a/test/SILGen/guaranteed_self.swift +++ b/test/SILGen/guaranteed_self.swift @@ -445,7 +445,7 @@ public protocol SequenceDefaults { } extension SequenceDefaults { - public final func _constrainElement(_: FakeGenerator.Element) {} + public func _constrainElement(_: FakeGenerator.Element) {} } public protocol Sequence : SequenceDefaults { diff --git a/test/SILGen/protocol_extensions.swift b/test/SILGen/protocol_extensions.swift index 5dd217367f4cc..4d2ab9ab86c0b 100644 --- a/test/SILGen/protocol_extensions.swift +++ b/test/SILGen/protocol_extensions.swift @@ -12,7 +12,7 @@ struct Box { extension P1 { // CHECK-LABEL: sil hidden @_T019protocol_extensions2P1PAAE6extP1a{{[_0-9a-zA-Z]*}}F : $@convention(method) (@in_guaranteed Self) -> () { // CHECK: bb0([[SELF:%[0-9]+]] : $*Self): - final func extP1a() { + func extP1a() { // CHECK: [[WITNESS:%[0-9]+]] = witness_method $Self, #P1.reqP1a!1 : {{.*}} : $@convention(witness_method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> () // CHECK-NEXT: apply [[WITNESS]]([[SELF]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> () reqP1a() @@ -21,7 +21,7 @@ extension P1 { // CHECK-LABEL: sil @_T019protocol_extensions2P1PAAE6extP1b{{[_0-9a-zA-Z]*}}F : $@convention(method) (@in_guaranteed Self) -> () { // CHECK: bb0([[SELF:%[0-9]+]] : $*Self): - public final func extP1b() { + public func extP1b() { // CHECK: [[FN:%[0-9]+]] = function_ref @_T019protocol_extensions2P1PAAE6extP1a{{[_0-9a-zA-Z]*}}F : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> () // CHECK-NEXT: apply [[FN]]([[SELF]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> () extP1a() @@ -36,7 +36,7 @@ extension P1 { set {} } - final func callSubscript() -> Int { + func callSubscript() -> Int { // But here we have to do a witness method call: // CHECK-LABEL: sil hidden @_T019protocol_extensions2P1PAAE13callSubscript{{[_0-9a-zA-Z]*}}F @@ -474,24 +474,24 @@ func testG(_ m: GenericMetaHolder, gg: G.Type) { // Using protocol extension members with existentials // ---------------------------------------------------------------------------- extension P1 { - final func f1() { } + func f1() { } - final subscript (i: Int64) -> Bool { + subscript (i: Int64) -> Bool { get { return true } } - final var prop: Bool { + var prop: Bool { get { return true } } - final func returnsSelf() -> Self { return self } + func returnsSelf() -> Self { return self } - final var prop2: Bool { + var prop2: Bool { get { return true } set { } } - final subscript (b: Bool) -> Bool { + subscript (b: Bool) -> Bool { get { return b } set { } } @@ -641,7 +641,7 @@ func test_open_existential_semantics_opaque(_ guaranteed: P1, protocol CP1: class {} extension CP1 { - final func f1() { } + func f1() { } } func plusOneCP1() -> CP1 {} diff --git a/test/SILGen/witnesses_canonical.swift b/test/SILGen/witnesses_canonical.swift index a23d0f9c9b612..620c66deb2659 100644 --- a/test/SILGen/witnesses_canonical.swift +++ b/test/SILGen/witnesses_canonical.swift @@ -14,7 +14,7 @@ struct _S : CT { } extension _CDT { - final subscript(b: Int) -> _S { + subscript(b: Int) -> _S { return _S(a: self, b: b) } } diff --git a/test/SILOptimizer/devirt_extension.swift b/test/SILOptimizer/devirt_extension.swift index 1e4390c3194da..4c18fd4d924ed 100644 --- a/test/SILOptimizer/devirt_extension.swift +++ b/test/SILOptimizer/devirt_extension.swift @@ -3,7 +3,7 @@ protocol DrawingElementDispatch {} extension DrawingElementDispatch { - final var boundingBox: Int32 { + var boundingBox: Int32 { return 0 } } diff --git a/test/Serialization/Inputs/def_class.swift b/test/Serialization/Inputs/def_class.swift index cd8a875299222..8ad60ca83bee5 100644 --- a/test/Serialization/Inputs/def_class.swift +++ b/test/Serialization/Inputs/def_class.swift @@ -52,7 +52,7 @@ public protocol Resettable { } public extension Resettable { - final func doReset() { self.reset() } + func doReset() { self.reset() } } open class ResettableIntWrapper : Resettable { @@ -80,7 +80,7 @@ public protocol PairLike { } public extension PairLike where FirstType : Cacheable { - final func cacheFirst() { } + func cacheFirst() { } } public protocol ClassProto : class {} diff --git a/test/SourceKit/DocSupport/Inputs/cake.swift b/test/SourceKit/DocSupport/Inputs/cake.swift index 9c2851873635c..7b3411327e0e9 100644 --- a/test/SourceKit/DocSupport/Inputs/cake.swift +++ b/test/SourceKit/DocSupport/Inputs/cake.swift @@ -17,7 +17,7 @@ public class C1 : Prot { public func genfoo(x ix: T1, y iy: T2) where T1.Element == Int, T2.Element == T1.Element {} public extension Prot where Self.Element == Int { - final func extfoo() {} + func extfoo() {} } public enum MyEnum : Int { diff --git a/test/attr/attr_final.swift b/test/attr/attr_final.swift index f3c0921916039..393fe81ddbd53 100644 --- a/test/attr/attr_final.swift +++ b/test/attr/attr_final.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -swift-version 4 class Super { final var i: Int { get { return 5 } } // expected-note{{overridden declaration is here}} @@ -34,9 +34,26 @@ enum SomeEnum { final func f() {} // expected-error {{only classes and class members may be marked with 'final'}} } +protocol SomeProtocol { + final var i: Int { get } // expected-error {{only classes and class members may be marked with 'final'}} + final func protoFunc() // expected-error {{only classes and class members may be marked with 'final'}} {{3-9=}} +} + +extension SomeProtocol { + final var i: Int { return 1 } // expected-error {{only classes and class members may be marked with 'final'}} + final func protoExtensionFunc() {} // expected-error {{only classes and class members may be marked with 'final'}} {{3-9=}} +} + +extension SomeStruct { + final func structExtensionFunc() {} // expected-error {{only classes and class members may be marked with 'final'}} {{3-9=}} +} + +extension SomeEnum { + final func enumExtensionFunc() {} // expected-error {{only classes and class members may be marked with 'final'}} {{3-9=}} +} + extension Super { final func someClassMethod() {} // ok - } final func global_function() {} // expected-error {{only classes and class members may be marked with 'final'}} @@ -64,19 +81,3 @@ class Sub2 : Super2 { //// expected-error{{inheritance from a final class 'Super final override init() {} // expected-error {{'final' modifier cannot be applied to this declaration}} {{3-9=}} } - -protocol SomeProtocol { - final var i: Int { get } // expected-error {{only classes and class members may be marked with 'final'}} - final func f() // expected-error {{only classes and class members may be marked with 'final'}} -} - -extension SomeProtocol { - final var i: Int { return 1 } // Ok, ignored. - final func f() {} // Ok, ignored. -} - -// Just to make sure 'final' in protocol extension doesn't prevent concrete implementation. -class TestC_SomeProtocol : SomeProtocol { - var i: Int { return 42 } - func f() {} -} diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index 8e40fe22bf253..b22006e3f3b19 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -1934,22 +1934,22 @@ class Load1 { // Members of protocol extensions cannot be @objc extension PlainProtocol { - @objc final var property: Int { return 5 } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} - @objc final subscript(x: Int) -> Class_ObjC1 { return Class_ObjC1() } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} - @objc final func fun() { } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} + @objc var property: Int { return 5 } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} + @objc subscript(x: Int) -> Class_ObjC1 { return Class_ObjC1() } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} + @objc func fun() { } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} } extension Protocol_ObjC1 { - @objc final var property: Int { return 5 } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} - @objc final subscript(x: Int) -> Class_ObjC1 { return Class_ObjC1() } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} - @objc final func fun() { } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} + @objc var property: Int { return 5 } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} + @objc subscript(x: Int) -> Class_ObjC1 { return Class_ObjC1() } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} + @objc func fun() { } // expected-error{{@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes}} } extension Protocol_ObjC1 { // Don't infer @objc for extensions of @objc protocols. // CHECK: {{^}} var propertyOK: Int - final var propertyOK: Int { return 5 } + var propertyOK: Int { return 5 } } //===--- diff --git a/test/decl/ext/protocol.swift b/test/decl/ext/protocol.swift index 946a0105f592c..0693b7de93696 100644 --- a/test/decl/ext/protocol.swift +++ b/test/decl/ext/protocol.swift @@ -9,13 +9,13 @@ protocol P1 { } extension P1 { - final func extP1a() -> Bool { return !reqP1a() } + func extP1a() -> Bool { return !reqP1a() } - final var extP1b: Bool { + var extP1b: Bool { return self.reqP1a() } - final var extP1c: Bool { + var extP1c: Bool { return extP1b && self.extP1a() } } @@ -27,13 +27,13 @@ protocol P2 { } extension P2 { - final func extP2a() -> AssocP2? { return reqP2a() } + func extP2a() -> AssocP2? { return reqP2a() } - final func extP2b() { + func extP2b() { self.reqP2a().reqP1a() } - final func extP2c() -> Self.AssocP2 { return extP2a()! } + func extP2c() -> Self.AssocP2 { return extP2a()! } } protocol P3 { @@ -43,7 +43,7 @@ protocol P3 { } extension P3 { - final func extP3a() -> AssocP3.AssocP2 { + func extP3a() -> AssocP3.AssocP2 { return reqP3a().reqP2a() } } @@ -60,14 +60,14 @@ protocol P4 { func acceptsP1(_ t: T) { } extension P1 { - final func extP1d() { acceptsP1(self) } + func extP1d() { acceptsP1(self) } } func acceptsP2(_ t: T) { } extension P2 { - final func extP2acceptsP1() { acceptsP1(reqP2a()) } - final func extP2acceptsP2() { acceptsP2(self) } + func extP2acceptsP1() { acceptsP1(reqP2a()) } + func extP2acceptsP2() { acceptsP2(self) } } // Use of 'Self' as a return type within a protocol extension. @@ -83,7 +83,7 @@ func acceptSelfP1(_ t: T, _ u: U) -> T where U.AssocType == T { } extension SelfP1 { - final func tryAcceptSelfP1(_ z: Z)-> Self where Z.AssocType == Self { + func tryAcceptSelfP1(_ z: Z)-> Self where Z.AssocType == Self { return acceptSelfP1(self, z) } } @@ -126,7 +126,7 @@ protocol SubscriptP1 { } extension SubscriptP1 { - final subscript(i: Int) -> String { + subscript(i: Int) -> String { get { return readAt(i) } set(newValue) { writeAt(i, string: newValue) } } @@ -180,7 +180,7 @@ extension S1 { // Protocol extensions with additional requirements // ---------------------------------------------------------------------------- extension P4 where Self.AssocP4 : P1 { - final func extP4a() { // expected-note 2 {{found this candidate}} + func extP4a() { // expected-note 2 {{found this candidate}} acceptsP1(reqP4a()) } } @@ -207,11 +207,11 @@ struct S4d : P4 { } extension P4 where Self.AssocP4 == Int { - final func extP4Int() { } + func extP4Int() { } } extension P4 where Self.AssocP4 == Bool { - final func extP4a() -> Bool { return reqP4a() } // expected-note 2 {{found this candidate}} + func extP4a() -> Bool { return reqP4a() } // expected-note 2 {{found this candidate}} } func testP4(_ s4a: S4a, s4b: S4b, s4c: S4c, s4d: S4d) { @@ -234,7 +234,7 @@ protocol P5 { // extension of P5 provides a witness for P6 extension P5 { - final func reqP6a() { reqP5a() } + func reqP6a() { reqP5a() } } protocol P6 { @@ -285,7 +285,7 @@ protocol P8 { // extension of P8 provides conformance to P7Assoc extension P8 { - final func getP7Assoc() -> P7FromP8 { return P7FromP8() } + func getP7Assoc() -> P7FromP8 { return P7FromP8() } } // Okay, P7 requirements satisfied by P8 @@ -315,7 +315,7 @@ protocol PConforms1 { } extension PConforms1 { - final func pc2() { } // expected-note{{candidate exactly matches}} + func pc2() { } // expected-note{{candidate exactly matches}} } protocol PConforms2 : PConforms1, MakePC2Ambiguous { @@ -326,7 +326,7 @@ protocol MakePC2Ambiguous { } extension MakePC2Ambiguous { - final func pc2() { } // expected-note{{candidate exactly matches}} + func pc2() { } // expected-note{{candidate exactly matches}} } struct SConforms2a : PConforms2 { } // expected-error{{type 'SConforms2a' does not conform to protocol 'PConforms2'}} @@ -381,7 +381,7 @@ struct OtherIndexedIterator : IteratorProtocol { } extension _MyCollection { - final func myGenerate() -> MyIndexedIterator { + func myGenerate() -> MyIndexedIterator { return MyIndexedIterator(container: self, index: self.myEndIndex) } } @@ -420,7 +420,7 @@ func testSomeCollections(_ sc1: SomeCollection1, sc2: SomeCollection2) { public protocol PConforms3 {} extension PConforms3 { - final public var z: Int { + public var z: Int { return 0 } } @@ -440,7 +440,7 @@ protocol PConforms5 { protocol PConforms6 : PConforms5 {} extension PConforms6 { - final func f() -> Int { return 42 } + func f() -> Int { return 42 } } func test(_ x: T) -> Int { return x.f() } @@ -458,9 +458,9 @@ protocol PConforms7 { } extension PConforms7 { - final func method() { } - final var property: Int { return 5 } - final subscript (i: Int) -> Int { return i } + func method() { } + var property: Int { return 5 } + subscript (i: Int) -> Int { return i } } struct SConforms7a : PConforms7 { } @@ -474,9 +474,9 @@ protocol PConforms8 { } extension PConforms8 { - final func method() -> Int { return 5 } - final var property: Int { return 5 } - final subscript (i: Int) -> Int { return i } + func method() -> Int { return 5 } + var property: Int { return 5 } + subscript (i: Int) -> Int { return i } } struct SConforms8a : PConforms8 { } @@ -519,9 +519,9 @@ protocol PConforms9 { } extension PConforms9 { - final func method() -> Self.Assoc { return Assoc() } - final var property: Self.Assoc { return Assoc() } - final subscript (i: Self.Assoc) -> Self.Assoc { return Assoc() } + func method() -> Self.Assoc { return Assoc() } + var property: Self.Assoc { return Assoc() } + subscript (i: Self.Assoc) -> Self.Assoc { return Assoc() } } struct SConforms9a : PConforms9 { // expected-error{{type 'SConforms9a' does not conform to protocol 'PConforms9'}} @@ -559,7 +559,7 @@ func testSConforms9d(_ s9d: SConforms9d) { protocol PConforms10 {} extension PConforms10 { - final func f() {} + func f() {} } protocol PConforms11 { func f() @@ -602,7 +602,7 @@ protocol PTypeAliasSuper2 { } extension PTypeAliasSuper2 { - final func foo() -> TypeAliasHelper { return TypeAliasHelper() } + func foo() -> TypeAliasHelper { return TypeAliasHelper() } } protocol PTypeAliasSub2 : PTypeAliasSuper2 { @@ -648,19 +648,19 @@ protocol PInherit3 : PInherit2 { } protocol PInherit4 : PInherit2 { } extension PInherit1 { - final func order1() -> Int { return 0 } + func order1() -> Int { return 0 } } extension PInherit2 { - final func order1() -> Bool { return true } + func order1() -> Bool { return true } } extension PInherit3 { - final func order1() -> Double { return 1.0 } + func order1() -> Double { return 1.0 } } extension PInherit4 { - final func order1() -> String { return "hello" } + func order1() -> String { return "hello" } } struct SInherit1 : PInherit1 { } @@ -693,15 +693,15 @@ protocol PConstrained1 { } extension PConstrained1 { - final func pc1() -> Int { return 0 } + func pc1() -> Int { return 0 } } extension PConstrained1 where AssocTypePC1 : PInherit2 { - final func pc1() -> Bool { return true } + func pc1() -> Bool { return true } } extension PConstrained1 where Self.AssocTypePC1 : PInherit3 { - final func pc1() -> String { return "hello" } + func pc1() -> String { return "hello" } } struct SConstrained1 : PConstrained1 { @@ -739,11 +739,11 @@ protocol PConstrained3 : PConstrained2 { } extension PConstrained2 where Self.AssocTypePC2 : PInherit1 { - final func pc2() -> Bool { return true } + func pc2() -> Bool { return true } } extension PConstrained3 { - final func pc2() -> String { return "hello" } + func pc2() -> String { return "hello" } } struct SConstrained3a : PConstrained3 { @@ -777,14 +777,14 @@ class Superclass { protocol PConstrained4 { } extension PConstrained4 where Self : Superclass { - final func testFoo() -> Foo { + func testFoo() -> Foo { foo() self.foo() return Foo(5) } - final static func testBar() { + static func testBar() { bar() self.bar() } @@ -800,49 +800,49 @@ protocol PConstrained6 { protocol PConstrained7 { } extension PConstrained6 { - final var prop1: Int { return 0 } - final var prop2: Int { return 0 } // expected-note{{'prop2' previously declared here}} + var prop1: Int { return 0 } + var prop2: Int { return 0 } // expected-note{{'prop2' previously declared here}} - final subscript (key: Int) -> Int { return key } - final subscript (key: Double) -> Double { return key } // expected-note{{'subscript' previously declared here}} + subscript (key: Int) -> Int { return key } + subscript (key: Double) -> Double { return key } // expected-note{{'subscript' previously declared here}} } extension PConstrained6 { - final var prop2: Int { return 0 } // expected-error{{invalid redeclaration of 'prop2'}} - final subscript (key: Double) -> Double { return key } // expected-error{{invalid redeclaration of 'subscript'}} + var prop2: Int { return 0 } // expected-error{{invalid redeclaration of 'prop2'}} + subscript (key: Double) -> Double { return key } // expected-error{{invalid redeclaration of 'subscript'}} } extension PConstrained6 where Assoc : PConstrained5 { - final var prop1: Int { return 0 } // okay - final var prop3: Int { return 0 } // expected-note{{'prop3' previously declared here}} - final subscript (key: Int) -> Int { return key } // ok - final subscript (key: String) -> String { return key } // expected-note{{'subscript' previously declared here}} + var prop1: Int { return 0 } // okay + var prop3: Int { return 0 } // expected-note{{'prop3' previously declared here}} + subscript (key: Int) -> Int { return key } // ok + subscript (key: String) -> String { return key } // expected-note{{'subscript' previously declared here}} - final func foo() { } // expected-note{{'foo()' previously declared here}} + func foo() { } // expected-note{{'foo()' previously declared here}} } extension PConstrained6 where Assoc : PConstrained5 { - final var prop3: Int { return 0 } // expected-error{{invalid redeclaration of 'prop3'}} - final subscript (key: String) -> String { return key } // expected-error{{invalid redeclaration of 'subscript'}} - final func foo() { } // expected-error{{invalid redeclaration of 'foo()'}} + var prop3: Int { return 0 } // expected-error{{invalid redeclaration of 'prop3'}} + subscript (key: String) -> String { return key } // expected-error{{invalid redeclaration of 'subscript'}} + func foo() { } // expected-error{{invalid redeclaration of 'foo()'}} } extension PConstrained6 where Assoc : PConstrained7 { - final var prop1: Int { return 0 } // okay - final subscript (key: Int) -> Int { return key } // okay - final func foo() { } // okay + var prop1: Int { return 0 } // okay + subscript (key: Int) -> Int { return key } // okay + func foo() { } // okay } extension PConstrained6 where Assoc == Int { - final var prop4: Int { return 0 } - final subscript (key: Character) -> Character { return key } - final func foo() { } // okay + var prop4: Int { return 0 } + subscript (key: Character) -> Character { return key } + func foo() { } // okay } extension PConstrained6 where Assoc == Double { - final var prop4: Int { return 0 } // okay - final subscript (key: Character) -> Character { return key } // okay - final func foo() { } // okay + var prop4: Int { return 0 } // okay + subscript (key: Character) -> Character { return key } // okay + func foo() { } // okay } // Interaction between RawRepresentable and protocol extensions. diff --git a/test/decl/ext/protocol_objc.swift b/test/decl/ext/protocol_objc.swift index d1ee08e932f4e..9d536ab61c73a 100644 --- a/test/decl/ext/protocol_objc.swift +++ b/test/decl/ext/protocol_objc.swift @@ -7,7 +7,7 @@ } extension OP1 { - final func extOP1a() -> Bool { return !reqOP1a() } + func extOP1a() -> Bool { return !reqOP1a() } } class OC1 : OP1 { diff --git a/test/decl/protocol/req/associated_type_inference.swift b/test/decl/protocol/req/associated_type_inference.swift index 16f7323a7cb6a..4ed948013cf14 100644 --- a/test/decl/protocol/req/associated_type_inference.swift +++ b/test/decl/protocol/req/associated_type_inference.swift @@ -80,8 +80,8 @@ protocol P1 { } extension P1 { - final func f0(_ x: Int) { } - final func g0(_ x: Int) { } + func f0(_ x: Int) { } + func g0(_ x: Int) { } } struct X0j : P0, P1 { } @@ -93,8 +93,8 @@ protocol P2 { } extension P2 where Self.P2Assoc : PSimple { - final func f0(_ x: P2Assoc) { } // expected-note{{inferred type 'Float' (by matching requirement 'f0') is invalid: does not conform to 'PSimple'}} - final func g0(_ x: P2Assoc) { } // expected-note{{inferred type 'Float' (by matching requirement 'g0') is invalid: does not conform to 'PSimple'}} + func f0(_ x: P2Assoc) { } // expected-note{{inferred type 'Float' (by matching requirement 'f0') is invalid: does not conform to 'PSimple'}} + func g0(_ x: P2Assoc) { } // expected-note{{inferred type 'Float' (by matching requirement 'g0') is invalid: does not conform to 'PSimple'}} } struct X0k : P0, P2 { diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index 658d297436f83..96f9b3f6a4869 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -469,8 +469,8 @@ protocol ProtocolWithExtension1 { static var fooStatic : Int { get } } extension ProtocolWithExtension1 { - final var fooExt: Int // expected-error{{extensions may not contain stored properties}} - final static var fooExtStatic = 4 // expected-error{{static stored properties not supported in generic types}} + var fooExt: Int // expected-error{{extensions may not contain stored properties}} + static var fooExtStatic = 4 // expected-error{{static stored properties not supported in generic types}} } func getS() -> S { From 1ab9e451e5bdc5da8ccda451ad6a96a8bce4239d Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 10 Mar 2017 14:14:51 -0500 Subject: [PATCH 2/3] Remove the final attribute instead of invalidating it to ensure that child decls pass the ASTVerifier --- lib/Sema/TypeCheckAttr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 90e94bf48deb6..767e4f02cec8e 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -194,9 +194,9 @@ class AttributeEarlyChecker : public AttributeVisitor { TC.diagnose(attr->getLocation(), diag::member_cannot_be_final) .fixItRemove(attr->getRange()); - // Invalidate the attribute so child declarations are not flagged as final + // Remove the attribute so child declarations are not flagged as final // and duplicate the error message. - attr->setInvalid(); + D->getAttrs().removeAttribute(attr); return; } } From 0770037f6b252edccbc2c5a4a18c0a1716f6b1b9 Mon Sep 17 00:00:00 2001 From: Brian King Date: Sat, 11 Mar 2017 20:34:55 -0500 Subject: [PATCH 3/3] Only generate a warning for Swift 3 and 4 mode. --- lib/Sema/TypeCheckAttr.cpp | 3 +-- test/Compatibility/final_protocol_extension.swift | 8 -------- test/attr/attr_final.swift | 6 +++--- 3 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 test/Compatibility/final_protocol_extension.swift diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 767e4f02cec8e..c34659bb6508e 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -185,8 +185,7 @@ class AttributeEarlyChecker : public AttributeVisitor { // 'final' only makes sense in the context of a class declaration. // Reject it on global functions, protocols, structs, enums, etc. if (!D->getDeclContext()->getAsClassOrClassExtensionContext()) { - if (TC.Context.isSwiftVersion3() && - D->getDeclContext()->getAsProtocolExtensionContext()) + if (D->getDeclContext()->getAsProtocolExtensionContext()) TC.diagnose(attr->getLocation(), diag::protocol_extension_cannot_be_final) .fixItRemove(attr->getRange()); diff --git a/test/Compatibility/final_protocol_extension.swift b/test/Compatibility/final_protocol_extension.swift deleted file mode 100644 index 00e116446c158..0000000000000 --- a/test/Compatibility/final_protocol_extension.swift +++ /dev/null @@ -1,8 +0,0 @@ -// RUN: %target-typecheck-verify-swift -swift-version 3 -// Generate a swift 3 compatible warning if final is specified in an extension - -protocol P {} - -extension P { - final func inExtension() {} // expected-warning{{functions in a protocol extension do not need to be marked with 'final'}} {{3-9=}} -} diff --git a/test/attr/attr_final.swift b/test/attr/attr_final.swift index 393fe81ddbd53..40db8e59ce190 100644 --- a/test/attr/attr_final.swift +++ b/test/attr/attr_final.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -swift-version 4 +// RUN: %target-typecheck-verify-swift class Super { final var i: Int { get { return 5 } } // expected-note{{overridden declaration is here}} @@ -40,8 +40,8 @@ protocol SomeProtocol { } extension SomeProtocol { - final var i: Int { return 1 } // expected-error {{only classes and class members may be marked with 'final'}} - final func protoExtensionFunc() {} // expected-error {{only classes and class members may be marked with 'final'}} {{3-9=}} + final var i: Int { return 1 } // expected-warning {{functions in a protocol extension do not need to be marked with 'final'}} + final func protoExtensionFunc() {} // expected-warning {{functions in a protocol extension do not need to be marked with 'final'}} {{3-9=}} } extension SomeStruct {