@@ -295,35 +295,65 @@ object Denotations {
295295 val sym1 = denot1.symbol
296296 val sym2 = denot2.symbol
297297
298- if (isDoubleDef(sym1, sym2)) doubleDefError(denot1, denot2, pre)
299-
300298 val sym2Accessible = sym2.isAccessibleFrom(pre)
299+
301300 /** Does `sym1` come before `sym2` in the linearization of `pre`? */
302301 def precedes (sym1 : Symbol , sym2 : Symbol ) = {
303302 def precedesIn (bcs : List [ClassSymbol ]): Boolean = bcs match {
304303 case bc :: bcs1 => (sym1 eq bc) || ! (sym2 eq bc) && precedesIn(bcs1)
305304 case Nil => true
306305 }
307- sym1.derivesFrom(sym2) ||
308- ! sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses)
306+ (sym1 ne sym2) &&
307+ (sym1.derivesFrom(sym2) ||
308+ ! sym2.derivesFrom(sym1) && precedesIn(pre.baseClasses))
309309 }
310310
311- /** Preference according to partial pre-order (isConcrete, precedes) */
311+ /** Similar to SymDenotation#accessBoundary, but without the special cases. */
312+ def accessBoundary (sym : Symbol ) =
313+ if (sym.is(Private )) sym.owner
314+ else sym.privateWithin.orElse(
315+ if (sym.is(Protected )) sym.owner.enclosingPackageClass
316+ else defn.RootClass
317+ )
318+
319+ /** Establish a partial order "preference" order between symbols.
320+ * Give preference to `sym1` over `sym2` if one of the following
321+ * conditions holds, in decreasing order of weight:
322+ * 1. sym1 is concrete and sym2 is abstract
323+ * 2. The owner of sym1 comes before the owner of sym2 in the linearization
324+ * of the type of the prefix `pre`.
325+ * 3. The access boundary of sym2 is properly contained in the access
326+ * boundary of sym1. For protected access, we count the enclosing
327+ * package as access boundary.
328+ * 4. sym1 a method but sym2 is not.
329+ * The aim of these criteria is to give some disambiguation on access which
330+ * - does not depend on textual order or other arbitrary choices
331+ * - minimizes raising of doubleDef errors
332+ */
312333 def preferSym (sym1 : Symbol , sym2 : Symbol ) =
313334 sym1.eq(sym2) ||
314335 sym1.isAsConcrete(sym2) &&
315- (! sym2.isAsConcrete(sym1) || precedes(sym1.owner, sym2.owner))
336+ (! sym2.isAsConcrete(sym1) ||
337+ precedes(sym1.owner, sym2.owner) ||
338+ accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) ||
339+ sym1.is(Method ) && ! sym2.is(Method ))
316340
317341 /** Sym preference provided types also override */
318342 def prefer (sym1 : Symbol , sym2 : Symbol , info1 : Type , info2 : Type ) =
319343 preferSym(sym1, sym2) && info1.overrides(info2)
320344
345+ def handleDoubleDef =
346+ if (preferSym(sym1, sym2)) denot1
347+ else if (preferSym(sym2, sym1)) denot2
348+ else doubleDefError(denot1, denot2, pre)
349+
321350 if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2
322351 else {
323352 val sym1Accessible = sym1.isAccessibleFrom(pre)
324353 if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
325354 else if (sym1Accessible && sym2.exists && ! sym2Accessible) denot1
326355 else if (sym2Accessible && sym1.exists && ! sym1Accessible) denot2
356+ else if (isDoubleDef(sym1, sym2)) handleDoubleDef
327357 else {
328358 val sym =
329359 if (! sym1.exists) sym2
0 commit comments