@@ -607,7 +607,11 @@ fn activate(
607607 // TODO: this disable is not a long term solution.
608608 // This needs to be removed before public dependencies are stabilized!
609609 if dep. platform ( ) . is_none ( ) && dep. explicit_name_in_toml ( ) . is_none ( ) {
610- let cs: Vec < PackageId > = cx
610+ // one tricky part is that `candidate_pid` may already be active and
611+ // have public dependencies of its own. So we not only need to mark
612+ // `candidate_pid` as visible to its parents but also all of its existing
613+ // public dependencies.
614+ let existing_public_deps: Vec < PackageId > = cx
611615 . public_dependency
612616 . get ( & candidate_pid)
613617 . iter ( )
@@ -616,24 +620,34 @@ fn activate(
616620 . chain ( & Some ( candidate_pid) )
617621 . cloned ( )
618622 . collect ( ) ;
619- for c in cs {
623+ for c in existing_public_deps {
624+ // for each (transitive) parent that can newly see `t`
620625 let mut stack = vec ! [ ( parent_pid, dep. is_public( ) ) ] ;
621626 while let Some ( ( p, public) ) = stack. pop ( ) {
622627 match cx. public_dependency . entry ( p) . or_default ( ) . entry ( c. name ( ) ) {
623628 im_rc:: hashmap:: Entry :: Occupied ( mut o) => {
629+ // the (transitive) parent can already see something by `c`s name, it had better be `c`.
624630 assert_eq ! ( o. get( ) . 0 , c) ;
625631 if o. get ( ) . 1 {
632+ // The previous time the parent saw `c`, it was a public dependency.
633+ // So all of its parents already know about `c`
634+ // and we can save some time by stopping now.
626635 continue ;
627636 }
628637 if public {
638+ // Mark that `c` has now bean seen publicly
629639 o. insert ( ( c, public) ) ;
630640 }
631641 }
632642 im_rc:: hashmap:: Entry :: Vacant ( v) => {
643+ // The (transitive) parent does not have anything by `c`s name,
644+ // so we add `c`.
633645 v. insert ( ( c, public) ) ;
634646 }
635647 }
648+ // if `candidate_pid` was a private dependency of `p` then `p` parents can't see `c` thru `p`
636649 if public {
650+ // if it was public, then we add all of `p`s parents to be checked
637651 for & ( grand, ref d) in cx. parents . edges ( & p) {
638652 stack. push ( ( grand, d. iter ( ) . any ( |x| x. is_public ( ) ) ) ) ;
639653 }
@@ -788,25 +802,32 @@ impl RemainingCandidates {
788802 // TODO: this disable is not a long term solution.
789803 // This needs to be removed before public dependencies are stabilized!
790804 if dep. platform ( ) . is_none ( ) && dep. explicit_name_in_toml ( ) . is_none ( ) {
791- for & t in cx
805+ let existing_public_deps : Vec < PackageId > = cx
792806 . public_dependency
793807 . get ( & b. summary . package_id ( ) )
794808 . iter ( )
795809 . flat_map ( |x| x. values ( ) )
796810 . filter_map ( |x| if x. 1 { Some ( & x. 0 ) } else { None } )
797811 . chain ( & Some ( b. summary . package_id ( ) ) )
798- {
812+ . cloned ( )
813+ . collect ( ) ;
814+ for t in existing_public_deps {
815+ // for each (transitive) parent that can newly see `t`
799816 let mut stack = vec ! [ ( parent, dep. is_public( ) ) ] ;
800817 while let Some ( ( p, public) ) = stack. pop ( ) {
801818 // TODO: dont look at the same thing more then once
802819 if let Some ( o) = cx. public_dependency . get ( & p) . and_then ( |x| x. get ( & t. name ( ) ) )
803820 {
804821 if o. 0 != t {
822+ // the (transitive) parent can already see a different version by `t`s name.
823+ // So, adding `b` will cause `p` to have a public dependency conflict on `t`.
805824 conflicting_prev_active. insert ( p, ConflictReason :: PublicDependency ) ;
806825 continue ' main;
807826 }
808827 }
828+ // if `b` was a private dependency of `p` then `p` parents can't see `t` thru `p`
809829 if public {
830+ // if it was public, then we add all of `p`s parents to be checked
810831 for & ( grand, ref d) in cx. parents . edges ( & p) {
811832 stack. push ( ( grand, d. iter ( ) . any ( |x| x. is_public ( ) ) ) ) ;
812833 }
0 commit comments