Skip to content

Commit 24a8dd6

Browse files
committed
correct the invalid namespaces recorded by lib/SymbolGraphGen
1 parent 157528e commit 24a8dd6

File tree

5 files changed

+88
-42
lines changed

5 files changed

+88
-42
lines changed

Sources/SymbolGraphCompiler/Declarations/SSGC.DeclObject.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ extension SSGC
1313
class DeclObject
1414
{
1515
let conditions:Set<GenericConstraint<Symbol.Decl>>
16-
let namespace:Symbol.Module
16+
var namespace:Symbol.Module
1717
let culture:Symbol.Module
18-
let access:Symbol.ACL
18+
var access:Symbol.ACL
1919

2020
/// The outer set is populated by redundant implicit conformances produced by
2121
/// lib/SymbolGraphGen.

Sources/SymbolGraphCompiler/Declarations/SSGC.Declarations.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ extension SSGC
2424
}
2525
extension SSGC.Declarations
2626
{
27+
/// Returns the declaration object, or nil if it has already been indexed, or does not meet
28+
/// the minimum visibility threshold.
2729
mutating
2830
func include(_ vertex:SymbolGraphPart.Vertex,
2931
namespace:Symbol.Module,
30-
culture:Symbol.Module) -> SSGC.DeclObject
32+
culture:Symbol.Module) -> SSGC.DeclObject?
3133
{
3234
guard
3335
case .scalar(let symbol) = vertex.usr,
@@ -37,11 +39,12 @@ extension SSGC.Declarations
3739
fatalError("vertex is not a decl!")
3840
}
3941

40-
let decl:SSGC.DeclObject =
42+
let decl:SSGC.DeclObject? =
4143
{
42-
if let decl:SSGC.DeclObject = $0
44+
guard case nil = $0
45+
else
4346
{
44-
return decl
47+
return nil
4548
}
4649

4750
var kinks:Phylum.Decl.Kinks = []
@@ -72,7 +75,7 @@ extension SSGC.Declarations
7275
comment: vertex.doccomment.map { .init($0.text, at: $0.start) } ?? nil))
7376

7477
$0 = decl
75-
return decl
78+
return decl.access < self.threshold ? nil : decl
7679

7780
} (&self.decls[symbol])
7881

