@@ -1350,50 +1350,46 @@ trait Applications extends Compatibility {
1350
1350
* Module classes also inherit the relationship from their companions. This means,
1351
1351
* if no direct derivation exists between `sym1` and `sym2` also perform the following
1352
1352
* tests:
1353
- * - If both sym1 and sym1 are module classes that have companion classes, compare the companions
1354
- * - If sym1 is a module class with a companion, and sym2 is a normal class or trait, compare
1355
- * the companion with sym2.
1353
+ * - If both sym1 and sym1 are module classes that have companion classes,
1354
+ * and sym2 does not inherit implicit members from a base class (#),
1355
+ * compare the companion classes.
1356
+ * - If sym1 is a module class with a companion, and sym2 is a normal class or trait,
1357
+ * compare the companion with sym2.
1356
1358
*
1357
- * Note that this makes `compareOwner(_, _) > 0` not transitive! For instance:
1359
+ * Condition (#) is necessary to make `compareOwner(_, _) > 0` a transitive relation.
1360
+ * For instance:
1358
1361
*
1359
1362
* class A extends B
1360
- * object A
1363
+ * object A { given a ... }
1361
1364
* class B
1362
- * object B extends C
1365
+ * object B extends C { given b ... }
1366
+ * class C { given c }
1363
1367
*
1364
- * Then compareOwner(A$, B$) = 1 and compareOwner(B$, C) == 1, but
1365
- * compareOwner(A$, C) == 0.
1368
+ * Then without (#), and taking A$ for the module class of A,
1369
+ * compareOwner(A$, B$) = 1 and compareOwner(B$, C) == 1,
1370
+ * but compareOwner(A$, C) == 0.
1371
+ * Violating transitivity in this way is bad, since it makes implicit search
1372
+ * outcomes compilation order dependent. E.g. if we compare `b` with `c`
1373
+ * first, we pick `b`. Then, if we compare `a` and `b`, we pick `a` as
1374
+ * solution of the search. But if we start with comparing `a` with `c`,
1375
+ * we get an ambiguity.
1376
+ *
1377
+ * With the added condition (#), compareOwner(A$, B$) == 0.
1378
+ * This means we get an ambiguity between `a` and `b` in all cases.
1366
1379
*/
1367
1380
def compareOwner (sym1 : Symbol , sym2 : Symbol )(using Context ): Int =
1368
1381
if sym1 == sym2 then 0
1369
1382
else if sym1.isSubClass(sym2) then 1
1370
1383
else if sym2.isSubClass(sym1) then - 1
1371
1384
else if sym1.is(Module ) then
1372
- compareOwner(sym1.companionClass, if sym2.is(Module ) then sym2.companionClass else sym2)
1385
+ val cls1 = sym1.companionClass
1386
+ if sym2.is(Module ) then
1387
+ if sym2.thisType.implicitMembers.forall(_.symbol.owner == sym2) then // test for (#)
1388
+ compareOwner(cls1, sym2.companionClass)
1389
+ else 0
1390
+ else compareOwner(cls1, sym2)
1373
1391
else 0
1374
1392
1375
- /** A version of `compareOwner` that is transitive, to be used in sorting
1376
- * It would be nice if we could use this as the general method for comparing
1377
- * owners, but unfortunately this does not compile all existsing code.
1378
- * An example is `enrich-gentraversable.scala`. Here we have
1379
- *
1380
- * trait BuildFrom...
1381
- * object BuildFrom extends BuildFromLowPriority1
1382
- *
1383
- * and we need to pick an implicit in BuildFrom over BuildFromLowPriority1
1384
- * the rules in `compareOwner` give us that, but the rules in `isSubOwner`
1385
- * don't.
1386
- * So we need to stick with `compareOwner` for backwards compatibility, even
1387
- * though it is arguably broken. We can still use `isSubOwner` for sorting
1388
- * since that is just a performance optimization, so if the two methods
1389
- * don't agree sometimes that's OK.
1390
- */
1391
- def isSubOwner (sym1 : Symbol , sym2 : Symbol )(using Context ): Boolean =
1392
- if sym1.is(Module ) && sym1.companionClass.exists then
1393
- isSubOwner(sym1.companionClass, if sym2.is(Module ) then sym2.companionClass else sym2)
1394
- else
1395
- sym1 != sym2 && sym1.isSubClass(sym2)
1396
-
1397
1393
/** Compare to alternatives of an overloaded call or an implicit search.
1398
1394
*
1399
1395
* @param alt1, alt2 Non-overloaded references indicating the two choices
0 commit comments