@@ -295,35 +295,65 @@ object Denotations {
295
295
val sym1 = denot1.symbol
296
296
val sym2 = denot2.symbol
297
297
298
- if (isDoubleDef(sym1, sym2)) doubleDefError(denot1, denot2, pre)
299
-
300
298
val sym2Accessible = sym2.isAccessibleFrom(pre)
299
+
301
300
/** Does `sym1` come before `sym2` in the linearization of `pre`? */
302
301
def precedes (sym1 : Symbol , sym2 : Symbol ) = {
303
302
def precedesIn (bcs : List [ClassSymbol ]): Boolean = bcs match {
304
303
case bc :: bcs1 => (sym1 eq bc) || ! (sym2 eq bc) && precedesIn(bcs1)
305
304
case Nil => true
306
305
}
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))
309
309
}
310
310
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
+ */
312
333
def preferSym (sym1 : Symbol , sym2 : Symbol ) =
313
334
sym1.eq(sym2) ||
314
335
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 ))
316
340
317
341
/** Sym preference provided types also override */
318
342
def prefer (sym1 : Symbol , sym2 : Symbol , info1 : Type , info2 : Type ) =
319
343
preferSym(sym1, sym2) && info1.overrides(info2)
320
344
345
+ def handleDoubleDef =
346
+ if (preferSym(sym1, sym2)) denot1
347
+ else if (preferSym(sym2, sym1)) denot2
348
+ else doubleDefError(denot1, denot2, pre)
349
+
321
350
if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2
322
351
else {
323
352
val sym1Accessible = sym1.isAccessibleFrom(pre)
324
353
if (sym1Accessible && prefer(sym1, sym2, info1, info2)) denot1
325
354
else if (sym1Accessible && sym2.exists && ! sym2Accessible) denot1
326
355
else if (sym2Accessible && sym1.exists && ! sym1Accessible) denot2
356
+ else if (isDoubleDef(sym1, sym2)) handleDoubleDef
327
357
else {
328
358
val sym =
329
359
if (! sym1.exists) sym2
0 commit comments