Skip to content

Commit 5463b7a

Browse files
committed
Fix cooking of docstrings
1 parent ea24c55 commit 5463b7a

File tree

11 files changed

+94
-32
lines changed

11 files changed

+94
-32
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,8 +17,8 @@ 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)
2120
ctx.setSetting(ctx.settings.YnoInline, true)
21+
ctx.setSetting(ctx.settings.Ydocrun, true)
2222
base.initialize()(ctx)
2323
ctx
2424
}

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
@@ -171,6 +171,7 @@ class ScalaSettings extends Settings.SettingGroup {
171171
val Ybuildmanagerdebug = BooleanSetting("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
172172
val Ycompletion = BooleanSetting("-Ycompletion-debug", "Trace all tab completion activity.")
173173
val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
174+
val Ydocrun = BooleanSetting("-Ydoc-run", "Current run should be treated as a docrun, enables `@usecase` annotations in comments")
174175
val Yidedebug = BooleanSetting("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
175176
val Yinferdebug = BooleanSetting("-Yinfer-debug", "Trace type inference and implicit search.")
176177
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
@@ -582,6 +582,8 @@ object Contexts {
582582
private[this] val _docstrings: mutable.Map[Symbol, Comment] =
583583
mutable.Map.empty
584584

585+
def docstrings: Map[Symbol, Comment] = _docstrings.toMap
586+
585587
def docstring(sym: Symbol): Option[Comment] = _docstrings.get(sym)
586588

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

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,13 +1541,15 @@ object SymDenotations {
15411541

15421542
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
15431543
def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
1544-
1544+
lazy val isUsecase = ctx.settings.Ydocrun.value && sym.name.show.takeRight(4) == "$doc"
15451545
require(
15461546
(sym.denot.flagsUNSAFE is Private) ||
15471547
!(this is Frozen) ||
15481548
(scope ne this.unforcedDecls) ||
15491549
sym.hasAnnotation(defn.ScalaStaticAnnot) ||
1550-
sym.name.isInlineAccessor)
1550+
sym.name.isInlineAccessor ||
1551+
isUsecase)
1552+
15511553
scope.enter(sym)
15521554

15531555
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
@@ -172,7 +172,7 @@ object Scanners {
172172
}
173173

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

177177
/** All doc comments as encountered, each list contains doc comments from
178178
* 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._
@@ -456,14 +456,7 @@ class Namer { typer: Typer =>
456456

457457

458458
def setDocstring(sym: Symbol, tree: Tree)(implicit ctx: Context) = tree match {
459-
case t: MemberDef if t.rawComment.isDefined =>
460-
val cmt = t.rawComment
461-
ctx.docbase.addDocstring(sym, cmt)
462-
463-
cmt.get.usecases.foreach { usecase =>
464-
usecase.symbol = enterSymbol(createSymbol(usecase.untpdCode))
465-
}
466-
459+
case t: MemberDef if t.rawComment.isDefined => ctx.docbase.addDocstring(sym, t.rawComment)
467460
case _ => ()
468461
}
469462

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._
@@ -1246,7 +1247,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
12461247
val dummy = localDummy(cls, impl)
12471248
val body1 = typedStats(impl.body, dummy)(inClassContext(self1.symbol))
12481249

1249-
typedUsecases(body1.map(_.symbol), self1.symbol)
1250+
if (ctx.settings.Ydocrun.value)
1251+
typedUsecases(body1.map(_.symbol), self1.symbol)
12501252

12511253
checkNoDoubleDefs(cls)
12521254
val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1)
@@ -1536,16 +1538,37 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
15361538
tpd.cpy.DefDef(mdef)(rhs = Inliner.bodyToInline(mdef.symbol)) ::
15371539
Inliner.removeInlineAccessors(mdef.symbol)
15381540

1539-
def typedUsecases(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit =
1540-
for {
1541-
sym <- syms
1542-
usecase <- ctx.docbase.docstring(sym).map(_.usecases).getOrElse(Nil)
1543-
List(tpdTree) = typedStats(usecase.untpdCode :: Nil, owner)
1544-
} yield {
1545-
if (tpdTree.isInstanceOf[tpd.DefDef])
1546-
usecase.tpdCode = tpdTree.asInstanceOf[tpd.DefDef]
1547-
else
1548-
ctx.error("Couldn't compile `@usecase`", usecase.codePos)
1541+
def typedUsecases(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit = {
1542+
val relevantSyms = syms.filter(ctx.docbase.docstring(_).isDefined)
1543+
relevantSyms.foreach { sym =>
1544+
expandParentDocs(sym)
1545+
val usecases = ctx.docbase.docstring(sym).map(_.usecases).getOrElse(Nil)
1546+
1547+
usecases.foreach { usecase =>
1548+
enterSymbol(createSymbol(usecase.untpdCode))
1549+
1550+
typedStats(usecase.untpdCode :: Nil, owner) match {
1551+
case List(df: tpd.DefDef) => usecase.tpdCode = df
1552+
case _ => ctx.error("`@usecase` was not a valid definition", usecase.codePos)
1553+
}
1554+
}
1555+
}
1556+
}
1557+
1558+
import dotty.tools.dottydoc.model.comment.CommentExpander
1559+
val expander = new CommentExpander {}
1560+
def expandParentDocs(sym: Symbol)(implicit ctx: Context): Unit =
1561+
ctx.docbase.docstring(sym).foreach { cmt =>
1562+
def expandDoc(owner: Symbol): Unit = {
1563+
expander.defineVariables(sym)
1564+
val newCmt = Comment(cmt.pos, expander.expandedDocComment(sym, owner, cmt.raw))
1565+
ctx.docbase.addDocstring(sym, Some(newCmt))
1566+
}
1567+
1568+
if (sym ne NoSymbol) {
1569+
expandParentDocs(sym.owner)
1570+
expandDoc(sym.owner)
1571+
}
15491572
}
15501573

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

0 commit comments

Comments
 (0)