Skip to content

Commit acf890d

Browse files
committed
record same-package @_exported relationships
1 parent aa10fe0 commit acf890d

12 files changed

+148
-29
lines changed

Sources/SymbolGraphCompiler/SSGC.ModuleIndex.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ extension SSGC
1919
public
2020
let extensions:[SSGC.Extension]
2121
public
22+
let reexports:[Symbol.Decl]
23+
public
2224
let features:[Symbol.Decl: Feature]
2325

2426
public
@@ -34,6 +36,7 @@ extension SSGC
3436
resolvableLinks:UCF.ResolutionTable<UCF.CausalOverload>,
3537
declarations:[(id:Symbol.Module, decls:[Decl])],
3638
extensions:[SSGC.Extension],
39+
reexports:[Symbol.Decl],
3740
features:[Symbol.Decl: Feature],
3841
language:Phylum.Language? = nil,
3942
markdown:[any SSGC.ResourceFile] = [],
@@ -44,6 +47,7 @@ extension SSGC
4447
self.resolvableLinks = resolvableLinks
4548
self.declarations = declarations
4649
self.extensions = extensions
50+
self.reexports = reexports
4751
self.features = features
4852
self.language = language
4953
self.markdown = markdown

Sources/SymbolGraphCompiler/SSGC.TypeChecker.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ extension SSGC.TypeChecker
616616
$0.register($1)
617617
}
618618

619+
var reexported:[Symbol.Decl] = []
619620
for decl:SSGC.DeclObject in self.declarations.all
620621
{
621622
/// The target may have been re-exported from multiple modules. Swift allows
@@ -626,7 +627,13 @@ extension SSGC.TypeChecker
626627
{
627628
resolvableLinks[namespace, decl.value.path].append(target)
628629
}
630+
631+
if decl.culture != culture, decl.namespaces.contains(culture)
632+
{
633+
reexported.append(decl.id)
634+
}
629635
}
636+
630637
for `extension`:SSGC.ExtensionObject in self.extensions.all
631638
{
632639
// We add the feature paths here and not in `insert(_:by:)` because those
@@ -665,6 +672,7 @@ extension SSGC.TypeChecker
665672
resolvableLinks: resolvableLinks,
666673
declarations: self.declarations.load(culture: culture),
667674
extensions: extensions,
675+
reexports: reexported,
668676
features: features)
669677
}
670678
}

Sources/SymbolGraphLinker/SSGC.Linker.Tables.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,19 @@ extension SSGC.Linker.Tables
141141
}
142142
extension SSGC.Linker.Tables
143143
{
144+
func citizen(_ id:Symbol.Decl) -> Int32?
145+
{
146+
guard
147+
let scalar:Int32 = self.decls[id],
148+
self.graph.decls.contains(citizen: scalar)
149+
else
150+
{
151+
return nil
152+
}
153+
154+
return scalar
155+
}
156+
144157
/// Returns the scalar for the given declaration symbol, registering it in the symbol table
145158
/// if needed. You should never call ``allocate(decl:)`` or ``allocate(extension:)`` after
146159
/// calling this function.

Sources/SymbolGraphLinker/SSGC.Linker.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ extension SSGC.Linker
134134

135135
for (offset, module):(Int, SSGC.ModuleIndex) in zip(self.contexts.indices, indexes)
136136
{
137+
self.unfurl(reexported: module.reexports, by: offset)
137138
self.unfurl(extensions: module.extensions,
138139
featuresBySymbol: module.features,
139140
at: offset)
@@ -225,6 +226,21 @@ extension SSGC.Linker
225226
}
226227
}
227228

