1
1
/*
2
2
This source file is part of the Swift.org open source project
3
3
4
- Copyright (c) 2023-2024 Apple Inc. and the Swift project authors
4
+ Copyright (c) 2023-2025 Apple Inc. and the Swift project authors
5
5
Licensed under Apache License v2.0 with Runtime Library Exception
6
6
7
7
See https://swift.org/LICENSE.txt for license information
@@ -20,11 +20,11 @@ extension PathHierarchy {
20
20
/// - onlyFindSymbols: Whether or not only symbol matches should be found.
21
21
/// - Returns: Returns the unique identifier for the found match or raises an error if no match can be found.
22
22
/// - Throws: Raises a ``PathHierarchy/Error`` if no match can be found.
23
- func find( path rawPath: String , parent: ResolvedIdentifier ? = nil , onlyFindSymbols: Bool ) throws -> ResolvedIdentifier {
23
+ func find( path rawPath: String , parent: ResolvedIdentifier ? = nil , onlyFindSymbols: Bool ) throws ( Error ) -> ResolvedIdentifier {
24
24
return try findNode ( path: rawPath, parentID: parent, onlyFindSymbols: onlyFindSymbols) . identifier
25
25
}
26
26
27
- private func findNode( path rawPath: String , parentID: ResolvedIdentifier ? , onlyFindSymbols: Bool ) throws -> Node {
27
+ private func findNode( path rawPath: String , parentID: ResolvedIdentifier ? , onlyFindSymbols: Bool ) throws ( Error ) -> Node {
28
28
// The search for a documentation element can be though of as 3 steps:
29
29
// - First, parse the path into structured path components.
30
30
// - Second, find nodes that match the beginning of the path as starting points for the search
@@ -79,15 +79,15 @@ extension PathHierarchy {
79
79
}
80
80
81
81
// A function to avoid repeating the
82
- func searchForNodeInModules( ) throws -> Node {
82
+ func searchForNodeInModules( ) throws ( Error ) -> Node {
83
83
// Note: This captures `parentID`, `remaining`, and `rawPathForError`.
84
84
if let moduleMatch = modules. first ( where: { $0. matches ( firstComponent) } ) {
85
85
return try searchForNode ( descendingFrom: moduleMatch, pathComponents: remaining. dropFirst ( ) , onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPath)
86
86
}
87
87
if modules. count == 1 {
88
88
do {
89
89
return try searchForNode ( descendingFrom: modules. first!, pathComponents: remaining, onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPath)
90
- } catch let error as PathHierarchy . Error {
90
+ } catch {
91
91
switch error {
92
92
case . notFound:
93
93
// Ignore this error and raise an error about not finding the module instead.
@@ -129,7 +129,7 @@ extension PathHierarchy {
129
129
}
130
130
131
131
// A recursive function to traverse up the path hierarchy searching for the matching node
132
- func searchForNodeUpTheHierarchy( from startingPoint: Node ? , path: ArraySlice < PathComponent > ) throws -> Node {
132
+ func searchForNodeUpTheHierarchy( from startingPoint: Node ? , path: ArraySlice < PathComponent > ) throws ( Error ) -> Node {
133
133
guard let possibleStartingPoint = startingPoint else {
134
134
// If the search has reached the top of the hierarchy, check the modules as a base case to break the recursion.
135
135
do {
@@ -147,7 +147,7 @@ extension PathHierarchy {
147
147
let firstComponent = path. first!
148
148
149
149
// Keep track of the inner most error and raise that if no node is found.
150
- var innerMostError : ( any Swift . Error ) ?
150
+ var innerMostError : Error ?
151
151
152
152
// If the starting point's children match this component, descend the path hierarchy from there.
153
153
if possibleStartingPoint. anyChildMatches ( firstComponent) {
@@ -211,7 +211,7 @@ extension PathHierarchy {
211
211
pathComponents: ArraySlice < PathComponent > ,
212
212
onlyFindSymbols: Bool ,
213
213
rawPathForError: String
214
- ) throws -> Node {
214
+ ) throws ( Error ) -> Node {
215
215
// All code paths through this function wants to perform extra verification on the return value before returning it to the caller.
216
216
// To accomplish that, the core implementation happens in `_innerImplementation`, which is called once, right below its definition.
217
217
@@ -220,7 +220,7 @@ extension PathHierarchy {
220
220
pathComponents: ArraySlice < PathComponent > ,
221
221
onlyFindSymbols: Bool ,
222
222
rawPathForError: String
223
- ) throws -> Node {
223
+ ) throws ( Error ) -> Node {
224
224
var node = startingPoint
225
225
var remaining = pathComponents [ ... ]
226
226
@@ -234,21 +234,13 @@ extension PathHierarchy {
234
234
while true {
235
235
let ( children, pathComponent) = try findChildContainer ( node: & node, remaining: remaining, rawPathForError: rawPathForError)
236
236
237
+ let child : PathHierarchy . Node ?
237
238
do {
238
- guard let child = try children. find ( pathComponent. disambiguation) else {
239
- // The search has ended with a node that doesn't have a child matching the next path component.
240
- throw makePartialResultError ( node: node, remaining: remaining, rawPathForError: rawPathForError)
241
- }
242
- node = child
243
- remaining = remaining. dropFirst ( )
244
- if remaining. isEmpty {
245
- // If all path components are consumed, then the match is found.
246
- return child
247
- }
248
- } catch DisambiguationContainer . Error . lookupCollision( let collisions) {
249
- func handleWrappedCollision( ) throws -> Node {
250
- let match = try handleCollision ( node: node, remaining: remaining, collisions: collisions, onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPathForError)
251
- return match
239
+ child = try children. find ( pathComponent. disambiguation)
240
+ } catch {
241
+ let collisions = error. collisions
242
+ func handleWrappedCollision( ) throws ( Error) -> Node {
243
+ try handleCollision ( node: node, remaining: remaining, collisions: collisions, onlyFindSymbols: onlyFindSymbols, rawPathForError: rawPathForError)
252
244
}
253
245
254
246
// When there's a collision, use the remaining path components to try and narrow down the possible collisions.
@@ -314,6 +306,17 @@ extension PathHierarchy {
314
306
// Couldn't resolve the collision by look ahead.
315
307
return try handleWrappedCollision ( )
316
308
}
309
+
310
+ guard let child else {
311
+ // The search has ended with a node that doesn't have a child matching the next path component.
312
+ throw makePartialResultError ( node: node, remaining: remaining, rawPathForError: rawPathForError)
313
+ }
314
+ node = child
315
+ remaining = remaining. dropFirst ( )
316
+ if remaining. isEmpty {
317
+ // If all path components are consumed, then the match is found.
318
+ return child
319
+ }
317
320
}
318
321
}
319
322
@@ -336,7 +339,7 @@ extension PathHierarchy {
336
339
collisions: [ ( node: PathHierarchy . Node , disambiguation: String ) ] ,
337
340
onlyFindSymbols: Bool ,
338
341
rawPathForError: String
339
- ) throws -> Node {
342
+ ) throws ( Error ) -> Node {
340
343
if let favoredMatch = collisions. singleMatch ( { !$0. node. isDisfavoredInLinkCollisions } ) {
341
344
return favoredMatch. node
342
345
}
@@ -421,7 +424,7 @@ extension PathHierarchy {
421
424
node: inout Node ,
422
425
remaining: ArraySlice < PathComponent > ,
423
426
rawPathForError: String
424
- ) throws -> ( DisambiguationContainer , PathComponent ) {
427
+ ) throws ( Error ) -> ( DisambiguationContainer , PathComponent ) {
425
428
var pathComponent = remaining. first!
426
429
if let match = node. children [ pathComponent. full] {
427
430
// The path component parsing may treat dash separated words as disambiguation information.
@@ -439,12 +442,10 @@ extension PathHierarchy {
439
442
// MARK: Disambiguation Container
440
443
441
444
extension PathHierarchy . DisambiguationContainer {
442
- /// Errors finding values in the disambiguation tree
443
- enum Error : Swift . Error {
444
- /// Multiple matches found.
445
- ///
446
- /// Includes a list of values paired with their missing disambiguation suffixes.
447
- case lookupCollision( [ ( node: PathHierarchy . Node , disambiguation: String ) ] )
445
+ /// Multiple matches found.
446
+ struct LookupCollisionError : Swift . Error {
447
+ /// A list of values paired with their missing disambiguation suffixes.
448
+ let collisions : [ ( node: PathHierarchy . Node , disambiguation: String ) ]
448
449
}
449
450
450
451
/// Attempts to find the only element in the disambiguation container without using any disambiguation information.
@@ -464,7 +465,7 @@ extension PathHierarchy.DisambiguationContainer {
464
465
/// - No match is found; indicated by a `nil` return value.
465
466
/// - Exactly one match is found; indicated by a non-nil return value.
466
467
/// - More than one match is found; indicated by a raised error listing the matches and their missing disambiguation.
467
- func find( _ disambiguation: PathHierarchy . PathComponent . Disambiguation ? ) throws -> PathHierarchy . Node ? {
468
+ func find( _ disambiguation: PathHierarchy . PathComponent . Disambiguation ? ) throws ( LookupCollisionError ) -> PathHierarchy . Node ? {
468
469
if disambiguation == nil , let match = singleMatch ( ) {
469
470
return match
470
471
}
@@ -478,13 +479,13 @@ extension PathHierarchy.DisambiguationContainer {
478
479
let matches = storage. filter ( { $0. kind == kind } )
479
480
guard matches. count <= 1 else {
480
481
// Suggest not only hash disambiguation, but also type signature disambiguation.
481
- throw Error . lookupCollision ( Self . disambiguatedValues ( for: matches) . map { ( $0. value, $0. disambiguation. makeSuffix ( ) ) } )
482
+ throw LookupCollisionError ( collisions : Self . disambiguatedValues ( for: matches) . map { ( $0. value, $0. disambiguation. makeSuffix ( ) ) } )
482
483
}
483
484
return matches. first? . node
484
485
case ( nil , let hash? ) :
485
486
let matches = storage. filter ( { $0. hash == hash } )
486
487
guard matches. count <= 1 else {
487
- throw Error . lookupCollision ( matches. map { ( $0. node, " - " + $0. kind!) } ) // An element wouldn't match if it didn't have kind disambiguation.
488
+ throw LookupCollisionError ( collisions : matches. map { ( $0. node, " - " + $0. kind!) } ) // An element wouldn't match if it didn't have kind disambiguation.
488
489
}
489
490
return matches. first? . node
490
491
case ( nil , nil ) :
@@ -498,13 +499,13 @@ extension PathHierarchy.DisambiguationContainer {
498
499
case ( let parameterTypes? , nil ) :
499
500
let matches = storage. filter ( { typesMatch ( provided: parameterTypes, actual: $0. parameterTypes) } )
500
501
guard matches. count <= 1 else {
501
- throw Error . lookupCollision ( matches. map { ( $0. node, " -> " + formattedTypes( $0. parameterTypes) !) } ) // An element wouldn't match if it didn't have parameter type disambiguation.
502
+ throw LookupCollisionError ( collisions : matches. map { ( $0. node, " -> " + formattedTypes( $0. parameterTypes) !) } ) // An element wouldn't match if it didn't have parameter type disambiguation.
502
503
}
503
504
return matches. first? . node
504
505
case ( nil , let returnTypes? ) :
505
506
let matches = storage. filter ( { typesMatch ( provided: returnTypes, actual: $0. returnTypes) } )
506
507
guard matches. count <= 1 else {
507
- throw Error . lookupCollision ( matches. map { ( $0. node, " - " + formattedTypes( $0. returnTypes) !) } ) // An element wouldn't match if it didn't have return type disambiguation.
508
+ throw LookupCollisionError ( collisions : matches. map { ( $0. node, " - " + formattedTypes( $0. returnTypes) !) } ) // An element wouldn't match if it didn't have return type disambiguation.
508
509
}
509
510
return matches. first? . node
510
511
case ( nil , nil ) :
@@ -515,7 +516,7 @@ extension PathHierarchy.DisambiguationContainer {
515
516
}
516
517
517
518
// Disambiguate by a mix of kinds and USRs
518
- throw Error . lookupCollision ( self . disambiguatedValues ( ) . map { ( $0. value, $0. disambiguation. makeSuffix ( ) ) } )
519
+ throw LookupCollisionError ( collisions : self . disambiguatedValues ( ) . map { ( $0. value, $0. disambiguation. makeSuffix ( ) ) } )
519
520
}
520
521
}
521
522
0 commit comments