Skip to content

Commit 5e79ca2

Browse files
authored
Merge pull request #348 from tayloraswift/fix-false-positive-ambiguous-link
fix false-positive ambiguous link error, and add a regression test
2 parents 1db4476 + af433a4 commit 5e79ca2

File tree

8 files changed

+84
-18
lines changed

8 files changed

+84
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import InlineArray
2+
import Symbols
23
import UCF
34

45
extension UCF.ResolutionTable
@@ -9,15 +10,15 @@ extension UCF.ResolutionTable
910
let predicate:UCF.Selector.Suffix?
1011

1112
private
12-
var selected:InlineArray<Overload>
13+
var selected:[Symbol.Decl: Overload]
1314
private
14-
var rejected:[Overload]
15+
var rejected:[Symbol.Decl: Overload]
1516

1617
init(matching predicate:UCF.Selector.Suffix?)
1718
{
1819
self.predicate = predicate
19-
self.selected = []
20-
self.rejected = []
20+
self.selected = [:]
21+
self.rejected = [:]
2122
}
2223
}
2324
}
@@ -26,43 +27,62 @@ extension UCF.ResolutionTable.Search
2627
mutating
2728
func add(_ candidates:InlineArray<Overload>)
2829
{
30+
// Because of the way `@_exported` paths are represented in the search tree, it is
31+
// possible to encounter the same overload multiple times, due to namespace inference
2932
if let predicate:UCF.Selector.Suffix = self.predicate
3033
{
3134
for overload:Overload in candidates
3235
{
33-
predicate ~= overload ?
34-
self.selected.append(overload) :
35-
self.rejected.append(overload)
36+
guard predicate ~= overload
37+
else
38+
{
39+
self.rejected[overload.id] = overload
40+
continue
41+
}
42+
43+
self.selected[overload.id] = overload
3644
}
3745
}
3846
else
3947
{
4048
for overload:Overload in candidates
4149
{
42-
self.selected.append(overload)
50+
self.selected[overload.id] = overload
4351
}
4452
}
4553
}
4654

4755
func any() -> UCF.Resolution<Overload>?
4856
{
49-
switch self.selected
57+
guard
58+
let overload:Overload = self.selected.values.first
59+
else
5060
{
51-
case .one(let overload):
52-
.overload(overload)
61+
return nil
62+
}
5363

54-
case .some(let overloads):
55-
overloads.isEmpty ? nil : .ambiguous(overloads, rejected: self.rejected)
64+
if self.selected.count == 1
65+
{
66+
return .overload(overload)
67+
}
68+
else
69+
{
70+
return .ambiguous(self.selected.values.sorted { $0.id < $1.id },
71+
rejected: self.rejected.values.sorted { $0.id < $1.id })
5672
}
5773
}
5874

5975
consuming
6076
func get() -> UCF.Resolution<Overload>
6177
{
62-
switch self.selected
78+
if let overload:Overload = self.selected.values.first, self.selected.count == 1
79+
{
80+
return .overload(overload)
81+
}
82+
else
6383
{
64-
case .one(let overload): .overload(overload)
65-
case .some(let overloads): .ambiguous(overloads, rejected: self.rejected)
84+
return .ambiguous(self.selected.values.sorted { $0.id < $1.id },
85+
rejected: self.rejected.values.sorted { $0.id < $1.id })
6686
}
6787
}
6888
}

Sources/SymbolGraphBuilder/Builds/SSGC.Workspace.swift

+10-2
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,25 @@ extension SSGC.Workspace
5454
public
5555
func build(package build:SSGC.PackageBuild,
5656
with swift:SSGC.Toolchain,
57+
validation:SSGC.ValidationBehavior = .ignoreErrors,
5758
clean:Bool = true) throws -> SymbolGraphObject<Void>
5859
{
59-
try self.build(some: build, toolchain: swift, status: nil, clean: clean)
60+
try self.build(some: build, toolchain: swift,
61+
status: nil,
62+
logger: .init(validation: validation, file: nil),
63+
clean: clean)
6064
}
6165

6266
public
6367
func build(special build:SSGC.StandardLibraryBuild,
6468
with swift:SSGC.Toolchain,
69+
validation:SSGC.ValidationBehavior = .ignoreErrors,
6570
clean:Bool = true) throws -> SymbolGraphObject<Void>
6671
{
67-
try self.build(some: build, toolchain: swift, status: nil, clean: clean)
72+
try self.build(some: build, toolchain: swift,
73+
status: nil,
74+
logger: .init(validation: validation, file: nil),
75+
clean: clean)
6876
}
6977
}
7078
extension SSGC.Workspace

Sources/SymbolGraphBuilderTests/Main.swift

+11
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,17 @@ enum Main:TestMain, TestBattery
153153

154154
#endif
155155

156+
if let tests:TestGroup = tests / "Reexportation",
157+
let _:SymbolGraphObject<Void> = (tests.do
158+
{
159+
try workspace.build(
160+
package: .local(project: "TestPackages" / "swift-exportation"),
161+
with: toolchain,
162+
validation: .failOnErrors)
163+
})
164+
{
165+
}
166+
156167
group:
157168
if let tests:TestGroup = tests / "Local",
158169
let docs:SymbolGraphObject<Void> = (tests.do
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// swift-tools-version:5.10
2+
import PackageDescription
3+
4+
let package:Package = .init(name: "Swift Unidoc Exportation Tests",
5+
products:
6+
[
7+
.library(name: "A", targets: ["A"]),
8+
.library(name: "B", targets: ["B"]),
9+
],
10+
targets:
11+
[
12+
.target(name: "_A"),
13+
.target(name: "A", dependencies: ["_A"]),
14+
.target(name: "B", dependencies: ["A"]),
15+
])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@_exported import _A

TestPackages/swift-exportation/Sources/B/anchor.swift

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Exportation tests
2+
3+
All of the following should be valid links:
4+
5+
- ``A``
6+
- ``A.A``
7+
- ``_A.A``
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public
2+
enum A
3+
{
4+
}

0 commit comments

Comments
 (0)