Skip to content

Commit 4182fb7

Browse files
committed
Refine "&" for denotations.
The policy is now made clear in a doc comment. The new part is that we will prefer a symbol defined in a subclass over a symbol defined in a superclass. With the previous commit 0a0d3dd on "More precise and uniform modelling of isCurrent" we got runtime test failures for Course-2002-03.scala because the new definition isCurrent assumed a behavior of `member` which was not assured: Namely that the merged denotation would prefer symbols in subclasses over symbols in superclasses.
1 parent 0a0d3dd commit 4182fb7

File tree

1 file changed

+45
-9
lines changed

1 file changed

+45
-9
lines changed

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

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -227,16 +227,36 @@ object Denotations {
227227
else
228228
asSingleDenotation
229229

230-
/** Form a denotation by conjoining with denotation `that` */
230+
/** Form a denotation by conjoining with denotation `that`.
231+
*
232+
* NoDenotations are dropped. MultiDenotations are handled by merging
233+
* parts with same signatures. SingleDenotations with equal signatures
234+
* are joined as follows:
235+
*
236+
* In a first step, consider only those denotations which have symbols
237+
* that are accessible from prefix `pre`.
238+
*
239+
* If there are several such denotations, try to pick one by applying the following
240+
* three precedence rules in decreasing order of priority:
241+
*
242+
* 1. Prefer denotations with more specific infos.
243+
* 2. If infos are equally specific, prefer denotations with concrete symbols over denotations
244+
* with abstract symbols.
245+
* 3. If infos are equally specific and symbols are equally concrete,
246+
* prefer denotations with symbols defined in subclasses
247+
* over denotations with symbols defined in proper superclasses.
248+
*
249+
* If there is exactly one (preferred) accessible denotation, return it.
250+
*
251+
* If there is no preferred accessible denotation, return a JointRefDenotation
252+
* with one of the operand symbols (unspecified which one), and an info which
253+
* is intersection (&) of the infos of the operand denotations.
254+
*
255+
* If SingleDenotations with different signatures are joined, return NoDenotation.
256+
*/
231257
def & (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = {
232258

233-
/** Try to merge denot1 and denot2 without adding a new signature.
234-
* Prefer denotations with more specific types, provided the symbol stays accessible
235-
* Prefer denotations with accessible symbols over denotations with
236-
* existing, but inaccessible symbols.
237-
* If there's no preference, produce a JointRefDenotation with the intersection of both infos.
238-
* If unsuccessful, return NoDenotation.
239-
*/
259+
/** Try to merge denot1 and denot2 without adding a new signature. */
240260
def mergeDenot(denot1: Denotation, denot2: SingleDenotation): Denotation = denot1 match {
241261
case denot1 @ MultiDenotation(denot11, denot12) =>
242262
val d1 = mergeDenot(denot11, denot2)
@@ -254,8 +274,24 @@ object Denotations {
254274
val sym1 = denot1.symbol
255275
val sym2 = denot2.symbol
256276
val sym2Accessible = sym2.isAccessibleFrom(pre)
277+
def shadows(sym1: Symbol, sym2: Symbol) = {
278+
val owner1 = sym1.owner
279+
val owner2 = sym2.owner
280+
owner1.derivesFrom(owner2) && owner1.ne(owner2)
281+
}
282+
/** Preference according to order (overrides, isAsConcrete, shadows)*/
257283
def prefer(info1: Type, sym1: Symbol, info2: Type, sym2: Symbol) =
258-
info1.overrides(info2) && (sym1.isAsConcrete(sym2) || !info2.overrides(info1))
284+
info1.overrides(info2) && (
285+
// non-standard ordering of tests for efficiency -
286+
// overrides is costlier to compute than the others, so its 2nd test comes last.
287+
sym1.isAsConcrete(sym2) && (
288+
!sym2.isAsConcrete(sym1)
289+
||
290+
shadows(sym1, sym2)
291+
)
292+
||
293+
!info2.overrides(info1)
294+
)
259295
if (sym2Accessible && prefer(info2, sym2, info1, sym1)) denot2
260296
else {
261297
val sym1Accessible = sym1.isAccessibleFrom(pre)

0 commit comments

Comments
 (0)