@@ -171,7 +171,7 @@ extension SSGC.TypeChecker
171
171
// which is why it is done after the inheritance relationships are recorded.
172
172
for type : SSGC . DeclObject in typesConformed
173
173
{
174
- try self . comptuteConformances ( of: type, by: id)
174
+ try self . computeConformances ( of: type, by: id)
175
175
}
176
176
177
177
// lib/SymbolGraphGen fails to emit a `memberOf` edge if the member is a default
@@ -413,45 +413,75 @@ extension SSGC.TypeChecker
413
413
}
414
414
extension SSGC . TypeChecker
415
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
+ }
416
448
private mutating
417
- func comptuteConformances ( of type: SSGC . DeclObject , by culture: Symbol . Module ) throws
449
+ func computeConformances ( of type: SSGC . DeclObject , by culture: Symbol . Module ) throws
418
450
{
419
- for (conformance , overlapping) : ( Symbol . Decl , Set < Set < GenericConstraint < Symbol . Decl > > > )
451
+ for (target , overlapping) : ( Symbol . Decl , Set < Set < GenericConstraint < Symbol . Decl > > > )
420
452
in type. conformanceStatements
421
453
{
422
- let canonical : Set < GenericConstraint < Symbol . Decl > >
423
- do
424
- {
425
- canonical = try overlapping. simplified ( with: self . declarations)
426
- }
427
- catch SSGC . ConstraintReductionError . chimaeric( let reduced, from: let lists)
428
- {
429
- throw AssertionError . init ( message: """
430
- Failed to simplify constraints for conditional conformance \
431
- ( \( conformance) ) of ' \( type. value. path) ' because multiple conflicting \
432
- conformances unify to a heterogeneous set of constraints
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
+ }
433
472
434
- Declared constraints: \( lists)
435
- Simplified constraints: \( reduced)
436
- """ )
437
- }
438
- catch SSGC . ConstraintReductionError . redundant( let reduced, from: let lists)
439
- {
440
- throw AssertionError . init ( message: """
441
- Failed to simplify constraints for conditional conformance \
442
- ( \( conformance) ) of ' \( type. value. path) ' because at least one of the \
443
- constraint lists had redundancies within itself
473
+ let canonical : Set < GenericConstraint < Symbol . Decl > > = try self . computeConformance (
474
+ where: overlapping,
475
+ to: target,
476
+ of: type)
444
477
445
- Declared constraints: \( lists)
446
- Simplified constraints: \( reduced)
447
- """ )
448
- }
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
449
483
450
- type. conformances [ conformance] = canonical
451
- // Generate an implicit, internal extension for this conformance,
452
- // if one does not already exist.
453
- self . extensions [ extending: type, where: canonical] . add ( conformance: conformance,
454
- by: culture)
484
+ } ( & type. conformances [ target] )
455
485
}
456
486
457
487
// We don’t need this table anymore.
0 commit comments