Skip to content

Commit

Permalink
Merge pull request #348 from tayloraswift/fix-false-positive-ambiguou…
Browse files Browse the repository at this point in the history
…s-link

fix false-positive ambiguous link error, and add a regression test
  • Loading branch information
tayloraswift authored Sep 29, 2024
2 parents 1db4476 + af433a4 commit 5e79ca2
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 18 deletions.
52 changes: 36 additions & 16 deletions Sources/LinkResolution/UCF.ResolutionTable.Search.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import InlineArray
import Symbols
import UCF

extension UCF.ResolutionTable
Expand All @@ -9,15 +10,15 @@ extension UCF.ResolutionTable
let predicate:UCF.Selector.Suffix?

private
var selected:InlineArray<Overload>
var selected:[Symbol.Decl: Overload]
private
var rejected:[Overload]
var rejected:[Symbol.Decl: Overload]

init(matching predicate:UCF.Selector.Suffix?)
{
self.predicate = predicate
self.selected = []
self.rejected = []
self.selected = [:]
self.rejected = [:]
}
}
}
Expand All @@ -26,43 +27,62 @@ extension UCF.ResolutionTable.Search
mutating
func add(_ candidates:InlineArray<Overload>)
{
// Because of the way `@_exported` paths are represented in the search tree, it is
// possible to encounter the same overload multiple times, due to namespace inference
if let predicate:UCF.Selector.Suffix = self.predicate
{
for overload:Overload in candidates
{
predicate ~= overload ?
self.selected.append(overload) :
self.rejected.append(overload)
guard predicate ~= overload
else
{
self.rejected[overload.id] = overload
continue
}

self.selected[overload.id] = overload
}
}
else
{
for overload:Overload in candidates
{
self.selected.append(overload)
self.selected[overload.id] = overload
}
}
}

func any() -> UCF.Resolution<Overload>?
{
switch self.selected
guard
let overload:Overload = self.selected.values.first
else
{
case .one(let overload):
.overload(overload)
return nil
}

case .some(let overloads):
overloads.isEmpty ? nil : .ambiguous(overloads, rejected: self.rejected)
if self.selected.count == 1
{
return .overload(overload)
}
else
{
return .ambiguous(self.selected.values.sorted { $0.id < $1.id },
rejected: self.rejected.values.sorted { $0.id < $1.id })
}
}

consuming
func get() -> UCF.Resolution<Overload>
{
switch self.selected
if let overload:Overload = self.selected.values.first, self.selected.count == 1
{
return .overload(overload)
}
else
{
case .one(let overload): .overload(overload)
case .some(let overloads): .ambiguous(overloads, rejected: self.rejected)
return .ambiguous(self.selected.values.sorted { $0.id < $1.id },
rejected: self.rejected.values.sorted { $0.id < $1.id })
}
}
}
12 changes: 10 additions & 2 deletions Sources/SymbolGraphBuilder/Builds/SSGC.Workspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,25 @@ extension SSGC.Workspace
public
func build(package build:SSGC.PackageBuild,
with swift:SSGC.Toolchain,
validation:SSGC.ValidationBehavior = .ignoreErrors,
clean:Bool = true) throws -> SymbolGraphObject<Void>
{
try self.build(some: build, toolchain: swift, status: nil, clean: clean)
try self.build(some: build, toolchain: swift,
status: nil,
logger: .init(validation: validation, file: nil),
clean: clean)
}

public
func build(special build:SSGC.StandardLibraryBuild,
with swift:SSGC.Toolchain,
validation:SSGC.ValidationBehavior = .ignoreErrors,
clean:Bool = true) throws -> SymbolGraphObject<Void>
{
try self.build(some: build, toolchain: swift, status: nil, clean: clean)
try self.build(some: build, toolchain: swift,
status: nil,
logger: .init(validation: validation, file: nil),
clean: clean)
}
}
extension SSGC.Workspace
Expand Down
11 changes: 11 additions & 0 deletions Sources/SymbolGraphBuilderTests/Main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ enum Main:TestMain, TestBattery

#endif

if let tests:TestGroup = tests / "Reexportation",
let _:SymbolGraphObject<Void> = (tests.do
{
try workspace.build(
package: .local(project: "TestPackages" / "swift-exportation"),
with: toolchain,
validation: .failOnErrors)
})
{
}

group:
if let tests:TestGroup = tests / "Local",
let docs:SymbolGraphObject<Void> = (tests.do
Expand Down
15 changes: 15 additions & 0 deletions TestPackages/swift-exportation/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// swift-tools-version:5.10
import PackageDescription

let package:Package = .init(name: "Swift Unidoc Exportation Tests",
products:
[
.library(name: "A", targets: ["A"]),
.library(name: "B", targets: ["B"]),
],
targets:
[
.target(name: "_A"),
.target(name: "A", dependencies: ["_A"]),
.target(name: "B", dependencies: ["A"]),
])
1 change: 1 addition & 0 deletions TestPackages/swift-exportation/Sources/A/exports.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@_exported import _A
Empty file.
7 changes: 7 additions & 0 deletions TestPackages/swift-exportation/Sources/B/docs.docc/Article.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Exportation tests

All of the following should be valid links:

- ``A``
- ``A.A``
- ``_A.A``
4 changes: 4 additions & 0 deletions TestPackages/swift-exportation/Sources/_A/A.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public
enum A
{
}

0 comments on commit 5e79ca2

Please sign in to comment.