Skip to content

Commit b47ed81

Browse files
committed
Load docstings lazily from TASTy
Now we are always able to load docstings from TASTy, even if `-Yread-docs` is not set. The `-Yread-docs` flag loads the doc strings eagerly, as it did before. Fixes #20106
1 parent adf089b commit b47ed81

File tree

15 files changed

+92
-24
lines changed

15 files changed

+92
-24
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class Driver {
7979
Positioned.init(using ictx)
8080

8181
inContext(ictx) {
82-
if !ctx.settings.YdropComments.value || ctx.settings.YreadComments.value then
82+
if !ctx.settings.YdropComments.value then
8383
ictx.setProperty(ContextDoc, new ContextDocstrings)
8484
val fileNamesOrNone = command.checkUsage(summary, sourcesRequired)(using ctx.settings)(using ctx.settingsState)
8585
fileNamesOrNone.map { fileNames =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ private sealed trait YSettings:
394394
val YcheckReentrant: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycheck-reentrant", "Check that compiled program does not contain vars that can be accessed from a global root.")
395395
val YdropComments: Setting[Boolean] = BooleanSetting(ForkSetting, "Ydrop-docs", "Drop documentation when scanning source files.", aliases = List("-Ydrop-comments"))
396396
val YcookComments: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycook-docs", "Cook the documentation (type check `@usecase`, etc.)", aliases = List("-Ycook-comments"))
397-
val YreadComments: Setting[Boolean] = BooleanSetting(ForkSetting, "Yread-docs", "Read documentation from tasty.")
397+
val YreadDocsEagerly: Setting[Boolean] = BooleanSetting(ForkSetting, "Yread-docs", "Read documentation eagerly from TASTy")
398398
val YforceSbtPhases: Setting[Boolean] = BooleanSetting(ForkSetting, "Yforce-sbt-phases", "Run the phases used by sbt for incremental compilation (ExtractDependencies and ExtractAPI) even if the compiler is ran outside of sbt, for debugging.")
399399
val YdumpSbtInc: Setting[Boolean] = BooleanSetting(ForkSetting, "Ydump-sbt-inc", "For every compiled foo.scala, output the API representation and dependencies used for sbt incremental compilation in foo.inc, implies -Yforce-sbt-phases.")
400400
val YcheckAllPatmat: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycheck-all-patmat", "Check exhaustivity and redundancy of all pattern matching (used for testing the algorithm).")

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,31 @@ object Comments {
2424
*/
2525
class ContextDocstrings {
2626

27-
private val _docstrings: MutableSymbolMap[Comment] = MutableSymbolMap[Comment](512) // FIXME: 2nd [Comment] needed or "not a class type"
27+
private val docstrings: MutableSymbolMap[Comment | CommentLoader] = MutableSymbolMap[Comment | CommentLoader](512) // FIXME: 2nd [Comment] needed or "not a class type"
28+
29+
private class CommentLoader(val load: () => Option[Comment])
2830

2931
val templateExpander: CommentExpander = new CommentExpander
3032

31-
def docstrings: ReadOnlyMap[Symbol, Comment] = _docstrings
33+
def docstring(sym: Symbol): Option[Comment] =
34+
docstrings.get(sym).flatMap {
35+
case comment: Comment => Some(comment)
36+
case commentLoader: CommentLoader =>
37+
val commentOpt = commentLoader.load()
38+
commentOpt match
39+
case Some(comment) => docstrings.update(sym, comment)
40+
case None => docstrings.remove(sym)
41+
commentOpt
42+
}
3243

33-
def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym)
44+
def registerLoader(sym: Symbol, loader: () => Option[Comment]): Unit =
45+
docstrings.update(sym, CommentLoader(loader))
3446

3547
def addDocstring(sym: Symbol, doc: Option[Comment]): Unit =
36-
doc.foreach(d => _docstrings.update(sym, d))
48+
doc.foreach(d => docstrings.update(sym, d))
3749
}
3850

51+
3952
/**
4053
* A `Comment` contains the unformatted docstring, it's position and potentially more
4154
* information that is populated when the comment is "cooked".

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,10 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
366366
if sym.is(Method) && sym.owner.isClass then
367367
profile.recordMethodSize(sym, (currentAddr.index - addr.index) max 1, mdef.span)
368368
for docCtx <- ctx.docCtx do
369-
val comment = docCtx.docstrings.lookup(sym)
370-
if comment != null then
371-
docStrings(mdef) = comment
369+
docCtx.docstring(sym) match
370+
case Some(comment) =>
371+
docStrings(mdef) = comment
372+
case _ =>
372373
}
373374

374375
def pickleParam(tree: Tree)(using Context): Unit = {

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -981,13 +981,15 @@ class TreeUnpickler(reader: TastyReader,
981981
if !sym.isType && !sym.is(ParamAccessor) then
982982
sym.info = ta.avoidPrivateLeaks(sym)
983983

984-
if (ctx.settings.YreadComments.value) {
985-
assert(ctx.docCtx.isDefined, "`-Yread-docs` enabled, but no `docCtx` is set.")
986-
commentUnpicklerOpt.foreach { commentUnpickler =>
984+
commentUnpicklerOpt.foreach { commentUnpickler =>
985+
def loadComment() =
987986
val comment = commentUnpickler.commentAt(start)
988-
ctx.docCtx.get.addDocstring(tree.symbol, comment)
989-
tree.setComment(comment)
990-
}
987+
tree.setComment(comment) // TODO should this be set?
988+
comment
989+
if ctx.settings.YreadDocsEagerly.value then
990+
ctx.docCtx.get.addDocstring(tree.symbol, loadComment())
991+
else
992+
ctx.docCtx.get.registerLoader(tree.symbol, loadComment)
991993
}
992994

993995
tree.setDefTree

compiler/src/dotty/tools/dotc/decompiler/IDEDecompilerDriver.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ class IDEDecompilerDriver(val settings: List[String]) extends dotc.Driver {
1919

2020
private val myInitCtx: Context = {
2121
val rootCtx = initCtx.fresh.addMode(Mode.Interactive | Mode.ReadPositions)
22-
rootCtx.setSetting(rootCtx.settings.YreadComments, true)
2322
rootCtx.setSetting(rootCtx.settings.YretainTrees, true)
2423
rootCtx.setSetting(rootCtx.settings.fromTasty, true)
2524
val ctx = setup(settings.toArray :+ "dummy.scala", rootCtx).get._2

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
3434
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions).addMode(Mode.Interactive)
3535
rootCtx.setSetting(rootCtx.settings.YretainTrees, true)
3636
rootCtx.setSetting(rootCtx.settings.YcookComments, true)
37-
rootCtx.setSetting(rootCtx.settings.YreadComments, true)
3837
val ctx = setup(settings.toArray, rootCtx) match
3938
case Some((_, ctx)) => ctx
4039
case None => rootCtx

compiler/src/dotty/tools/dotc/transform/Pickler.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,6 @@ class Pickler extends Phase {
203203
super.runOn(units)
204204
if ctx.settings.YtestPickler.value then
205205
val ctx2 = ctx.fresh
206-
.setSetting(ctx.settings.YreadComments, true)
207206
.setSetting(ctx.settings.YshowPrintErrors, true)
208207
testUnpickler(
209208
using ctx2

compiler/src/dotty/tools/repl/ReplDriver.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ class ReplDriver(settings: Array[String],
8383
private def initialCtx(settings: List[String]) = {
8484
val rootCtx = initCtx.fresh.addMode(Mode.ReadPositions | Mode.Interactive)
8585
rootCtx.setSetting(rootCtx.settings.YcookComments, true)
86-
rootCtx.setSetting(rootCtx.settings.YreadComments, true)
8786
setupRootCtx(this.settings ++ settings, rootCtx)
8887
}
8988

compiler/test/dotty/tools/dotc/core/tasty/CommentPicklingTest.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,6 @@ class CommentPicklingTest {
108108
}
109109

110110
private class UnpicklingDriver extends Driver {
111-
override def initCtx =
112-
val ctx = super.initCtx.fresh
113-
ctx.setSetting(ctx.settings.YreadComments, true)
114-
ctx
115111

116112
def unpickle[T](args: Array[String], files: List[File])(fn: (List[tpd.Tree], Context) => T): T = {
117113
implicit val ctx: Context = setup(args, initCtx).map(_._2).getOrElse(initCtx)

tasty-inspector/src/scala/tasty/inspector/TastyInspector.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ object TastyInspector:
100100
reset()
101101
val ctx2 = ctx.fresh
102102
.addMode(Mode.ReadPositions)
103-
.setSetting(ctx.settings.YreadComments, true)
104103
new TASTYRun(this, ctx2)
105104

106105
new InspectorDriver

tests/run-macros/i20106.check

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
docs from same compilation run:
2+
Some(/**
3+
* my doc string for Main
4+
*
5+
* @param tracks track listing
6+
* */)
7+
docs loaded from tasty:
8+
Some(/**
9+
* my doc string for Main
10+
*
11+
* @param tracks track listing
12+
* */)
13+
docs from same compilation run:
14+
Some(/**
15+
* Doc of Test
16+
* */)

tests/run-macros/i20106/Macro_1.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import scala.quoted.*
2+
3+
object Doc {
4+
inline def of[A]: Option[String] = ${ ofImpl[A] }
5+
6+
def ofImpl[A: Type](using Quotes): Expr[Option[String]] = {
7+
import quotes.reflect.*
8+
9+
val symbol = TypeRepr.of[A].typeSymbol
10+
Expr(symbol.docstring)
11+
}
12+
}

tests/run-macros/i20106/Main_1.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* my doc string for Main
3+
*
4+
* @param tracks track listing
5+
* */
6+
7+
class Main(tracks: String)
8+
9+
object Main {
10+
def printdoc(): Unit = {
11+
val docString = Doc.of[Main]
12+
println(docString)
13+
}
14+
}

tests/run-macros/i20106/Test_2.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Doc of Test
3+
* */
4+
class Test
5+
6+
object Test {
7+
def main(args: Array[String]): Unit = {
8+
println("docs from same compilation run:")
9+
Main.printdoc()
10+
11+
println("docs loaded from tasty:")
12+
val docString = Doc.of[Main]
13+
println(docString)
14+
15+
println("docs from same compilation run:")
16+
val docStringTest = Doc.of[Test]
17+
println(docStringTest)
18+
}
19+
}

0 commit comments

Comments
 (0)