@@ -76,7 +76,7 @@ extension SSGC.TypeChecker
76
76
/// We use this to look up protocols by name instead of symbol. This is needed in order
77
77
/// to work around some bizarre lib/SymbolGraphGen bugs.
78
78
var protocolsByName : [ UnqualifiedPath : Symbol . Decl ] = [ : ]
79
- var children : [ SSGC . DeclObject ] = [ ]
79
+ var children : [ Int : [ SSGC . DeclObject ] ] = [ : ]
80
80
// Pass I. Gather scalars, extension blocks, and extension relationships.
81
81
for part : SSGC . SymbolDump in culture. symbols
82
82
{
@@ -91,33 +91,40 @@ extension SSGC.TypeChecker
91
91
switch vertex. usr
92
92
{
93
93
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.
99
99
self . extensions. include ( vertex,
100
100
extending: try extensions. extendee ( of: symbol) ,
101
101
culture: id)
102
102
103
103
case . scalar( let symbol) :
104
+ guard
104
105
let decl: SSGC . DeclObject = self . declarations. include ( vertex,
105
106
namespace: namespace,
106
107
culture: id)
108
+ else
109
+ {
110
+ // Declaration is private or re-exported.
111
+ continue
112
+ }
107
113
108
114
if case . decl( . protocol) = vertex. phylum
109
115
{
110
116
protocolsByName [ vertex. path] = symbol
111
117
}
112
- else if !decl. value. path. prefix. isEmpty
118
+
119
+ let depth : Int = decl. value. path. prefix. count
120
+ if depth > 0
113
121
{
114
- children. append ( decl)
122
+ children [ depth , default : [ ] ] . append ( decl)
115
123
}
116
-
117
- if decl. culture == id
124
+ else
118
125
{
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 .
121
128
self . resolvableLinks [ namespace, decl. value. path] . append (
122
129
. decl( decl. value) )
123
130
}
@@ -154,15 +161,15 @@ extension SSGC.TypeChecker
154
161
try nesting. do { try self . assign ( $0, by: id) }
155
162
}
156
163
}
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
158
165
// implementation of a protocol requirement. Because the requirement might be a
159
166
// requirement from a different protocol than the protocol containing the default
160
167
// implementation, this means we need to use lexical name lookup to resolve the true
161
168
// parent of the default implementation.
162
169
//
163
170
// Luckily for us, this lib/SymbolGraphGen bug only seems to affect default
164
171
// 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 ( )
166
173
{
167
174
guard decl. scopes. isEmpty,
168
175
let parent: UnqualifiedPath = . init( decl. value. path. prefix) ,
@@ -176,6 +183,39 @@ extension SSGC.TypeChecker
176
183
177
184
try self . assign ( inferred, by: id)
178
185
}
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
+ }
179
219
180
220
// Pass II. Populate remaining relationships.
181
221
for part : SSGC . SymbolDump in culture. symbols
@@ -453,31 +493,10 @@ extension SSGC.TypeChecker
453
493
let conformance: Symbol . Decl = feature. scopes. first
454
494
else
455
495
{
456
- // We hit this on an extremely unusual edge case where a feature and an heir
457
- // are public, but the protocol the feature is defined on is not. Here is some
458
- // valid Swift code that demonstrates this:
459
- //
460
- /* ```
461
- protocol P
462
- {
463
- }
464
- extension P
465
- {
466
- public
467
- func f()
468
- {
469
- }
470
- }
471
-
472
- public
473
- struct S:P
474
- {
475
- }
476
- ```
477
- */
478
- // Ideally, lib/SymbolGraphGen would not emit the feature in this case, but
479
- // it does anyway.
480
- return
496
+ throw AssertionError . init ( message: """
497
+ Declaration ' \( feature. value. path) ' has ' \( feature. access) ' access but \
498
+ has no known lexical parents
499
+ """ )
481
500
}
482
501
483
502
guard feature. scopes. count == 1
0 commit comments