Skip to content

Expose methods used by Scaladoc in Quotes API #13382

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

Closed
wants to merge 1 commit into from
Closed
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
20 changes: 20 additions & 0 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
optional(self.rhs.asInstanceOf[tpd.Template].self)
def body: List[Statement] =
self.rhs.asInstanceOf[tpd.Template].body
def tpe: TypeRepr =
self.symbol.typeRef.appliedTo(self.symbol.typeParams.map(_.typeRef))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applying this type to the types refs of the parameter symbol seems wrong. Not sure what the resulting type represents.

def supertypes: List[TypeRepr] = self.symbol match
case cls: dotc.core.Symbols.ClassSymbol =>
val ref = cls.classDenot.classInfo.appliedRef
ref.baseClasses.map(ref.baseType(_))
case _ => List()
end extension
end ClassDefMethods

Expand Down Expand Up @@ -1694,11 +1701,17 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
val tpNoRefinement = self.dropDependentRefinement
tpNoRefinement != self
&& dotc.core.Symbols.defn.isNonRefinedFunction(tpNoRefinement)
def isTupleType: Boolean =
dotc.core.Symbols.defn.isTupleType(self)
def isCompiletimeAppliedType: Boolean =
dotc.core.Symbols.defn.isCompiletimeAppliedType(self.typeSymbol)
def select(sym: Symbol): TypeRepr = self.select(sym)
def appliedTo(targ: TypeRepr): TypeRepr =
dotc.core.Types.decorateTypeApplications(self).appliedTo(targ)
def appliedTo(targs: List[TypeRepr]): TypeRepr =
dotc.core.Types.decorateTypeApplications(self).appliedTo(targs)
def memberInfo(sym: Symbol): TypeRepr =
self.memberInfo(sym)
end extension
end TypeReprMethods

Expand Down Expand Up @@ -2465,6 +2478,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
def isAnonymousFunction: Boolean = self.denot.isAnonymousFunction
def isAbstractType: Boolean = self.denot.isAbstractType
def isClassConstructor: Boolean = self.denot.isClassConstructor
def isSuperAccessor = self.name.is(dotc.core.NameKinds.SuperAccessorName)
def isType: Boolean = self.isType
def isTerm: Boolean = self.isTerm
def isPackageDef: Boolean = self.is(dotc.core.Flags.Package)
Expand Down Expand Up @@ -2544,6 +2558,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
def typeMembers: List[Symbol] =
self.unforcedDecls.filter(_.isType)

def allTypeMembers: List[Symbol] =
lookupPrefix.allMembers.iterator.map(_.symbol).collect {
case sym if sym.isType => sym.asType
}.toList

def declarations: List[Symbol] =
self.typeRef.info.decls.toList

Expand Down Expand Up @@ -2733,6 +2752,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
def sourceCode: Option[String] =
// TODO detect when we do not have a source and return None
Some(new String(self.source.content(), self.start, self.end - self.start))
def exists: Boolean = self.exists
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe all positions should exist. If one does not we should figure out why it is not set.

end extension
end PositionMethods

Expand Down
27 changes: 27 additions & 0 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,10 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* @syntax markdown
*/
def body: List[Statement]
/** Type of the class */
def tpe: TypeRepr
/** Supertypes of the class */
def supertypes: List[TypeRepr]
end extension
end ClassDefMethods

Expand Down Expand Up @@ -2473,6 +2477,17 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
*/
def isDependentFunctionType: Boolean

/** Is this type a tuple type?
*
* @return true if the dealiased type of `self` without refinement is `TupleN[T1, T2, ..., Tn]`
*/
def isTupleType: Boolean

/** Is this type a compile-time applied type?
*
*/
def isCompiletimeAppliedType: Boolean

/** The type <this . sym>, reduced if possible */
def select(sym: Symbol): TypeRepr

Expand All @@ -2482,6 +2497,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** The current type applied to given type arguments: `this[targ0, ..., targN]` */
def appliedTo(targs: List[TypeRepr]): TypeRepr

