Skip to content

Commit d561cb9

Browse files
committed
Fix cooking of docstrings
1 parent 7d5bd7c commit d561cb9

File tree

11 files changed

+93
-31
lines changed

11 files changed

+93
-31
lines changed

dottydoc/src/dotty/tools/dottydoc/DottyDoc.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ abstract class DocDriver extends Driver {
5454
val summary = CompilerCommand.distill(args)(ctx)
5555

5656
ctx.setSettings(summary.sstate)
57-
ctx.setSetting(ctx.settings.YkeepComments, true)
57+
ctx.setSetting(ctx.settings.Ydocrun, true)
5858

5959
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)(ctx)
6060
(fileNames, ctx)

dottydoc/src/dotty/tools/dottydoc/model/comment/CommentExpander.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ trait CommentExpander {
4747
val defines = sections filter { startsWithTag(raw, _, "@define") }
4848
val usecases = sections filter { startsWithTag(raw, _, "@usecase") }
4949

50-
val end = startTag(raw, (defines ::: usecases).sortBy(_._1))
50+
val end = startTag(raw, (defines /*::: usecases*/).sortBy(_._1))
5151

5252
if (end == raw.length - 2) raw else raw.substring(0, end) + "*/"
5353
}

dottydoc/test/BaseTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ trait DottyTest {
1717
import base.settings._
1818
val ctx = base.initialCtx.fresh
1919
ctx.setSetting(ctx.settings.language, List("Scala2"))
20-
ctx.setSetting(ctx.settings.YkeepComments, true)
20+
ctx.setSetting(ctx.settings.Ydocrun, true)
2121
base.initialize()(ctx)
2222
ctx
2323
}

dottydoc/test/UsecaseTest.scala

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,49 @@ class UsecaseTest extends DottyTest {
141141
}
142142
}
143143

