Skip to content

Reduce internal API usage from Scaladoc #14892

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

Merged
merged 7 commits into from
Apr 13, 2022
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
13 changes: 8 additions & 5 deletions scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ trait ClassLikeSupport:
getSupertypesGraph(LinkToType(selfSignature, classDef.symbol.dri, bareClasslikeKind(classDef.symbol)), unpackTreeToClassDef(classDef).parents)
)

val baseMember = mkMember(classDef.symbol, kindForClasslike(classDef), selfSignature)(
val kind = if intrinsicClassDefs.contains(classDef.symbol) then Kind.Class(Nil, Nil) else kindForClasslike(classDef)

val baseMember = mkMember(classDef.symbol, kind, selfSignature)(
modifiers = modifiers,
graph = graph,
deprecated = classDef.symbol.isDeprecated(),
Expand Down Expand Up @@ -253,8 +255,9 @@ trait ClassLikeSupport:
}

def getParentsAsTreeSymbolTuples: List[(Tree, Symbol)] =
for
parentTree <- c.parents if isValidPos(parentTree.pos) // We assume here that order is correct
if noPosClassDefs.contains(c.symbol) then Nil
else for
parentTree <- c.parents if parentTree.pos.start != parentTree.pos.end // We assume here that order is correct
parentSymbol = parentTree match
case t: TypeTree => t.tpe.typeSymbol
case tree if tree.symbol.isClassConstructor => tree.symbol.owner
Expand Down Expand Up @@ -482,7 +485,7 @@ trait ClassLikeSupport:


def unwrapMemberInfo(c: ClassDef, symbol: Symbol): MemberInfo =
val baseTypeRepr = memberInfo(c, symbol)
val baseTypeRepr = typeForClass(c).memberType(symbol)

def isSyntheticEvidence(name: String) =
if !name.startsWith(NameKinds.EvidenceParamName.separator) then false else
Expand Down Expand Up @@ -551,4 +554,4 @@ trait ClassLikeSupport:
if parameters(0).symbol.flags.is(Flags.Given) then "using "
else if parameters(0).symbol.flags.is(Flags.Implicit) then "implicit "
else ""
else ""
else ""
75 changes: 10 additions & 65 deletions scaladoc/src/dotty/tools/scaladoc/tasty/SyntheticSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,6 @@ import scala.quoted._

object SyntheticsSupport:

extension (using Quotes)(t: reflect.TypeRepr)

def isCompiletimeAppliedType: Boolean = t.hackIsCompiletimeAppliedType(t)

private def hackIsCompiletimeAppliedType(rtpe: reflect.TypeRepr): Boolean =
import dotty.tools.dotc
given ctx: dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val tpe = rtpe.asInstanceOf[dotc.core.Types.Type]
ctx.definitions.isCompiletimeAppliedType(tpe.typeSymbol)
end extension

extension (using Quotes)(s: reflect.Symbol)
def isSyntheticFunc: Boolean =
import reflect._
Expand All @@ -29,39 +18,32 @@ object SyntheticsSupport:
import reflect._
s.flags.is(Flags.Opaque)

def isInfix: Boolean = hackIsInfix(s)

def getmembers: List[reflect.Symbol] = hackGetmembers(s)

end extension

def isValidPos(using Quotes)(pos: reflect.Position) =
if hackExists(pos) then pos.start != pos.end else false

def isSyntheticField(using Quotes)(c: reflect.Symbol) =
import reflect._
c.flags.is(Flags.CaseAccessor) || (c.flags.is(Flags.Module) && !c.flags.is(Flags.Given))

def constructorWithoutParamLists(using Quotes)(c: reflect.ClassDef): Boolean =
!isValidPos(c.constructor.pos) || {
c.constructor.pos.start == c.constructor.pos.end || {
val end = c.constructor.pos.end
val typesEnd = c.constructor.leadingTypeParams.lastOption.fold(end - 1)(_.pos.end)
val classDefTree = c.constructor.show
c.constructor.leadingTypeParams.nonEmpty && end <= typesEnd + 1
}

// TODO: #49 Remove it after TASTY-Reflect release with published flag Extension
private def hackIsInfix(using Quotes)(rsym: reflect.Symbol): Boolean = {
import reflect._
import dotty.tools.dotc
given ctx: dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val sym = rsym.asInstanceOf[dotc.core.Symbols.Symbol]
ctx.definitions.isInfix(sym)
}
def getSupertypes(using Quotes)(c: reflect.ClassDef) =
c.symbol.typeRef.baseClasses.map(b => b -> c.symbol.typeRef.baseType(b)).tail

def typeForClass(using Quotes)(c: reflect.ClassDef): reflect.TypeRepr =
c.symbol.typeRef.appliedTo(c.symbol.typeMembers.filter(_.isTypeParam).map(_.typeRef))

/* We need there to filter out symbols with certain flagsets, because these symbols come from compiler and TASTY can't handle them well.
They are valdefs that describe case companion objects and cases from enum.
TASTY crashed when calling _.tree on them.
*/
They are valdefs that describe case companion objects and cases from enum.
TASTY crashed when calling _.tree on them.
*/
private def hackGetmembers(using Quotes)(rsym: reflect.Symbol): List[reflect.Symbol] = {
import reflect._
import dotty.tools.dotc
Expand All @@ -75,40 +57,3 @@ object SyntheticsSupport:
sym.asInstanceOf[Symbol]
}.toList
}

private def hackGetSupertypes(using Quotes)(rdef: reflect.ClassDef) = {
import reflect._
import dotty.tools.dotc
given dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val classdef = rdef.asInstanceOf[dotc.ast.tpd.TypeDef]
val ref = classdef.symbol.info.asInstanceOf[dotc.core.Types.ClassInfo].appliedRef
val baseTypes: List[(dotc.core.Symbols.Symbol, dotc.core.Types.Type)] =
ref.baseClasses.map(b => b -> ref.baseType(b))
baseTypes.asInstanceOf[List[(Symbol, TypeRepr)]]
}

private def hackExists(using Quotes)(rpos: reflect.Position) = {
import reflect._
import dotty.tools.dotc
import dotty.tools.dotc.util.Spans._
given dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val pos = rpos.asInstanceOf[dotc.util.SourcePosition]
pos.exists
}

def getSupertypes(using Quotes)(c: reflect.ClassDef) = hackGetSupertypes(c).tail

def typeForClass(using Quotes)(c: reflect.ClassDef): reflect.TypeRepr =
import reflect._
import dotty.tools.dotc
given dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val cSym = c.symbol.asInstanceOf[dotc.core.Symbols.Symbol]
cSym.typeRef.appliedTo(cSym.typeParams.map(_.typeRef)).asInstanceOf[TypeRepr]

def memberInfo(using Quotes)(c: reflect.ClassDef, symbol: reflect.Symbol): reflect.TypeRepr =
import reflect._
import dotty.tools.dotc
given dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
typeForClass(c).asInstanceOf[dotc.core.Types.Type]
.memberInfo(symbol.asInstanceOf[dotc.core.Symbols.Symbol])
.asInstanceOf[TypeRepr]
56 changes: 33 additions & 23 deletions scaladoc/src/dotty/tools/scaladoc/tasty/TastyParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,27 +123,17 @@ case class ScaladocTastyInspector()(using ctx: DocContext) extends DocTastyInspe
topLevels ++= parser.parseRootTree(treeRoot)
}

