@@ -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