Files
swift-mirror/test/decl/protocol/conforms/near_miss_objc.swift
Anthony Latsis 934964d49d Use AbstractStorageDecl::isSettableInSwift to prohibit direct writes to optional requirements
Stop pretending that an optional requirement is immutable via the `StorageImplInfo` request.
This approach has lead astray the conformance checker and may have had a negative impact
on other code paths, and it doesn't work for imported declarations because they bypass the
request. Instead, use a forwarding `AbstractStorageDecl::isSettableInSwift` method
that special-cases optional requirements.
2022-04-20 14:27:15 +03:00

167 lines
6.8 KiB
Swift

// RUN: %target-typecheck-verify-swift -enable-objc-interop
// Test "near misses" where a member of a class or extension thereof
// nearly matches an optional requirement, but does not exactly match.
@objc protocol P1 {
@objc optional func doSomething(a: Int, b: Double) // expected-note 2{{requirement 'doSomething(a:b:)' declared here}}
}
class C1a : P1 {
@objc func doSomething(a: Int, c: Double) { }
// expected-warning@-1{{instance method 'doSomething(a:c:)' nearly matches optional requirement 'doSomething(a:b:)' of protocol 'P1'}}
// expected-note@-2{{rename to 'doSomething(a:b:)' to satisfy this requirement}}{{34-34=b }}
// expected-note@-3{{move 'doSomething(a:c:)' to an extension to silence this warning}}
// expected-note@-4{{make 'doSomething(a:c:)' private to silence this warning}}{{9-9=private }}
}
class C1b : P1 {
}
extension C1b {
@objc func doSomething(a: Int, c: Double) { } // don't warn
}
class C1c {
}
extension C1c : P1 {
func doSomething(a: Int, c: Double) { }
// expected-warning@-1{{instance method 'doSomething(a:c:)' nearly matches optional requirement 'doSomething(a:b:)' of protocol 'P1'}}
// expected-note@-2{{rename to 'doSomething(a:b:)' to satisfy this requirement}}{{28-28=b }}{{none}}
// expected-note@-3{{move 'doSomething(a:c:)' to another extension to silence this warning}}
// expected-note@-4{{make 'doSomething(a:c:)' private to silence this warning}}{{3-3=private }}
}
class C1d : P1 {
@objc private func doSomething(a: Int, c: Double) { } // don't warn
}
class C1e : P1 {
@nonobjc func doSomething(a: Int, c: Double) { } // don't warn
}
// Don't try to match an optional requirement against a declaration
// that already satisfies one witness.
@objc protocol P2 {
@objc optional func doSomething(a: Int, b: Double)
@objc optional func doSomething(a: Int, d: Double)
}
class C2a : P2 {
@objc func doSomething(a: Int, b: Double) { } // don't warn: this matches something
}
// Cope with base names that change.
@objc protocol P3 {
@objc optional func doSomethingWithPriority(_ a: Int, d: Double) // expected-note{{requirement 'doSomethingWithPriority(_:d:)' declared here}}
}
class C3a : P3 {
func doSomething(priority: Int, d: Double) { }
// expected-warning@-1{{instance method 'doSomething(priority:d:)' nearly matches optional requirement 'doSomethingWithPriority(_:d:)' of protocol 'P3'}}
// expected-note@-2{{rename to 'doSomethingWithPriority(_:d:)' to satisfy this requirement}}{{20-20=_ }}
// expected-note@-3{{move 'doSomething(priority:d:)' to an extension to silence this warning}}
// expected-note@-4{{make 'doSomething(priority:d:)' private to silence this warning}}{{3-3=private }}
}
@objc protocol P4 {
@objc optional func doSomething(priority: Int, d: Double) // expected-note{{requirement 'doSomething(priority:d:)' declared here}}
}
class C4a : P4 {
func doSomethingWithPriority(_ a: Int, d: Double) { }
// expected-warning@-1{{instance method 'doSomethingWithPriority(_:d:)' nearly matches optional requirement 'doSomething(priority:d:)' of protocol 'P4'}}
// expected-note@-2{{rename to 'doSomething(priority:d:)' to satisfy this requirement}}{{32-33=priority}}
// expected-note@-3{{move 'doSomethingWithPriority(_:d:)' to an extension to silence this warning}}
// expected-note@-4{{make 'doSomethingWithPriority(_:d:)' private to silence this warning}}{{3-3=private }}
}
@objc class SomeClass { }
@objc protocol P5 {
@objc optional func methodWithInt(_: Int, forSomeClass: SomeClass, dividingDouble: Double)
// expected-note@-1{{requirement 'methodWithInt(_:forSomeClass:dividingDouble:)' declared here}}
}
class C5a : P5 {
func method(_: Int, for someClass: SomeClass, dividing double: Double) { }
// expected-warning@-1{{instance method 'method(_:for:dividing:)' nearly matches optional requirement 'methodWithInt(_:forSomeClass:dividingDouble:)' of protocol 'P5'}}
// expected-note@-2{{rename to 'methodWithInt(_:forSomeClass:dividingDouble:)' to satisfy this requirement}}{{8-14=methodWithInt}}{{23-26=forSomeClass}}{{49-57=dividingDouble}}{{none}}
// expected-note@-3{{move 'method(_:for:dividing:)' to an extension to silence this warning}}
// expected-note@-4{{make 'method(_:for:dividing:)' private to silence this warning}}{{3-3=private }}
}
@objc protocol P6 {
@objc optional func method(_: Int, for someClass: SomeClass, dividing double: Double)
// expected-note@-1{{requirement 'method(_:for:dividing:)' declared here}}
}
class C6a : P6 {
func methodWithInt(_: Int, forSomeClass: SomeClass, dividingDouble: Double) { }
// expected-warning@-1{{instance method 'methodWithInt(_:forSomeClass:dividingDouble:)' nearly matches optional requirement 'method(_:for:dividing:)' of protocol 'P6'}}
// expected-note@-2{{rename to 'method(_:for:dividing:)' to satisfy this requirement}}{{8-21=method}}{{30-30=for }}{{55-55=dividing }}{{none}}
// expected-note@-3{{move 'methodWithInt(_:forSomeClass:dividingDouble:)' to an extension to silence this warning}}
// expected-note@-4{{make 'methodWithInt(_:forSomeClass:dividingDouble:)' private to silence this warning}}{{3-3=private }}
}
// Use the first note to always describe why it didn't match.
@objc protocol P7 {
@objc optional func method(foo: Float)
// expected-note@-1{{requirement 'method(foo:)' declared here}}
}
class C7a : P7 {
@objc func method(foo: Double) { }
// expected-warning@-1{{instance method 'method(foo:)' nearly matches optional requirement 'method(foo:)' of protocol 'P7'}}
// expected-note@-2{{candidate has non-matching type '(Double) -> ()'}}
// expected-note@-3{{move 'method(foo:)' to an extension to silence this warning}}
// expected-note@-4{{make 'method(foo:)' private to silence this warning}}
}
// Don't complain about near misses that satisfy other protocol
// requirements.
@objc protocol P8 {
@objc optional func foo(exactMatch: Int)
}
@objc protocol P9 : P8 {
@objc optional func foo(nearMatch: Int)
}
class C8Super : P8 { }
class C9Sub : C8Super, P9 {
func foo(exactMatch: Int) { }
}
// Don't complain about overriding methods that are near misses;
// the user cannot make it satisfy the protocol requirement.
class C10Super {
func foo(nearMatch: Int) { }
}
class C10Sub : C10Super, P8 {
override func foo(nearMatch: Int) { }
}
// Be more strict about near misses than we had previously.
@objc protocol P11 {
@objc optional func foo(wibble: Int)
}
class C11 : P11 {
func f(waggle: Int) { } // no warning
}
@objc protocol P12 {
@objc optional var prop: Bool { get set } // expected-note {{requirement 'prop' declared here}}
}
class C12: P12 {
var prop: Bool { true }
// expected-warning@-1 {{property 'prop' nearly matches optional requirement 'prop' of protocol 'P12'}}
// expected-note@-2 {{candidate is not settable, but protocol requires it}}
// expected-note@-3 {{move 'prop' to an extension to silence this warning}}
// expected-note@-4 {{make 'prop' private to silence this warning}}
}