@@ -505,7 +505,7 @@ private func createResolvedPackages(
505505 throw InternalError ( " dependency reference for \( product. packageBuilder. package . manifest. packageLocation) not found " )
506506 }
507507 let referencedPackageName = referencedPackageDependency. nameForTargetDependencyResolutionOnly
508- if productRef. name != referencedPackageName {
508+ if productRef. name != referencedPackageName {
509509 let error = PackageGraphError . productDependencyMissingPackage (
510510 productName: productRef. name,
511511 targetName: targetBuilder. target. name,
@@ -522,16 +522,84 @@ private func createResolvedPackages(
522522
523523 // If a target with similar name was encountered before, we emit a diagnostic.
524524 if foundDuplicateTarget {
525+ var duplicateTargets = [ String: [ Package] ] ( )
525526 for targetName in allTargetNames. sorted ( ) {
526- // Find the packages this target is present in.
527527 let packages = packageBuilders
528528 . filter ( { $0. targets. contains ( where: { $0. target. name == targetName } ) } )
529- . map { $0. package . identity. description }
530- . sorted ( )
529+ . map { $0. package }
531530 if packages. count > 1 {
532- observabilityScope . emit ( ModuleError . duplicateModule ( targetName, packages) )
531+ duplicateTargets [ targetName, default : [ ] ] . append ( contentsOf : packages)
533532 }
534533 }
534+
535+ struct Pair : Hashable {
536+ let package1 : Package
537+ let package2 : Package
538+
539+ static func == ( lhs: Pair , rhs: Pair ) -> Bool {
540+ return lhs. package1. identity == rhs. package1. identity &&
541+ lhs. package2. identity == rhs. package2. identity
542+ }
543+
544+ public func hash( into hasher: inout Hasher ) {
545+ hasher. combine ( self . package1. identity)
546+ hasher. combine ( self . package2. identity)
547+ }
548+ }
549+
550+ var potentiallyDuplicatePackages = [ Pair: [ String] ] ( )
551+ for entry in duplicateTargets {
552+ // the duplicate is across exactly two packages
553+ if entry. value. count == 2 {
554+ potentiallyDuplicatePackages [ Pair ( package1: entry. value [ 0 ] , package2: entry. value [ 1 ] ) , default: [ ] ] . append ( entry. key)
555+ }
556+ }
557+
558+ var duplicateTargetsAddressed = [ String] ( )
559+ for potentiallyDuplicatePackage in potentiallyDuplicatePackages {
560+ // more than three target matches, or all targets in the package match
561+ if potentiallyDuplicatePackage. value. count > 3 ||
562+ ( potentiallyDuplicatePackage. value. sorted ( ) == potentiallyDuplicatePackage. key. package1. targets. map ( { $0. name } ) . sorted ( )
563+ &&
564+ potentiallyDuplicatePackage. value. sorted ( ) == potentiallyDuplicatePackage. key. package2. targets. map ( { $0. name } ) . sorted ( ) )
565+ {
566+ switch ( potentiallyDuplicatePackage. key. package1. identity. registry, potentiallyDuplicatePackage. key. package2. identity. registry) {
567+ case ( . some( let registryIdentity) , . none) :
568+ observabilityScope. emit (
569+ ModuleError . duplicateModulesScmAndRegistry (
570+ regsitryPackage: registryIdentity,
571+ scmPackage: potentiallyDuplicatePackage. key. package2. identity,
572+ targets: potentiallyDuplicatePackage. value
573+ )
574+ )
575+ case ( . none, . some( let registryIdentity) ) :
576+ observabilityScope. emit (
577+ ModuleError . duplicateModulesScmAndRegistry (
578+ regsitryPackage: registryIdentity,
579+ scmPackage: potentiallyDuplicatePackage. key. package1. identity,
580+ targets: potentiallyDuplicatePackage. value
581+ )
582+ )
583+ default :
584+ observabilityScope. emit (
585+ ModuleError . duplicateModules (
586+ package : potentiallyDuplicatePackage. key. package1. identity,
587+ otherPackage: potentiallyDuplicatePackage. key. package2. identity,
588+ targets: potentiallyDuplicatePackage. value
589+ )
590+ )
591+ }
592+ duplicateTargetsAddressed += potentiallyDuplicatePackage. value
593+ }
594+ }
595+
596+ for entry in duplicateTargets. filter ( { !duplicateTargetsAddressed. contains ( $0. key) } ) {
597+ observabilityScope. emit (
598+ ModuleError . duplicateModule (
599+ targetName: entry. key,
600+ packages: entry. value. map { $0. identity } )
601+ )
602+ }
535603 }
536604
537605 return try packageBuilders. map { try $0. construct ( ) }
0 commit comments