@@ -133,6 +133,16 @@ impl ReportFormatter<PubGrubPackage, Range<Version>, UnavailableReason>
133133 External :: FromDependencyOf ( package, package_set, dependency, dependency_set) => {
134134 let package_set = self . simplify_set ( package_set, package) ;
135135 let dependency_set = self . simplify_set ( dependency_set, dependency) ;
136+
137+ if package == dependency {
138+ if let Some ( member) = self . format_workspace_member ( package) {
139+ return format ! (
140+ "{member} depends on itself at an incompatible version ({})" ,
141+ PackageRange :: dependency( package, & dependency_set, None )
142+ ) ;
143+ }
144+ }
145+
136146 if let Some ( root) = self . format_root_requires ( package) {
137147 return format ! (
138148 "{root} {}" ,
@@ -407,6 +417,24 @@ impl PubGrubReportFormatter<'_> {
407417 }
408418 }
409419
420+ /// Return whether the given package is the root package.
421+ fn is_root ( package : & PubGrubPackage ) -> bool {
422+ matches ! ( & * * package, PubGrubPackageInner :: Root ( _) )
423+ }
424+
425+ /// Return whether the given package is a workspace member.
426+ fn is_single_project_workspace_member ( & self , package : & PubGrubPackage ) -> bool {
427+ match & * * package {
428+ // TODO(zanieb): Improve handling of dev and extra for single-project workspaces
429+ PubGrubPackageInner :: Package {
430+ name, extra, dev, ..
431+ } if self . workspace_members . contains ( name) => {
432+ self . is_single_project_workspace ( ) && extra. is_none ( ) && dev. is_none ( )
433+ }
434+ _ => false ,
435+ }
436+ }
437+
410438 /// Create a [`PackageRange::compatibility`] display with this formatter attached.
411439 fn compatible_range < ' a > (
412440 & ' a self ,
@@ -467,6 +495,18 @@ impl PubGrubReportFormatter<'_> {
467495 . and( dependency2. package, & dependency_set2) ,
468496 )
469497 }
498+ ( .., External :: FromDependencyOf ( package, _, dependency, _) )
499+ if Self :: is_root ( package)
500+ && self . is_single_project_workspace_member ( dependency) =>
501+ {
502+ self . format_external ( external1)
503+ }
504+ ( External :: FromDependencyOf ( package, _, dependency, _) , ..)
505+ if Self :: is_root ( package)
506+ && self . is_single_project_workspace_member ( dependency) =>
507+ {
508+ self . format_external ( external2)
509+ }
470510 _ => {
471511 let external1 = self . format_external ( external1) ;
472512 let external2 = self . format_external ( external2) ;
@@ -570,6 +610,16 @@ impl PubGrubReportFormatter<'_> {
570610 workspace : self . is_workspace ( ) && !self . is_single_project_workspace ( ) ,
571611 } ) ;
572612 }
613+
614+ if package_name == dependency_name
615+ && ( dependency. extra ( ) . is_none ( ) || package. extra ( ) == dependency. extra ( ) )
616+ && ( dependency. dev ( ) . is_none ( ) || dependency. dev ( ) == package. dev ( ) )
617+ && workspace_members. contains ( package_name)
618+ {
619+ output_hints. insert ( PubGrubHint :: DependsOnItself {
620+ package : package. clone ( ) ,
621+ } ) ;
622+ }
573623 }
574624 // Check for no versions due to `Requires-Python`.
575625 if matches ! (
@@ -899,6 +949,8 @@ pub(crate) enum PubGrubHint {
899949 dependency : PubGrubPackage ,
900950 workspace : bool ,
901951 } ,
952+ /// A package depends on itself at an incompatible version.
953+ DependsOnItself { package : PubGrubPackage } ,
902954 /// A package was available on an index, but not at the correct version, and at least one
903955 /// subsequent index was not queried. As such, a compatible version may be available on an
904956 /// one of the remaining indexes.
@@ -963,6 +1015,9 @@ enum PubGrubHintCore {
9631015 dependency : PubGrubPackage ,
9641016 workspace : bool ,
9651017 } ,
1018+ DependsOnItself {
1019+ package : PubGrubPackage ,
1020+ } ,
9661021 UncheckedIndex {
9671022 package : PubGrubPackage ,
9681023 } ,
@@ -1027,6 +1082,7 @@ impl From<PubGrubHint> for PubGrubHintCore {
10271082 dependency,
10281083 workspace,
10291084 } ,
1085+ PubGrubHint :: DependsOnItself { package } => Self :: DependsOnItself { package } ,
10301086 PubGrubHint :: UncheckedIndex { package, .. } => Self :: UncheckedIndex { package } ,
10311087 PubGrubHint :: UnauthorizedIndex { index } => Self :: UnauthorizedIndex { index } ,
10321088 PubGrubHint :: ForbiddenIndex { index } => Self :: ForbiddenIndex { index } ,
@@ -1269,6 +1325,15 @@ impl std::fmt::Display for PubGrubHint {
12691325 dependency. cyan( ) ,
12701326 )
12711327 }
1328+ Self :: DependsOnItself { package } => {
1329+ write ! (
1330+ f,
1331+ "{}{} The package `{}` depends on itself. This is likely a mistake. Consider removing the dependency." ,
1332+ "hint" . bold( ) . cyan( ) ,
1333+ ":" . bold( ) ,
1334+ package. cyan( ) ,
1335+ )
1336+ }
12721337 Self :: UncheckedIndex {
12731338 package,
12741339 range,
0 commit comments