Sources/SymbolGraphCompiler/SSGC.TypeChecker.swift

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ extension SSGC.TypeChecker
7676
/// We use this to look up protocols by name instead of symbol. This is needed in order
7777
/// to work around some bizarre lib/SymbolGraphGen bugs.
7878
var protocolsByName:[UnqualifiedPath: Symbol.Decl] = [:]
79-
var children:[SSGC.DeclObject] = []
79+
var children:[Int: [SSGC.DeclObject]] = [:]
8080
// Pass I. Gather scalars, extension blocks, and extension relationships.
8181
for part:SSGC.SymbolDump in culture.symbols
8282
{
@@ -91,33 +91,40 @@ extension SSGC.TypeChecker
9191
switch vertex.usr
9292
{
9393
case .block(let symbol):
94-
// We *do* in fact care about extension blocks that only contain
95-
// internal/private members, because they might contain a conformance
96-
// to an internal protocol that inherits from a public protocol.
97-
// SymbolGraphGen probably shouldn’t be marking these extension blocks
98-
// as internal, but SymbolGraphGen doesn’t care what we think.
94+
// We *do* in fact care about extension blocks that only contain
95+
// internal/private members, because they might contain a conformance
96+
// to an internal protocol that inherits from a public protocol.
97+
// SymbolGraphGen probably shouldn’t be marking these extension blocks
98+
// as internal, but SymbolGraphGen doesn’t care what we think.
9999
self.extensions.include(vertex,
100100
extending: try extensions.extendee(of: symbol),
101101
culture: id)
102102

103103
case .scalar(let symbol):
104+
guard
104105
let decl:SSGC.DeclObject = self.declarations.include(vertex,
105106
namespace: namespace,
106107
culture: id)
108+
else
109+
{
110+
// Declaration is private or re-exported.
111+
continue
112+
}
107113

108114
if case .decl(.protocol) = vertex.phylum
109115
{
110116
protocolsByName[vertex.path] = symbol
111117
}
112-
else if !decl.value.path.prefix.isEmpty
118+
119+
let depth:Int = decl.value.path.prefix.count
120+
if depth > 0
113121
{
114-
children.append(decl)
122+
children[depth, default: []].append(decl)
115123
}
116-
117-
if decl.culture == id
124+
else
118125
{
119-
// If this is not a re-exported symbol, make it available for
120-
// link resolution.
126+
// We need to wait until the next pass for the nested declarations,
127+
// because we do not know if their namespaces are correct yet.
121128
self.resolvableLinks[namespace, decl.value.path].append(
122129
.decl(decl.value))
123130
}
@@ -154,15 +161,15 @@ extension SSGC.TypeChecker
154161
try nesting.do { try self.assign($0, by: id) }
155162
}
156163
}
157-
// SymbolGraphGen fails to emit a `memberOf` edge if the member is a default
164+
// lib/SymbolGraphGen fails to emit a `memberOf` edge if the member is a default
158165
// implementation of a protocol requirement. Because the requirement might be a
159166
// requirement from a different protocol than the protocol containing the default
160167
// implementation, this means we need to use lexical name lookup to resolve the true
161168
// parent of the default implementation.
162169
//
163170
// Luckily for us, this lib/SymbolGraphGen bug only seems to affect default
164171
// implementations that implement requirements from protocols in the current module.
165-
for decl:SSGC.DeclObject in children
172+
for decl:SSGC.DeclObject in children.values.joined()
166173
{
167174
guard decl.scopes.isEmpty,
168175
let parent:UnqualifiedPath = .init(decl.value.path.prefix),
@@ -176,6 +183,39 @@ extension SSGC.TypeChecker
176183

177184
try self.assign(inferred, by: id)
178185
}
186+
// lib/SymbolGraphGen will place nested declarations under the wrong namespace if the
187+
// outer type was re-exported from another module. This is a bug in lib/SymbolGraphGen.
188+
// There is an alternative source of this information, in the `extendedModule` field of
189+
// the extension context, but this field is only present for declarations that are
190+
// physically written in an extension block, and also does not specify the correct
191+
// namespace for types under more than one level of nesting.
192+
//
193+
// Therefore, we need to correct the namespaces by actually inspecting the extended
194+
// types of nested declarations. It is most efficient to visit the shallower
195+
// declarations first, as this avoids the need to traverse the entire path hierarchy.
196+
for (_, decls):(Int, [SSGC.DeclObject]) in children.sorted(by: { $0.key < $1.key })
197+
{
198+
for decl:SSGC.DeclObject in decls
199+
{
200+
guard
201+
let scope:Symbol.Decl = decl.scopes.first,
202+
let scope:SSGC.DeclObject = self.declarations[visible: scope]
203+
else
204+
{
205+
// If we can’t find the parent, this symbol is probably a public member of
206+
// a private type, which is a common bug in lib/SymbolGraphGen.
207+
decl.access = .private
208+
continue
209+
}
210+
211+
let namespace:Symbol.Module = scope.namespace
212+
213+
decl.access = min(decl.access, scope.access)
214+
decl.namespace = namespace
215+
216+
self.resolvableLinks[namespace, decl.value.path].append(.decl(decl.value))
217+
}
218+
}
179219

180220
// Pass II. Populate remaining relationships.
181221
for part:SSGC.SymbolDump in culture.symbols

Sources/SymbolGraphParts/Vertices/SymbolGraphPart.Vertex.ExtensionContext.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@ extension SymbolGraphPart.Vertex.ExtensionContext:JSONObjectDecodable
2626
public
2727
enum CodingKey:String, Sendable
2828
{
29-
case conditions = "constraints"
29+
case constraints
30+
31+
@available(*, unavailable, message: "Not useful")
32+
case extendedModule
3033
}
3134

