diff options
-rw-r--r-- | src/dotty/annotation/internal/Child.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Flags.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Symbols.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TypeErasure.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TastyFormat.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreePickler.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 299 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/CheckReentrant.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/CheckStatic.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/FirstTransform.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeTransform.scala | 30 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 10 |
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) |