aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Denotations.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-06-02 12:56:11 +0200
committerMartin Odersky <odersky@gmail.com>2015-06-02 12:56:11 +0200
commit4182fb78ce173ed234a184cee4fc4493b706c77f (patch)
tree8454387014864a5ba3284b15e825614c6a0b8e8d /src/dotty/tools/dotc/core/Denotations.scala
parent0a0d3dd1a79cb211e5caf93f37b7ef6f484508b2 (diff)
downloaddotty-4182fb78ce173ed234a184cee4fc4493b706c77f.tar.gz
dotty-4182fb78ce173ed234a184cee4fc4493b706c77f.tar.bz2
dotty-4182fb78ce173ed234a184cee4fc4493b706c77f.zip
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 0a0d3dd1 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.
Diffstat (limited to 'src/dotty/tools/dotc/core/Denotations.scala')
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala54
1 files changed, 45 insertions, 9 deletions
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 6ac15dbca..4d475fe2b 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -227,16 +227,36 @@ object Denotations {
else
asSingleDenotation
- /** Form a denotation by conjoining with denotation `that` */
+ /** Form a denotation by conjoining with denotation `that`.
+ *
+ * NoDenotations are dropped. MultiDenotations are handled by merging
+ * parts with same signatures. SingleDenotations with equal signatures
+ * are joined as follows:
+ *
+ * In a first step, consider only those denotations which have symbols
+ * that are accessible from prefix `pre`.
+ *
+ * If there are several such denotations, try to pick one by applying the following
+ * three precedence rules in decreasing order of priority:
+ *
+ * 1. Prefer denotations with more specific infos.
+ * 2. If infos are equally specific, prefer denotations with concrete symbols over denotations
+ * with abstract symbols.
+ * 3. If infos are equally specific and symbols are equally concrete,
+ * prefer denotations with symbols defined in subclasses
+ * over denotations with symbols defined in proper superclasses.
+ *
+ * If there is exactly one (preferred) accessible denotation, return it.
+ *
+ * If there is no preferred accessible denotation, return a JointRefDenotation
+ * with one of the operand symbols (unspecified which one), and an info which
+ * is intersection (&) of the infos of the operand denotations.
+ *
+ * If SingleDenotations with different signatures are joined, return NoDenotation.
+ */
def & (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = {
- /** Try to merge denot1 and denot2 without adding a new signature.
- * Prefer denotations with more specific types, provided the symbol stays accessible
- * Prefer denotations with accessible symbols over denotations with
- * existing, but inaccessible symbols.
- * If there's no preference, produce a JointRefDenotation with the intersection of both infos.
- * If unsuccessful, return NoDenotation.
- */
+ /** Try to merge denot1 and denot2 without adding a new signature. */
def mergeDenot(denot1: Denotation, denot2: SingleDenotation): Denotation = denot1 match {
case denot1 @ MultiDenotation(denot11, denot12) =>
val d1 = mergeDenot(denot11, denot2)
@@ -254,8 +274,24 @@ object Denotations {
val sym1 = denot1.symbol
val sym2 = denot2.symbol
val sym2Accessible = sym2.isAccessibleFrom(pre)
+ def shadows(sym1: Symbol, sym2: Symbol) = {
+ val owner1 = sym1.owner
+ val owner2 = sym2.owner
+ owner1.derivesFrom(owner2) && owner1.ne(owner2)
+ }
+ /** Preference according to order (overrides, isAsConcrete, shadows)*/
def prefer(info1: Type, sym1: Symbol, info2: Type, sym2: Symbol) =
- info1.overrides(info2) && (sym1.isAsConcrete(sym2) || !info2.overrides(info1))
+ info1.overrides(info2) && (
+ // non-standard ordering of tests for efficiency -
+ // overrides is costlier to compute than the others, so its 2nd test comes last.
+ sym1.isAsConcrete(sym2) && (
+ !sym2.isAsConcrete(sym1)
+ ||
+ shadows(sym1, sym2)
+ )
+ ||
+ !info2.overrides(info1)
+ )
if (sym2Accessible && prefer(info2, sym2, info1, sym1)) denot2
else {
val sym1Accessible = sym1.isAccessibleFrom(pre)