val defn = ctx.compilerContext.definitions

if ctx.args.documentSyntheticTypes then
val intrinsicClassDefs = Seq(
defn.AnyClass,
defn.MatchableClass,
defn.AnyKindClass,
defn.AnyValClass,
defn.NullClass,
defn.NothingClass,
defn.SingletonClass,
defn.andType,
defn.orType,
).map { s =>
"scala" -> s.asInstanceOf[parser.qctx.reflect.Symbol].tree.match {
case cd: parser.qctx.reflect.ClassDef => parser.parseClasslike(cd)
case td: parser.qctx.reflect.TypeDef => parser.parseTypeDef(td)
}
import parser.qctx.reflect._
val intrinsicTypeDefs = parser.intrinsicTypeDefs.toSeq.map { s =>
"scala" -> parser.parseTypeDef(s.tree.asInstanceOf[TypeDef])
}
val intrinsicClassDefs = parser.intrinsicClassDefs.toSeq.map { s =>
"scala" -> parser.parseClasslike(s.tree.asInstanceOf[ClassDef])
}
topLevels ++= intrinsicClassDefs
val scalaPckg = defn.ScalaPackageVal.asInstanceOf[parser.qctx.reflect.Symbol]
topLevels ++= intrinsicTypeDefs
val scalaPckg = defn.ScalaPackage
given parser.qctx.type = parser.qctx
topLevels += "scala" -> Member(scalaPckg.fullName, scalaPckg.dri, Kind.Package)
topLevels += mergeAnyRefAliasAndObject(parser)
Expand All @@ -167,12 +157,13 @@ case class ScaladocTastyInspector()(using ctx: DocContext) extends DocTastyInspe
}.toList -> rootDoc

def mergeAnyRefAliasAndObject(parser: TastyParser) =
val defn = ctx.compilerContext.definitions
val oM = parser.parseClasslike(defn.ObjectClass.asInstanceOf[parser.qctx.reflect.Symbol].tree.asInstanceOf[parser.qctx.reflect.ClassDef])
val aM = parser.parseTypeDef(defn.AnyRefAlias.asInstanceOf[parser.qctx.reflect.Symbol].tree.asInstanceOf[parser.qctx.reflect.TypeDef])
import parser.qctx.reflect._
val javaLangObjectDef = defn.ObjectClass.tree.asInstanceOf[ClassDef]
val objectMembers = parser.extractPatchedMembers(javaLangObjectDef)
val aM = parser.parseTypeDef(defn.AnyRefClass.tree.asInstanceOf[TypeDef])
"scala" -> aM.copy(
kind = oM.kind,
members = oM.members
kind = Kind.Class(Nil, Nil),
members = objectMembers
)
/** Parses a single Tasty compilation unit. */
case class TastyParser(
Expand All @@ -187,6 +178,25 @@ case class TastyParser(

private given qctx.type = qctx

val intrinsicClassDefs = Set(
defn.AnyClass,
defn.MatchableClass,
defn.ScalaPackage.typeMember("AnyKind"),
defn.AnyValClass,
defn.NullClass,
defn.NothingClass,
defn.ScalaPackage.typeMember("Singleton"),
)

val noPosClassDefs = intrinsicClassDefs ++ Set(
defn.ObjectClass,
defn.AnyRefClass
)

val intrinsicTypeDefs = Set(
defn.ScalaPackage.typeMember("&"),
defn.ScalaPackage.typeMember("|"),
)
def processTree[T](tree: Tree)(op: => T): Option[T] = try Option(op) catch
case e: Exception =>
report.warning(throwableToString(e), tree.pos)
Expand Down