@@ -138,26 +138,42 @@ extension SSGC.TypeChecker
138
138
}
139
139
140
140
// Pass II. Populate protocol conformance tables and nesting relationships.
141
- for part : SSGC . SymbolDump in culture. symbols
141
+ let typesConformed : Set < SSGC . DeclObject > = try culture. symbols. reduce ( into : [ ] )
142
142
{
143
- for conformance : Symbol . ConformanceRelationship in part . conformances
143
+ for conformance : Symbol . ConformanceRelationship in $1 . conformances
144
144
{
145
- try conformance. do { try self . insert ( $0, by: id) }
145
+ let typeConformed : SSGC . DeclObject ? = try conformance. do
146
+ {
147
+ try self . collectConformance ( $0, by: id)
148
+ }
149
+ if let typeConformed: SSGC . DeclObject
150
+ {
151
+ $0. insert ( typeConformed)
152
+ }
146
153
}
147
- for inheritance : Symbol . InheritanceRelationship in part. inheritances
154
+
155
+ for inheritance : Symbol . InheritanceRelationship in $1. inheritances
148
156
{
149
157
try inheritance. do { try self . insert ( $0, by: id) }
150
158
}
151
159
152
- for nesting : Symbol . RequirementRelationship in part . requirements
160
+ for nesting : Symbol . RequirementRelationship in $1 . requirements
153
161
{
154
162
try nesting. do { try self . assign ( $0) }
155
163
}
156
- for nesting : Symbol . MemberRelationship in part . memberships
164
+ for nesting : Symbol . MemberRelationship in $1 . memberships
157
165
{
158
166
try nesting. do { try self . assign ( $0, by: id) }
159
167
}
160
168
}
169
+
170
+ // This uses information about the superforms of a type to simplify the constraints,
171
+ // which is why it is done after the inheritance relationships are recorded.
172
+ for type : SSGC . DeclObject in typesConformed
173
+ {
174
+ try self . computeConformances ( of: type, by: id)
175
+ }
176
+
161
177
// lib/SymbolGraphGen fails to emit a `memberOf` edge if the member is a default
162
178
// implementation of a protocol requirement. Because the requirement might be a
163
179
// requirement from a different protocol than the protocol containing the default
@@ -306,19 +322,18 @@ extension SSGC.TypeChecker
306
322
extension SSGC . TypeChecker
307
323
{
308
324
private mutating
309
- func insert( _ conformance: Symbol . ConformanceRelationship , by culture: Symbol . Module ) throws
325
+ func collectConformance( _ conformance: Symbol . ConformanceRelationship ,
326
+ by culture: Symbol . Module ) throws -> SSGC . DeclObject ?
310
327
{
311
328
guard
312
329
let target: SSGC . DeclObject = self . declarations [ visible: conformance. target]
313
330
else
314
331
{
315
- return
332
+ return nil
316
333
}
317
334
318
335
let conditions : Set < GenericConstraint < Symbol . Decl > > = . init( conformance. conditions)
319
-
320
- let typeExtension : SSGC . ExtensionObject
321
- let typeConformed : SSGC . DeclObject
336
+ let conformer : SSGC . DeclObject
322
337
323
338
switch conformance. source
324
339
{
@@ -331,7 +346,7 @@ extension SSGC.TypeChecker
331
346
let type: SSGC . DeclObject = self . declarations [ visible: symbol]
332
347
else
333
348
{
334
- return
349
+ return nil
335
350
}
336
351
337
352
if let origin: Symbol . Decl = conformance. origin
@@ -346,35 +361,33 @@ extension SSGC.TypeChecker
346
361
try type. add ( superform: Symbol . InheritanceRelationship. init (
347
362
by: type. id,
348
363
of: target. id) )
349
- return
364
+ return nil
350
365
}
351
- // Generate an implicit, internal extension for this conformance,
352
- // if one does not already exist.
353
- typeExtension = self . extensions [ extending: type, where: conditions]
354
- typeConformed = type
366
+
367
+ conformer = type
355
368
356
369
case . block( let symbol) :
357
370
// Look up the extension associated with this block name.
358
- typeExtension = try self . extensions [ named: symbol]
371
+ let named : SSGC . ExtensionObject = try self . extensions [ named: symbol]
359
372
360
373
guard
361
- let type: SSGC . DeclObject = self . declarations [ visible: typeExtension . extendee]
374
+ let type: SSGC . DeclObject = self . declarations [ visible: named . extendee]
362
375
else
363
376
{
364
- return
377
+ return nil
365
378
}
366
379
367
- typeConformed = type
380
+ conformer = type
368
381
369
- guard typeExtension . conditions == conditions
382
+ guard named . conditions == conditions
370
383
else
371
384
{
372
- throw SSGC . ExtensionSignatureError. init ( expected: typeExtension . signature)
385
+ throw SSGC . ExtensionSignatureError. init ( expected: named . signature)
373
386
}
374
387
}
375
388
376
- typeConformed . conformances [ target. id, default: [ ] ] . insert ( conditions)
377
- typeExtension . add ( conformance : target . id , by : culture )
389
+ conformer . conformanceStatements [ target. id, default: [ ] ] . insert ( conditions)
390
+ return conformer
378
391
}
379
392
380
393
private mutating
@@ -397,7 +410,86 @@ extension SSGC.TypeChecker
397
410
superform. kinks [ is: . implemented] = true
398
411
}
399
412
}
413
+ }
414
+ extension SSGC . TypeChecker
415
+ {
416
+ private
417
+ func computeConformance( where conditions: Set < Set < GenericConstraint < Symbol . Decl > > > ,
418
+ to target: Symbol . Decl ,
419
+ of type: SSGC . DeclObject ) throws -> Set < GenericConstraint < Symbol . Decl > >
420
+ {
421
+ do
422
+ {
423
+ return try conditions. simplified ( with: self . declarations)
424
+ }
425
+ catch SSGC . ConstraintReductionError . chimaeric( let reduced, from: let lists)
426
+ {
427
+ throw AssertionError . init ( message: """
428
+ Failed to simplify constraints for conditional conformance \
429
+ ( \( target) ) of ' \( type. value. path) ' because multiple conflicting \
430
+ conformances unify to a heterogeneous set of constraints
431
+
432
+ Declared constraints: \( lists)
433
+ Simplified constraints: \( reduced)
434
+ """ )
435
+ }
436
+ catch SSGC . ConstraintReductionError . redundant( let reduced, from: let lists)
437
+ {
438
+ throw AssertionError . init ( message: """
439
+ Failed to simplify constraints for conditional conformance \
440
+ ( \( target) ) of ' \( type. value. path) ' because at least one of the \
441
+ constraint lists had redundancies within itself
442
+
443
+ Declared constraints: \( lists)
444
+ Simplified constraints: \( reduced)
445
+ """ )
446
+ }
447
+ }
448
+ private mutating
449
+ func computeConformances( of type: SSGC . DeclObject , by culture: Symbol . Module ) throws
450
+ {
451
+ for (target, overlapping) : ( Symbol . Decl , Set < Set < GenericConstraint < Symbol . Decl > > > )
452
+ in type. conformanceStatements
453
+ {
454
+ try
455
+ {
456
+ // A Swift type may only conform to a protocol once, even with different
457
+ // conditional constraints.
458
+ //
459
+ // Exiting here not only prevents us from doing unnecessary simplification
460
+ // work, but also prevents us from accidentally capturing another module’s
461
+ // conformances as our own.
462
+ //
463
+ // For example: `Foundation` conforms `Array` to `Sequence` where `Element`
464
+ // is `UInt8`. Because the constraints are different (and tighter) than the
465
+ // original conformance, our regular de-duplication logic would not flag this
466
+ // as a duplicate were it not for this guard.
467
+ guard case nil = $0
468
+ else
469
+ {
470
+ return
471
+ }
472
+
473
+ let canonical : Set < GenericConstraint < Symbol . Decl > > = try self . computeConformance (
474
+ where: overlapping,
475
+ to: target,
476
+ of: type)
477
+
478
+ // Generate an implicit, internal extension for this conformance,
479
+ // if one does not already exist.
480
+ self . extensions [ extending: type, where: canonical] . add ( conformance: target,
481
+ by: culture)
482
+ $0 = canonical
483
+
484
+ } ( & type. conformances [ target] )
485
+ }
400
486
487
+ // We don’t need this table anymore.
488
+ type. conformanceStatements = [ : ]
489
+ }
490
+ }
491
+ extension SSGC . TypeChecker
492
+ {
401
493
private mutating
402
494
func insert( _ relationship: Symbol . FeatureRelationship , by culture: Symbol . Module ) throws
403
495
{
@@ -454,37 +546,8 @@ extension SSGC.TypeChecker
454
546
""" )
455
547
}
456
548
457
- let conditions : Set < GenericConstraint < Symbol . Decl > > ?
458
- do
459
- {
460
- conditions = try heir. conformances [ conformance] ? . simplify (
461
- with: self . declarations)
462
- }
463
- catch SSGC . ConstraintReductionError . chimaeric( let reduced, from: let lists)
464
- {
465
- throw AssertionError . init ( message: """
466
- Failed to simplify constraints for conditional conformance \
467
- ( \( conformance) ) of ' \( heir. value. path) ' because multiple conflicting \
468
- conformances unify to a heterogeneous set of constraints
469
-
470
- Declared constraints: \( lists)
471
- Simplified constraints: \( reduced)
472
- """ )
473
- }
474
- catch SSGC . ConstraintReductionError . redundant( let reduced, from: let lists)
475
- {
476
- throw AssertionError . init ( message: """
477
- Failed to simplify constraints for conditional conformance \
478
- ( \( conformance) ) of ' \( heir. value. path) ' because at least one of the \
479
- constraint lists had redundancies within itself
480
-
481
- Declared constraints: \( lists)
482
- Simplified constraints: \( reduced)
483
- """ )
484
- }
485
-
486
549
guard
487
- let conditions: Set < GenericConstraint < Symbol . Decl > >
550
+ let conditions: Set < GenericConstraint < Symbol . Decl > > = heir . conformances [ conformance ]
488
551
else
489
552
{
490
553
throw AssertionError . init ( message: """
0 commit comments