Skip to content

Commit fd861b0

Browse files
authored
Merge pull request #3525 from dotty-staging/tasty-symbols-pos
Give position to symbols when unpickling
2 parents 18767e0 + 6b19932 commit fd861b0

27 files changed

+168
-84
lines changed

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ import Types._
1010
import Scopes._
1111
import typer.{FrontEnd, Typer, ImportInfo, RefChecks}
1212
import Decorators._
13-
import io.PlainFile
13+
import io.{AbstractFile, PlainFile}
1414
import scala.io.Codec
15-
import util._
15+
import util.{Set => _, _}
1616
import reporting.Reporter
1717
import transform.TreeChecker
1818
import rewrite.Rewrites
1919
import java.io.{BufferedWriter, OutputStreamWriter}
2020
import printing.XprintMode
21+
import typer.ImplicitRunInfo
2122

2223
import scala.annotation.tailrec
2324
import dotty.tools.io.VirtualFile
2425
import scala.util.control.NonFatal
2526

2627
/** A compiler run. Exports various methods to compile source files */
2728
class Run(comp: Compiler, ictx: Context) {
28-
29-
var units: List[CompilationUnit] = _
29+
import Run._
3030

3131
/** Produces the following contexts, from outermost to innermost
3232
*
@@ -78,7 +78,7 @@ class Run(comp: Compiler, ictx: Context) {
7878
compileSources(sources)
7979
} catch {
8080
case NonFatal(ex) =>
81-
ctx.echo(i"exception occurred while compiling $units%, %")
81+
ctx.echo(i"exception occurred while compiling ${ctx.runInfo.units}%, %")
8282
throw ex
8383
}
8484

@@ -90,17 +90,17 @@ class Run(comp: Compiler, ictx: Context) {
9090
*/
9191
def compileSources(sources: List[SourceFile]) =
9292
if (sources forall (_.exists)) {
93-
units = sources map (new CompilationUnit(_))
93+
ctx.runInfo.units = sources map (new CompilationUnit(_))
9494
compileUnits()
9595
}
9696

9797
def compileUnits(us: List[CompilationUnit]): Unit = {
98-
units = us
98+
ctx.runInfo.units = us
9999
compileUnits()
100100
}
101101

102102
def compileUnits(us: List[CompilationUnit], ctx: Context): Unit = {
103-
units = us
103+
ctx.runInfo.units = us
104104
compileUnits()(ctx)
105105
}
106106

@@ -122,16 +122,16 @@ class Run(comp: Compiler, ictx: Context) {
122122
if (phase.isRunnable)
123123
Stats.trackTime(s"$phase ms ") {
124124
val start = System.currentTimeMillis
125-
units = phase.runOn(units)
125+
ctx.runInfo.units = phase.runOn(ctx.runInfo.units)
126126
if (ctx.settings.Xprint.value.containsPhase(phase)) {
127-
for (unit <- units) {
127+
for (unit <- ctx.runInfo.units) {
128128
lastPrintedTree =
129129
printTree(lastPrintedTree)(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
130130
}
131131
}
132132
ctx.informTime(s"$phase ", start)
133133
Stats.record(s"total trees at end of $phase", ast.Trees.ntrees)
134-
for (unit <- units)
134+
for (unit <- ctx.runInfo.units)
135135
Stats.record(s"retained typed trees at end of $phase", unit.tpdTree.treeSize)
136136
}
137137
}
@@ -191,3 +191,35 @@ class Run(comp: Compiler, ictx: Context) {
191191
r
192192
}
193193
}
194+
195+
object Run {
196+
/** Info that changes on each compiler run */
197+
class RunInfo(initctx: Context) extends ImplicitRunInfo with ConstraintRunInfo {
198+
implicit val ctx: Context = initctx
199+
200+
private[this] var myUnits: List[CompilationUnit] = _
201+
private[this] var myUnitsCached: List[CompilationUnit] = _
202+
private[this] var myFiles: Set[AbstractFile] = _
203+
204+
/** The compilation units currently being compiled, this may return different
205+
* results over time.
206+
*/
207+
def units: List[CompilationUnit] = myUnits
208+
209+
private[Run] def units_=(us: List[CompilationUnit]): Unit =
210+
myUnits = us
211+
212+
213+
/** The files currently being compiled, this may return different results over time.
214+
* These files do not have to be source files since it's possible to compile
215+
* from TASTY.
216+
*/
217+
def files: Set[AbstractFile] = {
218+
if (myUnits ne myUnitsCached) {
219+
myUnitsCached = myUnits
220+
myFiles = myUnits.map(_.source.file).toSet
221+
}
222+
myFiles
223+
}
224+
}
225+
}

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
196196
case tp: MethodType =>
197197
def valueParam(name: TermName, info: Type): TermSymbol = {
198198
val maybeImplicit = if (tp.isImplicitMethod) Implicit else EmptyFlags
199-
ctx.newSymbol(sym, name, TermParam | maybeImplicit, info)
199+
ctx.newSymbol(sym, name, TermParam | maybeImplicit, info, coord = sym.coord)
200200
}
201201
val params = (tp.paramNames, tp.paramInfos).zipped.map(valueParam)
202202
val (paramss, rtp) = valueParamss(tp.instantiate(params map (_.termRef)))
@@ -262,7 +262,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
262262
val parents1 =
263263
if (parents.head.classSymbol.is(Trait)) parents.head.parents.head :: parents
264264
else parents
265-
val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_FUN, Synthetic, parents1,
265+
val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_CLASS, Synthetic, parents1,
266266
coord = fns.map(_.pos).reduceLeft(_ union _))
267267
val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered
268268
def forwarder(fn: TermSymbol, name: TermName) = {

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class ScalaSettings extends Settings.SettingGroup {
9696
val YdetailedStats = BooleanSetting("-Ydetailed-stats", "show detailed internal compiler stats (needs Stats.enabled to be set to true).")
9797
val Yheartbeat = BooleanSetting("-Ydetailed-stats", "show heartbeat stack trace of compiler operations (needs Stats.enabled to be set to true).")
9898
val YprintPos = BooleanSetting("-Yprint-pos", "show tree positions.")
99+
val YprintPosSyms = BooleanSetting("-Yprint-pos-syms", "show symbol definitions positions.")
99100
val YnoDeepSubtypes = BooleanSetting("-Yno-deep-subtypes", "throw an exception on deep subtyping call stacks.")
100101
val YnoPatmatOpt = BooleanSetting("-Yno-patmat-opt", "disable all pattern matching optimizations.")
101102
val YplainPrinter = BooleanSetting("-Yplain-printer", "Pretty-print using a plain printer.")

compiler/src/dotty/tools/dotc/core/ConstraintRunInfo.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dotty.tools.dotc
22
package core
33

44
import Contexts._
5+
import Run.RunInfo
56
import config.Printers.typr
67

78
trait ConstraintRunInfo { self: RunInfo =>

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ import NameOps._
1414
import Uniques._
1515
import SymDenotations._
1616
import Comments._
17+
import Run.RunInfo
1718
import util.Positions._
1819
import ast.Trees._
1920
import ast.untpd
2021
import util.{FreshNameCreator, SimpleIdentityMap, SourceFile, NoSource}
21-
import typer.{Implicits, ImplicitRunInfo, ImportInfo, Inliner, NamerContextOps, SearchHistory, TypeAssigner, Typer}
22+
import typer.{Implicits, ImportInfo, Inliner, NamerContextOps, SearchHistory, TypeAssigner, Typer}
2223
import Implicits.ContextualImplicits
2324
import config.Settings._
2425
import config.Config
@@ -675,11 +676,6 @@ object Contexts {
675676
// @sharable val theBase = new ContextBase // !!! DEBUG, so that we can use a minimal context for reporting even in code that normally cannot access a context
676677
}
677678

678-
/** Info that changes on each compiler run */
679-
class RunInfo(initctx: Context) extends ImplicitRunInfo with ConstraintRunInfo {
680-
implicit val ctx: Context = initctx
681-
}
682-
683679
class GADTMap(initBounds: SimpleIdentityMap[Symbol, TypeBounds]) extends util.DotClass {
684680
private[this] var myBounds = initBounds
685681
def setBounds(sym: Symbol, b: TypeBounds): Unit =

compiler/src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ trait Symbols { this: Context =>
130130
newClassSymbol(owner, name, flags, completer, privateWithin, coord, assocFile)
131131
}
132132

133-
def newRefinedClassSymbol = newCompleteClassSymbol(
134-
ctx.owner, tpnme.REFINE_CLASS, NonMember, parents = Nil)
133+
def newRefinedClassSymbol(coord: Coord = NoCoord) =
134+
newCompleteClassSymbol(ctx.owner, tpnme.REFINE_CLASS, NonMember, parents = Nil, coord = coord)
135135

136136
/** Create a module symbol with associated module class
137137
* from its non-info fields and a function producing the info
@@ -288,7 +288,7 @@ trait Symbols { this: Context =>
288288
val tparamBuf = new mutable.ListBuffer[TypeSymbol]
289289
val trefBuf = new mutable.ListBuffer[TypeRef]
290290
for (name <- names) {
291-
val tparam = newNakedSymbol[TypeName](NoCoord)
291+
val tparam = newNakedSymbol[TypeName](owner.coord)
292292
tparamBuf += tparam
293293
trefBuf += TypeRef(owner.thisType, tparam)
294294
}
@@ -443,9 +443,11 @@ object Symbols {
443443
if (lastDenot == null) NoRunId else lastDenot.validFor.runId
444444

445445
/** Does this symbol come from a currently compiled source file? */
446-
final def isDefinedInCurrentRun(implicit ctx: Context): Boolean = {
447-
pos.exists && defRunId == ctx.runId
448-
}
446+
final def isDefinedInCurrentRun(implicit ctx: Context): Boolean =
447+
pos.exists && defRunId == ctx.runId && {
448+
val file = associatedFile
449+
file != null && ctx.runInfo.files.contains(file)
450+
}
449451

450452
/** Is symbol valid in current run? */
451453
final def isValidInCurrentRun(implicit ctx: Context): Boolean =
@@ -539,7 +541,7 @@ object Symbols {
539541
* Overridden in ClassSymbol
540542
*/
541543
def associatedFile(implicit ctx: Context): AbstractFile =
542-
denot.topLevelClass.symbol.associatedFile
544+
if (lastDenot == null) null else lastDenot.topLevelClass.symbol.associatedFile
543545

544546
/** The class file from which this class was generated, null if not applicable. */
545547
final def binaryFile(implicit ctx: Context): AbstractFile = {
@@ -563,8 +565,12 @@ object Symbols {
563565
}
564566
}
565567

566-
/** The position of this symbol, or NoPosition is symbol was not loaded
567-
* from source.
568+
/** The position of this symbol, or NoPosition if the symbol was not loaded
569+
* from source or from TASTY. This is always a zero-extent position.
570+
*
571+
* NOTE: If the symbol was not loaded from the current compilation unit,
572+
* the implicit conversion `sourcePos` will return the wrong result, careful!
573+
* TODO: Consider changing this method return type to `SourcePosition`.
568574
*/
569575
def pos: Position = if (coord.isPosition) coord.toPosition else NoPosition
570576

compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,21 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr
4141
lastPos = pos
4242
}
4343

44-
/** True if x's position cannot be reconstructed automatically from its initialPos
44+
/** True if x's position shouldn't be reconstructed automatically from its initialPos
4545
*/
4646
def alwaysNeedsPos(x: Positioned) = x match {
47-
case _: WithLazyField[_] // initialPos is inaccurate for trees with lazy field
48-
| _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files
47+
case
48+
// initialPos is inaccurate for trees with lazy field
49+
_: WithLazyField[_]
50+
51+
// A symbol is created before the corresponding tree is unpickled,
52+
// and its position cannot be changed afterwards.
53+
// so we cannot use the tree initialPos to set the symbol position.
54+
// Instead, we always pickle the position of definitions.
55+
| _: Trees.DefTree[_]
56+
57+
// package defs might be split into several Tasty files
58+
| _: Trees.PackageDef[_] => true
4959
case _ => false
5060
}
5161

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
259259
case TYPEARGtype =>
260260
TypeArgRef(readType(), readType().asInstanceOf[TypeRef], readNat())
261261
case BIND =>
262-
val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType())
262+
val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType(),
263+
coord = coordAt(start))
263264
registerSym(start, sym)
264265
if (currentAddr != end) readType()
265266
TypeRef(NoPrefix, sym)
@@ -464,11 +465,14 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
464465
rootd.symbol
465466
case _ =>
466467
val completer = adjustIfModule(new Completer(ctx.owner, subReader(start, end)))
468+
469+
val coord = coordAt(start)
470+
467471
if (isClass)
468-
ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord = start.index)
472+
ctx.newClassSymbol(ctx.owner, name.asTypeName, flags, completer, privateWithin, coord)
469473
else
470-
ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord = start.index)
471-
} // TODO set position somehow (but take care not to upset Symbol#isDefinedInCurrentRun)
474+
ctx.newSymbol(ctx.owner, name, flags, completer, privateWithin, coord)
475+
}
472476
sym.annotations = annots
473477
ctx.enter(sym)
474478
registerSym(start, sym)
@@ -995,7 +999,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
995999
case BIND =>
9961000
val name = readName()
9971001
val info = readType()
998-
val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, info)
1002+
val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, info, coord = coordAt(start))
9991003
registerSym(start, sym)
10001004
Bind(sym, readTerm())
10011005
case ALTERNATIVE =>
@@ -1011,7 +1015,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
10111015
val argPats = until(end)(readTerm())
10121016
UnApply(fn, implicitArgs, argPats, patType)
10131017
case REFINEDtpt =>
1014-
val refineCls = ctx.newRefinedClassSymbol
1018+
val refineCls = ctx.newRefinedClassSymbol(coordAt(start))
10151019
typeAtAddr(start) = refineCls.typeRef
10161020
val parent = readTpt()
10171021
val refinements = readStats(refineCls, end)(localContext(refineCls))
@@ -1087,21 +1091,32 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
10871091

