Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix snippets in scala.compiletime and fix snippet compiler reporting line numbers in specific cases #13528

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions library/src/scala/compiletime/ops/int.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object int:
* case 0 => 1
* case 1 => 2
* case 2 => 3
* ...
* // ...
* case 2147483646 => 2147483647
* }
* ```
Expand Down Expand Up @@ -152,8 +152,8 @@ object int:

/** Negation of an `Int` singleton type.
* ```scala
* val neg1: Neg[-1] = 1
* val neg2: Neg[1] = -1
* val neg1: Negate[-1] = 1
* val neg2: Negate[1] = -1
* ```
* @syntax markdown
*/
Expand Down
35 changes: 28 additions & 7 deletions library/src/scala/compiletime/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ import annotation.compileTimeOnly
* pattern match on it. For example, given a type `Tup <: Tuple`, one can
* pattern-match on it as follows:
* ```scala
* //{
* type Tup
* inline def f = {
* //}
* inline erasedValue[Tup] match {
* case _: EmptyTuple => ...
* case _: h *: t => ...
* case _: EmptyTuple => ???
* case _: (h *: t) => ???
* }
* //{
* }
* //}
* ```
* This value can only be used in an inline match and the value cannot be used in
* the branches.
Expand All @@ -21,7 +28,12 @@ def erasedValue[T]: T = ???

/** Used as the initializer of a mutable class or object field, like this:
*
* var x: T = uninitialized
* ```scala
* //{
* type T
* //}
* var x: T = uninitialized
* ```
*
* This signifies that the field is not initialized on its own. It is still initialized
* as part of the bulk initialization of the object it belongs to, which assigns zero
Expand All @@ -33,7 +45,7 @@ def uninitialized: Nothing = ???
/** The error method is used to produce user-defined compile errors during inline expansion.
* If an inline expansion results in a call error(msgStr) the compiler produces an error message containing the given msgStr.
*
* ```scala
* ```scala sc:fail
* error("My error message")
* ```
* or
Expand Down Expand Up @@ -71,13 +83,13 @@ transparent inline def codeOf(arg: Any): String =
* inlining and constant folding.
*
* Usage:
* ```scala
* ```scala sc:fail
* inline def twice(inline n: Int): Int =
* requireConst(n) // compile-time assertion that the parameter `n` is a constant
* n + n
*
* twice(1)
* val m: Int = ...
* val m: Int = ???
* twice(m) // error: expected a constant value but found: m
* ```
* @syntax markdown
Expand Down Expand Up @@ -116,14 +128,23 @@ end constValueTuple
/** Summons first given matching one of the listed cases. E.g. in
*
* ```scala
* given B { ... }
* //{
* type A
* trait B
* type C
* inline def f = {
* //}
* given B with { }
*
* summonFrom {
* case given A => 1
* case given B => 2
* case given C => 3
* case _ => 4
* }
* //{
* }
* //}
* ```
* the returned value would be `2`.
* @syntax markdown
Expand Down
2 changes: 1 addition & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,7 @@ object Build {
"-versions-dictionary-url",
"https://scala-lang.org/api/versions.json",
"-Ydocument-synthetic-types",
s"-snippet-compiler:${dottyLibRoot}/scala/quoted=compile"
s"-snippet-compiler:${dottyLibRoot}/scala/quoted=compile,${dottyLibRoot}/scala/compiletime=compile"
) ++ (if (justAPI) Nil else Seq("-siteroot", "docs", "-Yapi-subdirectory")))

if (dottyJars.isEmpty) Def.task { streams.value.log.error("Dotty lib wasn't found") }
Expand Down
35 changes: 35 additions & 0 deletions scaladoc-testcases/src/tests/snippetTestcase3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package tests

package snippetTestcase3

class SnippetTestcase3:
/** Text on line 0.
*
* SNIPPET(OUTERLINEOFFSET:11,OUTERCOLUMNOFFSET:6,INNERLINEOFFSET:5,INNERCOLUMNOFFSET:2)
* ERROR(LINE:11,COLUMN:8)
* ```scala sc:fail
* 2 + List()
* ```
*/
def a = 3
/**
* Text on line 1.
*
* SNIPPET(OUTERLINEOFFSET:21,OUTERCOLUMNOFFSET:6,INNERLINEOFFSET:5,INNERCOLUMNOFFSET:2)
* ERROR(LINE:21,COLUMN:8)
* ```scala sc:fail
* 2 + List()
* ```
*/
def b = 3
/**
*
* Text on line 2.
*
* SNIPPET(OUTERLINEOFFSET:32,OUTERCOLUMNOFFSET:6,INNERLINEOFFSET:5,INNERCOLUMNOFFSET:2)
* ERROR(LINE:32,COLUMN:8)
* ```scala sc:fail
* 2 + List()
* ```
*/
def c = 3
2 changes: 1 addition & 1 deletion scaladoc/src/dotty/tools/scaladoc/site/templates.scala
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ case class TemplateFile(
// Snippet compiler currently supports markdown only
val parser: Parser = Parser.builder(defaultMarkdownOptions).build()
val parsedMd = parser.parse(rendered)
val processed = FlexmarkSnippetProcessor.processSnippets(parsedMd, snippetCheckingFunc, withContext = false)(using ssctx.outerCtx)
val processed = FlexmarkSnippetProcessor.processSnippets(parsedMd, None, snippetCheckingFunc, withContext = false)(using ssctx.outerCtx)
HtmlRenderer.builder(defaultMarkdownOptions).build().render(processed)

layoutTemplate match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ import com.vladsch.flexmark.util.options.MutableDataSet
import collection.JavaConverters._

import dotty.tools.scaladoc.tasty.comments.markdown.ExtendedFencedCodeBlock
import dotty.tools.scaladoc.tasty.comments.PreparsedComment

object FlexmarkSnippetProcessor:
def processSnippets(root: mdu.Node, checkingFunc: => SnippetChecker.SnippetCheckingFunc, withContext: Boolean)(using CompilerContext): mdu.Node = {
def processSnippets(root: mdu.Node, preparsed: Option[PreparsedComment], checkingFunc: => SnippetChecker.SnippetCheckingFunc, withContext: Boolean)(using CompilerContext): mdu.Node = {
lazy val cf: SnippetChecker.SnippetCheckingFunc = checkingFunc

val nodes = root.getDescendants().asScala.collect {
case fcb: mda.FencedCodeBlock => fcb
}.toList

nodes.foldLeft[Map[String, String]](Map()) { (snippetMap, node) =>
val lineOffset = node.getStartLineNumber
val lineOffset = node.getStartLineNumber + preparsed.fold(0)(_.strippedLinesBeforeNo)
val info = node.getInfo.toString.split(" ")
if info.contains("scala") then {
val argOverride = info
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class SnippetChecker(val args: Scaladoc.Args)(using cctx: CompilerContext):

// These constants were found empirically to make snippet compiler
// report errors in the same position as main compiler.
private val constantLineOffset = 3
private val constantLineOffset = 2
private val constantColumnOffset = 4

def checkSnippet(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import dotty.tools.scaladoc.DocContext
import dotty.tools.dotc.config.Settings._
import dotty.tools.dotc.config.ScalaSettings

case class SnippetCompilerSetting[T](setting: Setting[T], value: T)
case class SnippetCompilerSetting[T](setting: Setting[T], value: T)
11 changes: 6 additions & 5 deletions scaladoc/src/dotty/tools/scaladoc/tasty/comments/Comments.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ case class PreparsedComment(
hideImplicitConversions: List[String],
shortDescription: List[String],
syntax: List[String],
strippedLinesBeforeNo: Int,
)

case class DokkaCommentBody(summary: Option[DocPart], body: DocPart)
Expand All @@ -78,7 +79,7 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) {
protected def markupToDokkaCommentBody(t: T): DokkaCommentBody
protected def filterEmpty(xs: List[String]): List[T]
protected def filterEmpty(xs: SortedMap[String, String]): SortedMap[String, T]
protected def processSnippets(t: T): T
protected def processSnippets(t: T, preparsed: PreparsedComment): T

lazy val snippetChecker = dctx.snippetChecker

Expand Down Expand Up @@ -141,7 +142,7 @@ abstract class MarkupConversion[T](val repr: Repr)(using dctx: DocContext) {

final def parse(preparsed: PreparsedComment): Comment =
val markup = stringToMarkup(preparsed.body)
val body = markupToDokkaCommentBody(processSnippets(markup))
val body = markupToDokkaCommentBody(processSnippets(markup, preparsed))
Comment(
body = body.body,
short = body.summary,
Expand Down Expand Up @@ -193,8 +194,8 @@ class MarkdownCommentParser(repr: Repr)(using dctx: DocContext)
.filterNot { case (_, v) => v.isEmpty }
.mapValues(stringToMarkup).to(SortedMap)

def processSnippets(root: mdu.Node): mdu.Node =
FlexmarkSnippetProcessor.processSnippets(root, snippetCheckingFunc(owner), withContext = true)
def processSnippets(root: mdu.Node, preparsed: PreparsedComment): mdu.Node =
FlexmarkSnippetProcessor.processSnippets(root, Some(preparsed), snippetCheckingFunc(owner), withContext = true)
}

class WikiCommentParser(repr: Repr)(using DocContext)
Expand Down Expand Up @@ -249,6 +250,6 @@ class WikiCommentParser(repr: Repr)(using DocContext)
xs.view.mapValues(stringToMarkup).to(SortedMap)
.filterNot { case (_, v) => v.blocks.isEmpty }

def processSnippets(root: wiki.Body): wiki.Body =
def processSnippets(root: wiki.Body, preparsed: PreparsedComment): wiki.Body =
// Currently not supported
root
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ object Preparser {
tags: Map[TagKey, List[String]],
lastTagKey: Option[TagKey],
remaining: List[String],
inCodeBlock: Boolean
): PreparsedComment = remaining match {
inCodeBlock: Boolean,
)(using strippedLinesBeforeNo: Int = 0): PreparsedComment = remaining match {
case CodeBlockStartRegex(before, marker, after) :: ls if !inCodeBlock =>
if (!before.trim.isEmpty && !after.trim.isEmpty && marker == "```")
go(docBody, tags, lastTagKey, before :: (marker + after) :: ls, inCodeBlock = false)
Expand Down Expand Up @@ -108,7 +108,7 @@ object Preparser {
case line :: ls =>
if docBody.length > 0 then docBody.append(endOfLine)
docBody.append(line)
go(docBody, tags, lastTagKey, ls, inCodeBlock)
go(docBody, tags, lastTagKey, ls, inCodeBlock)(using strippedLinesBeforeNo + (if line.isEmpty && docBody.length == 0 then 1 else 0))


case Nil =>
Expand Down Expand Up @@ -177,6 +177,7 @@ object Preparser {
hideImplicitConversions = allTags(SimpleTagKey("hideImplicitConversion")),
shortDescription = allTags(SimpleTagKey("shortDescription")),
syntax = allTags(SimpleTagKey("syntax")),
strippedLinesBeforeNo = strippedLinesBeforeNo
)

cmt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ class SnippetE2eTestcase1 extends SnippetsE2eTest("snippetTestcase1", SCFlags.Co

class SnippetE2eTestcase2 extends SnippetsE2eTest("snippetTestcase2", SCFlags.Compile)


class SnippetE2eTestcase3 extends SnippetsE2eTest("snippetTestcase3", SCFlags.Compile)