aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-06-19 04:45:24 +0200
committerMartin Odersky <odersky@gmail.com>2013-06-19 04:48:11 +0200
commitb2dcc777e5a6a1e6d1fff89c7fa794129ad5d135 (patch)
tree2bac3a26ea6f7d62d713206687ba631c3c1cfad5 /src/dotty
parent928a2a99288c3aa425654e63aea5ddc70359d4ac (diff)
downloaddotty-b2dcc777e5a6a1e6d1fff89c7fa794129ad5d135.tar.gz
dotty-b2dcc777e5a6a1e6d1fff89c7fa794129ad5d135.tar.bz2
dotty-b2dcc777e5a6a1e6d1fff89c7fa794129ad5d135.zip
Taking accessibility into account for &, |
Changed the algorithm for & (and also |) to take accessibility into account. Fixed various problems that opened up when doing this. Under -debug, new and old behavior of & are checked side-by-side and any discrepancy is noted.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala114
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala5
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/Types.scala18
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala3
6 files changed, 115 insertions, 31 deletions
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index b69997836..76c5d79b4 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -213,8 +213,8 @@ object Denotations {
else
this.asInstanceOf[SingleDenotation]
- /** Form a denotation by conjoining with denotation `that` */
- def & (that: Denotation)(implicit ctx: Context): Denotation =
+ /** Form a denotation by conjoining with denotation `that` (OUTDATED, kept only for checking) */
+ private def & (that: Denotation)(implicit ctx: Context): Denotation =
if (this eq that) this
else if (!this.exists) that
else if (!that.exists) this
@@ -227,7 +227,7 @@ object Denotations {
}
/** Try to merge denot1 and denot2 without adding a new signature.
- * If unsuccessful, return NoDenotation.
+ * If unsuccessful, return NoDenotation. (OUTDATED, kept only for checking)
*/
private def mergeDenot(denot1: Denotation, denot2: SingleDenotation)(implicit ctx: Context): Denotation = denot1 match {
case denot1 @ MultiDenotation(denot11, denot12) =>
@@ -266,17 +266,97 @@ object Denotations {
}
}
+
+ /** Form a denotation by conjoining with denotation `that` */
+ def & (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = {
+
+ /** Try to merge denot1 and denot2 without adding a new signature.
+ * If unsuccessful, return NoDenotation.
+ */
+ def mergeDenot(denot1: Denotation, denot2: SingleDenotation): Denotation = denot1 match {
+ case denot1 @ MultiDenotation(denot11, denot12) =>
+ val d1 = mergeDenot(denot11, denot2)
+ if (d1.exists) denot1.derivedMultiDenotation(d1, denot2)
+ else {
+ val d2 = mergeDenot(denot12, denot2)
+ if (d2.exists) denot1.derivedMultiDenotation(denot11, d2)
+ else NoDenotation
+ }
+ case denot1: SingleDenotation =>
+ if (denot1 eq denot2) denot1
+ else if (denot1.signature != denot2.signature) NoDenotation
+ else {
+ val info1 = denot1.info
+ val info2 = denot2.info
+ val sym2 = denot2.symbol
+ def sym2Accessible = sym2.isAccessibleFrom(pre)
+ if (info2 <:< info1 && sym2Accessible) denot2
+ else {
+ val sym1 = denot1.symbol
+ def sym1Accessible = sym1.isAccessibleFrom(pre)
+ if (info1 <:< info2 && sym1Accessible) denot1
+ else {
+ val sym =
+ if (!sym1Accessible) sym2
+ else if (!sym2Accessible) sym1
+ else if (sym2 isAsConcrete sym1) sym2
+ else sym1
+ new JointRefDenotation(sym, info1 & info2, denot1.validFor & denot2.validFor)
+ }
+ }
+ }
+ }
+
+ val result =
+ if (this eq that) this
+ else if (!this.exists) that
+ else if (!that.exists) this
+ else that match {
+ case that: SingleDenotation =>
+ val r = mergeDenot(this, that)
+ if (r.exists) r else MultiDenotation(this, that)
+ case that @ MultiDenotation(denot1, denot2) =>
+ this & (denot1, pre) & (denot2, pre)
+ }
+ if (ctx.settings.debug.value) {
+ val alt = this & that
+ if (result != alt && (result.info != alt.info || result.symbol != alt.symbol))
+ println(s"""discrepancy when computing $this & $that from $pre
+ |previousy: $alt
+ |now : $result
+ |this.info = ${this.info.show}
+ |that.info = ${that.info.show}
+ |${this.info <:< that.info} ${that.info <:< this.info}""".stripMargin)
+ }
+ result
+ }
+
/** Form a choice between this denotation and that one.
* @param pre The prefix type of the members of the denotation, used
* to determine an accessible symbol if it exists.
*/
- def | (that: Denotation)(pre: Type)(implicit ctx: Context): Denotation = {
+ def | (that: Denotation, pre: Type)(implicit ctx: Context): Denotation = {
- def lubSym(sym1: Symbol, sym2: Symbol): Symbol = {
- def qualifies(sym: Symbol) =
- sym.isAccessibleFrom(pre) && sym2.owner.isSubClass(sym.owner)
- sym1.allOverriddenSymbols findSymbol qualifies
- }
+ def unionDenot(denot1: SingleDenotation, denot2: SingleDenotation): Denotation =
+ if (denot1.signature != denot2.signature) NoDenotation
+ else {
+ val info1 = denot1.info
+ val info2 = denot2.info
+ val sym2 = denot2.symbol
+ def sym2Accessible = sym2.isAccessibleFrom(pre)
+ if (info1 <:< info2 && sym2Accessible) denot2
+ else {
+ val sym1 = denot1.symbol
+ def sym1Accessible = sym1.isAccessibleFrom(pre)
+ if (info2 <:< info1 && sym1Accessible) denot1
+ else {
+ def qualifies(sym: Symbol) =
+ sym.isAccessibleFrom(pre) && sym2.owner.isSubClass(sym.owner)
+ val lubSym = sym1.allOverriddenSymbols findSymbol qualifies
+ new JointRefDenotation(lubSym, info1 | info2, denot1.validFor & denot2.validFor)
+ }
+ }
+ }
def throwError = throw new MatchError(s"$this | $that")
@@ -285,19 +365,15 @@ object Denotations {
else if (!that.exists) that
else this match {
case denot1 @ MultiDenotation(denot11, denot12) =>
- denot1.derivedMultiDenotation((denot11 | that)(pre), (denot12 | that)(pre))
+ denot1.derivedMultiDenotation(denot11 | (that, pre), denot12 | (that, pre))
case _ =>
that match {
case denot2 @ MultiDenotation(denot21, denot22) =>
- denot2.derivedMultiDenotation((this | denot21)(pre), (this | denot22)(pre))
+ denot2.derivedMultiDenotation(this | (denot21, pre), this | (denot22, pre))
case denot2: SingleDenotation =>
this match {
case denot1: SingleDenotation =>
- if (denot1.signature != denot2.signature) NoDenotation
- else new JointRefDenotation(
- lubSym(denot1.symbol, denot2.symbol),
- denot1.info | denot2.info,
- denot1.validFor & denot2.validFor)
+ unionDenot(denot1, denot2)
case _ =>
throwError
}
@@ -506,7 +582,7 @@ object Denotations {
// ------ PreDenotation ops ----------------------------------------------
final def first = this
- final def toDenot(implicit ctx: Context) = this
+ final def toDenot(pre: Type)(implicit ctx: Context) = this
final def containsSig(sig: Signature)(implicit ctx: Context) =
exists && signature == sig
final def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): SingleDenotation =
@@ -573,7 +649,7 @@ object Denotations {
def first: Denotation
/** Convert to full denotation by &-ing all elements */
- def toDenot(implicit ctx: Context): Denotation
+ def toDenot(pre: Type)(implicit ctx: Context): Denotation
/** Group contains a denotation with given signature */
def containsSig(sig: Signature)(implicit ctx: Context): Boolean
@@ -604,7 +680,7 @@ object Denotations {
assert(denots1.exists && denots2.exists)
def exists = true
def first = denots1.first
- def toDenot(implicit ctx: Context) = denots1.toDenot & denots2.toDenot
+ def toDenot(pre: Type)(implicit ctx: Context) = (denots1 toDenot pre) & (denots2 toDenot pre, pre)
def containsSig(sig: Signature)(implicit ctx: Context) =
(denots1 containsSig sig) || (denots2 containsSig sig)
def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): PreDenotation =
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 6e4777749..9f4cce728 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -274,11 +274,12 @@ object Flags {
final val Label = termFlag(22, "<label>")
/** Labeled with `abstract` modifier (an abstract class)
+ * Note: You should never see Abstract on any symbol except a class.
* Note: the flag counts as common, because it can be combined with OVERRIDE in a term.
*/
final val Abstract = commonFlag(23, "abstract")
- /** Labeled with of abstract & override */
+ /** Labeled with of abstract & override (needed?) */
final val AbsOverride = termFlag(24, "abstract override")
/** Method is assumed to be stable */
@@ -376,7 +377,7 @@ object Flags {
Erroneous
assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags)
- // TODO: Should check that FromStartFlags do not changed in completion
+ // TODO: Should check that FromStartFlags do not change in completion
/** A value that's unstable unless complemented with a Stable flag */
final val UnstableValue = Mutable | Method
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 3026562a3..95798d701 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -874,7 +874,7 @@ object SymDenotations {
} else NoDenotation
override final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation =
- membersNamed(name).filterExcluded(excluded).asSeenFrom(pre).toDenot
+ membersNamed(name).filterExcluded(excluded).asSeenFrom(pre).toDenot(pre)
private[this] var baseTypeCache: java.util.HashMap[CachedType, Type] = null
private[this] var baseTypeValid: RunId = NoRunId
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 1a1789eeb..851eb1301 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -295,7 +295,7 @@ object Types {
*/
final def findDecl(name: Name, excluded: FlagSet)(implicit ctx: Context): Denotation = this match {
case tp: ClassInfo =>
- tp.decls.denotsNamed(name).filterExcluded(excluded).toDenot
+ tp.decls.denotsNamed(name).filterExcluded(excluded).toDenot(NoPrefix)
case tp: TypeProxy =>
tp.underlying.findDecl(name, excluded)
}
@@ -317,7 +317,7 @@ object Types {
case tp: RefinedType =>
val pdenot = tp.parent.findMember(name, pre, excluded)
if (name eq tp.refinedName)
- pdenot & new JointRefDenotation(NoSymbol, tp.refinedInfo.substThis(tp, pre), Period.allInRun(ctx.runId))
+ pdenot & (new JointRefDenotation(NoSymbol, tp.refinedInfo.substThis(tp, pre), Period.allInRun(ctx.runId)), pre)
else
pdenot
case tp: ThisType =>
@@ -341,9 +341,9 @@ object Types {
case tp: ClassInfo =>
tp.cls.findMember(name, pre, excluded)
case AndType(l, r) =>
- l.findMember(name, pre, excluded) & r.findMember(name, pre, excluded)
+ l.findMember(name, pre, excluded) & (r.findMember(name, pre, excluded), pre)
case OrType(l, r) =>
- (l.findMember(name, pre, excluded) | r.findMember(name, pre, excluded))(pre)
+ l.findMember(name, pre, excluded) | (r.findMember(name, pre, excluded), pre)
case NoType =>
NoDenotation
} /* !!! DEBUG ensuring { denot =>
@@ -1527,12 +1527,12 @@ object Types {
if (optSelfType.exists) optSelfType else cls.typeConstructor
def rebase(tp: Type)(implicit ctx: Context): Type =
- if (prefix eq cls.owner.thisType) tp
- else tp.substThis(cls, prefix)
+ if ((prefix eq cls.owner.thisType) || !cls.owner.isClass) tp
+ else tp.substThis(cls.owner.asClass, prefix)
def typeConstructor(implicit ctx: Context): Type =
if ((cls is PackageClass) || cls.owner.isTerm) TypeRef.withSym(prefix, cls)
- else TypeRef(prefix, cls.name).withDenot(cls.denot.asSeenFrom(prefix))
+ else TypeRef(prefix, cls.name).withDenot(cls.denot.asSeenFrom(prefix)) // this ???
// cached because baseType needs parents
private var parentsCache: List[TypeRef] = null
@@ -1584,6 +1584,7 @@ object Types {
override def & (that: Type)(implicit ctx: Context) = that match {
case that: TypeBounds => this & that
+ case that: ClassInfo => this & that.bounds
}
override def | (that: Type)(implicit ctx: Context) = that match {
@@ -1733,6 +1734,9 @@ object Types {
tp.derivedTypeBounds(this(lo), this(hi))
}
+ case tp @ ClassInfo(prefix, _, _, _, _) =>
+ tp.derivedClassInfo(this(prefix))
+
case tp @ AnnotatedType(annot, underlying) =>
tp.derivedAnnotatedType(mapOver(annot), this(underlying))
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 0ada9eac5..5766dd2ec 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -216,7 +216,9 @@ class PlainPrinter(_ctx: Context) extends Printer {
val parentsText = Text(cparents.map(p =>
toTextLocal(reconstituteParent(cls, p))), " with ")
val trueDecls = otherDecls.filterNot(treatAsTypeArg)
- val declsText = if (trueDecls.isEmpty) Text() else dclsText(trueDecls)
+ val declsText =
+ if (trueDecls.isEmpty || !ctx.settings.debug.value) Text()
+ else dclsText(trueDecls)
tparamsText ~ " extends " ~ parentsText ~ "{" ~ selfText ~ declsText ~
"} at " ~ preText
case _ =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 47ffa40ce..4861b3949 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -158,7 +158,8 @@ class Typer extends Namer {
if (curOwner.isClass && (curOwner ne outer.owner)) curOwner.asClass.membersNamed(name)
else curScope.denotsNamed(name)
if (defDenots.exists) {
- val found = NamedType(curOwner.thisType, name).withDenot(defDenots.toDenot)
+ val pre = curOwner.thisType
+ val found = NamedType(pre, name).withDenot(defDenots toDenot pre)
if (!(curOwner is Package) || isDefinedInCurrentUnit(defDenots))
return checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry
else if (prevPrec < packageClause)