144+
@Test def expandColl = {
145+
val source = new SourceFile(
146+
"ExpandColl.scala",
147+
"""
148+
|package scala
149+
|
150+
|/** The trait $Coll
151+
| *
152+
| * @define Coll Iterable
153+
| */
154+
|trait Iterable[A] {
155+
| /** Definition with a "disturbing" signature
156+
| *
157+
| * @usecase def map[B](f: A => B): $Coll[B]
158+
| */
159+
| def map[B, M[B]](f: A => B): M[B] = ???
160+
|}
161+
""".stripMargin
162+
)
163+
164+
checkSources(source :: Nil) { packages =>
165+
packages("scala") match {
166+
case PackageImpl(_, _, List(trt: Trait), _, _) =>
167+
val List(map: Def) = trt.members
168+
169+
val returnValue = map.returnValue match {
170+
case ref: TypeReference => ref.title
171+
case _ =>
172+
assert(
173+
false,
174+
"Incorrect return value after usecase transformation"
175+
)
176+
""
177+
}
178+
179+
assert(
180+
returnValue == "Iterable",
181+
"Incorrect return type after usecase transformation"
182+
)
183+
}
184+
}
185+
}
186+
144187
@Test def checkIterator =
145188
checkFiles("./scala-scala/src/library/scala/collection/Iterator.scala" :: Nil) { _ =>
146189
// success if typer throws no errors! :)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class ScalaSettings extends Settings.SettingGroup {
170170
val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
171171
val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.")
172172
val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
173+
val Ydocrun = BooleanSetting("-Ydoc-run", "Current run should be treated as a docrun, enables `@usecase` annotations in comments")
173174
val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
174175
val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
175176
val Yissuedebug = BooleanSetting("-Yissue-debug", "Print stack traces when a context issues an error.")

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import dotty.tools.dottydoc.model.comment.CommentUtils._
1515
object Comments {
1616

1717
case class Comment(pos: Position, raw: String)(implicit ctx: Context) {
18+
1819
val isDocComment = raw.startsWith("/**")
1920

2021
private[this] lazy val sections = tagIndex(raw)
@@ -41,10 +42,10 @@ object Comments {
4142
val code = raw.substring(codeStart, codeEnd) + " = ???"
4243
val codePos = subPos(codeStart, codeEnd)
4344
val commentStart = skipLineLead(raw, codeEnd + 1) min end
44-
val comment = "/** " + raw.substring(commentStart, end) + "*/"
45+
val commentStr = "/** " + raw.substring(commentStart, end) + "*/"
4546
val commentPos = subPos(commentStart, end)
4647

47-
UseCase(Comment(commentPos, comment), code, codePos)
48+
UseCase(Comment(commentPos, commentStr), code, codePos)
4849
}
4950

5051
private def subPos(start: Int, end: Int) =
@@ -57,9 +58,6 @@ object Comments {
5758
}
5859

5960
case class UseCase(comment: Comment, code: String, codePos: Position)(implicit ctx: Context) {
60-
/** Entered by Namer */
61-
var symbol: Symbol = _
62-
6361
/** Set by typer */
6462
var tpdCode: tpd.DefDef = _
6563

@@ -68,7 +66,7 @@ object Comments {
6866

6967
tree match {
7068
case tree: untpd.DefDef =>
71-
val newName = (tree.name.show + "$" + codePos.start).toTermName
69+
val newName = (tree.name.show + "$" + codePos + "$doc").toTermName
7270
untpd.DefDef(newName, tree.tparams, tree.vparamss, tree.tpt, tree.rhs)
7371
case _ =>
7472
ctx.error("proper definition was not found in `@usecase`", codePos)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,8 @@ object Contexts {
577577
private[this] val _docstrings: mutable.Map[Symbol, Comment] =
578578
mutable.Map.empty
579579

580+
def docstrings: Map[Symbol, Comment] = _docstrings.toMap
581+
580582
def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym)
581583

582584
def addDocstring(sym: Symbol, doc: Option[Comment]): Unit =

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1515,7 +1515,9 @@ object SymDenotations {
15151515

15161516
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
15171517
def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
1518-
require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen) || (scope ne this.unforcedDecls) || sym.hasAnnotation(defn.ScalaStaticAnnot))
1518+
lazy val isUsecase = ctx.settings.Ydocrun.value && sym.name.show.takeRight(4) == "$doc"
1519+
1520+
require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen) || (scope ne this.unforcedDecls) || sym.hasAnnotation(defn.ScalaStaticAnnot) || isUsecase)
15191521
scope.enter(sym)
15201522

15211523
if (myMemberFingerPrint != FingerPrint.unknown)

src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ object Scanners {
171171
}
172172

173173
class Scanner(source: SourceFile, override val startFrom: Offset = 0)(implicit ctx: Context) extends ScannerCommon(source)(ctx) {
174-
val keepComments = ctx.settings.YkeepComments.value
174+
val keepComments = ctx.settings.YkeepComments.value || ctx.settings.Ydocrun.value
175175

176176
/** All doc comments as encountered, each list contains doc comments from
177177
* the same block level. Starting with the deepest level and going upward

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package typer
44

55
import core._
66
import ast._
7-
import Trees._, Constants._, StdNames._, Scopes._, Denotations._
7+
import Trees._, Constants._, StdNames._, Scopes._, Denotations._, Comments._
88
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
99
import ast.desugar, ast.desugar._
1010
import ProtoTypes._
@@ -426,14 +426,7 @@ class Namer { typer: Typer =>
426426
}
427427

428428
def setDocstring(sym: Symbol, tree: Tree)(implicit ctx: Context) = tree match {
429-
case t: MemberDef if t.rawComment.isDefined =>
430-
val cmt = t.rawComment
431-
ctx.docbase.addDocstring(sym, cmt)
432-
433-
cmt.get.usecases.foreach { usecase =>
434-
usecase.symbol = enterSymbol(createSymbol(usecase.untpdCode))
435-
}
436-
429+
case t: MemberDef if t.rawComment.isDefined => ctx.docbase.addDocstring(sym, t.rawComment)
437430
case _ => ()
438431
}
439432

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Scopes._
1111
import Denotations._
1212
import ProtoTypes._
1313
import Contexts._
14+
import Comments._
1415
import Symbols._
1516
import Types._
1617
import SymDenotations._
@@ -1184,7 +1185,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
11841185
val dummy = localDummy(cls, impl)
11851186
val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol))
11861187

1187-
typedUsecases(body1.map(_.symbol), self1.symbol)
1188+
if (ctx.settings.Ydocrun.value)
1189+
typedUsecases(body1.map(_.symbol), self1.symbol)
11881190

11891191
checkNoDoubleDefs(cls)
11901192
val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1)
@@ -1452,16 +1454,37 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
14521454
traverse(stats)
14531455
}
14541456

1455-
def typedUsecases(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit =
1456-
for {
1457-
sym <- syms
1458-
usecase <- ctx.docbase.docstring(sym).map(_.usecases).getOrElse(Nil)
1459-
List(tpdTree) = typedStats(usecase.untpdCode :: Nil, owner)
1460-
} yield {
1461-
if (tpdTree.isInstanceOf[tpd.DefDef])
1462-
usecase.tpdCode = tpdTree.asInstanceOf[tpd.DefDef]
1463-
else
1464-
ctx.error("Couldn't compile `@usecase`", usecase.codePos)
1457+
def typedUsecases(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit = {
1458+
val relevantSyms = syms.filter(ctx.docbase.docstring(_).isDefined)
1459+
relevantSyms.foreach { sym =>
1460+
expandParentDocs(sym)
1461+
val usecases = ctx.docbase.docstring(sym).map(_.usecases).getOrElse(Nil)
1462+
1463+
usecases.foreach { usecase =>
1464+
enterSymbol(createSymbol(usecase.untpdCode))
1465+
1466+
typedStats(usecase.untpdCode :: Nil, owner) match {
1467+
case List(df: tpd.DefDef) => usecase.tpdCode = df
1468+
case _ => ctx.error("`@usecase` was not a valid definition", usecase.codePos)
1469+
}
1470+
}
1471+
}
1472+
}
1473+
1474+
import dotty.tools.dottydoc.model.comment.CommentExpander
1475+
val expander = new CommentExpander {}
1476+
def expandParentDocs(sym: Symbol)(implicit ctx: Context): Unit =
1477+
ctx.docbase.docstring(sym).foreach { cmt =>
1478+
def expandDoc(owner: Symbol): Unit = {
1479+
expander.defineVariables(sym)
1480+
val newCmt = Comment(cmt.pos, expander.expandedDocComment(sym, owner, cmt.raw))
1481+
ctx.docbase.addDocstring(sym, Some(newCmt))
1482+
}
1483+
1484+
if (sym ne NoSymbol) {
1485+
expandParentDocs(sym.owner)
1486+
expandDoc(sym.owner)
1487+
}
14651488
}
14661489

14671490
def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =

0 commit comments

Comments
 (0)