229+
private mutating
230+
func unfurl(reexported:[Symbol.Decl], by offset:Int)
231+
{
232+
// @_exported can duplicate a truly staggering number of declarations. To prevent this
233+
// from creating a lot of almost-empty declaration nodes, we only track modules that
234+
// re-export symbols from the same package.
235+
for id:Symbol.Decl in reexported
236+
{
237+
if let reexported:Int32 = self.tables.citizen(id)
238+
{
239+
self.tables.graph.decls.nodes[reexported].exporters.append(offset)
240+
}
241+
}
242+
}
243+
228244
/// This function also exposes any features manifested by the extensions for
229245
/// codelink resolution.
230246
///
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import BSON
2+
3+
extension SymbolGraph
4+
{
5+
/// A type that can serialize an array of ``Int`` indices much more compactly than a native
6+
/// BSON list. This must only be used for arrays of indices that are known to be small,
7+
/// like modules. Specifically, indices must be less than 2^16.
8+
@frozen @usableFromInline
9+
struct Buffer16:Equatable, Sendable
10+
{
11+
@usableFromInline
12+
var elements:[Int]
13+
14+
@inlinable internal
15+
init(_ elements:[Int])
16+
{
17+
self.elements = elements
18+
}
19+
}
20+
}
21+
extension SymbolGraph.Buffer16
22+
{
23+
@inlinable internal
24+
init?(elidingEmpty elements:[Int])
25+
{
26+
if elements.isEmpty
27+
{
28+
return nil
29+
}
30+
else
31+
{
32+
self.init(elements)
33+
}
34+
}
35+
}
36+
37+
extension SymbolGraph.Buffer16:RandomAccessCollection
38+
{
39+
@inlinable
40+
var startIndex:Int { self.elements.startIndex }
41+
42+
@inlinable
43+
var endIndex:Int { self.elements.endIndex }
44+
45+
@inlinable
46+
subscript(position:Int) -> CodingElement
47+
{
48+
get
49+
{
50+
let scalar:Int = self.elements[position]
51+
return
52+
(
53+
UInt8.init(truncatingIfNeeded: scalar),
54+
UInt8.init(truncatingIfNeeded: scalar >> 8)
55+
)
56+
}
57+
}
58+
}
59+
extension SymbolGraph.Buffer16:BSONArrayEncodable
60+
{
61+
}
62+
extension SymbolGraph.Buffer16:BSONArrayDecodable
63+
{
64+
@usableFromInline
65+
typealias CodingElement = (UInt8, UInt8)
66+
67+
@inlinable
68+
init(from bson:borrowing BSON.BinaryArray<CodingElement>) throws
69+
{
70+
self.init(bson.map { Int.init($0) | Int.init($1) << 8 })
71+
}
72+
}

Sources/SymbolGraphs/Buffers/SymbolGraph.Buffer.swift renamed to Sources/SymbolGraphs/Buffers/SymbolGraph.Buffer24.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@ extension SymbolGraph
77
///
88
/// Empirically, this type reduces symbol graph archive size by around
99
/// 3 to 8 percent.
10-
@frozen @usableFromInline internal
11-
struct Buffer:Equatable, Sendable
10+
@frozen @usableFromInline
11+
struct Buffer24:Equatable, Sendable
1212
{
13-
@usableFromInline internal
13+
@usableFromInline
1414
var elements:[Int32]
1515

16-
@inlinable internal
16+
@inlinable
1717
init(_ elements:[Int32])
1818
{
1919
self.elements = elements
2020
}
2121
}
2222
}
23-
extension SymbolGraph.Buffer
23+
extension SymbolGraph.Buffer24
2424
{
25-
@inlinable internal
25+
@inlinable
2626
init?(elidingEmpty elements:[Int32])
2727
{
2828
if elements.isEmpty
@@ -36,7 +36,7 @@ extension SymbolGraph.Buffer
3636
}
3737
}
3838

