@@ -1615,11 +1615,12 @@ trait Applications extends Compatibility {
16151615    *  Module classes also inherit the relationship from their companions. This means, 
16161616    *  if no direct derivation exists between `sym1` and `sym2` also perform the following 
16171617    *  tests: 
1618-     *   - If both sym1 and sym1 are module classes that have companion classes, 
1619-     *     and sym2 does not inherit implicit members from a base class (#), 
1620-     *     compare the companion classes. 
1621-     *   - If sym1 is a module class with a companion, and sym2 is a normal class or trait, 
1622-     *     compare the companion with sym2. 
1618+     *   - If both sym1 and sym2 are module classes that have companion classes, 
1619+     *     compare the companion classes. Return the result of that comparison, 
1620+     *     provided the module class with the larger companion class does not itself 
1621+     *     inherit implicit members from a base class (#), 
1622+     *   - If one sym is a module class with a companion, and the other is a normal class or trait, 
1623+     *     compare the companion with the other class or trait. 
16231624    * 
16241625    *  Condition (#) is necessary to make `compareOwner(_, _) > 0` a transitive relation. 
16251626    *  For instance: 
@@ -1643,17 +1644,22 @@ trait Applications extends Compatibility {
16431644    *  This means we get an ambiguity between `a` and `b` in all cases. 
16441645    */  
16451646  def  compareOwner (sym1 : Symbol , sym2 : Symbol )(using  Context ):  Int  = 
1647+     def  cls1  =  sym1.companionClass
1648+     def  cls2  =  sym2.companionClass
16461649    if  sym1 ==  sym2 then  0 
16471650    else  if  sym1.isSubClass(sym2) then  1 
16481651    else  if  sym2.isSubClass(sym1) then  - 1 
1649-     else  if  sym1.is(Module ) then 
1650-       val  cls1  =  sym1.companionClass
1651-       if  sym2.is(Module ) then 
1652-         if  sym2.thisType.implicitMembers.forall(_.symbol.owner ==  sym2) then  //  test for (#)
1653-           compareOwner(cls1, sym2.companionClass)
1654-         else  0 
1655-       else  compareOwner(cls1, sym2)
1656-     else  0 
1652+     else 
1653+       if  sym1.is(Module ) &&  sym2.is(Module ) then 
1654+         val  r  =  compareOwner(cls1, cls2)
1655+         if  r ==  0  then  0 
1656+         else 
1657+           val  larger  =  if  r <  0  then  sym1 else  sym2
1658+           if  larger.thisType.implicitMembers.forall(_.symbol.owner ==  larger) then  r
1659+           else  0 
1660+       else  if  sym1.is(Module ) then  compareOwner(cls1, sym2)
1661+       else  if  sym2.is(Module ) then  compareOwner(sym1, cls2)
1662+       else  0 
16571663
16581664  /**  Compare two alternatives of an overloaded call or an implicit search. 
16591665   * 
@@ -1808,10 +1814,38 @@ trait Applications extends Compatibility {
18081814        else  tp
18091815    }
18101816
1811-     def  compareWithTypes (tp1 : Type , tp2 : Type ) =  {
1817+     def  widenPrefix (alt : TermRef ):  Type  =  alt.prefix.widen match 
1818+       case  pre : (TypeRef  |  ThisType ) if  pre.typeSymbol.is(Module ) => 
1819+         pre.parents.reduceLeft(TypeComparer .andType(_, _))
1820+       case  wpre =>  wpre
1821+ 
1822+     /**  If two alternatives have the same symbol, we pick the one with the most 
1823+      *  specific prefix. To determine that, we widen the prefix types and also 
1824+      *  widen module classes to the intersection of their parent classes. Then 
1825+      *  if one of the resulting types is a more specific value type than the other, 
1826+      *  it wins. Example: 
1827+      * 
1828+      *     trait A { given M = ... } 
1829+      *     trait B extends A 
1830+      *     object a extends A 
1831+      *     object b extends B 
1832+      * 
1833+      *  In this case `b.M` would be regarded as more specific than `a.M`. 
1834+      */  
1835+     def  comparePrefixes  = 
1836+       val  pre1  =  widenPrefix(alt1)
1837+       val  pre2  =  widenPrefix(alt2)
1838+       val  winsPrefix1  =  isAsSpecificValueType(pre1, pre2)
1839+       val  winsPrefix2  =  isAsSpecificValueType(pre2, pre1)
1840+       if  winsPrefix1 ==  winsPrefix2 then  0 
1841+       else  if  winsPrefix1 then  1 
1842+       else  - 1 
1843+ 
1844+     def  compareWithTypes (tp1 : Type , tp2 : Type ) = 
18121845      val  ownerScore  =  compareOwner(alt1.symbol.maybeOwner, alt2.symbol.maybeOwner)
1813-       def  winsType1  =  isAsSpecific(alt1, tp1, alt2, tp2)
1814-       def  winsType2  =  isAsSpecific(alt2, tp2, alt1, tp1)
1846+ 
1847+       val  winsType1  =  isAsSpecific(alt1, tp1, alt2, tp2)
1848+       val  winsType2  =  isAsSpecific(alt2, tp2, alt1, tp1)
18151849
18161850      overload.println(i " compare( $alt1,  $alt2)?  $tp1  $tp2  $ownerScore  $winsType1  $winsType2" )
18171851      if  winsType1 &&  winsType2
@@ -1820,15 +1854,14 @@ trait Applications extends Compatibility {
18201854        //  alternatives are the same after following ExprTypes, pick one of them
18211855        //  (prefer the one that is not a method, but that's arbitrary).
18221856        if  alt1.widenExpr =:=  alt2 then  - 1  else  1 
1823-       else  if  ownerScore ==  1  then 
1824-         if  winsType1 ||  ! winsType2 then  1  else  0 
1825-       else  if  ownerScore ==  - 1  then 
1826-         if  winsType2 ||  ! winsType1 then  - 1  else  0 
1827-       else  if  winsType1 then 
1828-         if  winsType2 then  0  else  1 
1829-       else 
1830-         if  winsType2 then  - 1  else  0 
1831-     }
1857+       else  ownerScore match 
1858+         case   1  =>  if  winsType1 ||  ! winsType2 then   1  else  0 
1859+         case  - 1  =>  if  winsType2 ||  ! winsType1 then  - 1  else  0 
1860+         case   0  => 
1861+           if  winsType1 !=  winsType2 then  if  winsType1 then  1  else  - 1 
1862+           else  if  alt1.symbol ==  alt2.symbol then  comparePrefixes
1863+           else  0 
1864+     end  compareWithTypes 
18321865
18331866    if  alt1.symbol.is(ConstructorProxy ) &&  ! alt2.symbol.is(ConstructorProxy ) then  - 1 
18341867    else  if  alt2.symbol.is(ConstructorProxy ) &&  ! alt1.symbol.is(ConstructorProxy ) then  1 
0 commit comments