Skip to content

Commit b93ffa5

Browse files
committed
Fix #1386: Reduce double def errors
Use additional disambiguation criteria before raising a double def error. See for context: #1240. Review by @DarkDimius
1 parent 4bec4fa commit b93ffa5

File tree

1 file changed

+24
-6
lines changed

1 file changed

+24
-6
lines changed

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,24 +292,41 @@ object Denotations {
292292
val sym1 = denot1.symbol
293293
val sym2 = denot2.symbol
294294

295-
if (isDoubleDef(sym1, sym2)) doubleDefError(denot1, denot2, pre)
296-
297295
val sym2Accessible = sym2.isAccessibleFrom(pre)
296+
298297
/** Does `sym1` come before `sym2` in the linearization of `pre`? */
299298
def precedes(sym1: Symbol, sym2: Symbol) = {
300299
def precedesIn(bcs: List[ClassSymbol]): Boolean = bcs match {
301300
case bc :: bcs1 => (sym1 eq bc) || !(sym2 eq bc) && precedesIn(bcs1)
302301
case Nil => true
303302
}
304-
sym1.derivesFrom(sym2) ||
305-
!sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses)
303+
(sym1 ne sym2) &&
304+
(sym1.derivesFrom(sym2) ||
305+
!sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses))
306306
}
307307

308-
/** Preference according to partial pre-order (isConcrete, precedes) */
308+
/** Establish a partial order "preference" order between symbols.
309+
* Give preference to `sym1` over `sym2` if one of the following
310+
* conditions holds, in decreasing order of weight:
311+
* 1. sym1 is concrete and sym2 is abstract
312+
* 2. The owner of sym1 comes before the owner of sym2 in the linearization
313+
* of the type of the prefix `pre`.
314+
* 3. The access boundary of sym2 is properly contained in the access
315+
* boundary of sym1. For protected access, we count the enclosing
316+
* package as access boundary.
317+
* 4. sym1 a method but sym2 is not.
318+
* The aim of these criteria is to give some disambiguation on access which
319+
* - does not depend on textual order or other arbitrary choices
320+
* - minimizes raising of doubleDef errors
321+
*/
309322
def preferSym(sym1: Symbol, sym2: Symbol) =
310323
sym1.eq(sym2) ||
311324
sym1.isAsConcrete(sym2) &&
312-
(!sym2.isAsConcrete(sym1) || precedes(sym1.owner, sym2.owner))
325+
(!sym2.isAsConcrete(sym1) ||
326+
precedes(sym1.owner, sym2.owner) ||
327+
sym2.accessBoundary(sym2.enclosingPackageClass)
328+
.isProperlyContainedIn(sym1.accessBoundary(sym1.enclosingPackageClass)) ||
329+
sym1.is(Method) && !sym2.is(Method))
313330

314331
/** Sym preference provided types also override */
315332
def prefer(sym1: Symbol, sym2: Symbol, info1: Type, info2: Type) =
@@ -321,6 +338,7 @@ object Denotations {
321338
if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
322339
else if (sym1Accessible && sym2.exists && !sym2Accessible) denot1
323340
else if (sym2Accessible && sym1.exists && !sym1Accessible) denot2
341+
else if (isDoubleDef(sym1, sym2)) doubleDefError(denot1, denot2, pre)
324342
else {
325343
val sym =
326344
if (!sym1.exists) sym2

0 commit comments

Comments
 (0)