-
Notifications
You must be signed in to change notification settings - Fork 158
Update Swift tools version to 5.9 #861
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
Conversation
…om Swift 5.7 This also leverages "primary associated types" (SE-0358) available from Swift 5.7
…of SPI for FileManagerProtocol
|
I made each change as its own commit, to make it easier to review. If you prefer I can break it apart into separate PRs but I didn't feel that that would make it easier to review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great improvement! Thanks a lot.
I found some additional fixes you can make that follow the same patterns, if you're interested in adding those now. Also various code questions for you.
| /// Adds the difference between two properties to the DifferenceBuilder. | ||
| mutating func addDifferences<E>(atKeyPath keyPath: KeyPath<T, E>, forKey codingKey: CodingKey) | ||
| where E: Equatable & Encodable { | ||
| mutating func addDifferences(atKeyPath keyPath: KeyPath<T, some Equatable & Encodable>, forKey codingKey: CodingKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the precedence order for some Equatable & Encodable ? We don't need parentheses here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't find the specific precedence order but from what I've understood some A & B is the same as some (A & B). In other cases I needed to add parentheses around the full expression to write (some A)?
|
|
||
| @_spi(FileManagerProtocol) | ||
| public init( | ||
| package init( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also use package access level for ExternalLinks? For example:
extension OutOfProcessReferenceResolver: ConvertServiceFallbackResolver {
@_spi(ExternalLinks)
public func entityIfPreviouslyResolved(with reference: ResolvedTopicReference) -> LinkResolver.ExternalEntity? {
Could this become:
extension OutOfProcessReferenceResolver: ConvertServiceFallbackResolver {
package func entityIfPreviouslyResolved(with reference: ResolvedTopicReference) -> LinkResolver.ExternalEntity? {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't because it's used in a public protocol and I couldn't use different access levels in the same protocol.
We will eventually settle on a stable API for it and then we can change the SPI to public API.
| } | ||
| } | ||
|
|
||
| extension Sequence where Element == RenderBlockContent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found a couple more examples of where we could use generic syntax for extending collections...
DocCSymbolRepresentable.swift
public extension Collection where Element: DocCSymbolRepresentable {
Collection+ConcurrentPerform.swift
extension Collection where Index == Int {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first example can't be written as Collection<DocCSymbolRepresentable> because that would change its meaning from where Element: DocCSymbolRepresentable to where Element == DocCSymbolRepresentable (which also doesn't compile). In other places this would be described by Collection<some DocCSymbolRepresentable> but syntax wasn't supported in extensions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding extension Collection where Index == Int {: The primary associated type of Collection is the element, so
Collection<Int> would mean Collection where Element == Int, not Collection where Index == Int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it - I see the new generic syntax refers to the associated type of the parent type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically the primary associated type. Collection is generic over both the Element and Index but only Element is the primary associated type.
| var container = encoder.container(keyedBy: CodingKeys.self) | ||
| try container.encode(url.absoluteString, forKey: .url) | ||
|
|
||
| let sourceLanguageIDVariants = DocumentationDataVariants<String>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found a few other places where we could use modern syntax for dictionaries:
DocumentationContext.swift
/// The documentation bundles that are currently registered with the context.
public var registeredBundles: Dictionary<String, DocumentationBundle>.Values {
return dataProvider.bundles.values
}
BidirectionalMap.swift
func makeIterator() -> Dictionary<Value1, Value2>.Iterator {
return forward.makeIterator()
}
GroupedSequence.swift
/// Returns an iterator over the members of the sequence.
func makeIterator() -> Dictionary<Key, Element>.Values.Iterator {
storage.values.makeIterator()
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of these can be written using opaque types (the some keyword) to not define a specific type. For example:
- public var registeredBundles: Dictionary<String, DocumentationBundle>.Values
+ public var registeredBundles: some Collection<DocumentationBundle> /// Returns an iterator over the members of the sequence.
- func makeIterator() -> Dictionary<Key, Element>.Values.Iterator {
+ func makeIterator() -> some IteratorProtocol<Element> { but for the bidirectional map I don't feel like some IteratorProtocol<(key: Value1, value: Value2)> is any more readable than [Value1: Value2].Iterator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree - some IteratorProtocol<Element> is actually quite readable even though it uses the verbose generic syntax. Calling this will return some something that can iterate over Element's.
But yea some IteratorProtocol<(key: Value1, value: Value2)> seems confusing either because there's a key and a value in the tuple, or just because of the unhelpful names Value1 and Value2.
| } | ||
|
|
||
| /// Determines the difference between the two dictionaries mapping strings to diffable objects at the KeyPaths given. | ||
| mutating func addDifferences<Element>(atKeyPath keyPath: KeyPath<T, Array<Element>>, forKey codingKey: CodingKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few other examples of modern syntax for arrays:
MarkupContainer.swift
extension MarkupContainer: RandomAccessCollection {
public subscript(position: Array<Markup>.Index) -> Markup {
return elements[position]
}
public var startIndex: Array<Markup>.Index {
return elements.startIndex
}
public var endIndex: Array<Markup>.Index {
return elements.endIndex
}
}
|
|
||
| /// Creates a checker that performs the combined work of the given checkers. | ||
| public init<Checkers: Sequence>(_ checkers: Checkers) where Checkers.Element: Checker { | ||
| public init(_ checkers: some Sequence<Checker>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found a few more places where we could simplify the generic syntax using some:
SemanticAnalysis.swift
func analyze<Children: Sequence>(
_ directive: BlockDirective,
children: Children, source: URL?,
for bundle: DocumentationBundle,
in context: DocumentationContext, problems: inout [Problem]
) -> Result where Children.Element == Markup
to:
func analyze(
_ directive: BlockDirective,
children: some Sequence<Markup>,
source: URL?,
for bundle: DocumentationBundle,
in context: DocumentationContext, problems: inout [Problem]
) -> Result
DocumentationConverter.swift
mutating func convert<OutputConsumer: ConvertOutputConsumer>(
outputConsumer: OutputConsumer
) throws -> (analysisProblems: [Problem], conversionProblems: [Problem])
to:
mutating func convert(
outputConsumer: some ConvertOutputConsumer
) throws -> (analysisProblems: [Problem], conversionProblems: [Problem])
DirectiveArgumentWrapper.swift
func setProperty<T: AutomaticDirectiveConvertible>(
on containingDirective: T,
named propertyName: String,
to any: Any
)
to:
func setProperty(
on containingDirective: some AutomaticDirectiveConvertible,
named propertyName: String,
to any: Any
)
There are many other places in the code where we have generic constraints that appear to be places where we could add some - but actually don't compile. The most common example of these are the places where we use the visitor pattern:
Symbol.swift
public override func accept<V: SemanticVisitor>(_ visitor: inout V) -> V.Result {
return visitor.visitSymbol(self)
}
Here it appears we could write
public override func accept(_ visitor: inout some SemanticVisitor) -> SemanticVisitor.Result {
return visitor.visitSymbol(self)
}
.... but Swift returns an error: Cannot access associated type 'Result' from 'SemanticVisitor'; use a concrete type or generic parameter base instead
Any idea why? Why can't Swift access the Result associated type? Is there a better way to write the function declaration in this example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize that I could update the declaration in the protocols themselves. I got some error message about that earlier and thought that it wasn't supported but it looks like it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.... but Swift returns an error: Cannot access associated type 'Result' from 'SemanticVisitor'; use a concrete type or generic parameter base instead
V.Result is referring to the specific Result associated type of V. However SemanticVisitor.Result isn't connected to the some SemanticVisitor parameter, so it doesn't define a return type that's associated with the parameter type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
V.Result is referring to the specific Result associated type of V. However SemanticVisitor.Result isn't connected to the some SemanticVisitor parameter, so it doesn't define a return type that's associated with the parameter type.
Ok. But don't all types that conform to SemanticVisitor have the same associated type Result? It seems to me that Swift should be able to make this compile and run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each SemanticVisitor has an associate Result but it doesn't have to be the same across different visitors. That's why this needs to label the visitor as V to specifically be able to refer to its Result type
|
@swift-ci please test |
|
Hm.. the Linux CI seems to be pinned to |
|
This is blocked on the CI (rdar://125077916) |
…instead of SPI for FileManagerProtocol" f1ca44c
|
@swift-ci please test |
|
The team talked about this today and decided to revert the |
* Update Swift tools version to 5.9 rdar://116871051 * Use if-let shorthand (SE-0345) available from Swift 5.7 * Modernize generics with opaque types (SE-0328 & SE-0341) available from Swift 5.7 This also leverages "primary associated types" (SE-0358) available from Swift 5.7 * Remove unused AnyCommunicationBridge type-erasure wrapper * Remove back-port of pointer API (SE-0370) available in Swift 5.8 * Use package access level (SE-0386, available from Swift 5.9) instead of SPI for FileManagerProtocol * Simplify extensions using bound generic types (SE-0361) available since Swift 5.7 * Use shorthand syntax for array, dictionary, and optional types (always available) * Define primary associated type (SE-0346) for DirectiveArgument protocol * Use opaque parameter types (SE-0341) in protocol definitions * Use opaque return types (SE-0328) for some properties * Use array and dictionary shorthand syntax in more places * Use bound generic types (SE-0361) for extensions in more places * Revert "Use package access level (SE-0386, available from Swift 5.9) instead of SPI for FileManagerProtocol" f1ca44c
* Update Swift tools version to 5.9 rdar://116871051 * Use if-let shorthand (SE-0345) available from Swift 5.7 * Modernize generics with opaque types (SE-0328 & SE-0341) available from Swift 5.7 This also leverages "primary associated types" (SE-0358) available from Swift 5.7 * Remove unused AnyCommunicationBridge type-erasure wrapper * Remove back-port of pointer API (SE-0370) available in Swift 5.8 * Use package access level (SE-0386, available from Swift 5.9) instead of SPI for FileManagerProtocol * Simplify extensions using bound generic types (SE-0361) available since Swift 5.7 * Use shorthand syntax for array, dictionary, and optional types (always available) * Define primary associated type (SE-0346) for DirectiveArgument protocol * Use opaque parameter types (SE-0341) in protocol definitions * Use opaque return types (SE-0328) for some properties * Use array and dictionary shorthand syntax in more places * Use bound generic types (SE-0361) for extensions in more places * Revert "Use package access level (SE-0386, available from Swift 5.9) instead of SPI for FileManagerProtocol" f1ca44c
Bug/issue #, if applicable: rdar://116871051
Summary
This updates SwiftDocC to Swift 5.9 and
if let(SE-0345)There are lots more that we can do now, but I feel that those are better addressed in separate PRs. I opted for these changes because they each make the code more readable and have small (but very frequent) and understandable diffs.
Dependencies
None
Testing
Nothing in particular. There should be
Checklist
Make sure you check off the following items. If they cannot be completed, provide a reason.
[] Added tests./bin/testscript and it succeeded[ ] Updated documentation if necessary