That sounds awesome! Don't have much time right now to check the details but 
these 'near misses' have been a real problem for us.

> On 26 Oct 2017, at 9:28 pm, Douglas Gregor via swift-dev 
> <swift-dev@swift.org> wrote:
> 
> I have a pull request up to introduce “near-miss” warnings for protocol 
> conformances:
> 
>       https://github.com/apple/swift/pull/12645
> 
> A “near-miss” warning fires when there is a protocol conformance for which:
> 
> 1) One of the requirements is satisfied by a “default” definition (e.g., one 
> from a protocol extension), and
> 2) There is a member of the same nominal type declaration (or extension 
> declaration) that declared the conformance that has the same name as the 
> requirement and isn’t satisfying another requirement.
> 
> These are heuristics, of course, and we can tune the heuristics over time. By 
> way of experiment, here are the results of running this on the standard 
> library. Here’s the first one:
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/DoubleWidth.swift.gyb:27:3:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  init(_ _value: (High, Low)) {
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/DoubleWidth.swift.gyb:27:3:
>  note: candidate has non-matching type '(DoubleWidth.High, DoubleWidth.Low)'
>  init(_ _value: (High, Low)) {
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/DoubleWidth.swift.gyb:27:3:
>  note: move 'init' to an extension to silence this warning
>  init(_ _value: (High, Low)) {
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> 
> Unlabeled single-value initializers are probably going to cause a number of 
> false positives, because we can’t figure out which one we meant.
> 
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:835:15:
>  warning: instance method 'filter' nearly matches defaulted requirement 
> 'filter' of protocol 'Sequence'
>  public func filter(
>              ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:835:15:
>  note: candidate has non-matching type '<Element> ((Set.Element) throws -> 
> Bool) throws -> Set<Element>' (aka '<τ_0_0> ((τ_0_0) throws -> Bool) throws 
> -> Set<τ_0_0>') [with Element = Element, Iterator = SetIterator<Element>, 
> SubSequence = Slice<Set<Element>>]
>  public func filter(
>              ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:835:15:
>  note: move 'filter' to an extension to silence this warning
>  public func filter(
>              ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Sequence.swift:383:8: 
> note: requirement 'filter' declared here
>  func filter(
>       ^
> 
> The filter method it’s warning on produces a Set, whereas the requirement 
> expects an Array<Element>. This is a case of intentional overloading, but IMO 
> it’s a reasonable thing to warn about.
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:2021:10:
>  warning: subscript 'subscript' nearly matches defaulted requirement 
> 'subscript' of protocol 'Collection'
>  public subscript(key: Key) -> Value? {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:2021:10:
>  note: candidate has non-matching type '<Key, Value where Key : Hashable> 
> (Dictionary.Key) -> Dictionary.Value?' (aka '<τ_0_0, τ_0_1 where τ_0_0 : 
> Hashable> (τ_0_0) -> Optional<τ_0_1>') [with IndexDistance = Int, Iterator = 
> DictionaryIterator<Key, Value>, SubSequence = Slice<Dictionary<Key, Value>>, 
> Indices = DefaultIndices<Dictionary<Key, Value>>]
>  public subscript(key: Key) -> Value? {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:2021:10:
>  note: move 'subscript' to an extension to silence this warning
>  public subscript(key: Key) -> Value? {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Collection.swift:454:3:
>  note: requirement 'subscript' declared here
>  subscript(bounds: Range<Index>) -> SubSequence { get }
>  ^
> 
> The defaulted Range subscript operation for Dictionary is reasonable, but it 
> has a few other subscripts. I think this is a reasonable diagnostic, despite 
> being a false positive.
> 
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:2063:15:
>  warning: instance method 'filter' nearly matches defaulted requirement 
> 'filter' of protocol 'Sequence'
>  public func filter(
>              ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:2063:15:
>  note: candidate has non-matching type '<Key, Value> ((Dictionary.Element) 
> throws -> Bool) throws -> [Dictionary.Key : Dictionary.Value]' (aka '<τ_0_0, 
> τ_0_1> (((key: τ_0_0, value: τ_0_1)) throws -> Bool) throws -> 
> Dictionary<τ_0_0, τ_0_1>') [with Iterator = DictionaryIterator<Key, Value>, 
> SubSequence = Slice<Dictionary<Key, Value>>]
>  public func filter(
>              ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/HashedCollections.swift.gyb:2063:15:
>  note: move 'filter' to an extension to silence this warning
>  public func filter(
>              ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Sequence.swift:383:8: 
> note: requirement 'filter' declared here
>  func filter(
>       ^
> 
> Same as the “filter” example above, but for Dictionary. This is a reasonable 
> diagnostic.
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  warning: initializer 'init' nearly matches defaulted requirement 'init' of 
> protocol 'LosslessStringConvertible'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: candidate has non-matching type 'Float'
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/Integers.swift.gyb:2962:10:
>  note: move 'init' to an extension to silence this warning
>  public init(_ source: Float) {
>         ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/OutputStream.swift:182:3:
>  note: requirement 'init' declared here
>  init?(_ description: String)
>  ^
> 
> LosslessStringConvertible’s single-argument, unlabeled initializer is causing 
> a *lot* of false positives :(.
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/UIntBuffer.swift:202:24:
>  warning: instance method 'removeFirst()' nearly matches defaulted 
> requirement 'removeFirst()' of protocol 'RangeReplaceableCollection'
>  public mutating func removeFirst() {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/UIntBuffer.swift:202:24:
>  note: candidate has non-matching type '<Storage, Element> () -> ()'
>  public mutating func removeFirst() {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/UIntBuffer.swift:202:24:
>  note: move 'removeFirst()' to another extension to silence this warning
>  public mutating func removeFirst() {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/RangeReplaceableCollection.swift.gyb:323:17:
>  note: requirement 'removeFirst()' declared here
>  mutating func removeFirst() -> Element
>                ^
> 
> Smells like a bug: we end up getting the default removeFirst() 
> implementation, because the one written within the struct doesn’t return the 
> element type.
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/ValidUTF8Buffer.swift:178:24:
>  warning: instance method 'removeFirst()' nearly matches defaulted 
> requirement 'removeFirst()' of protocol 'RangeReplaceableCollection'
>  public mutating func removeFirst() {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/ValidUTF8Buffer.swift:178:24:
>  note: candidate has non-matching type '<Storage> () -> ()'
>  public mutating func removeFirst() {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/ValidUTF8Buffer.swift:178:24:
>  note: move 'removeFirst()' to another extension to silence this warning
>  public mutating func removeFirst() {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/RangeReplaceableCollection.swift.gyb:323:17:
>  note: requirement 'removeFirst()' declared here
>  mutating func removeFirst() -> Element
>                ^
> 
> Also looks like a bug!
> 
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/ValidUTF8Buffer.swift:205:24:
>  warning: instance method 'append(contentsOf:)' nearly matches defaulted 
> requirement 'append(contentsOf:)' of protocol 'RangeReplaceableCollection'
>  public mutating func append<T>(contentsOf other: _ValidUTF8Buffer<T>) {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/ValidUTF8Buffer.swift:205:24:
>  note: candidate has non-matching type '<Storage, T> (contentsOf: 
> _ValidUTF8Buffer<T>) -> ()'
>  public mutating func append<T>(contentsOf other: _ValidUTF8Buffer<T>) {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/ValidUTF8Buffer.swift:205:24:
>  note: move 'append(contentsOf:)' to another extension to silence this warning
>  public mutating func append<T>(contentsOf other: _ValidUTF8Buffer<T>) {
>                       ^
> /Users/dgregor/Projects/swift/swift/stdlib/public/core/RangeReplaceableCollection.swift.gyb:200:17:
>  note: requirement 'append(contentsOf:)' declared here
>  mutating func append<S : Sequence>(contentsOf newElements: S)
>                ^
> 
> It… might… be a false positive? I don’t really understand why 
> _ValidUTF8Buffer’s append here takes a parameterized _ValidUTF8Buffer. At 
> best, it’d likely be more efficient to implement a customization of 
> append(contentsOf:) in _ValidUTF8Buffer, which would suppress the diagnostic.
> 
> Thoughts?
> 
>       - Doug
> 
> _______________________________________________
> swift-dev mailing list
> swift-dev@swift.org
> https://lists.swift.org/mailman/listinfo/swift-dev

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to