aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2016-05-27 14:26:33 +0200
committerDmitry Petrashko <dark@d-d.me>2016-05-27 14:26:33 +0200
commitcf2ae5ed82599b988f8c1a625e31fb03b5c1a0fe (patch)
treebd57c6177876ee2a7b88ab3fb1a9f1be65b0cfa9 /src
parent079192ea78e53084bbe91460a2941ddb46bcbc20 (diff)
parentc996e42224eedaf3b097fea0c6175eba7d3cbe63 (diff)
downloaddotty-cf2ae5ed82599b988f8c1a625e31fb03b5c1a0fe.tar.gz
dotty-cf2ae5ed82599b988f8c1a625e31fb03b5c1a0fe.tar.bz2
dotty-cf2ae5ed82599b988f8c1a625e31fb03b5c1a0fe.zip
Merge pull request #1270 from dotty-staging/fix-bootstrap
Fix bootstrap
Diffstat (limited to 'src')
-rw-r--r--src/dotty/annotation/internal/Child.scala5
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala2
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala8
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala3
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala4
-rw-r--r--src/dotty/tools/dotc/core/TypeErasure.scala2
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyFormat.scala11
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala2
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala299
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala6
-rw-r--r--src/dotty/tools/dotc/transform/CheckReentrant.scala2
-rw-r--r--src/dotty/tools/dotc/transform/CheckStatic.scala2
-rw-r--r--src/dotty/tools/dotc/transform/FirstTransform.scala7
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala30
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala10
15 files changed, 281 insertions, 112 deletions
diff --git a/src/dotty/annotation/internal/Child.scala b/src/dotty/annotation/internal/Child.scala
index 4f3ceb6c0..9295de73e 100644
--- a/src/dotty/annotation/internal/Child.scala
+++ b/src/dotty/annotation/internal/Child.scala
@@ -9,7 +9,8 @@ import scala.annotation.Annotation
* case class B() extends A
* case class C() extends A
*
- * Then `A` would carry the annotations `@Child[B] @Child[C]` where
- * `B`, `C` are TypeRefs.
+ * Then the class symbol `A` would carry the annotations
+ * `@Child[Bref] @Child[Cref]` where `Bref`, `Cref` are TypeRefs
+ * referring to the class symbols of `B` and `C`
*/
class Child[T] extends Annotation
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index bbe8e920c..e1aeac8c3 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -248,7 +248,7 @@ object Contexts {
withPhase(phase.id)
final def withPhaseNoLater(phase: Phase) =
- if (ctx.phase.id > phase.id) withPhase(phase) else ctx
+ if (phase.exists && ctx.phase.id > phase.id) withPhase(phase) else ctx
/** If -Ydebug is on, the top of the stack trace where this context
* was created, otherwise `null`.
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 69624b01a..5ce8cbcd8 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -658,7 +658,13 @@ object Denotations {
var startPid = nextTransformerId + 1
val transformer = ctx.denotTransformers(nextTransformerId)
//println(s"transforming $this with $transformer")
- next = transformer.transform(cur)(ctx.withPhase(transformer)).syncWithParents
+ try {
+ next = transformer.transform(cur)(ctx.withPhase(transformer)).syncWithParents
+ } catch {
+ case ex: CyclicReference =>
+ println(s"error while transforming $this") // DEBUG
+ throw ex
+ }
if (next eq cur)
startPid = cur.validFor.firstPhaseId
else {
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index f866621f2..cd660aa46 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -525,6 +525,9 @@ object Flags {
/** Either method or lazy */
final val MethodOrLazy = Method | Lazy
+ /** Either method or lazy or deferred */
+ final val MethodOrLazyOrDeferred = Method | Lazy | Deferred
+
/** Labeled `private` or `final` */
final val PrivateOrFinal = Private | Final
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 473f107cb..4c1654e47 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -400,10 +400,10 @@ object Symbols {
/** Subclass tests and casts */
final def isTerm(implicit ctx: Context): Boolean =
- (if(isDefinedInCurrentRun) lastDenot else denot).isTerm
+ (if (defRunId == ctx.runId) lastDenot else denot).isTerm
final def isType(implicit ctx: Context): Boolean =
- (if(isDefinedInCurrentRun) lastDenot else denot).isType
+ (if (defRunId == ctx.runId) lastDenot else denot).isType
final def isClass: Boolean = isInstanceOf[ClassSymbol]
diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala
index 89077897a..39d02e069 100644
--- a/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -374,7 +374,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
tr1 :: trs1.filterNot(_ isRef defn.ObjectClass)
case nil => nil
}
- val erasedDecls = decls.filteredScope(d => !d.isType || d.isClass)
+ val erasedDecls = decls.filteredScope(sym => !sym.isType || sym.isClass)
tp.derivedClassInfo(NoPrefix, parents, erasedDecls, erasedRef(tp.selfType))
// can't replace selftype by NoType because this would lose the sourceModule link
}
diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index ea7e985c9..221170622 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
@@ -485,4 +485,15 @@ object TastyFormat {
case PRIVATEqualified => "PRIVATEqualified"
case PROTECTEDqualified => "PROTECTEDqualified"
}
+
+ /** @return If non-negative, the number of leading references of a length/trees entry.
+ * If negative, minus the number of leading non-reference trees.
+ */
+ def numRefs(tag: Int) = tag match {
+ case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | RETURN | BIND |
+ SELFDEF | REFINEDtype => 1
+ case RENAMED | PARAMtype => 2
+ case POLYtype | METHODtype => -1
+ case _ => 0
+ }
}
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index f8f9c993f..37b9341eb 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -217,8 +217,8 @@ class TreePickler(pickler: TastyPickler) {
case tpe: RefinedType =>
writeByte(REFINEDtype)
withLength {
- pickleType(tpe.parent)
pickleName(tpe.refinedName)
+ pickleType(tpe.parent)
pickleType(tpe.refinedInfo, richTypes = true)
}
case tpe: TypeAlias =>
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 535ddd216..91ac4ea3e 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -22,6 +22,7 @@ import config.Printers.pickling
class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
import TastyFormat._
import TastyName._
+ import TreeUnpickler._
import tpd._
private var readPositions = false
@@ -40,25 +41,45 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
this.positions = positions
}
+ /** A map from addresses of definition entries to the symbols they define */
private val symAtAddr = new mutable.HashMap[Addr, Symbol]
- private val unpickledSyms = new mutable.HashSet[Symbol]
+
+ /** A temporary map from addresses of definition entries to the trees they define.
+ * Used to remember trees of symbols that are created by a completion. Emptied
+ * once the tree is inlined into a larger tree.
+ */
private val treeAtAddr = new mutable.HashMap[Addr, Tree]
- private val typeAtAddr = new mutable.HashMap[Addr, Type] // currently populated only for types that are known to be SHAREd.
- private var stubs: Set[Symbol] = Set()
+ /** A map from addresses of type entries to the types they define.
+ * Currently only populated for types that might be recursively referenced
+ * from within themselves (i.e. RefinedTypes, PolyTypes, MethodTypes).
+ */
+ private val typeAtAddr = new mutable.HashMap[Addr, Type]
+
+ /** The root symbol denotation which are defined by the Tasty file associated with this
+ * TreeUnpickler. Set by `enterTopLevel`.
+ */
private var roots: Set[SymDenotation] = null
- private def registerSym(addr: Addr, sym: Symbol) = {
+ /** The root symbols that are defined in this Tasty file. This
+ * is a subset of `roots.map(_.symbol)`.
+ */
+ private var seenRoots: Set[Symbol] = Set()
+
+ /** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
+ private var ownerTree: OwnerTree = _
+
+ private def registerSym(addr: Addr, sym: Symbol) =
symAtAddr(addr) = sym
- unpickledSyms += sym
- }
/** Enter all toplevel classes and objects into their scopes
* @param roots a set of SymDenotations that should be overwritten by unpickling
*/
def enterTopLevel(roots: Set[SymDenotation])(implicit ctx: Context): Unit = {
this.roots = roots
- new TreeReader(reader).fork.indexStats(reader.endAddr)
+ var rdr = new TreeReader(reader).fork
+ ownerTree = new OwnerTree(NoAddr, 0, rdr.fork, reader.endAddr)
+ rdr.indexStats(reader.endAddr)
}
/** The unpickled trees */
@@ -84,10 +105,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
def toTermName(ref: NameRef): TermName = toTermName(tastyName(ref))
def toTypeName(ref: NameRef): TypeName = toTermName(ref).toTypeName
- class Completer(reader: TastyReader) extends LazyType {
+ class Completer(owner: Symbol, reader: TastyReader) extends LazyType {
import reader._
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
- treeAtAddr(currentAddr) = new TreeReader(reader).readIndexedDef()
+ treeAtAddr(currentAddr) =
+ new TreeReader(reader).readIndexedDef()(
+ ctx.withPhaseNoLater(ctx.picklerPhase).withOwner(owner))
}
}
@@ -107,6 +130,47 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
def skipParams(): Unit =
while (nextByte == PARAMS || nextByte == TYPEPARAM) skipTree()
+ /** Record all directly nested definitions and templates in current tree
+ * as `OwnerTree`s in `buf`
+ */
+ def scanTree(buf: ListBuffer[OwnerTree], mode: MemberDefMode = AllDefs): Unit = {
+ val start = currentAddr
+ val tag = readByte()
+ tag match {
+ case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | TEMPLATE =>
+ val end = readEnd()
+ for (i <- 0 until numRefs(tag)) readNat()
+ if (tag == TEMPLATE) scanTrees(buf, end, MemberDefsOnly)
+ if (mode != NoMemberDefs) buf += new OwnerTree(start, tag, fork, end)
+ goto(end)
+ case tag =>
+ if (mode == MemberDefsOnly) skipTree(tag)
+ else if (tag >= firstLengthTreeTag) {
+ val end = readEnd()
+ var nrefs = numRefs(tag)
+ if (nrefs < 0) {
+ for (i <- nrefs until 0) scanTree(buf)
+ goto(end)
+ }
+ else {
+ for (i <- 0 until nrefs) readNat()
+ scanTrees(buf, end)
+ }
+ }
+ else if (tag >= firstNatASTTreeTag) { readNat(); scanTree(buf) }
+ else if (tag >= firstASTTreeTag) scanTree(buf)
+ else if (tag >= firstNatTreeTag) readNat()
+ }
+ }
+
+ /** Record all directly nested definitions and templates between current address and `end`
+ * as `OwnerTree`s in `buf`
+ */
+ def scanTrees(buf: ListBuffer[OwnerTree], end: Addr, mode: MemberDefMode = AllDefs): Unit = {
+ while (currentAddr.index < end.index) scanTree(buf, mode)
+ assert(currentAddr.index == end.index)
+ }
+
/** The next tag, following through SHARED tags */
def nextUnsharedTag: Int = {
val tag = nextByte
@@ -145,19 +209,25 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
until(end) { readNat(); readType().asInstanceOf[T] }
/** Read referece to definition and return symbol created at that definition */
- def readSymRef()(implicit ctx: Context): Symbol = {
- val start = currentAddr
- val addr = readAddr()
- symAtAddr get addr match {
- case Some(sym) => sym
- case None =>
- // Create a stub; owner might be wrong but will be overwritten later.
- forkAt(addr).createSymbol()
- val sym = symAtAddr(addr)
- ctx.log(i"forward reference to $sym")
- stubs += sym
- sym
- }
+ def readSymRef()(implicit ctx: Context): Symbol = symbolAt(readAddr())
+
+ /** The symbol at given address; createa new one if none exists yet */
+ def symbolAt(addr: Addr)(implicit ctx: Context): Symbol = symAtAddr.get(addr) match {
+ case Some(sym) =>
+ sym
+ case None =>
+ val sym = forkAt(addr).createSymbol()(ctx.withOwner(ownerTree.findOwner(addr)))
+ ctx.log(i"forward reference to $sym")
+ sym
+ }
+
+ /** The symbol defined by current definition */
+ def symbolAtCurrent()(implicit ctx: Context): Symbol = symAtAddr.get(currentAddr) match {
+ case Some(sym) =>
+ assert(ctx.owner == sym.owner, i"owner discrepancy for $sym, expected: ${ctx.owner}, found: ${sym.owner}")
+ sym
+ case None =>
+ createSymbol()
}
/** Read a type */
@@ -186,8 +256,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
case SUPERtype =>
SuperType(readType(), readType())
case REFINEDtype =>
- val parent = readType()
var name: Name = readName()
+ val parent = readType()
val ttag = nextUnsharedTag
if (ttag == TYPEBOUNDS || ttag == TYPEALIAS) name = name.toTypeName
RefinedType(parent, name, rt => registeringType(rt, readType()))
@@ -360,10 +430,23 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
}
/** Create symbol of definition node and enter in symAtAddr map
- * @return the largest subset of {NoInits, PureInterface} that a
- * trait owning this symbol can have as flags.
+ * @return the created symbol
+ */
+ def createSymbol()(implicit ctx: Context): Symbol = nextByte match {
+ case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
+ createMemberSymbol()
+ case TEMPLATE =>
+ val localDummy = ctx.newLocalDummy(ctx.owner)
+ registerSym(currentAddr, localDummy)
+ localDummy
+ case tag =>
+ throw new Error(s"illegal createSymbol at $currentAddr, tag = $tag")
+ }
+
+ /** Create symbol of member definition or parameter node and enter in symAtAddr map
+ * @return the created symbol
*/
- def createSymbol()(implicit ctx: Context): FlagSet = {
+ def createMemberSymbol()(implicit ctx: Context): Symbol = {
val start = currentAddr
val tag = readByte()
val end = readEnd()
@@ -393,29 +476,18 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
case Some(rootd) =>
pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}")
rootd.info = adjustIfModule(
- new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter)
+ new Completer(ctx.owner, subReader(start, end)) with SymbolLoaders.SecondCompleter)
rootd.flags = flags &~ Touched // allow one more completion
rootd.privateWithin = privateWithin
+ seenRoots += rootd.symbol
rootd.symbol
case _ =>
- val completer = adjustIfModule(new Completer(subReader(start, end)))
+ val completer = adjustIfModule(new Completer(ctx.owner, subReader(start, end)))
if (isClass)
- ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer,
- privateWithin, coord = start.index)
- else {
- val sym = symAtAddr.get(start) match {
- case Some(preExisting) =>
- assert(stubs contains preExisting)
- stubs -= preExisting
- preExisting
- case none =>
- ctx.newNakedSymbol(start.index)
- }
- val denot = ctx.SymDenotation(symbol = sym, owner = ctx.owner, name, flags, completer, privateWithin)
- sym.denot = denot
- sym
- }
- } // TODO set position
+ ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord = start.index)
+ else
+ ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord = start.index)
+ } // TODO set position somehow (but take care not to upset Symbol#isDefinedInCurrentRun)
sym.annotations = annots
ctx.enter(sym)
registerSym(start, sym)
@@ -423,14 +495,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
sym.completer.withDecls(newScope)
forkAt(templateStart).indexTemplateParams()(localContext(sym))
}
- if (isClass) NoInits
- else if (sym.isType || sym.isConstructor || flags.is(Deferred)) NoInitsInterface
- else if (tag == VALDEF) EmptyFlags
- else NoInits
+ goto(start)
+ sym
}
/** Read modifier list into triplet of flags, annotations and a privateWithin
- * boindary symbol.
+ * boundary symbol.
*/
def readModifiers(end: Addr)(implicit ctx: Context): (FlagSet, List[Annotation], Symbol) = {
var flags: FlagSet = EmptyFlags
@@ -493,28 +563,34 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
(flags, annots.toList, privateWithin)
}
- /** Create symbols for a definitions in statement sequence between
+ /** Create symbols for the definitions in the statement sequence between
* current address and `end`.
* @return the largest subset of {NoInits, PureInterface} that a
* trait owning the indexed statements can have as flags.
*/
def indexStats(end: Addr)(implicit ctx: Context): FlagSet = {
- val flagss =
- until(end) {
- nextByte match {
- case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
- createSymbol()
- case IMPORT =>
- skipTree()
- NoInitsInterface
- case PACKAGE =>
- processPackage { (pid, end) => implicit ctx => indexStats(end) }
- case _ =>
- skipTree()
- EmptyFlags
- }
+ var initsFlags = NoInitsInterface
+ while (currentAddr.index < end.index) {
+ nextByte match {
+ case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM =>
+ val sym = symbolAtCurrent()
+ skipTree()
+ if (sym.isTerm && !sym.is(MethodOrLazyOrDeferred))
+ initsFlags = EmptyFlags
+ else if (sym.isClass ||
+ sym.is(Method, butNot = Deferred) && !sym.isConstructor)
+ initsFlags &= NoInits
+ case IMPORT =>
+ skipTree()
+ case PACKAGE =>
+ processPackage { (pid, end) => implicit ctx => indexStats(end) }
+ case _ =>
+ skipTree()
+ initsFlags = EmptyFlags
}
- (NoInitsInterface /: flagss)(_ & _)
+ }
+ assert(currentAddr.index == end.index)
+ initsFlags
}
/** Process package with given operation `op`. The operation takes as arguments
@@ -533,7 +609,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
* `tag` starting at current address.
*/
def indexParams(tag: Int)(implicit ctx: Context) =
- while (nextByte == tag) createSymbol()
+ while (nextByte == tag) {
+ symbolAtCurrent()
+ skipTree()
+ }
/** Create symbols for all type and value parameters of template starting
* at current address.
@@ -560,7 +639,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
val end = readEnd()
def readParams[T <: MemberDef](tag: Int)(implicit ctx: Context): List[T] = {
- fork.indexParams(tag)
+ fork.indexParams(tag)(localContext(sym))
readIndexedParams(tag)
}
@@ -610,7 +689,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
case TYPEDEF | TYPEPARAM =>
if (sym.isClass) {
val companion = sym.scalacLinkedClass
- if (companion != NoSymbol && unpickledSyms.contains(companion)) {
+
+ // Is the companion defined in the same Tasty file as `sym`?
+ // The only case to check here is if `sym` is a root. In this case
+ // `companion` might have been entered by the environment but it might
+ // be missing from the Tasty file. So we check explicitly for that.
+ def isCodefined =
+ roots.contains(companion.denot) == seenRoots.contains(companion)
+ if (companion.exists && isCodefined) {
import transform.SymUtils._
if (sym is Flags.ModuleClass) sym.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, companion)
else sym.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, companion)
@@ -646,8 +732,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
val cls = ctx.owner.asClass
def setClsInfo(parents: List[TypeRef], selfType: Type) =
cls.info = ClassInfo(cls.owner.thisType, cls, parents, cls.unforcedDecls, selfType)
- setClsInfo(Nil, NoType)
- val localDummy = ctx.newLocalDummy(cls)
+ val assumedSelfType =
+ if (cls.is(Module) && cls.owner.isClass)
+ TermRef.withSig(cls.owner.thisType, cls.name.sourceModuleName, Signature.NotAMethod)
+ else NoType
+ setClsInfo(Nil, assumedSelfType)
+ val localDummy = symbolAtCurrent()
assert(readByte() == TEMPLATE)
val end = readEnd()
val tparams = readIndexedParams[TypeDef](TYPEPARAM)
@@ -659,7 +749,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
}
}
val parentRefs = ctx.normalizeToClassRefs(parents.map(_.tpe), cls, cls.unforcedDecls)
- val self =
+ val self =
if (nextByte == SELFDEF) {
readByte()
untpd.ValDef(readName(), readTpt(), EmptyTree).withType(NoType)
@@ -703,9 +793,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
@tailrec def read(acc: ListBuffer[Tree]): List[Tree] = nextByte match {
case IMPORT | PACKAGE =>
acc += readIndexedStat(NoSymbol)
- if (!isAtEnd)
- read(acc)
- else acc.toList
+ if (!isAtEnd) read(acc) else acc.toList
case _ => // top-level trees which are not imports or packages are not part of tree
acc.toList
}
@@ -938,7 +1026,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
class LazyReader[T <: AnyRef](reader: TreeReader, op: TreeReader => Context => T) extends Trees.Lazy[T] with DeferredPosition {
def complete(implicit ctx: Context): T = {
pickling.println(i"starting to read at ${reader.reader.currentAddr}")
- val res = op(reader)(ctx.addMode(Mode.AllowDependentFunctions))
+ val res = op(reader)(ctx.addMode(Mode.AllowDependentFunctions).withPhaseNoLater(ctx.picklerPhase))
normalizePos(res, parentPos)
res
}
@@ -947,9 +1035,68 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
class LazyAnnotationReader(sym: Symbol, reader: TreeReader)
extends LazyAnnotation(sym) with DeferredPosition {
def complete(implicit ctx: Context) = {
- val res = reader.readTerm()
+ val res = reader.readTerm()(ctx.withPhaseNoLater(ctx.picklerPhase))
normalizePos(res, parentPos)
res
}
}
+
+ /** A lazy datastructure that records how definitions are nested in TASTY data.
+ * The structure is lazy because it needs to be computed only for forward references
+ * to symbols that happen before the referenced symbol is created (see `symbolAt`).
+ * Such forward references are rare.
+ *
+ * @param addr The address of tree representing an owning definition, NoAddr for root tree
+ * @param tag The tag at `addr`. Used to determine which subtrees to scan for children
+ * (i.e. if `tag` is template, don't scan member defs, as these belong already
+ * to enclosing class).
+ * @param reader The reader to be used for scanning for children
+ * @param end The end of the owning definition
+ */
+ class OwnerTree(val addr: Addr, tag: Int, reader: TreeReader, val end: Addr) {
+
+ /** All definitions that have the definition at `addr` as closest enclosing definition */
+ lazy val children: List[OwnerTree] = {
+ val buf = new ListBuffer[OwnerTree]
+ reader.scanTrees(buf, end, if (tag == TEMPLATE) NoMemberDefs else AllDefs)
+ buf.toList
+ }
+
+ /** Find the owner of definition at `addr` */
+ def findOwner(addr: Addr)(implicit ctx: Context): Symbol = {
+ def search(cs: List[OwnerTree], current: Symbol): Symbol =
+ try cs match {
+ case ot :: cs1 =>
+ if (ot.addr.index == addr.index)
+ current
+ else if (ot.addr.index < addr.index && addr.index < ot.end.index)
+ search(ot.children, reader.symbolAt(ot.addr))
+ else
+ search(cs1, current)
+ case Nil =>
+ throw new TreeWithoutOwner
+ }
+ catch {
+ case ex: TreeWithoutOwner =>
+ println(i"no owner for $addr among $cs") // DEBUG
+ throw ex
+ }
+ search(children, NoSymbol)
+ }
+
+ override def toString = s"OwnerTree(${addr.index}, ${end.index}"
+ }
+}
+
+object TreeUnpickler {
+
+ /** An enumeration indicating which subtrees should be added to an OwnerTree. */
+ type MemberDefMode = Int
+ final val MemberDefsOnly = 0 // add only member defs; skip other statements
+ final val NoMemberDefs = 1 // add only statements that are not member defs
+ final val AllDefs = 2 // add everything
+
+ class TreeWithoutOwner extends Exception
}
+
+
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index cceaed53d..71a919ca3 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -573,7 +573,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
// println(s"unpickled ${denot.debugString}, info = ${denot.info}") !!! DEBUG
}
atReadPos(startCoord(denot).toIndex,
- () => parseToCompletion(denot)(ctx.addMode(Mode.Scala2Unpickling)))
+ () => parseToCompletion(denot)(
+ ctx.addMode(Mode.Scala2Unpickling).withPhaseNoLater(ctx.picklerPhase)))
} catch {
case ex: RuntimeException => handleRuntimeException(ex)
}
@@ -922,7 +923,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
val start = readIndex
val atp = readTypeRef()
Annotation.deferred(
- atp.typeSymbol, implicit ctx => atReadPos(start, () => readAnnotationContents(end)))
+ atp.typeSymbol, implicit ctx1 =>
+ atReadPos(start, () => readAnnotationContents(end)(ctx1.withPhase(ctx.phase))))
}
/* Read an abstract syntax tree */
diff --git a/src/dotty/tools/dotc/transform/CheckReentrant.scala b/src/dotty/tools/dotc/transform/CheckReentrant.scala
index 2569b3aae..7e0e368b5 100644
--- a/src/dotty/tools/dotc/transform/CheckReentrant.scala
+++ b/src/dotty/tools/dotc/transform/CheckReentrant.scala
@@ -3,7 +3,7 @@ package transform
import core._
import Names._
-import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer}
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, MiniPhaseTransform, TreeTransformer}
import ast.Trees._
import Flags._
import Types._
diff --git a/src/dotty/tools/dotc/transform/CheckStatic.scala b/src/dotty/tools/dotc/transform/CheckStatic.scala
index 445e9f839..77c6dfc51 100644
--- a/src/dotty/tools/dotc/transform/CheckStatic.scala
+++ b/src/dotty/tools/dotc/transform/CheckStatic.scala
@@ -5,7 +5,7 @@ import core._
import Names._
import StdNames.nme
import Types._
-import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer}
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, MiniPhaseTransform, TreeTransformer}
import ast.Trees._
import Flags._
import Contexts.Context
diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala
index ae72d5f6c..6e1fed607 100644
--- a/src/dotty/tools/dotc/transform/FirstTransform.scala
+++ b/src/dotty/tools/dotc/transform/FirstTransform.scala
@@ -30,7 +30,7 @@ import StdNames._
* - stubs out native methods
* - eliminate self tree in Template and self symbol in ClassInfo
*/
-class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer with AnnotationTransformer { thisTransformer =>
+class FirstTransform extends MiniPhaseTransform with InfoTransformer with AnnotationTransformer { thisTransformer =>
import ast.tpd._
override def phaseName = "firstTransform"
@@ -46,12 +46,13 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
}
/** eliminate self symbol in ClassInfo */
- def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp match {
- case tp@ClassInfo(_, _, _, _, self: Symbol) =>
+ override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp match {
+ case tp @ ClassInfo(_, _, _, _, self: Symbol) =>
tp.derivedClassInfo(selfInfo = self.info)
case _ =>
tp
}
+
/*
tp match {
//create companions for value classes that are not from currently compiled source file
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index abada9ab4..89ae927b7 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -174,32 +174,22 @@ object TreeTransforms {
}
/** A helper trait to transform annotations on MemberDefs */
- trait AnnotationTransformer extends MiniPhaseTransform with InfoTransformer {
+ trait AnnotationTransformer extends MiniPhaseTransform with DenotTransformer {
val annotationTransformer = mkTreeTransformer
override final def treeTransformPhase = this
// need to run at own phase because otherwise we get ahead of ourselves in transforming denotations
- override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
- val info1 = transformInfo(ref.info, ref.symbol)
-
- ref match {
- case ref: SymDenotation =>
- val annots1 =
- if (!ref.symbol.isDefinedInCurrentRun) ref.annotations // leave annotations read from class files alone
- else {
- val annotTrees = ref.annotations.map(_.tree)
- val annotTrees1 = annotTrees.mapConserve(annotationTransformer.macroTransform)
- if (annotTrees eq annotTrees1) ref.annotations
- else annotTrees1.map(new ConcreteAnnotation(_))
- }
- if ((info1 eq ref.info) && (annots1 eq ref.annotations)) ref
- else ref.copySymDenotation(info = info1, annotations = annots1)
- case _ =>
- if (info1 eq ref.info) ref
- else ref.derivedSingleDenotation(ref.symbol, info1)
+ abstract override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation =
+ super.transform(ref) match {
+ case ref1: SymDenotation if ref1.symbol.isDefinedInCurrentRun =>
+ val annotTrees = ref1.annotations.map(_.tree)
+ val annotTrees1 = annotTrees.mapConserve(annotationTransformer.macroTransform)
+ if (annotTrees eq annotTrees1) ref1
+ else ref1.copySymDenotation(annotations = annotTrees1.map(new ConcreteAnnotation(_)))
+ case ref1 =>
+ ref1
}
- }
}
@sharable val NoTransform = new TreeTransform {
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index a540b6ea5..a8f3b8918 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -825,13 +825,21 @@ class Namer { typer: Typer =>
// println(s"final inherited for $sym: ${inherited.toString}") !!!
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
def isInline = sym.is(Final, butNot = Method)
+
+ // Widen rhs type and approximate `|' but keep ConstantTypes if
+ // definition is inline (i.e. final in Scala2).
def widenRhs(tp: Type): Type = tp.widenTermRefExpr match {
case tp: ConstantType if isInline => tp
case _ => tp.widen.approximateUnion
}
+
+ // Replace aliases to Unit by Unit itself. If we leave the alias in
+ // it would be erased to BoxedUnit.
+ def dealiasIfUnit(tp: Type) = if (tp.isRef(defn.UnitClass)) defn.UnitType else tp
+
val rhsCtx = ctx.addMode(Mode.InferringReturnType)
def rhsType = typedAheadExpr(mdef.rhs, inherited orElse rhsProto)(rhsCtx).tpe
- def cookedRhsType = ctx.deskolemize(widenRhs(rhsType))
+ def cookedRhsType = ctx.deskolemize(dealiasIfUnit(widenRhs(rhsType)))
lazy val lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.pos)
//if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType")
if (inherited.exists)