Skip to content

Commit 2e640c2

Browse files
committed
Make compareOwner symmetric
compareOwner did certain tests for one side but not for the other, which made its outcome dependent on the order in which alternatives were presented.
1 parent 205272c commit 2e640c2

File tree

2 files changed

+21
-15
lines changed

2 files changed

+21
-15
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

+19-13
Original file line numberDiff line numberDiff line change
@@ -1614,11 +1614,12 @@ trait Applications extends Compatibility {
16141614
* Module classes also inherit the relationship from their companions. This means,
16151615
* if no direct derivation exists between `sym1` and `sym2` also perform the following
16161616
* tests:
1617-
* - If both sym1 and sym1 are module classes that have companion classes,
1618-
* and sym2 does not inherit implicit members from a base class (#),
1619-
* compare the companion classes.
1620-
* - If sym1 is a module class with a companion, and sym2 is a normal class or trait,
1621-
* compare the companion with sym2.
1617+
* - If both sym1 and sym2 are module classes that have companion classes,
1618+
* compare the companion classes. Return the result of that comparison,
1619+
* provided the module class with the larger companion class does not itself
1620+
* inherit implicit members from a base class (#),
1621+
* - If one sym is a module class with a companion, and the other is a normal class or trait,
1622+
* compare the companion with the other class or trait.
16221623
*
16231624
* Condition (#) is necessary to make `compareOwner(_, _) > 0` a transitive relation.
16241625
* For instance:
@@ -1642,17 +1643,22 @@ trait Applications extends Compatibility {
16421643
* This means we get an ambiguity between `a` and `b` in all cases.
16431644
*/
16441645
def compareOwner(sym1: Symbol, sym2: Symbol)(using Context): Int =
1646+
def cls1 = sym1.companionClass
1647+
def cls2 = sym2.companionClass
16451648
if sym1 == sym2 then 0
16461649
else if sym1.isSubClass(sym2) then 1
16471650
else if sym2.isSubClass(sym1) then -1
1648-
else if sym1.is(Module) then
1649-
val cls1 = sym1.companionClass
1650-
if sym2.is(Module) then
1651-
if sym2.thisType.implicitMembers.forall(_.symbol.owner == sym2) then // test for (#)
1652-
compareOwner(cls1, sym2.companionClass)
1653-
else 0
1654-
else compareOwner(cls1, sym2)
1655-
else 0
1651+
else
1652+
if sym1.is(Module) && sym2.is(Module) then
1653+
val r = compareOwner(cls1, cls2)
1654+
if r == 0 then 0
1655+
else
1656+
val larger = if r < 0 then sym1 else sym2
1657+
if larger.thisType.implicitMembers.forall(_.symbol.owner == larger) then r
1658+
else 0
1659+
else if sym1.is(Module) then compareOwner(cls1, sym2)
1660+
else if sym2.is(Module) then compareOwner(sym1, cls2)
1661+
else 0
16561662

16571663
/** Compare two alternatives of an overloaded call or an implicit search.
16581664
*

compiler/src/dotty/tools/dotc/util/Signatures.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -495,8 +495,8 @@ object Signatures {
495495
case res => List(tpe)
496496

497497
def isSyntheticEvidence(name: String) =
498-
if !name.startsWith(NameKinds.ContextBoundParamName.separator) then false else
499-
symbol.paramSymss.flatten.find(_.name.show == name).exists(_.flags.is(Flags.Implicit))
498+
name.startsWith(NameKinds.ContextBoundParamName.separator)
499+
&& symbol.paramSymss.flatten.find(_.name.show == name).exists(_.flags.is(Flags.Implicit))
500500

501501
def toTypeParam(tpe: PolyType): List[Param] =
502502
val evidenceParams = (tpe.paramNamess.flatten zip tpe.paramInfoss.flatten).flatMap:

0 commit comments

Comments
 (0)