@@ -138,26 +138,42 @@ extension SSGC.TypeChecker
138138 }
139139
140140 // 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 : [ ] )
142142 {
143- for conformance : Symbol . ConformanceRelationship in part . conformances
143+ for conformance : Symbol . ConformanceRelationship in $1 . conformances
144144 {
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+ }
146153 }
147- for inheritance : Symbol . InheritanceRelationship in part. inheritances
154+
155+ for inheritance : Symbol . InheritanceRelationship in $1. inheritances
148156 {
149157 try inheritance. do { try self . insert ( $0, by: id) }
150158 }
151159
152- for nesting : Symbol . RequirementRelationship in part . requirements
160+ for nesting : Symbol . RequirementRelationship in $1 . requirements
153161 {
154162 try nesting. do { try self . assign ( $0) }
155163 }
156- for nesting : Symbol . MemberRelationship in part . memberships
164+ for nesting : Symbol . MemberRelationship in $1 . memberships
157165 {
158166 try nesting. do { try self . assign ( $0, by: id) }
159167 }
160168 }
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+
161177 // lib/SymbolGraphGen fails to emit a `memberOf` edge if the member is a default
162178 // implementation of a protocol requirement. Because the requirement might be a
163179 // requirement from a different protocol than the protocol containing the default
@@ -306,19 +322,18 @@ extension SSGC.TypeChecker
306322extension SSGC . TypeChecker
307323{
308324 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 ?
310327 {
311328 guard
312329 let target: SSGC . DeclObject = self . declarations [ visible: conformance. target]
313330 else
314331 {
315- return
332+ return nil
316333 }
317334
318335 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
322337
323338 switch conformance. source
324339 {
@@ -331,7 +346,7 @@ extension SSGC.TypeChecker
331346 let type: SSGC . DeclObject = self . declarations [ visible: symbol]
332347 else
333348 {
334- return
349+ return nil
335350 }
336351
337352 if let origin: Symbol . Decl = conformance. origin
@@ -346,35 +361,33 @@ extension SSGC.TypeChecker
346361 try type. add ( superform: Symbol . InheritanceRelationship. init (
347362 by: type. id,
348363 of: target. id) )
349- return
364+ return nil
350365 }
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
355368
356369 case . block( let symbol) :
357370 // 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]
359372
360373 guard
361- let type: SSGC . DeclObject = self . declarations [ visible: typeExtension . extendee]
374+ let type: SSGC . DeclObject = self . declarations [ visible: named . extendee]
362375 else
363376 {
364- return
377+ return nil
365378 }
366379
367- typeConformed = type
380+ conformer = type
368381
369- guard typeExtension . conditions == conditions
382+ guard named . conditions == conditions
370383 else
371384 {
372- throw SSGC . ExtensionSignatureError. init ( expected: typeExtension . signature)
385+ throw SSGC . ExtensionSignatureError. init ( expected: named . signature)
373386 }
374387 }
375388
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
378391 }
379392
380393 private mutating
@@ -397,7 +410,86 @@ extension SSGC.TypeChecker
397410 superform. kinks [ is: . implemented] = true
398411 }
399412 }
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+ }
400486
487+ // We don’t need this table anymore.
488+ type. conformanceStatements = [ : ]
489+ }
490+ }
491+ extension SSGC . TypeChecker
492+ {
401493 private mutating
402494 func insert( _ relationship: Symbol . FeatureRelationship , by culture: Symbol . Module ) throws
403495 {
@@ -454,37 +546,8 @@ extension SSGC.TypeChecker
454546 """ )
455547 }
456548
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-
486549 guard
487- let conditions: Set < GenericConstraint < Symbol . Decl > >
550+ let conditions: Set < GenericConstraint < Symbol . Decl > > = heir . conformances [ conformance ]
488551 else
489552 {
490553 throw AssertionError . init ( message: """
0 commit comments