10881092
// ------ Setting positions ------------------------------------------------
10891093

1090-
/** Set position of `tree` at given `addr`. */
1091-
def setPos[T <: untpd.Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type =
1094+
/** Pickled position for `addr`. */
1095+
def posAt(addr: Addr)(implicit ctx: Context): Position =
10921096
if (ctx.mode.is(Mode.ReadPositions)) {
10931097
posUnpicklerOpt match {
10941098
case Some(posUnpickler) =>
1095-
//println(i"setPos $tree / ${tree.getClass} at $addr to ${posUnpickler.posAt(addr)}")
1096-
val pos = posUnpickler.posAt(addr)
1097-
if (pos.exists) tree.setPosUnchecked(pos)
1098-
tree
1099+
posUnpickler.posAt(addr)
10991100
case _ =>
1100-
//println(i"no pos $tree")
1101-
tree
1101+
NoPosition
11021102
}
1103-
}
1104-
else tree
1103+
} else NoPosition
1104+
1105+
/** Coordinate for the symbol at `addr`. */
1106+
def coordAt(addr: Addr)(implicit ctx: Context): Coord = {
1107+
val pos = posAt(addr)
1108+
if (pos.exists)
1109+
positionCoord(pos)
1110+
else
1111+
indexCoord(addr.index)
1112+
}
1113+
1114+
/** Set position of `tree` at given `addr`. */
1115+
def setPos[T <: untpd.Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type = {
1116+
val pos = posAt(addr)
1117+
if (pos.exists) tree.setPosUnchecked(pos)
1118+
tree
1119+
}
11051120
}
11061121