/** Member info of `sym` as seen from the TypeRepr */
def memberInfo(sym: Symbol): TypeRepr

end extension
}

Expand Down Expand Up @@ -3559,6 +3577,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** Is this the constructor of a class? */
def isClassConstructor: Boolean

/* Is this the super accessor? */
def isSuperAccessor: Boolean

/** Is this the definition of a type? */
def isType: Boolean

Expand Down Expand Up @@ -3649,6 +3670,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** Type member directly declared in the class */
def typeMembers: List[Symbol]

Comment on lines 3670 to 3672
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see there some inconsistency as methodMembers and fieldMembers return both declared and inherited members and typeMembers returns only declared members.

/** All type members declared or inherited */
def allTypeMembers: List[Symbol]

/** All members directly declared in the class */
def declarations: List[Symbol]

Expand Down Expand Up @@ -4126,6 +4150,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** Source code within the position */
def sourceCode: Option[String]

/** Does the position exist? */
def exists: Boolean

end extension
}

Expand Down
13 changes: 13 additions & 0 deletions scaladoc/src/dotty/tools/scaladoc/tasty/BasicSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ trait BasicSupport:

Annotation(dri, params)

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

/* Heuristics solving a problem if the constructor of class in source code contains param clauses or not.
It seems that this information is lost during source code processing */
def constructorWithoutParamLists(using Quotes)(c: reflect.ClassDef): Boolean =
!isValidPos(c.constructor.pos) || {
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
}

extension (using Quotes)(sym: reflect.Symbol)
def documentation = sym.docstring.map(parseComment(_, sym.tree))

Expand Down
20 changes: 11 additions & 9 deletions scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import scala.quoted._

import SymOps._
import NameNormalizer._
import SyntheticsSupport._
import dotty.tools.dotc.core.NameKinds

trait ClassLikeSupport:
Expand Down Expand Up @@ -79,7 +78,10 @@ trait ClassLikeSupport:
Seq(link -> superLink) ++ getSupertypesGraph(tree, superLink)
}

val supertypes = getSupertypes(using qctx)(classDef).map {
val supertypes = classDef.supertypes
.tail
.map(t => t.typeSymbol -> t)
.map {
case (symbol, tpe) =>
LinkToType(tpe.asSignature, symbol.dri, bareClasslikeKind(symbol))
}
Expand All @@ -88,7 +90,7 @@ trait ClassLikeSupport:
val tpe = valdef.tpt.tpe
LinkToType(tpe.asSignature, symbol.dri, Kind.Type(false, false, Seq.empty))
}
val selfSignature: DSignature = typeForClass(classDef).asSignature
val selfSignature: DSignature = classDef.tpe.asSignature