3235
public
3336
init(json:JSON.ObjectDecoder<CodingKey>) throws
3437
{
35-
self.init(conditions: try json[.conditions]?.decode() ?? [])
38+
self.init(conditions: try json[.constraints]?.decode() ?? [])
3639
}
3740
}

Sources/SymbolGraphParts/Vertices/SymbolGraphPart.Vertex.swift

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -155,19 +155,19 @@ extension SymbolGraphPart.Vertex:JSONObjectDecodable
155155
public
156156
enum CodingKey:String, Sendable
157157
{
158-
case acl = "accessLevel"
158+
case accessLevel
159159
case availability
160160

161-
case declaration = "declarationFragments"
162-
case doccomment = "docComment"
161+
case declarationFragments
162+
case docComment
163163

164-
case `extension` = "swiftExtension"
165-
case generics = "swiftGenerics"
164+
case swiftExtension
165+
case swiftGenerics
166166

167167
case names
168168
enum Names:String, Sendable
169169
{
170-
case subheading = "subHeading"
170+
case subHeading
171171
}
172172

173173
case identifier
@@ -176,8 +176,8 @@ extension SymbolGraphPart.Vertex:JSONObjectDecodable
176176
case precise
177177
}
178178

179-
case interfaces = "spi"
180-
case path = "pathComponents"
179+
case spi
180+
case pathComponents
181181
case kind
182182
enum Kind:String, Sendable
183183
{
@@ -187,12 +187,12 @@ extension SymbolGraphPart.Vertex:JSONObjectDecodable
187187
case location
188188
enum Location:String, Sendable
189189
{
190-
case file = "uri"
190+
case uri
191191
case position
192192
enum Position:String, Sendable
193193
{
194194
case line
195-
case column = "character"
195+
case character
196196
}
197197
}
198198
}
@@ -205,23 +205,23 @@ extension SymbolGraphPart.Vertex:JSONObjectDecodable
205205
{
206206
try $0[.precise].decode()
207207
},
208-
acl: try json[.acl].decode(),
208+
acl: try json[.accessLevel].decode(),
209209
phylum: try json[.kind].decode(using: CodingKey.Kind.self)
210210
{
211211
try $0[.identifier].decode()
212212
},
213213
availability: try json[.availability]?.decode() ?? .init(),
214-
doccomment: try json[.doccomment]?.decode(),
215-
interfaces: try json[.interfaces]?.decode(as: Bool.self) { $0 ? .init() : nil },
216-
extension: try json[.extension]?.decode() ?? .init(),
217-
fragments: try json[.declaration].decode(),
218-
generics: try json[.generics]?.decode() ?? .init(),
214+
doccomment: try json[.docComment]?.decode(),
215+
interfaces: try json[.spi]?.decode(as: Bool.self) { $0 ? .init() : nil },
216+
extension: try json[.swiftExtension]?.decode() ?? .init(),
217+
fragments: try json[.declarationFragments].decode(),
218+
generics: try json[.swiftGenerics]?.decode() ?? .init(),
219219
location: try json[.location]?.decode(using: CodingKey.Location.self)
220220
{
221221
let (line, column):(Int, Int) = try $0[.position].decode(
222222
using: CodingKey.Location.Position.self)
223223
{
224-
(try $0[.line].decode(), try $0[.column].decode())
224+
(try $0[.line].decode(), try $0[.character].decode())
225225
}
226226
guard
227227
let position:SourcePosition = .init(line: line, column: column)
@@ -231,8 +231,8 @@ extension SymbolGraphPart.Vertex:JSONObjectDecodable
231231
return nil
232232
}
233233

234-
return .init(position: position, file: try .uri(file: try $0[.file].decode()))
234+
return .init(position: position, file: try .uri(file: try $0[.uri].decode()))
235235
},
236-
path: try json[.path].decode())
236+
path: try json[.pathComponents].decode())
237237
}
238238
}

0 commit comments

Comments
 (0)