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