39-
extension SymbolGraph.Buffer:RandomAccessCollection
39+
extension SymbolGraph.Buffer24:RandomAccessCollection
4040
{
4141
@inlinable
4242
var startIndex:Int { self.elements.startIndex }
@@ -59,10 +59,10 @@ extension SymbolGraph.Buffer:RandomAccessCollection
5959
}
6060
}
6161
}
62-
extension SymbolGraph.Buffer:BSONArrayEncodable
62+
extension SymbolGraph.Buffer24:BSONArrayEncodable
6363
{
6464
}
65-
extension SymbolGraph.Buffer:BSONArrayDecodable
65+
extension SymbolGraph.Buffer24:BSONArrayDecodable
6666
{
6767
@usableFromInline
6868
typealias CodingElement = (UInt8, UInt8, UInt8)

Sources/SymbolGraphs/Declarations/SymbolGraph.Decl.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,10 @@ extension SymbolGraph.Decl:BSONDocumentEncodable
190190
/// Do *not* elide empty SPI arrays!
191191
bson[.signature_spis] = self.signature.spis
192192

193-
bson[.requirements] = SymbolGraph.Buffer.init(elidingEmpty: self.requirements)
194-
bson[.inhabitants] = SymbolGraph.Buffer.init(elidingEmpty: self.inhabitants)
195-
bson[.superforms] = SymbolGraph.Buffer.init(elidingEmpty: self.superforms)
196-
bson[.features] = SymbolGraph.Buffer.init(elidingEmpty: self.features)
193+
bson[.requirements] = SymbolGraph.Buffer24.init(elidingEmpty: self.requirements)
194+
bson[.inhabitants] = SymbolGraph.Buffer24.init(elidingEmpty: self.inhabitants)
195+
bson[.superforms] = SymbolGraph.Buffer24.init(elidingEmpty: self.superforms)
196+
bson[.features] = SymbolGraph.Buffer24.init(elidingEmpty: self.features)
197197

198198
bson[.renamed] = self.renamed
199199
bson[.origin] = self.origin
@@ -232,13 +232,13 @@ extension SymbolGraph.Decl:BSONDocumentDecodable
232232

233233
location: try bson[.location]?.decode(),
234234
article: try bson[.article]?.decode(),
235-
requirements: try bson[.requirements]?.decode(as: SymbolGraph.Buffer.self,
235+
requirements: try bson[.requirements]?.decode(as: SymbolGraph.Buffer24.self,
236236
with: \.elements) ?? [],
237-
inhabitants: try bson[.inhabitants]?.decode(as: SymbolGraph.Buffer.self,
237+
inhabitants: try bson[.inhabitants]?.decode(as: SymbolGraph.Buffer24.self,
238238
with: \.elements) ?? [],
239-
superforms: try bson[.superforms]?.decode(as: SymbolGraph.Buffer.self,
239+
superforms: try bson[.superforms]?.decode(as: SymbolGraph.Buffer24.self,
240240
with: \.elements) ?? [],
241-
features: try bson[.features]?.decode(as: SymbolGraph.Buffer.self,
241+
features: try bson[.features]?.decode(as: SymbolGraph.Buffer24.self,
242242
with: \.elements) ?? [],
243243
renamed: try bson[.renamed]?.decode(),
244244
origin: try bson[.origin]?.decode())

Sources/SymbolGraphs/Declarations/SymbolGraph.DeclNode.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ extension SymbolGraph
1111
public
1212
var extensions:[Extension]
1313
public
14+
var exporters:[Int]
15+
public
1416
var decl:Decl?
1517

1618
@inlinable public
17-
init(extensions:[Extension] = [], decl:Decl? = nil)
19+
init(extensions:[Extension] = [], exporters:[Int] = [], decl:Decl? = nil)
1820
{
1921
self.extensions = extensions
22+
self.exporters = exporters
2023
self.decl = decl
2124
}
2225
}
@@ -47,6 +50,7 @@ extension SymbolGraph.DeclNode
4750
enum CodingKey:String, Sendable
4851
{
4952
case extensions = "E"
53+
case exporters = "X"
5054
case decl = "V"
5155
}
5256
}
@@ -56,6 +60,7 @@ extension SymbolGraph.DeclNode:BSONDocumentEncodable
5660
func encode(to bson:inout BSON.DocumentEncoder<CodingKey>)
5761
{
5862
bson[.decl] = self.decl
63+
bson[.exporters] = SymbolGraph.Buffer16.init(elidingEmpty: self.exporters)
5964
bson[.extensions] = self.extensions.isEmpty ? nil : self.extensions
6065
}
6166
}
@@ -66,6 +71,8 @@ extension SymbolGraph.DeclNode:BSONDocumentDecodable
6671
{
6772
self.init(
6873
extensions: try bson[.extensions]?.decode() ?? [],
74+
exporters: try bson[.exporters]?.decode(
75+
as: SymbolGraph.Buffer16.self, with: \.elements) ?? [],
6976
decl: try bson[.decl]?.decode())
7077
}
7178
}

Sources/SymbolGraphs/Declarations/SymbolGraph.DeclPlane.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ extension SymbolGraph
33
@frozen public
44
enum DeclPlane:SymbolGraph.PlaneType
55
{
6-
@inlinable public static
7-
var plane:SymbolGraph.Plane { .decl }
6+
@inlinable public
7+
static var plane:SymbolGraph.Plane { .decl }
88
}
99
}

Sources/SymbolGraphs/Declarations/SymbolGraph.Extension.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ extension SymbolGraph.Extension:BSONDocumentEncodable
7878
bson[.namespace] = self.culture == self.namespace ? nil : self.namespace
7979
bson[.culture] = self.culture
8080

81-
bson[.conformances] = SymbolGraph.Buffer.init(elidingEmpty: self.conformances)
82-
bson[.features] = SymbolGraph.Buffer.init(elidingEmpty: self.features)
83-
bson[.nested] = SymbolGraph.Buffer.init(elidingEmpty: self.nested)
81+
bson[.conformances] = SymbolGraph.Buffer24.init(elidingEmpty: self.conformances)
82+
bson[.features] = SymbolGraph.Buffer24.init(elidingEmpty: self.features)
83+
bson[.nested] = SymbolGraph.Buffer24.init(elidingEmpty: self.nested)
8484

8585
bson[.article] = self.article
8686
}
@@ -95,11 +95,11 @@ extension SymbolGraph.Extension:BSONDocumentDecodable
9595
namespace: try bson[.namespace]?.decode() ?? culture,
9696
culture: culture,
9797
conformances: try bson[.conformances]?.decode(
98-
as: SymbolGraph.Buffer.self, with: \.elements) ?? [],
98+
as: SymbolGraph.Buffer24.self, with: \.elements) ?? [],
9999
features: try bson[.features]?.decode(
100-
as: SymbolGraph.Buffer.self, with: \.elements) ?? [],
100+
as: SymbolGraph.Buffer24.self, with: \.elements) ?? [],
101101
nested: try bson[.nested]?.decode(
102-
as: SymbolGraph.Buffer.self, with: \.elements) ?? [],
102+
as: SymbolGraph.Buffer24.self, with: \.elements) ?? [],
103103
article: try bson[.article]?.decode())
104104
}
105105
}

0 commit comments

Comments
 (0)