11071122
class LazyReader[T <: AnyRef](reader: TreeReader, op: TreeReader => Context => T) extends Trees.Lazy[T] {

compiler/src/dotty/tools/dotc/fromtasty/TASTYRun.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core.Contexts._
66

77
class TASTYRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) {
88
override def compile(classNames: List[String]) = {
9-
units = classNames.map(new TASTYCompilationUnit(_))
10-
compileUnits()
9+
val units = classNames.map(new TASTYCompilationUnit(_))
10+
compileUnits(units)
1111
}
1212
}

compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class InteractiveDriver(settings: List[String]) extends Driver {
226226

227227
run.compileSources(List(source))
228228
run.printSummary()
229-
val t = run.units.head.tpdTree
229+
val t = ctx.runInfo.units.head.tpdTree
230230
cleanup(t)
231231
myOpenedTrees(uri) = topLevelClassTrees(t, source)
232232

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,8 @@ object Parsers {
11811181
t
11821182
}
11831183

1184-
def ascription(t: Tree, location: Location.Value) = atPos(startOffset(t), in.skipToken()) {
1184+
def ascription(t: Tree, location: Location.Value) = atPos(startOffset(t)) {
1185+
in.skipToken()
11851186
in.token match {
11861187
case USCORE =>
11871188
val uscoreStart = in.skipToken()

0 commit comments

Comments
 (0)