val graph = HierarchyGraph.withEdges(
getSupertypesGraph(classDef, LinkToType(selfSignature, classDef.symbol.dri, bareClasslikeKind(classDef.symbol)))
Expand Down Expand Up @@ -303,13 +305,13 @@ trait ClassLikeSupport:
case td: TypeDef if !td.symbol.flags.is(Flags.Synthetic) && (!td.symbol.flags.is(Flags.Case) || !td.symbol.flags.is(Flags.Enum)) =>
Some(parseTypeDef(td))

case vd: ValDef if !isSyntheticField(vd.symbol)
case vd: ValDef if !vd.symbol.isSyntheticField
&& (!vd.symbol.flags.is(Flags.Case) || !vd.symbol.flags.is(Flags.Enum))
&& vd.symbol.isGiven =>
val classDef = Some(vd.tpt.tpe).flatMap(_.classSymbol.map(_.tree.asInstanceOf[ClassDef]))
Some(classDef.filter(_.symbol.flags.is(Flags.Module)).fold[Member](parseValDef(c, vd))(parseGivenClasslike(_)))

case vd: ValDef if !isSyntheticField(vd.symbol) && (!vd.symbol.flags.is(Flags.Case) || !vd.symbol.flags.is(Flags.Enum)) =>
case vd: ValDef if !vd.symbol.isSyntheticField && (!vd.symbol.flags.is(Flags.Case) || !vd.symbol.flags.is(Flags.Enum)) =>
Some(parseValDef(c, vd))

case c: ClassDef if c.symbol.owner.methodMember(c.name).exists(_.flags.is(Flags.Given)) =>
Expand Down Expand Up @@ -368,14 +370,14 @@ trait ClassLikeSupport:
def membersToDocument = c.body.filterNot(_.symbol.isHiddenByVisibility)

def getNonTrivialInheritedMemberTrees =
c.symbol.getmembers.filterNot(s => s.isHiddenByVisibility || s.maybeOwner == c.symbol)
c.symbol.getAllMembers.filterNot(s => s.isHiddenByVisibility || s.maybeOwner == c.symbol)
.filter(s => s.maybeOwner != defn.ObjectClass && s.maybeOwner != defn.AnyClass)
.map(_.tree)

extension (c: ClassDef)
def extractMembers: Seq[Member] = {
val inherited = c.getNonTrivialInheritedMemberTrees.collect {
case dd: DefDef if !dd.symbol.isClassConstructor && !(dd.symbol.isSuperBridgeMethod || dd.symbol.isDefaultHelperMethod) => dd
case dd: DefDef if !dd.symbol.isClassConstructor && !dd.symbol.isSyntheticFunc => dd
case other => other
}
c.membersToDocument.flatMap(parseMember(c)) ++
Expand Down Expand Up @@ -458,7 +460,7 @@ trait ClassLikeSupport:
val companion = classDef.symbol.getCompanionSymbol.map(_.tree.asInstanceOf[ClassDef]).get

val enumVals = companion.membersToDocument.collect {
case vd: ValDef if !isSyntheticField(vd.symbol) && vd.symbol.flags.is(Flags.Enum) && vd.symbol.flags.is(Flags.Case) => vd
case vd: ValDef if !vd.symbol.isSyntheticField && vd.symbol.flags.is(Flags.Enum) && vd.symbol.flags.is(Flags.Case) => vd
}.toList.map(parseValDef(classDef, _))

val enumTypes = companion.membersToDocument.collect {
Expand Down Expand Up @@ -631,7 +633,7 @@ trait ClassLikeSupport:


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

def isSyntheticEvidence(name: String) =
if !name.startsWith(NameKinds.EvidenceParamName.separator) then false else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import scala.quoted._

import SymOps._
import NameNormalizer._
import SyntheticsSupport._

trait InkuireSupport:
self: TastyParser =>
Expand Down
15 changes: 15 additions & 0 deletions scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,16 @@ object SymOps:
import reflect._
sym.flags.is(Flags.Artifact)

def isOpaque: Boolean =
import reflect._
sym.flags.is(Flags.Opaque)

def isLeftAssoc: Boolean = !sym.name.endsWith(":")

def isSyntheticField =
import reflect._
sym.flags.is(Flags.CaseAccessor) || (sym.flags.is(Flags.Module) && !sym.flags.is(Flags.Given))

def extendedSymbol: Option[reflect.ValDef] =
import reflect.*
Option.when(sym.isExtensionMethod){
Expand Down Expand Up @@ -191,6 +199,13 @@ object SymOps:
case TypeParamClause(params) => params
}.toList.flatten

def getAllMembers: List[reflect.Symbol] = sym.methodMembers ++ sym.allTypeMembers ++ sym.fieldMembers

def isSyntheticFunc: Boolean =
import reflect._
/* Most of flag getters have Synthetic flag set but there are some exceptions which need to be filtered by name */
sym.flags.is(Flags.Synthetic) || sym.flags.is(Flags.FieldAccessor) || sym.isSuperAccessor || sym.name.contains("default$")

end extension

end SymOps
Expand Down
121 changes: 0 additions & 121 deletions scaladoc/src/dotty/tools/scaladoc/tasty/SyntheticSupport.scala

This file was deleted.

1 change: 0 additions & 1 deletion scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import collection.JavaConverters._
import scala.quoted._

import NameNormalizer._
import SyntheticsSupport._

trait TypesSupport:
self: TastyParser =>
Expand Down