Skip to content

Trying Scaladoc + scala2-library-cc #23471

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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2584,7 +2584,7 @@ object ScaladocConfigs {

def defaultSourceLinks(version: String = dottyNonBootstrappedVersion, refVersion: String = dottyVersion) = Def.task {
def stdLibVersion = stdlibVersion(NonBootstrapped)
def srcManaged(v: String, s: String) = s"out/bootstrap/scala2-library-bootstrapped/scala-$v/src_managed/main/$s-library-src"
def srcManaged(v: String, s: String) = s"out/bootstrap/scala2-library-cc/scala-$v/src_managed/main/$s-library-src"
SourceLinks(
List(
scalaSrcLink(stdLibVersion, srcManaged(version, "scala") + "="),
Expand Down Expand Up @@ -2673,7 +2673,7 @@ object ScaladocConfigs {

lazy val Scala3 = Def.task {
val dottyJars: Seq[java.io.File] = Seq(
(`scala2-library-bootstrapped`/Compile/products).value,
(`scala2-library-cc`/Compile/products).value,
(`scala3-library-bootstrapped`/Compile/products).value,
(`scala3-interfaces`/Compile/products).value,
(`tasty-core-bootstrapped`/Compile/products).value,
Expand All @@ -2682,7 +2682,7 @@ object ScaladocConfigs {
val roots = dottyJars.map(_.getAbsolutePath)

val managedSources =
(`scala2-library-bootstrapped`/Compile/sourceManaged).value / "scala-library-src"
(`scala2-library-cc`/Compile/sourceManaged).value / "scala-library-src"
val projectRoot = (ThisBuild/baseDirectory).value.toPath
val stdLibRoot = projectRoot.relativize(managedSources.toPath.normalize())
val docRootFile = stdLibRoot.resolve("rootdoc.txt")
Expand Down Expand Up @@ -2718,7 +2718,7 @@ object ScaladocConfigs {
}

def stableScala3(version: String) = Def.task {
val scalaLibrarySrc = s"out/bootstrap/scala2-library-bootstrapped/scala-$version-bin-SNAPSHOT-nonbootstrapped/src_managed"
val scalaLibrarySrc = s"out/bootstrap/scala2-library-cc/scala-$version-bin-SNAPSHOT-nonbootstrapped/src_managed"
val dottyLibrarySrc = "library/src"
Scala3.value
.add(defaultSourceLinks(version + "-bin-SNAPSHOT-nonbootstrapped", version).value)
Expand All @@ -2739,7 +2739,7 @@ object ScaladocConfigs {
.add(DocRootContent(s"$scalaLibrarySrc/rootdoc.txt"))
.withTargets(
Seq(
s"out/bootstrap/scala2-library-bootstrapped/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes",
s"out/bootstrap/scala2-library-cc/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes",
s"out/bootstrap/scala3-library-bootstrapped/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes",
s"tmp/interfaces/target/classes",
s"out/bootstrap/tasty-core-bootstrapped/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes"
Expand Down
86 changes: 86 additions & 0 deletions scaladoc/src/dotty/tools/scaladoc/cc/CaptureOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package dotty.tools.scaladoc

package cc

import scala.quoted._

object CaptureDefs:
// these should become part of the reflect API in the distant future
def retains(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.annotation.retains")
def retainsCap(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.annotation.retainsCap")
def retainsByName(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.annotation.retainsByName")
def CapsModule(using qctx: Quotes) = qctx.reflect.Symbol.requiredPackage("scala.caps")
def captureRoot(using qctx: Quotes) = qctx.reflect.Symbol.requiredPackage("scala.caps.cap")
def Caps_Capability(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.caps.Capability")
def Caps_CapSet(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.caps.CapSet")
def Caps_Mutable(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.caps.Mutable")
def Caps_SharedCapability(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.caps.SharedCapability")

def UseAnnot(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.caps.use")
def ConsumeAnnot(using qctx: Quotes) = qctx.reflect.Symbol.requiredClass("scala.caps.consume")

end CaptureDefs

extension (using qctx: Quotes)(ann: qctx.reflect.Symbol)
/** This symbol is one of `retains` or `retainsCap` */
def isRetains: Boolean =
ann == CaptureDefs.retains || ann == CaptureDefs.retainsCap

/** This symbol is one of `retains`, `retainsCap`, or `retainsByName` */
def isRetainsLike: Boolean =
ann.isRetains || ann == CaptureDefs.retainsByName
end extension

extension (using qctx: Quotes)(tpe: qctx.reflect.TypeRepr)
def isCaptureRoot: Boolean = tpe.termSymbol == CaptureDefs.captureRoot
end extension

/** Decompose capture sets in the union-type-encoding into the sequence of atomic `TypeRepr`s.
* Returns `None` if the type is not a capture set.
*/
def decomposeCaptureRefs(using qctx: Quotes)(typ0: qctx.reflect.TypeRepr): Option[List[qctx.reflect.TypeRepr]] =
import qctx.reflect._
val buffer = collection.mutable.ListBuffer.empty[TypeRepr]
def traverse(typ: TypeRepr): Boolean =
typ match
case OrType(t1, t2) => traverse(t1) && traverse(t2)
case t @ ThisType(_) => buffer += t; true
case t @ TermRef(_, _) => buffer += t; true
case t @ ParamRef(_, _) => buffer += t; true
// TODO: are atoms only ever the above? Then we could refine the return type
case _ => report.warning(s"Unexpected type tree $typ while trying to extract capture references from $typ0"); System.exit(1); false // TODO remove warning eventually
if traverse(typ0) then Some(buffer.toList) else None
end decomposeCaptureRefs

object CaptureSetType:
def unapply(using qctx: Quotes)(tt: qctx.reflect.TypeTree): Option[List[qctx.reflect.TypeRepr]] = decomposeCaptureRefs(tt.tpe)
end CaptureSetType

object CapturingType:
def unapply(using qctx: Quotes)(typ: qctx.reflect.TypeRepr): Option[(qctx.reflect.TypeRepr, List[qctx.reflect.TypeRepr])] =
import qctx.reflect._
typ match
case AnnotatedType(base, Apply(TypeApply(Select(New(annot), _), List(CaptureSetType(refs))), Nil)) if annot.symbol.isRetainsLike =>
Some((base, refs))
case AnnotatedType(base, Apply(Select(New(annot), _), Nil)) if annot.symbol == CaptureDefs.retainsCap =>
Some((base, List(CaptureDefs.captureRoot.termRef)))
case _ => None
end CapturingType

def renderCaptureSet(using qctx: Quotes)(refs: List[qctx.reflect.TypeRepr]): List[SignaturePart] =
import dotty.tools.scaladoc.tasty.NameNormalizer._
import qctx.reflect._
refs match
case List(ref) if ref.isCaptureRoot => List(Keyword("^"))
case refs =>
val res0 = refs.map { ref =>
ref match
case ThisType(_) => List(Keyword("this"))
case TermRef(_, sym) => List(Plain(sym)) // FIXME: use type other than Plain, can we have clickable links to say, caps.cap and other things?
case pf @ ParamRef(tpe, i) => List(Plain(tpe.asInstanceOf[MethodType].paramNames(i))) // FIXME: not sure if this covers all cases
case _ => List(Plain("<unknown>"))
}
val res1 = res0 match
case Nil => Nil
case other => other.reduce((r, e) => r ++ (List(Plain(", ")) ++ e))
Keyword("^") :: Plain("{") :: (res1 ++ List(Plain("}")))
6 changes: 3 additions & 3 deletions scaladoc/src/dotty/tools/scaladoc/tasty/NameNormalizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ object NameNormalizer {
val escaped = escapedName(constructorNormalizedName)
escaped
}

def ownerNameChain: List[String] = {
import reflect.*
if s.isNoSymbol then List.empty
else if s == defn.EmptyPackageClass then List.empty
else if s == defn.RootPackage then List.empty
else if s == defn.RootClass then List.empty
else s.owner.ownerNameChain :+ s.normalizedName
}
}

def normalizedFullName: String =
s.ownerNameChain.mkString(".")

Expand Down
13 changes: 12 additions & 1 deletion scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import scala.jdk.CollectionConverters._
import scala.quoted._
import scala.util.control.NonFatal

import dotty.tools.scaladoc.cc.*

import NameNormalizer._
import SyntheticsSupport._

Expand Down Expand Up @@ -99,7 +101,16 @@ trait TypesSupport:
inParens(inner(left), shouldWrapInParens(left, tp, true))
++ keyword(" & ").l
++ inParens(inner(right), shouldWrapInParens(right, tp, false))
case ByNameType(tpe) => keyword("=> ") :: inner(tpe)
case CapturingType(base, refs) =>
inner(base) ++ renderCaptureSet(refs)
case ByNameType(CapturingType(tpe, refs)) =>
refs match
case Nil => keyword("-> ") :: inner(tpe)
case List(ref) if ref.isCaptureRoot =>
keyword("=> ") :: inner(tpe)
case refs =>
keyword("->") :: (renderCaptureSet(refs) ++ inner(tpe))
case ByNameType(tpe) => keyword("=> ") :: inner(tpe) // FIXME: does it need change for CC?
case ConstantType(constant) =>
plain(constant.show).l
case ThisType(tpe) =>
Expand Down