From d61c9aa65983f961aa1409c5303d2d2dec8c32a2 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Thu, 17 Dec 2020 11:48:53 +0100 Subject: [PATCH 1/4] Fix missing applied types in inherited functions --- scala3doc-js/src/ux/ux.scala | 52 +++++++++++++++++++ scala3doc-testcases/src/tests/hkts.scala | 6 +++ .../src/tests/typeAppliance.scala | 10 ++++ .../dotty/dokka/tasty/ClassLikeSupport.scala | 27 ++++++---- .../dotty/dokka/tasty/SyntheticSupport.scala | 1 + 5 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 scala3doc-js/src/ux/ux.scala create mode 100644 scala3doc-testcases/src/tests/hkts.scala create mode 100644 scala3doc-testcases/src/tests/typeAppliance.scala diff --git a/scala3doc-js/src/ux/ux.scala b/scala3doc-js/src/ux/ux.scala new file mode 100644 index 000000000000..b18aad033929 --- /dev/null +++ b/scala3doc-js/src/ux/ux.scala @@ -0,0 +1,52 @@ +package dotty.dokka.ux + +import org.scalajs.dom._ +import org.querki.jquery._ +import dotty.dokka.Globals +import scala.scalajs.js +import scala.scalajs.js.annotation.JSGlobal + +def ux = + window.addEventListener("DOMContentLoaded", _ => { + Option(document.getElementById("leftToggler")).map { + _.addEventListener("click", _ => document.getElementById("leftColumn").classList.toggle("open")) + } + val documentableElements = document.getElementsByClassName("documentableElement") + for (i <- 0 until documentableElements.length) { + documentableElements(i).addEventListener("click", _ => documentableElements(i).classList.toggle("expand")) + } + + $("#sideMenu2 span").on("click", { (el: raw.Element) => + $(el).parent.toggleClass("expanded") + }: js.ThisFunction0[raw.Element, Unit]) + + $(".names .tab").on("click", { (el: raw.Element) => { + val parent = $(el).parents(".tabs").first() + val shown = $(el).hasClass("selected") + val single = parent.hasClass("single") + + if (single) parent.find(".tab.selected").removeClass("selected") + + val id = $(el).attr("data-togglable") + val myTab = parent.find("[data-togglable='" + id + "'].tab") + + if (!shown) { myTab.addClass("selected") } + if (shown && !single) myTab.removeClass("selected") + + if (!shown && $(el).find(".showGraph") != null) { + Globals.showGraph() + $(el).find(".showGraph").removeClass("showGraph") + } + }}: js.ThisFunction0[raw.Element, Unit]) + + Option(document.location.hash).flatMap { (x: String) => + Option(document.getElementById(x.substring(1))) + }.map(_.classList.toggle("expand")) + + Option(document.getElementById("logo")).map( + _.addEventListener("click", _ => window.location = Globals.pathToRoot) // global variable pathToRoot is created by the html renderer + ) + Globals.hljs.registerLanguage("scala", Globals.highlightDotty) + Globals.hljs.registerAliases(js.Array("dotty", "scala3"), "scala") + Globals.hljs.initHighlighting()https://www.youtube.com/watch?v=NvpbW7JRu0Q&feature=youtu.be + }) diff --git a/scala3doc-testcases/src/tests/hkts.scala b/scala3doc-testcases/src/tests/hkts.scala new file mode 100644 index 000000000000..286b571a52ab --- /dev/null +++ b/scala3doc-testcases/src/tests/hkts.scala @@ -0,0 +1,6 @@ +package tests +package hkts + +class A[F[_]] + +// class B[[A, B] =>> (A, B)] diff --git a/scala3doc-testcases/src/tests/typeAppliance.scala b/scala3doc-testcases/src/tests/typeAppliance.scala new file mode 100644 index 000000000000..8cddb608b8e3 --- /dev/null +++ b/scala3doc-testcases/src/tests/typeAppliance.scala @@ -0,0 +1,10 @@ +package tests +package typeAppliance + +trait AClass[A, B]: + def fun[C]: AClass[A, C] + +trait BClass[A, B] extends AClass[A, B]: + override def fun[C]: BClass[A, C] + +abstract class CClass[B] extends BClass[Int, B] diff --git a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala index b823d6f6d7d7..f612f98bc2fa 100644 --- a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala @@ -122,7 +122,7 @@ trait ClassLikeSupport: private def isDocumentableExtension(s: Symbol) = !s.isHiddenByVisibility && !s.isSyntheticFunc && s.isExtensionMethod - private def parseMember(s: Tree): Option[Member] = processTreeOpt(s)(s match + private def parseMember(c: ClassDef)(s: Tree): Option[Member] = processTreeOpt(s)(s match case dd: DefDef if isDocumentableExtension(dd.symbol) => dd.symbol.extendedSymbol.map { extSym => val target = ExtensionTarget( @@ -131,14 +131,14 @@ trait ClassLikeSupport: extSym.tpt.symbol.dri, extSym.symbol.pos.get.start ) - parseMethod(dd.symbol,specificKind = Kind.Extension(target, _)) + parseMethod(c, dd.symbol,specificKind = Kind.Extension(target, _)) } // TODO check given methods? case dd: DefDef if !dd.symbol.isHiddenByVisibility && dd.symbol.isGiven => Some(dd.symbol.owner.memberType(dd.name)) .filterNot(_.exists) .map { _ => - parseMethod(dd.symbol, specificKind = + parseMethod(c, dd.symbol, specificKind = Kind.Given(_, getGivenInstance(dd).map(_.asSignature), None) ) } @@ -157,11 +157,11 @@ trait ClassLikeSupport: case s: Select if s.symbol.isDefDef => s.symbol.dri }.orElse(exportedTarget.map(_.qualifier.tpe.typeSymbol.dri)) - Some(parseMethod(dd.symbol, specificKind = Kind.Exported(_)) + Some(parseMethod(c, dd.symbol, specificKind = Kind.Exported(_)) .withOrigin(Origin.ExportedFrom(s"$instanceName.$functionName", dri))) case dd: DefDef if !dd.symbol.isHiddenByVisibility && !dd.symbol.isGiven && !dd.symbol.isSyntheticFunc && !dd.symbol.isExtensionMethod => - Some(parseMethod(dd.symbol)) + Some(parseMethod(c, dd.symbol)) 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)) @@ -207,9 +207,9 @@ trait ClassLikeSupport: ) } - private def parseInheritedMember(s: Tree): Option[Member] = processTreeOpt(s)(s match + private def parseInheritedMember(c: ClassDef)(s: Tree): Option[Member] = processTreeOpt(s)(s match case c: ClassDef if c.symbol.shouldDocumentClasslike && !c.symbol.isGiven => Some(parseClasslike(c, signatureOnly = true)) - case other => parseMember(other) + case other => parseMember(c)(other) ).map(_.withInheritedFrom(InheritedFrom(s.symbol.owner.normalizedName, s.symbol.owner.dri))) extension (c: ClassDef) @@ -225,8 +225,8 @@ trait ClassLikeSupport: case dd: DefDef if !dd.symbol.isClassConstructor && !(dd.symbol.isSuperBridgeMethod || dd.symbol.isDefaultHelperMethod) => dd case other => other } - c.membersToDocument.flatMap(parseMember) ++ - inherited.flatMap(s => parseInheritedMember(s)) + c.membersToDocument.flatMap(parseMember(c)) ++ + inherited.flatMap(s => parseInheritedMember(c)(s)) } /** Extracts members while taking Dotty logic for patching the stdlib into account. */ @@ -237,7 +237,7 @@ trait ClassLikeSupport: val ownMemberDRIs = ownMembers.iterator.map(_.name).toSet + "experimental$" sym.tree.asInstanceOf[ClassDef] .membersToDocument.filterNot(m => ownMemberDRIs.contains(m.symbol.name)) - .flatMap(parseMember) + .flatMap(parseMember(c)) } c.symbol.fullName match { case "scala.Predef$" => @@ -318,6 +318,7 @@ trait ClassLikeSupport: classlikie.withNewMembers(cases).asInstanceOf[DClass] def parseMethod( + c: ClassDef, methodSymbol: Symbol, emptyParamsList: Boolean = false, paramPrefix: Symbol => String = _ => "", @@ -357,6 +358,12 @@ trait ClassLikeSupport: val origin = if !methodSymbol.isOverriden then Origin.RegularlyDefined else val overridenSyms = methodSymbol.allOverriddenSymbols.map(_.owner) Origin.Overrides(overridenSyms.map(s => Overriden(s.name, s.dri)).toSeq) + if(methodSymbol.normalizedName == "fun" && c.symbol.normalizedName == "CClass") + println(method.returnTpt) + println(typeForClass(c).asInstanceOf[dotty.tools.dotc.core.Types.Type] + .memberInfo(methodSymbol.asInstanceOf[dotty.tools.dotc.core.Symbols.Symbol])(using qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx) + ) + mkMember( method.symbol, diff --git a/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala b/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala index 7e923b5007a9..d19f64222038 100644 --- a/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala @@ -105,3 +105,4 @@ trait SyntheticsSupport: given dotc.core.Contexts.Context = qctx.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] + From d0babf682b0063075ac22e4926823676de297058 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Fri, 8 Jan 2021 17:43:16 +0100 Subject: [PATCH 2/4] Refactor ClassLikeSupports' parseMethod --- scala3doc-js/src/ux/ux.scala | 52 ------------- .../src/tests/typeAppliance.scala | 11 ++- .../dotty/dokka/tasty/ClassLikeSupport.scala | 74 ++++++++++++------- .../src/dotty/dokka/tasty/TypesSupport.scala | 12 ++- 4 files changed, 66 insertions(+), 83 deletions(-) delete mode 100644 scala3doc-js/src/ux/ux.scala diff --git a/scala3doc-js/src/ux/ux.scala b/scala3doc-js/src/ux/ux.scala deleted file mode 100644 index b18aad033929..000000000000 --- a/scala3doc-js/src/ux/ux.scala +++ /dev/null @@ -1,52 +0,0 @@ -package dotty.dokka.ux - -import org.scalajs.dom._ -import org.querki.jquery._ -import dotty.dokka.Globals -import scala.scalajs.js -import scala.scalajs.js.annotation.JSGlobal - -def ux = - window.addEventListener("DOMContentLoaded", _ => { - Option(document.getElementById("leftToggler")).map { - _.addEventListener("click", _ => document.getElementById("leftColumn").classList.toggle("open")) - } - val documentableElements = document.getElementsByClassName("documentableElement") - for (i <- 0 until documentableElements.length) { - documentableElements(i).addEventListener("click", _ => documentableElements(i).classList.toggle("expand")) - } - - $("#sideMenu2 span").on("click", { (el: raw.Element) => - $(el).parent.toggleClass("expanded") - }: js.ThisFunction0[raw.Element, Unit]) - - $(".names .tab").on("click", { (el: raw.Element) => { - val parent = $(el).parents(".tabs").first() - val shown = $(el).hasClass("selected") - val single = parent.hasClass("single") - - if (single) parent.find(".tab.selected").removeClass("selected") - - val id = $(el).attr("data-togglable") - val myTab = parent.find("[data-togglable='" + id + "'].tab") - - if (!shown) { myTab.addClass("selected") } - if (shown && !single) myTab.removeClass("selected") - - if (!shown && $(el).find(".showGraph") != null) { - Globals.showGraph() - $(el).find(".showGraph").removeClass("showGraph") - } - }}: js.ThisFunction0[raw.Element, Unit]) - - Option(document.location.hash).flatMap { (x: String) => - Option(document.getElementById(x.substring(1))) - }.map(_.classList.toggle("expand")) - - Option(document.getElementById("logo")).map( - _.addEventListener("click", _ => window.location = Globals.pathToRoot) // global variable pathToRoot is created by the html renderer - ) - Globals.hljs.registerLanguage("scala", Globals.highlightDotty) - Globals.hljs.registerAliases(js.Array("dotty", "scala3"), "scala") - Globals.hljs.initHighlighting()https://www.youtube.com/watch?v=NvpbW7JRu0Q&feature=youtu.be - }) diff --git a/scala3doc-testcases/src/tests/typeAppliance.scala b/scala3doc-testcases/src/tests/typeAppliance.scala index 8cddb608b8e3..34a8dc69c08a 100644 --- a/scala3doc-testcases/src/tests/typeAppliance.scala +++ b/scala3doc-testcases/src/tests/typeAppliance.scala @@ -2,9 +2,14 @@ package tests package typeAppliance trait AClass[A, B]: - def fun[C]: AClass[A, C] + def funASD[C, D](f: B => C): AClass[A, C] trait BClass[A, B] extends AClass[A, B]: - override def fun[C]: BClass[A, C] + override def funASD[X, D](f: B => X): BClass[A, X] + val f: (=> B) => String = _ => "abc" -abstract class CClass[B] extends BClass[Int, B] + +abstract class CClass[U] extends BClass[Int, U]: + def xdxdkk(n: Int)(b: Int): Int = 1 + def isByNameType: String = "xd" + def vararg1(a: A*): C diff --git a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala index f612f98bc2fa..4136dd8798ed 100644 --- a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala @@ -27,7 +27,7 @@ trait ClassLikeSupport: else Kind.Class(Nil, Nil) private def kindForClasslike(classDef: ClassDef): Kind = - def typeArgs = classDef.getTypeParams.map(mkTypeArgument) + def typeArgs = classDef.getTypeParams.map(mkTypeArgument(_)) def parameterModifier(parameter: Symbol): String = val fieldSymbol = classDef.symbol.declaredField(parameter.normalizedName) @@ -170,10 +170,10 @@ trait ClassLikeSupport: && (!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(vd))(parseGivenClasslike(_))) + 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)) => - Some(parseValDef(vd)) + Some(parseValDef(c, vd)) case c: ClassDef if c.symbol.owner.memberMethod(c.name).exists(_.flags.is(Flags.Given)) => Some(parseGivenClasslike(c)) @@ -299,7 +299,7 @@ trait ClassLikeSupport: 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 - }.toList.map(parseValDef(_)) + }.toList.map(parseValDef(classDef, _)) val enumTypes = companion.membersToDocument.collect { case td: TypeDef if !td.symbol.flags.is(Flags.Synthetic) && td.symbol.flags.is(Flags.Enum) && td.symbol.flags.is(Flags.Case) => td @@ -334,9 +334,13 @@ trait ClassLikeSupport: else method.paramss val genericTypes = if (methodSymbol.isClassConstructor) Nil else method.typeParams + val memberInfo = unwrapMemberInfo(c, methodSymbol) + val basicKind: Kind.Def = Kind.Def( - genericTypes.map(mkTypeArgument), - paramLists.map(pList => ParametersList(pList.map(mkParameter(_, paramPrefix)), if isUsingModifier(pList) then "using " else "")) + genericTypes.map(mkTypeArgument(_, Some(memberInfo.genericTypes))), + paramLists.zipWithIndex.map { (pList, index) => + ParametersList(pList.map(mkParameter(_, paramPrefix, memberInfo = Some(memberInfo.paramLists(index)))), if isUsingModifier(pList) then "using " else "") + } ) val methodKind = @@ -358,12 +362,6 @@ trait ClassLikeSupport: val origin = if !methodSymbol.isOverriden then Origin.RegularlyDefined else val overridenSyms = methodSymbol.allOverriddenSymbols.map(_.owner) Origin.Overrides(overridenSyms.map(s => Overriden(s.name, s.dri)).toSeq) - if(methodSymbol.normalizedName == "fun" && c.symbol.normalizedName == "CClass") - println(method.returnTpt) - println(typeForClass(c).asInstanceOf[dotty.tools.dotc.core.Types.Type] - .memberInfo(methodSymbol.asInstanceOf[dotty.tools.dotc.core.Symbols.Symbol])(using qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx) - ) - mkMember( method.symbol, @@ -372,7 +370,7 @@ trait ClassLikeSupport: methodSymbol.getExtraModifiers(), methodKind, methodSymbol.getAnnotations(), - method.returnTpt.dokkaType.asSignature, + memberInfo.res.dokkaType.asSignature, methodSymbol.source(using qctx), origin ) @@ -381,32 +379,33 @@ trait ClassLikeSupport: def mkParameter(argument: ValDef, prefix: Symbol => String = _ => "", isExtendedSymbol: Boolean = false, - isGrouped: Boolean = false) = + isGrouped: Boolean = false, + memberInfo: Option[Map[String, TypeRepr]] = None) = val inlinePrefix = if argument.symbol.flags.is(Flags.Inline) then "inline " else "" - val name = Option.when(!argument.symbol.flags.is(Flags.Synthetic))(argument.symbol.normalizedName) - + val nameIfNotSynthetic = Option.when(!argument.symbol.flags.is(Flags.Synthetic))(argument.symbol.normalizedName) + val name = argument.symbol.normalizedName Parameter( argument.symbol.getAnnotations(), inlinePrefix + prefix(argument.symbol), - name, + nameIfNotSynthetic, argument.symbol.dri, - argument.tpt.dokkaType.asSignature, + memberInfo.flatMap(_.get(name).map(_.dokkaType.asSignature)).getOrElse(argument.tpt.dokkaType.asSignature), isExtendedSymbol, isGrouped ) - def mkTypeArgument(argument: TypeDef): TypeParameter = + def mkTypeArgument(argument: TypeDef, memberInfo: Option[Map[String, TypeBounds]] = None): TypeParameter = val variancePrefix: "+" | "-" | "" = if argument.symbol.flags.is(Flags.Covariant) then "+" else if argument.symbol.flags.is(Flags.Contravariant) then "-" else "" - + val name = argument.symbol.normalizedName TypeParameter( argument.symbol.getAnnotations(), variancePrefix, - argument.symbol.normalizedName, + name, argument.symbol.dri, - argument.rhs.dokkaType.asSignature + memberInfo.flatMap(_.get(name).map(_.dokkaType.asSignature)).getOrElse(argument.rhs.dokkaType.asSignature) ) def parseTypeDef(typeDef: TypeDef): Member = @@ -417,7 +416,7 @@ trait ClassLikeSupport: } val (generics, tpeTree) = typeDef.rhs match - case LambdaTypeTree(params, body) => (params.map(mkTypeArgument), body) + case LambdaTypeTree(params, body) => (params.map(mkTypeArgument(_)), body) case tpe => (Nil, tpe) mkMember( @@ -432,8 +431,9 @@ trait ClassLikeSupport: ) ) - def parseValDef(valDef: ValDef): Member = + def parseValDef(c: ClassDef, valDef: ValDef): Member = def defaultKind = if valDef.symbol.flags.is(Flags.Mutable) then Kind.Var else Kind.Val + val memberInfo = unwrapMemberInfo(c, valDef.symbol) val kind = if valDef.symbol.flags.is(Flags.Implicit) then Kind.Implicit(Kind.Val, extractImplicitConversion(valDef.tpt.tpe)) else defaultKind @@ -445,7 +445,7 @@ trait ClassLikeSupport: valDef.symbol.getExtraModifiers(), kind, valDef.symbol.getAnnotations(), - valDef.tpt.tpe.dokkaType.asSignature, + memberInfo.res.dokkaType.asSignature, valDef.symbol.source(using qctx) ) ) @@ -476,5 +476,29 @@ trait ClassLikeSupport: PropertyContainer.Companion.empty().plus(member.copy(rawDoc = symbol.documentation)).plus(compositeExt) ) + case class MemberInfo(genericTypes: Map[String, TypeBounds], paramLists: List[Map[String, TypeRepr]], res: TypeRepr) + + def unwrapMemberInfo(c: ClassDef, symbol: Symbol): MemberInfo = + val baseTypeRepr = typeForClass(c).asInstanceOf[dotty.tools.dotc.core.Types.Type] + .memberInfo(symbol.asInstanceOf[dotty.tools.dotc.core.Symbols.Symbol])(using qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx) + .asInstanceOf[TypeRepr] + + def handlePolyType(polyType: PolyType): MemberInfo = + MemberInfo(polyType.paramNames.zip(polyType.paramBounds).toMap, List.empty, polyType.resType) + + def handleMethodType(memberInfo: MemberInfo, methodType: MethodType): MemberInfo = + MemberInfo(memberInfo.genericTypes, memberInfo.paramLists ++ List(methodType.paramNames.zip(methodType.paramTypes).toMap), methodType.resType) + + def handleByNameType(memberInfo: MemberInfo, byNameType: ByNameType): MemberInfo = + MemberInfo(memberInfo.genericTypes, memberInfo.paramLists, byNameType.underlying) + + def recursivelyCalculateMemberInfo(memberInfo: MemberInfo): MemberInfo = memberInfo.res match + case p: PolyType => recursivelyCalculateMemberInfo(handlePolyType(p)) + case m: MethodType => recursivelyCalculateMemberInfo(handleMethodType(memberInfo, m)) + case b: ByNameType => handleByNameType(memberInfo, b) + case _ => memberInfo + + recursivelyCalculateMemberInfo(MemberInfo(Map.empty, List.empty, baseTypeRepr)) + private def isUsingModifier(parameters: Seq[ValDef]): Boolean = parameters.size > 0 && parameters(0).symbol.flags.is(Flags.Given) diff --git a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala index fbbe095b93bf..8f0f6e2c9c10 100644 --- a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala @@ -68,10 +68,14 @@ trait TypesSupport: case List(single) => single case other => other.reduce((r, e) => r ++ texts(", ") ++ e) - private def isRepeated(tpeAnnotation: Term) = + // weird name fot type-erasure purposes + private def isRepeatedTerm(term: Term) = // For some reason annotation.tpe.typeSymbol != defn.RepeatedParamClass // annotation.tpe.typeSymbol prints 'class Repeated' and defn.RepeatedParamClass prints 'class ' - tpeAnnotation.tpe.typeSymbol.toString == "class Repeated" + term.tpe.typeSymbol.toString == "class Repeated" + + private def isRepeatedTypeRepr(typeRepr: TypeRepr) = + typeRepr.typeSymbol.toString == "class " // TODO #23 add support for all types signatures that makes sense private def inner(tp: TypeRepr): List[JProjection] = @@ -86,7 +90,9 @@ trait TypesSupport: case ConstantType(constant) => texts(constant.show) case ThisType(tpe) => inner(tpe) - case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeated(annotation) => + case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedTerm(annotation) => + inner(tpe) :+ text("*") + case AppliedType(repeatedClass, Seq(tpe)) if isRepeatedTypeRepr(repeatedClass) => inner(tpe) :+ text("*") case AnnotatedType(tpe, _) => inner(tpe) From 594652f6b6de29233150d8fd078556d6da41b1d2 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Tue, 12 Jan 2021 16:08:17 +0100 Subject: [PATCH 3/4] Apply requested changes, fix SignatureTests parser, fix type alliance for vals, add some tests --- scala3doc-testcases/src/tests/typeAppliance.scala | 9 +++++---- scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala | 8 +++----- scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala | 10 +++++++++- scala3doc/src/dotty/dokka/tasty/TypesSupport.scala | 5 ++++- scala3doc/test/dotty/dokka/SignatureTest.scala | 2 +- scala3doc/test/dotty/dokka/SignatureTestCases.scala | 4 +++- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/scala3doc-testcases/src/tests/typeAppliance.scala b/scala3doc-testcases/src/tests/typeAppliance.scala index 34a8dc69c08a..23a8325328ea 100644 --- a/scala3doc-testcases/src/tests/typeAppliance.scala +++ b/scala3doc-testcases/src/tests/typeAppliance.scala @@ -6,10 +6,11 @@ trait AClass[A, B]: trait BClass[A, B] extends AClass[A, B]: override def funASD[X, D](f: B => X): BClass[A, X] - val f: (=> B) => String = _ => "abc" + val f: (=> B) => String + = _ => "abc" abstract class CClass[U] extends BClass[Int, U]: - def xdxdkk(n: Int)(b: Int): Int = 1 - def isByNameType: String = "xd" - def vararg1(a: A*): C + def someFun(n: Int)(b: Int): Int + = 1 + diff --git a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala index 4136dd8798ed..87210a11c07f 100644 --- a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala @@ -389,7 +389,7 @@ trait ClassLikeSupport: inlinePrefix + prefix(argument.symbol), nameIfNotSynthetic, argument.symbol.dri, - memberInfo.flatMap(_.get(name).map(_.dokkaType.asSignature)).getOrElse(argument.tpt.dokkaType.asSignature), + memberInfo.flatMap(_.get(name)).fold(argument.tpt.dokkaType.asSignature)(_.dokkaType.asSignature), isExtendedSymbol, isGrouped ) @@ -405,7 +405,7 @@ trait ClassLikeSupport: variancePrefix, name, argument.symbol.dri, - memberInfo.flatMap(_.get(name).map(_.dokkaType.asSignature)).getOrElse(argument.rhs.dokkaType.asSignature) + memberInfo.flatMap(_.get(name)).fold(argument.rhs.dokkaType.asSignature)(_.dokkaType.asSignature) ) def parseTypeDef(typeDef: TypeDef): Member = @@ -479,9 +479,7 @@ trait ClassLikeSupport: case class MemberInfo(genericTypes: Map[String, TypeBounds], paramLists: List[Map[String, TypeRepr]], res: TypeRepr) def unwrapMemberInfo(c: ClassDef, symbol: Symbol): MemberInfo = - val baseTypeRepr = typeForClass(c).asInstanceOf[dotty.tools.dotc.core.Types.Type] - .memberInfo(symbol.asInstanceOf[dotty.tools.dotc.core.Symbols.Symbol])(using qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx) - .asInstanceOf[TypeRepr] + val baseTypeRepr = memberInfo(c, symbol) def handlePolyType(polyType: PolyType): MemberInfo = MemberInfo(polyType.paramNames.zip(polyType.paramBounds).toMap, List.empty, polyType.resType) diff --git a/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala b/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala index d19f64222038..6aecd7ef5a19 100644 --- a/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/SyntheticSupport.scala @@ -105,4 +105,12 @@ trait SyntheticsSupport: given dotc.core.Contexts.Context = qctx.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(c: ClassDef, symbol: Symbol): TypeRepr = + import qctx.reflect._ + import dotty.tools.dotc + given dotc.core.Contexts.Context = qctx.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx + typeForClass(c).asInstanceOf[dotc.core.Types.Type] + .memberInfo(symbol.asInstanceOf[dotc.core.Symbols.Symbol]) + .asInstanceOf[TypeRepr] + diff --git a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala index 8f0f6e2c9c10..80fef3ffda40 100644 --- a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala @@ -174,7 +174,10 @@ trait TypesSupport: case Seq(rtpe) => text("() => ") :: inner(rtpe) case Seq(arg, rtpe) => - inner(arg) ++ texts(" => ") ++ inner(rtpe) + val ar = arg match + case a: ByNameType => texts("(") ++ inner(a) ++ texts(")") + case o => inner(o) + ar ++ texts(" => ") ++ inner(rtpe) case args => texts("(") ++ commas(args.init.map(inner)) ++ texts(") => ") ++ inner(args.last) else if t.isTupleType then diff --git a/scala3doc/test/dotty/dokka/SignatureTest.scala b/scala3doc/test/dotty/dokka/SignatureTest.scala index 1df3e6592ccb..caabc9e05fa0 100644 --- a/scala3doc/test/dotty/dokka/SignatureTest.scala +++ b/scala3doc/test/dotty/dokka/SignatureTest.scala @@ -98,7 +98,7 @@ abstract class SignatureTest( case unexpectedRegex(signature) => findName(signature, kinds).map(Unexpected(_)) case expectedRegex(signature) => findName(signature, kinds).map(Expected(_, signature)) case signature => - findName(signature, kinds).map(Expected(_, commentRegex.replaceAllIn(signature, "").compactWhitespaces)) + findName(signature, kinds).map(Expected(_, commentRegex.replaceAllIn(signature, "").compactWhitespaces.reverse.dropWhile(List('{', ':').contains(_)).reverse)) } private def signaturesFromDocumentation(root: PageNode)(using DocContext): Seq[String] = diff --git a/scala3doc/test/dotty/dokka/SignatureTestCases.scala b/scala3doc/test/dotty/dokka/SignatureTestCases.scala index 2320fe51fe3b..2538332c1989 100644 --- a/scala3doc/test/dotty/dokka/SignatureTestCases.scala +++ b/scala3doc/test/dotty/dokka/SignatureTestCases.scala @@ -31,6 +31,8 @@ class FieldsSignatures extends SignatureTest("fieldsSignatures", SignatureTest.a class NestedSignatures extends SignatureTest("nested", SignatureTest.all) +class TypeAppliacneSignatures extends SignatureTest("typeAppliance", SignatureTest.all) + class CompanionObjectSignatures extends SignatureTest("companionObjectSignatures", SignatureTest.all) class PackageSymbolSignatures extends SignatureTest("packageSymbolSignatures", SignatureTest.all) @@ -84,4 +86,4 @@ class ImplicitConversionsTest3 extends SignatureTest( filterFunc = _.toString.endsWith("ClassWithConversionWithProperType.html") ) -class SpecializedSignature extends SignatureTest("specializedSignature", SignatureTest.all) \ No newline at end of file +class SpecializedSignature extends SignatureTest("specializedSignature", SignatureTest.all) From 91fdbdbda47da08ed81eea10f80b5340e95b3d2d Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Fri, 15 Jan 2021 13:26:25 +0100 Subject: [PATCH 4/4] Apply requested changes --- scala3doc-testcases/src/tests/hkts.scala | 6 ---- .../dotty/dokka/tasty/ClassLikeSupport.scala | 12 +++---- .../src/dotty/dokka/tasty/TypesSupport.scala | 33 +++++++++++-------- .../test/dotty/dokka/SignatureTest.scala | 5 ++- 4 files changed, 29 insertions(+), 27 deletions(-) delete mode 100644 scala3doc-testcases/src/tests/hkts.scala diff --git a/scala3doc-testcases/src/tests/hkts.scala b/scala3doc-testcases/src/tests/hkts.scala deleted file mode 100644 index 286b571a52ab..000000000000 --- a/scala3doc-testcases/src/tests/hkts.scala +++ /dev/null @@ -1,6 +0,0 @@ -package tests -package hkts - -class A[F[_]] - -// class B[[A, B] =>> (A, B)] diff --git a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala index 87210a11c07f..c8758103c80a 100644 --- a/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala @@ -337,9 +337,9 @@ trait ClassLikeSupport: val memberInfo = unwrapMemberInfo(c, methodSymbol) val basicKind: Kind.Def = Kind.Def( - genericTypes.map(mkTypeArgument(_, Some(memberInfo.genericTypes))), + genericTypes.map(mkTypeArgument(_, memberInfo.genericTypes)), paramLists.zipWithIndex.map { (pList, index) => - ParametersList(pList.map(mkParameter(_, paramPrefix, memberInfo = Some(memberInfo.paramLists(index)))), if isUsingModifier(pList) then "using " else "") + ParametersList(pList.map(mkParameter(_, paramPrefix, memberInfo = memberInfo.paramLists(index))), if isUsingModifier(pList) then "using " else "") } ) @@ -380,7 +380,7 @@ trait ClassLikeSupport: prefix: Symbol => String = _ => "", isExtendedSymbol: Boolean = false, isGrouped: Boolean = false, - memberInfo: Option[Map[String, TypeRepr]] = None) = + memberInfo: Map[String, TypeRepr] = Map.empty) = val inlinePrefix = if argument.symbol.flags.is(Flags.Inline) then "inline " else "" val nameIfNotSynthetic = Option.when(!argument.symbol.flags.is(Flags.Synthetic))(argument.symbol.normalizedName) val name = argument.symbol.normalizedName @@ -389,12 +389,12 @@ trait ClassLikeSupport: inlinePrefix + prefix(argument.symbol), nameIfNotSynthetic, argument.symbol.dri, - memberInfo.flatMap(_.get(name)).fold(argument.tpt.dokkaType.asSignature)(_.dokkaType.asSignature), + memberInfo.get(name).fold(argument.tpt.dokkaType.asSignature)(_.dokkaType.asSignature), isExtendedSymbol, isGrouped ) - def mkTypeArgument(argument: TypeDef, memberInfo: Option[Map[String, TypeBounds]] = None): TypeParameter = + def mkTypeArgument(argument: TypeDef, memberInfo: Map[String, TypeBounds] = Map.empty): TypeParameter = val variancePrefix: "+" | "-" | "" = if argument.symbol.flags.is(Flags.Covariant) then "+" else if argument.symbol.flags.is(Flags.Contravariant) then "-" @@ -405,7 +405,7 @@ trait ClassLikeSupport: variancePrefix, name, argument.symbol.dri, - memberInfo.flatMap(_.get(name)).fold(argument.rhs.dokkaType.asSignature)(_.dokkaType.asSignature) + memberInfo.get(name).fold(argument.rhs.dokkaType.asSignature)(_.dokkaType.asSignature) ) def parseTypeDef(typeDef: TypeDef): Member = diff --git a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala index 80fef3ffda40..d12e0f53b3a5 100644 --- a/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala +++ b/scala3doc/src/dotty/dokka/tasty/TypesSupport.scala @@ -68,14 +68,19 @@ trait TypesSupport: case List(single) => single case other => other.reduce((r, e) => r ++ texts(", ") ++ e) - // weird name fot type-erasure purposes - private def isRepeatedTerm(term: Term) = - // For some reason annotation.tpe.typeSymbol != defn.RepeatedParamClass - // annotation.tpe.typeSymbol prints 'class Repeated' and defn.RepeatedParamClass prints 'class ' - term.tpe.typeSymbol.toString == "class Repeated" - - private def isRepeatedTypeRepr(typeRepr: TypeRepr) = - typeRepr.typeSymbol.toString == "class " + private def isRepeatedAnnotation(term: Term) = + term.tpe match + case t: TypeRef => t.name == "Repeated" && t.qualifier.match + case ThisType(tref: TypeRef) if tref.name == "internal" => true + case _ => false + case _ => false + + private def isRepeated(typeRepr: TypeRepr) = + typeRepr match + case t: TypeRef => t.name == "" && t.qualifier.match + case ThisType(tref: TypeRef) if tref.name == "scala" => true + case _ => false + case _ => false // TODO #23 add support for all types signatures that makes sense private def inner(tp: TypeRepr): List[JProjection] = @@ -90,9 +95,9 @@ trait TypesSupport: case ConstantType(constant) => texts(constant.show) case ThisType(tpe) => inner(tpe) - case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedTerm(annotation) => + case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedAnnotation(annotation) => inner(tpe) :+ text("*") - case AppliedType(repeatedClass, Seq(tpe)) if isRepeatedTypeRepr(repeatedClass) => + case AppliedType(repeatedClass, Seq(tpe)) if isRepeated(repeatedClass) => inner(tpe) :+ text("*") case AnnotatedType(tpe, _) => inner(tpe) @@ -174,10 +179,10 @@ trait TypesSupport: case Seq(rtpe) => text("() => ") :: inner(rtpe) case Seq(arg, rtpe) => - val ar = arg match - case a: ByNameType => texts("(") ++ inner(a) ++ texts(")") - case o => inner(o) - ar ++ texts(" => ") ++ inner(rtpe) + val partOfSignature = arg match + case byName: ByNameType => texts("(") ++ inner(byName) ++ texts(")") + case _ => inner(arg) + partOfSignature ++ texts(" => ") ++ inner(rtpe) case args => texts("(") ++ commas(args.init.map(inner)) ++ texts(") => ") ++ inner(args.last) else if t.isTupleType then diff --git a/scala3doc/test/dotty/dokka/SignatureTest.scala b/scala3doc/test/dotty/dokka/SignatureTest.scala index caabc9e05fa0..3a82ccfc53e2 100644 --- a/scala3doc/test/dotty/dokka/SignatureTest.scala +++ b/scala3doc/test/dotty/dokka/SignatureTest.scala @@ -98,7 +98,10 @@ abstract class SignatureTest( case unexpectedRegex(signature) => findName(signature, kinds).map(Unexpected(_)) case expectedRegex(signature) => findName(signature, kinds).map(Expected(_, signature)) case signature => - findName(signature, kinds).map(Expected(_, commentRegex.replaceAllIn(signature, "").compactWhitespaces.reverse.dropWhile(List('{', ':').contains(_)).reverse)) + findName(signature, kinds).map( + Expected(_, commentRegex.replaceAllIn(signature, "") + .compactWhitespaces.reverse.dropWhile(List('{', ':').contains(_)).reverse) + ) } private def signaturesFromDocumentation(root: PageNode)(using DocContext): Seq[String] =