Skip to content

Remove final in protocol extensions #8010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down
27 changes: 17 additions & 10 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,15 +182,20 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
if (isa<ClassDecl>(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.
// '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 (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());

// Remove the attribute so child declarations are not flagged as final
// and duplicate the error message.
D->getAttrs().removeAttribute(attr);
} else if (!D->getDeclContext()->getAsClassOrClassExtensionContext()) {
diagnoseAndRemoveAttr(attr, diag::member_cannot_be_final);
return;
}
}
Expand Down Expand Up @@ -1008,7 +1013,8 @@ void AttributeChecker::visitFinalAttr(FinalAttr *attr) {
// We currently only support final on var/let, func and subscript
// declarations.
if (!isa<VarDecl>(D) && !isa<FuncDecl>(D) && !isa<SubscriptDecl>(D)) {
TC.diagnose(attr->getLocation(), diag::final_not_allowed_here);
TC.diagnose(attr->getLocation(), diag::final_not_allowed_here)
.fixItRemove(attr->getRange());
return;
}

Expand All @@ -1017,7 +1023,8 @@ void AttributeChecker::visitFinalAttr(FinalAttr *attr) {
unsigned Kind = 2;
if (auto *VD = dyn_cast<VarDecl>(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;
}
}
Expand Down
12 changes: 6 additions & 6 deletions stdlib/public/SDK/Foundation/NSError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand All @@ -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()))
}

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion test/Generics/existential_restrictions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions test/IRGen/protocol_extensions.sil
Original file line number Diff line number Diff line change
Expand Up @@ -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_
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/protocol_extensions_constrain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
20 changes: 10 additions & 10 deletions test/Interpreter/protocol_extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -17,7 +17,7 @@ print(["a", "b", "c", "d"].myCount)

// Extend a protocol with a function.
extension Collection {
final var myIndices: Range<Index> {
var myIndices: Range<Index> {
return startIndex..<endIndex
}

Expand All @@ -30,7 +30,7 @@ extension Collection {
print(["a", "b", "c", "d"].clone().myCount)

extension Sequence {
final public func myEnumerated() -> EnumeratedSequence<Self> {
public func myEnumerated() -> EnumeratedSequence<Self> {
return self.enumerated()
}
}
Expand All @@ -43,7 +43,7 @@ for (index, element) in ["a", "b", "c"].myEnumerated() {
}

extension Sequence {
final public func myReduce<T>(
public func myReduce<T>(
_ initial: T, combine: (T, Self.Iterator.Element) -> T
) -> T {
var result = initial
Expand All @@ -59,7 +59,7 @@ print([1, 2, 3, 4, 5].myReduce(0, combine: +))


extension Sequence {
final public func myZip<S : Sequence>(_ s: S) -> Zip2Sequence<Self, S> {
public func myZip<S : Sequence>(_ s: S) -> Zip2Sequence<Self, S> {
return Zip2Sequence(_sequence1: self, _sequence2: s)
}
}
Expand All @@ -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<S : Sequence where S.Iterator.Element == Self>(
public func myJoin<S : Sequence where S.Iterator.Element == Self>(
_ elements: S
) -> Self {
var result = Self()
Expand All @@ -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 = ""
Expand All @@ -133,7 +133,7 @@ protocol ExistP1 {
}

extension ExistP1 {
final func runExistP1() {
func runExistP1() {
print("runExistP1")
self.existP1()
}
Expand Down Expand Up @@ -167,7 +167,7 @@ protocol P {
}

extension P {
final var extValue: Bool {
var extValue: Bool {
get { return getValue() }
set(newValue) { setValue(newValue) }
}
Expand Down
4 changes: 2 additions & 2 deletions test/NameBinding/reference-dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ typealias MyArray = Array<Bool>

// 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"
Expand Down
4 changes: 2 additions & 2 deletions test/NameBinding/scope_map_lookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/boxed_existentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/guaranteed_self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ public protocol SequenceDefaults {
}

extension SequenceDefaults {
public final func _constrainElement(_: FakeGenerator.Element) {}
public func _constrainElement(_: FakeGenerator.Element) {}
}

public protocol Sequence : SequenceDefaults {
Expand Down
20 changes: 10 additions & 10 deletions test/SILGen/protocol_extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct Box {
extension P1 {
// CHECK-LABEL: sil hidden @_T019protocol_extensions2P1PAAE6extP1a{{[_0-9a-zA-Z]*}}F : $@convention(method) <Self where Self : P1> (@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>([[SELF]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
reqP1a()
Expand All @@ -21,7 +21,7 @@ extension P1 {

// CHECK-LABEL: sil @_T019protocol_extensions2P1PAAE6extP1b{{[_0-9a-zA-Z]*}}F : $@convention(method) <Self where Self : P1> (@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>([[SELF]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
extP1a()
Expand All @@ -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
Expand Down Expand Up @@ -474,24 +474,24 @@ func testG<T>(_ m: GenericMetaHolder<T>, gg: G<T>.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 { }
}
Expand Down Expand Up @@ -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 {}
Expand Down
2 changes: 1 addition & 1 deletion test/SILGen/witnesses_canonical.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct _S<T : _CDT> : CT {
}

extension _CDT {
final subscript(b: Int) -> _S<Self> {
subscript(b: Int) -> _S<Self> {
return _S(a: self, b: b)
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/SILOptimizer/devirt_extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
protocol DrawingElementDispatch {}

extension DrawingElementDispatch {
final var boundingBox: Int32 {
var boundingBox: Int32 {
return 0
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/Serialization/Inputs/def_class.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public protocol Resettable {
}

public extension Resettable {
final func doReset() { self.reset() }
func doReset() { self.reset() }
}

open class ResettableIntWrapper : Resettable {
Expand Down Expand Up @@ -80,7 +80,7 @@ public protocol PairLike {
}

public extension PairLike where FirstType : Cacheable {
final func cacheFirst() { }
func cacheFirst() { }
}

public protocol ClassProto : class {}
Expand Down
2 changes: 1 addition & 1 deletion test/SourceKit/DocSupport/Inputs/cake.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class C1 : Prot {
public func genfoo<T1 : Prot, T2 : C1>(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 {
Expand Down
Loading