Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -2707,7 +2707,7 @@ public class DocumentationContext {
- Returns: A ``DocumentationNode`` with the given identifier.
- Throws: ``ContextError/notFound(_:)`` if a documentation node with the given identifier was not found.
*/
public func entity(with reference: ResolvedTopicReference) throws -> DocumentationNode {
public func entity(with reference: ResolvedTopicReference) throws(ContextError) -> DocumentationNode {
if let cached = documentationCache[reference] {
return cached
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ final class ExternalPathHierarchyResolver {
}

return .success(foundReference)
} catch let error as PathHierarchy.Error {
} catch {
return .failure(unresolvedReference, error.makeTopicReferenceResolutionErrorInfo() { collidingNode in
self.fullName(of: collidingNode) // If the link was ambiguous, determine the full name of each colliding node to be presented in the link diagnostic.
})
} catch {
fatalError("Only PathHierarchy.Error errors are raised from the symbol link resolution code above.")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class LinkResolver {

do {
return try localResolver.resolve(unresolvedReference, in: parent, fromSymbolLink: isCurrentlyResolvingSymbolLink)
} catch let error as PathHierarchy.Error {
} catch {
// Check if there's a known external resolver for this module.
if case .moduleNotFound(_, let remainingPathComponents, _) = error, let resolver = externalResolvers[remainingPathComponents.first!.full] {
let result = resolver.resolve(unresolvedReference, fromSymbolLink: isCurrentlyResolvingSymbolLink)
Expand All @@ -86,8 +86,6 @@ public class LinkResolver {
} else {
return .failure(unresolvedReference, error.makeTopicReferenceResolutionErrorInfo() { localResolver.fullName(of: $0, in: context) })
}
} catch {
fatalError("Only SymbolPathTree.Error errors are raised from the symbol link resolution code above.")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2023-2024 Apple Inc. and the Swift project authors
Copyright (c) 2023-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand All @@ -20,11 +20,11 @@ extension PathHierarchy {
/// - onlyFindSymbols: Whether or not only symbol matches should be found.
/// - Returns: Returns the unique identifier for the found match or raises an error if no match can be found.
/// - Throws: Raises a ``PathHierarchy/Error`` if no match can be found.
func find(path rawPath: String, parent: ResolvedIdentifier? = nil, onlyFindSymbols: Bool) throws -> ResolvedIdentifier {
func find(path rawPath: String, parent: ResolvedIdentifier? = nil, onlyFindSymbols: Bool) throws(Error) -> ResolvedIdentifier {
return try findNode(path: rawPath, parentID: parent, onlyFindSymbols: onlyFindSymbols).identifier
}

private func findNode(path rawPath: String, parentID: ResolvedIdentifier?, onlyFindSymbols: Bool) throws -> Node {
private func findNode(path rawPath: String, parentID: ResolvedIdentifier?, onlyFindSymbols: Bool) throws(Error) -> Node {
// The search for a documentation element can be though of as 3 steps:
// - First, parse the path into structured path components.
// - Second, find nodes that match the beginning of the path as starting points for the search
Expand Down Expand Up @@ -79,15 +79,15 @@ extension PathHierarchy {
}

// A function to avoid repeating the
func searchForNodeInModules() throws -> Node {
func searchForNodeInModules() throws(Error) -> Node {
// Note: This captures `parentID`, `remaining`, and `rawPathForError`.
if let moduleMatch = modules.first(where: { $0.matches(firstComponent) }) {
return try searchForNode(descendingFrom: moduleMatch, pathComponents: remaining.dropFirst(), onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPath)
}
if modules.count == 1 {
do {
return try searchForNode(descendingFrom: modules.first!, pathComponents: remaining, onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPath)
} catch let error as PathHierarchy.Error {
} catch {
switch error {
case .notFound:
// Ignore this error and raise an error about not finding the module instead.
Expand Down Expand Up @@ -129,7 +129,7 @@ extension PathHierarchy {
}

// A recursive function to traverse up the path hierarchy searching for the matching node
func searchForNodeUpTheHierarchy(from startingPoint: Node?, path: ArraySlice<PathComponent>) throws -> Node {
func searchForNodeUpTheHierarchy(from startingPoint: Node?, path: ArraySlice<PathComponent>) throws(Error) -> Node {
guard let possibleStartingPoint = startingPoint else {
// If the search has reached the top of the hierarchy, check the modules as a base case to break the recursion.
do {
Expand All @@ -147,7 +147,7 @@ extension PathHierarchy {
let firstComponent = path.first!

// Keep track of the inner most error and raise that if no node is found.
var innerMostError: (any Swift.Error)?
var innerMostError: Error?

// If the starting point's children match this component, descend the path hierarchy from there.
if possibleStartingPoint.anyChildMatches(firstComponent) {
Expand Down Expand Up @@ -211,7 +211,7 @@ extension PathHierarchy {
pathComponents: ArraySlice<PathComponent>,
onlyFindSymbols: Bool,
rawPathForError: String
) throws -> Node {
) throws(Error) -> Node {
// All code paths through this function wants to perform extra verification on the return value before returning it to the caller.
// To accomplish that, the core implementation happens in `_innerImplementation`, which is called once, right below its definition.

Expand All @@ -220,7 +220,7 @@ extension PathHierarchy {
pathComponents: ArraySlice<PathComponent>,
onlyFindSymbols: Bool,
rawPathForError: String
) throws -> Node {
) throws(Error) -> Node {
var node = startingPoint
var remaining = pathComponents[...]

Expand All @@ -234,21 +234,13 @@ extension PathHierarchy {
while true {
let (children, pathComponent) = try findChildContainer(node: &node, remaining: remaining, rawPathForError: rawPathForError)

let child: PathHierarchy.Node?
do {
guard let child = try children.find(pathComponent.disambiguation) else {
// The search has ended with a node that doesn't have a child matching the next path component.
throw makePartialResultError(node: node, remaining: remaining, rawPathForError: rawPathForError)
}
node = child
remaining = remaining.dropFirst()
if remaining.isEmpty {
// If all path components are consumed, then the match is found.
return child
}
} catch DisambiguationContainer.Error.lookupCollision(let collisions) {
func handleWrappedCollision() throws -> Node {
let match = try handleCollision(node: node, remaining: remaining, collisions: collisions, onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPathForError)
return match
child = try children.find(pathComponent.disambiguation)
} catch {
let collisions = error.collisions
func handleWrappedCollision() throws(Error) -> Node {
try handleCollision(node: node, remaining: remaining, collisions: collisions, onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPathForError)
}

// When there's a collision, use the remaining path components to try and narrow down the possible collisions.
Expand Down Expand Up @@ -314,6 +306,17 @@ extension PathHierarchy {
// Couldn't resolve the collision by look ahead.
return try handleWrappedCollision()
}

guard let child else {
// The search has ended with a node that doesn't have a child matching the next path component.
throw makePartialResultError(node: node, remaining: remaining, rawPathForError: rawPathForError)
}
node = child
remaining = remaining.dropFirst()
if remaining.isEmpty {
// If all path components are consumed, then the match is found.
return child
}
}
}

Expand All @@ -336,7 +339,7 @@ extension PathHierarchy {
collisions: [(node: PathHierarchy.Node, disambiguation: String)],
onlyFindSymbols: Bool,
rawPathForError: String
) throws -> Node {
) throws(Error) -> Node {
if let favoredMatch = collisions.singleMatch({ !$0.node.isDisfavoredInLinkCollisions }) {
return favoredMatch.node
}
Expand Down Expand Up @@ -421,7 +424,7 @@ extension PathHierarchy {
node: inout Node,
remaining: ArraySlice<PathComponent>,
rawPathForError: String
) throws -> (DisambiguationContainer, PathComponent) {
) throws(Error) -> (DisambiguationContainer, PathComponent) {
var pathComponent = remaining.first!
if let match = node.children[pathComponent.full] {
// The path component parsing may treat dash separated words as disambiguation information.
Expand All @@ -439,12 +442,10 @@ extension PathHierarchy {
// MARK: Disambiguation Container

extension PathHierarchy.DisambiguationContainer {
/// Errors finding values in the disambiguation tree
enum Error: Swift.Error {
/// Multiple matches found.
///
/// Includes a list of values paired with their missing disambiguation suffixes.
case lookupCollision([(node: PathHierarchy.Node, disambiguation: String)])
/// Multiple matches found.
struct LookupCollisionError: Swift.Error {
/// A list of values paired with their missing disambiguation suffixes.
let collisions: [(node: PathHierarchy.Node, disambiguation: String)]
}

/// Attempts to find the only element in the disambiguation container without using any disambiguation information.
Expand All @@ -464,7 +465,7 @@ extension PathHierarchy.DisambiguationContainer {
/// - No match is found; indicated by a `nil` return value.
/// - Exactly one match is found; indicated by a non-nil return value.
/// - More than one match is found; indicated by a raised error listing the matches and their missing disambiguation.
func find(_ disambiguation: PathHierarchy.PathComponent.Disambiguation?) throws -> PathHierarchy.Node? {
func find(_ disambiguation: PathHierarchy.PathComponent.Disambiguation?) throws(LookupCollisionError) -> PathHierarchy.Node? {
if disambiguation == nil, let match = singleMatch() {
return match
}
Expand All @@ -478,13 +479,13 @@ extension PathHierarchy.DisambiguationContainer {
let matches = storage.filter({ $0.kind == kind })
guard matches.count <= 1 else {
// Suggest not only hash disambiguation, but also type signature disambiguation.
throw Error.lookupCollision(Self.disambiguatedValues(for: matches).map { ($0.value, $0.disambiguation.makeSuffix()) })
throw LookupCollisionError(collisions: Self.disambiguatedValues(for: matches).map { ($0.value, $0.disambiguation.makeSuffix()) })
}
return matches.first?.node
case (nil, let hash?):
let matches = storage.filter({ $0.hash == hash })
guard matches.count <= 1 else {
throw Error.lookupCollision(matches.map { ($0.node, "-" + $0.kind!) }) // An element wouldn't match if it didn't have kind disambiguation.
throw LookupCollisionError(collisions: matches.map { ($0.node, "-" + $0.kind!) }) // An element wouldn't match if it didn't have kind disambiguation.
}
return matches.first?.node
case (nil, nil):
Expand All @@ -498,13 +499,13 @@ extension PathHierarchy.DisambiguationContainer {
case (let parameterTypes?, nil):
let matches = storage.filter({ typesMatch(provided: parameterTypes, actual: $0.parameterTypes) })
guard matches.count <= 1 else {
throw Error.lookupCollision(matches.map { ($0.node, "->" + formattedTypes($0.parameterTypes)!) }) // An element wouldn't match if it didn't have parameter type disambiguation.
throw LookupCollisionError(collisions: matches.map { ($0.node, "->" + formattedTypes($0.parameterTypes)!) }) // An element wouldn't match if it didn't have parameter type disambiguation.
}
return matches.first?.node
case (nil, let returnTypes?):
let matches = storage.filter({ typesMatch(provided: returnTypes, actual: $0.returnTypes) })
guard matches.count <= 1 else {
throw Error.lookupCollision(matches.map { ($0.node, "-" + formattedTypes($0.returnTypes)!) }) // An element wouldn't match if it didn't have return type disambiguation.
throw LookupCollisionError(collisions: matches.map { ($0.node, "-" + formattedTypes($0.returnTypes)!) }) // An element wouldn't match if it didn't have return type disambiguation.
}
return matches.first?.node
case (nil, nil):
Expand All @@ -515,7 +516,7 @@ extension PathHierarchy.DisambiguationContainer {
}

// Disambiguate by a mix of kinds and USRs
throw Error.lookupCollision(self.disambiguatedValues().map { ($0.value, $0.disambiguation.makeSuffix()) })
throw LookupCollisionError(collisions: self.disambiguatedValues().map { ($0.value, $0.disambiguation.makeSuffix()) })
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ final class PathHierarchyBasedLinkResolver {
/// - isCurrentlyResolvingSymbolLink: Whether or not the documentation link is a symbol link.
/// - context: The documentation context to resolve the link in.
/// - Returns: The result of resolving the reference.
func resolve(_ unresolvedReference: UnresolvedTopicReference, in parent: ResolvedTopicReference, fromSymbolLink isCurrentlyResolvingSymbolLink: Bool) throws -> TopicReferenceResolutionResult {
func resolve(_ unresolvedReference: UnresolvedTopicReference, in parent: ResolvedTopicReference, fromSymbolLink isCurrentlyResolvingSymbolLink: Bool) throws(PathHierarchy.Error) -> TopicReferenceResolutionResult {
let parentID = resolvedReferenceMap[parent]
let found = try pathHierarchy.find(path: Self.path(for: unresolvedReference), parent: parentID, onlyFindSymbols: isCurrentlyResolvingSymbolLink)
guard let foundReference = resolvedReferenceMap[found] else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021 Apple Inc. and the Swift project authors
Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -569,7 +569,7 @@ extension ExtendedTypeFormatTransformation {
// MARK: Apply Mappings to SymbolGraph

private extension SymbolGraph {
mutating func apply(compactMap include: (SymbolGraph.Symbol) throws -> SymbolGraph.Symbol?) rethrows {
mutating func apply<Error>(compactMap include: (SymbolGraph.Symbol) throws(Error) -> SymbolGraph.Symbol?) throws(Error) {
for (key, symbol) in self.symbols {
self.symbols.removeValue(forKey: key)
if let newSymbol = try include(symbol) {
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftDocC/Semantics/Symbol/Symbol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -461,14 +461,14 @@ extension Symbol {
/// When building multi-platform documentation symbols might have more than one declaration
/// depending on variances in their implementation across platforms (e.g. use `NSPoint` vs `CGPoint` parameter in a method).
/// This method finds matching symbols between graphs and merges their declarations in case there are differences.
func mergeDeclaration(mergingDeclaration: SymbolGraph.Symbol.DeclarationFragments, identifier: String, symbolAvailability: SymbolGraph.Symbol.Availability?, alternateSymbols: SymbolGraph.Symbol.AlternateSymbols?, selector: UnifiedSymbolGraph.Selector) throws {
func mergeDeclaration(mergingDeclaration: SymbolGraph.Symbol.DeclarationFragments, identifier: String, symbolAvailability: SymbolGraph.Symbol.Availability?, alternateSymbols: SymbolGraph.Symbol.AlternateSymbols?, selector: UnifiedSymbolGraph.Selector) throws(DocumentationContext.ContextError) {
let trait = DocumentationDataVariantsTrait(for: selector)
let platformName = selector.platform

func merge<Value: Equatable>(
_ mergingValue: Value,
into variants: inout DocumentationDataVariants<[[PlatformName?] : Value]>
) throws {
) throws(DocumentationContext.ContextError) {
guard let platformName else {
variants[trait]?[[nil]] = mergingValue
return
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021 Apple Inc. and the Swift project authors
Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand All @@ -15,7 +15,7 @@ extension RangeReplaceableCollection {
///
/// - Parameter belongsInGroupWithPrevious: A check whether the given element belongs in the same group as the previous element
/// - Returns: An array of subsequences of elements that belong together.
func group(asLongAs belongsInGroupWithPrevious: (_ previous: Element, _ current: Element) throws -> Bool) rethrows -> [SubSequence] {
func group<Error>(asLongAs belongsInGroupWithPrevious: (_ previous: Element, _ current: Element) throws(Error) -> Bool) throws(Error) -> [SubSequence] {
var result = [SubSequence]()

let indexPairs = zip(indices, indices.dropFirst())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021 Apple Inc. and the Swift project authors
Copyright (c) 2021-2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -30,7 +30,7 @@ extension Sequence {
/// - Parameter predicate: A mapping closure that accepts an element of this sequence as its parameter and returns a transformed value or `nil`.
/// - Throws: Any error that's raised by the mapping closure.
/// - Returns: The first mapped, non-nil value, or `nil` if the mapping closure returned `nil` for every value in the sequence.
func mapFirst<T>(where predicate: (Element) throws -> T?) rethrows -> T? {
func mapFirst<Result, Error>(where predicate: (Element) throws(Error) -> Result?) throws(Error) -> Result? {
for element in self {
if let result = try predicate(element) {
return result
Expand Down
Loading