From 0dcbe93673c8470492cc8f03f5a4201f87a76611 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 13 Aug 2021 11:37:40 +0200 Subject: [PATCH 01/16] Treat implicit functions as normal defs --- scaladoc-testcases/src/tests/caseClassesWithVars.scala | 6 ++++++ .../dotty/tools/scaladoc/tasty/ClassLikeSupport.scala | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 scaladoc-testcases/src/tests/caseClassesWithVars.scala diff --git a/scaladoc-testcases/src/tests/caseClassesWithVars.scala b/scaladoc-testcases/src/tests/caseClassesWithVars.scala new file mode 100644 index 000000000000..8782846665ed --- /dev/null +++ b/scaladoc-testcases/src/tests/caseClassesWithVars.scala @@ -0,0 +1,6 @@ +package tests.caseClassesWithVars + +case class Sheep(var numberOfLegs: Int): + var name: String = "Lawrence" + +class Goat(var numberOfLegs: Int) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index bbf737464eff..30943e945bd0 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -6,6 +6,7 @@ import dotty.tools.scaladoc.{Signature => DSignature} import dotty.tools.scaladoc.Inkuire import scala.quoted._ +import scala.util.chaining._ import SymOps._ import NameNormalizer._ @@ -156,7 +157,7 @@ trait ClassLikeSupport: classDef.symbol.declaredMethods .filter(viableSymbol) - .foreach { + .tap { _.foreach { // Loop for implicit conversions case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) && classDef.symbol.flags.is(Flags.Module) && implicitConversion.owner.fullName == ("scala.Predef$") => @@ -168,7 +169,9 @@ trait ClassLikeSupport: (from, to) match case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) case _ => - + case _ => + }} + .tap { _.foreach { // Loop for functions and vals case methodSymbol: Symbol => val defdef = methodSymbol.tree.asInstanceOf[DefDef] val methodVars = defdef.paramss.flatMap(_.params).collect { @@ -198,7 +201,7 @@ trait ClassLikeSupport: ) val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) - } + }} classDef.symbol.declaredFields .filter(viableSymbol) From 4afc522540db3eebfeda3b406f300b702c9e297a Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 13 Aug 2021 12:45:13 +0200 Subject: [PATCH 02/16] Move Inkuire from ClassLikeSupport --- .../scaladoc/tasty/ClassLikeSupport.scala | 131 +----------------- .../tools/scaladoc/tasty/InkuireSupport.scala | 130 +++++++++++++++++ 2 files changed, 131 insertions(+), 130 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 30943e945bd0..6cdca1590eae 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -6,7 +6,6 @@ import dotty.tools.scaladoc.{Signature => DSignature} import dotty.tools.scaladoc.Inkuire import scala.quoted._ -import scala.util.chaining._ import SymOps._ import NameNormalizer._ @@ -101,135 +100,7 @@ trait ClassLikeSupport: deprecated = classDef.symbol.isDeprecated() ) - if summon[DocContext].args.generateInkuire then { - - val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type] - - def varName(t: Inkuire.TypeLike): Option[String] = t match { - case tpe: Inkuire.Type => Some(tpe.name.name) - case tl: Inkuire.TypeLambda => varName(tl.result) - case _ => None - } - - val variableNames: Set[String] = classType.params.map(_.typ) - .flatMap(varName(_).toList).toSet - - val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type]) - - val isModule = classDef.symbol.flags.is(Flags.Module) - - if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents))) - - classDef.symbol.declaredTypes - .filter(viableSymbol) - .foreach { - case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) => - val typ = typeSymbol.tree.asInkuire(variableNames) - if typ.isInstanceOf[Inkuire.Type] then { - val t = typ.asInstanceOf[Inkuire.Type] - Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) - } - case typeSymbol: Symbol if !typeSymbol.isClassDef => - val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] - val typ = typeSymbol.tree.asInkuire(variableNames) - if typ.isInstanceOf[Inkuire.Type] then { - val t = typ.asInstanceOf[Inkuire.Type] - val rhsTypeLike = typeDef.rhs.asInkuire(variableNames) - Inkuire.db = Inkuire.db.copy( - typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike), - types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)) - ) - } - if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then - val typJava = typeDef.rhs.asInkuire(variableNames) - if typJava.isInstanceOf[Inkuire.Type] then { - val tJava = typJava.asInstanceOf[Inkuire.Type] - Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) - } - case _ => - } - - def viableSymbol(s: Symbol): Boolean = - !s.flags.is(Flags.Private) && - !s.flags.is(Flags.Protected) && - !s.flags.is(Flags.Override) && - !s.flags.is(Flags.Synthetic) - - classDef.symbol.declaredMethods - .filter(viableSymbol) - .tap { _.foreach { // Loop for implicit conversions - case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) - && classDef.symbol.flags.is(Flags.Module) - && implicitConversion.owner.fullName == ("scala.Predef$") => - val defdef = implicitConversion.tree.asInstanceOf[DefDef] - val to = defdef.returnTpt.asInkuire(variableNames) - val from = defdef.paramss.flatMap(_.params).collectFirst { - case v: ValDef => v.tpt.asInkuire(variableNames) - } - (from, to) match - case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) - case _ => - case _ => - }} - .tap { _.foreach { // Loop for functions and vals - case methodSymbol: Symbol => - val defdef = methodSymbol.tree.asInstanceOf[DefDef] - val methodVars = defdef.paramss.flatMap(_.params).collect { - case TypeDef(name, _) => name - } - val vars = variableNames ++ methodVars - val receiver: Option[Inkuire.TypeLike] = - Some(classType) - .filter(_ => !isModule) - .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) - val sgn = Inkuire.ExternalSignature( - signature = Inkuire.Signature( - receiver = receiver, - arguments = methodSymbol.nonExtensionTermParamLists.collect { - case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters - }.flatten.map(_.tpt.asInkuire(vars)), - result = defdef.returnTpt.asInkuire(vars), - context = Inkuire.SignatureContext( - vars = vars.toSet, - constraints = Map.empty //TODO [Inkuire] Type bounds - ) - ), - name = methodSymbol.name, - packageName = methodSymbol.dri.location, - uri = methodSymbol.dri.externalLink.getOrElse(""), - entryType = "def" - ) - val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) - Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) - }} - - classDef.symbol.declaredFields - .filter(viableSymbol) - .foreach { - case valSymbol: Symbol => - val valdef = valSymbol.tree.asInstanceOf[ValDef] - val receiver: Option[Inkuire.TypeLike] = - Some(classType) - .filter(_ => !isModule) - val sgn = Inkuire.ExternalSignature( - signature = Inkuire.Signature( - receiver = receiver, - arguments = Seq.empty, - result = valdef.tpt.asInkuire(variableNames), - context = Inkuire.SignatureContext( - vars = variableNames.toSet, - constraints = Map.empty //TODO [Inkuire] Type bounds - ) - ), - name = valSymbol.name, - packageName = valSymbol.dri.location, - uri = valSymbol.dri.externalLink.getOrElse(""), - entryType = "val" - ) - val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) - Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) - } - } + if summon[DocContext].args.generateInkuire then doInkuireStuff(classDef) if signatureOnly then baseMember else baseMember.copy( members = classDef.extractPatchedMembers.sortBy(m => (m.name, m.kind.name)), diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index a5103c914732..04ee72dbfdcc 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -7,6 +7,7 @@ import dotty.tools.scaladoc.Inkuire import scala.util.Random import scala.quoted._ +import scala.util.chaining._ import SymOps._ import NameNormalizer._ @@ -18,6 +19,135 @@ trait InkuireSupport: private given qctx.type = qctx + def doInkuireStuff(classDef: ClassDef): Unit = { + val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type] + + def varName(t: Inkuire.TypeLike): Option[String] = t match { + case tpe: Inkuire.Type => Some(tpe.name.name) + case tl: Inkuire.TypeLambda => varName(tl.result) + case _ => None + } + + val variableNames: Set[String] = classType.params.map(_.typ) + .flatMap(varName(_).toList).toSet + + val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type]) + + val isModule = classDef.symbol.flags.is(Flags.Module) + + if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents))) + + classDef.symbol.declaredTypes + .filter(viableSymbol) + .foreach { + case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) => + val typ = typeSymbol.tree.asInkuire(variableNames) + if typ.isInstanceOf[Inkuire.Type] then { + val t = typ.asInstanceOf[Inkuire.Type] + Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) + } + case typeSymbol: Symbol if !typeSymbol.isClassDef => + val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] + val typ = typeSymbol.tree.asInkuire(variableNames) + if typ.isInstanceOf[Inkuire.Type] then { + val t = typ.asInstanceOf[Inkuire.Type] + val rhsTypeLike = typeDef.rhs.asInkuire(variableNames) + Inkuire.db = Inkuire.db.copy( + typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike), + types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)) + ) + } + if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then + val typJava = typeDef.rhs.asInkuire(variableNames) + if typJava.isInstanceOf[Inkuire.Type] then { + val tJava = typJava.asInstanceOf[Inkuire.Type] + Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) + } + case _ => + } + + def viableSymbol(s: Symbol): Boolean = + !s.flags.is(Flags.Private) && + !s.flags.is(Flags.Protected) && + !s.flags.is(Flags.Override) && + !s.flags.is(Flags.Synthetic) + + classDef.symbol.declaredMethods + .filter(viableSymbol) + .tap { _.foreach { // Loop for implicit conversions + case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) + && classDef.symbol.flags.is(Flags.Module) + && implicitConversion.owner.fullName == ("scala.Predef$") => + val defdef = implicitConversion.tree.asInstanceOf[DefDef] + val to = defdef.returnTpt.asInkuire(variableNames) + val from = defdef.paramss.flatMap(_.params).collectFirst { + case v: ValDef => v.tpt.asInkuire(variableNames) + } + (from, to) match + case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) + case _ => + case _ => + }} + .tap { _.foreach { // Loop for functions and vals + case methodSymbol: Symbol => + val defdef = methodSymbol.tree.asInstanceOf[DefDef] + val methodVars = defdef.paramss.flatMap(_.params).collect { + case TypeDef(name, _) => name + } + val vars = variableNames ++ methodVars + val receiver: Option[Inkuire.TypeLike] = + Some(classType) + .filter(_ => !isModule) + .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) + val sgn = Inkuire.ExternalSignature( + signature = Inkuire.Signature( + receiver = receiver, + arguments = methodSymbol.nonExtensionTermParamLists.collect { + case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters + }.flatten.map(_.tpt.asInkuire(vars)), + result = defdef.returnTpt.asInkuire(vars), + context = Inkuire.SignatureContext( + vars = vars.toSet, + constraints = Map.empty //TODO [Inkuire] Type bounds + ) + ), + name = methodSymbol.name, + packageName = methodSymbol.dri.location, + uri = methodSymbol.dri.externalLink.getOrElse(""), + entryType = "def" + ) + val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) + Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) + }} + + classDef.symbol.declaredFields + .filter(viableSymbol) + .foreach { + case valSymbol: Symbol => + val valdef = valSymbol.tree.asInstanceOf[ValDef] + val receiver: Option[Inkuire.TypeLike] = + Some(classType) + .filter(_ => !isModule) + val sgn = Inkuire.ExternalSignature( + signature = Inkuire.Signature( + receiver = receiver, + arguments = Seq.empty, + result = valdef.tpt.asInkuire(variableNames), + context = Inkuire.SignatureContext( + vars = variableNames.toSet, + constraints = Map.empty //TODO [Inkuire] Type bounds + ) + ), + name = valSymbol.name, + packageName = valSymbol.dri.location, + uri = valSymbol.dri.externalLink.getOrElse(""), + entryType = "val" + ) + val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) + Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) + } + } + private def paramsForClass(classDef: ClassDef, vars: Set[String]): Seq[Inkuire.Variance] = classDef.getTypeParams.map(mkTypeArgumentInkuire) From 636a430a838b21a15a5e473a703717d0b9a2fdfc Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 13 Aug 2021 16:03:07 +0200 Subject: [PATCH 03/16] Heuristic to determine a way for displaying static methods --- .../tools/scaladoc/tasty/InkuireSupport.scala | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 04ee72dbfdcc..8282f07ac8d5 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -99,6 +99,7 @@ trait InkuireSupport: Some(classType) .filter(_ => !isModule) .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) + val (name, ownerName) = nameAndOwnerName(classDef, methodSymbol) val sgn = Inkuire.ExternalSignature( signature = Inkuire.Signature( receiver = receiver, @@ -111,8 +112,8 @@ trait InkuireSupport: constraints = Map.empty //TODO [Inkuire] Type bounds ) ), - name = methodSymbol.name, - packageName = methodSymbol.dri.location, + name = name, + packageName = ownerName, uri = methodSymbol.dri.externalLink.getOrElse(""), entryType = "def" ) @@ -128,6 +129,7 @@ trait InkuireSupport: val receiver: Option[Inkuire.TypeLike] = Some(classType) .filter(_ => !isModule) + val (name, ownerName) = nameAndOwnerName(classDef, valSymbol) val sgn = Inkuire.ExternalSignature( signature = Inkuire.Signature( receiver = receiver, @@ -138,8 +140,8 @@ trait InkuireSupport: constraints = Map.empty //TODO [Inkuire] Type bounds ) ), - name = valSymbol.name, - packageName = valSymbol.dri.location, + name = name, + packageName = ownerName, uri = valSymbol.dri.externalLink.getOrElse(""), entryType = "val" ) @@ -148,6 +150,26 @@ trait InkuireSupport: } } + private def nameAndOwnerName(classDef: ClassDef, symbol: Symbol): (String, String) = + if classDef.symbol.flags.is(Flags.Module) + && (classDef.symbol.companionClass != Symbol.noSymbol || (Seq("apply", "unapply").contains(symbol.name))) then + ( + symbol.maybeOwner.normalizedName + "." + symbol.name, + ownerNameChain(classDef.symbol.maybeOwner).mkString(".") + ) + else + ( + symbol.name, + ownerNameChain(classDef.symbol).mkString(".") + ) + + def ownerNameChain(sym: Symbol): List[String] = + if sym.isNoSymbol then List.empty + else if sym == defn.EmptyPackageClass then List.empty + else if sym == defn.RootPackage then List.empty + else if sym == defn.RootClass then List.empty + else ownerNameChain(sym.owner) :+ sym.normalizedName + private def paramsForClass(classDef: ClassDef, vars: Set[String]): Seq[Inkuire.Variance] = classDef.getTypeParams.map(mkTypeArgumentInkuire) From 59cbbe1c15a7db8e693aea806d760f13ae38b74a Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 13 Aug 2021 17:20:08 +0200 Subject: [PATCH 04/16] Support implicit classes --- .../src/tests/anImplicitClass.scala | 4 +++ .../src/tests/justmethods.scala | 5 ++++ .../tools/scaladoc/tasty/InkuireSupport.scala | 28 +++++++++++++------ .../dotty/tools/scaladoc/tasty/SymOps.scala | 11 +++++++- 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 scaladoc-testcases/src/tests/anImplicitClass.scala create mode 100644 scaladoc-testcases/src/tests/justmethods.scala diff --git a/scaladoc-testcases/src/tests/anImplicitClass.scala b/scaladoc-testcases/src/tests/anImplicitClass.scala new file mode 100644 index 000000000000..3653e867302c --- /dev/null +++ b/scaladoc-testcases/src/tests/anImplicitClass.scala @@ -0,0 +1,4 @@ +package tests.anImplicitClass + +implicit class AddingOps(n: Int): + def inc: Int = n + 1 diff --git a/scaladoc-testcases/src/tests/justmethods.scala b/scaladoc-testcases/src/tests/justmethods.scala new file mode 100644 index 000000000000..13c957305aa8 --- /dev/null +++ b/scaladoc-testcases/src/tests/justmethods.scala @@ -0,0 +1,5 @@ +package tests.justmethods + +trait Animal + +def whatSoundDoIMake(animal: Animal): String = "IoIo" diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 8282f07ac8d5..99f1d202ca6b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -72,20 +72,20 @@ trait InkuireSupport: !s.flags.is(Flags.Override) && !s.flags.is(Flags.Synthetic) + if classDef.symbol.isImplicitClass then // Implicit classes + classDef.symbol.maybeOwner.declarations + .filter { methodSymbol => + methodSymbol.name == classDef.symbol.name && methodSymbol.flags.is(Flags.Implicit) && methodSymbol.flags.is(Flags.Method) + } + .foreach(handleImplicitConversion(_, variableNames)) + classDef.symbol.declaredMethods .filter(viableSymbol) .tap { _.foreach { // Loop for implicit conversions case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) && classDef.symbol.flags.is(Flags.Module) && implicitConversion.owner.fullName == ("scala.Predef$") => - val defdef = implicitConversion.tree.asInstanceOf[DefDef] - val to = defdef.returnTpt.asInkuire(variableNames) - val from = defdef.paramss.flatMap(_.params).collectFirst { - case v: ValDef => v.tpt.asInkuire(variableNames) - } - (from, to) match - case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) - case _ => + handleImplicitConversion(implicitConversion, variableNames) case _ => }} .tap { _.foreach { // Loop for functions and vals @@ -150,6 +150,17 @@ trait InkuireSupport: } } + private def handleImplicitConversion(implicitConversion: Symbol, variableNames: Set[String]) = { + val defdef = implicitConversion.tree.asInstanceOf[DefDef] + val to = defdef.returnTpt.asInkuire(variableNames) + val from = defdef.paramss.flatMap(_.params).collectFirst { + case v: ValDef => v.tpt.asInkuire(variableNames) + } + (from, to) match + case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) + case _ => + } + private def nameAndOwnerName(classDef: ClassDef, symbol: Symbol): (String, String) = if classDef.symbol.flags.is(Flags.Module) && (classDef.symbol.companionClass != Symbol.noSymbol || (Seq("apply", "unapply").contains(symbol.name))) then @@ -168,6 +179,7 @@ trait InkuireSupport: else if sym == defn.EmptyPackageClass then List.empty else if sym == defn.RootPackage then List.empty else if sym == defn.RootClass then List.empty + else if sym.normalizedName.contains("$package") then ownerNameChain(sym.owner) else ownerNameChain(sym.owner) :+ sym.normalizedName private def paramsForClass(classDef: ClassDef, vars: Set[String]): Seq[Inkuire.Variance] = diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index defbdd5bbee7..3bc1678bff2b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -12,6 +12,13 @@ object SymOps: extension (using Quotes)(sym: reflect.Symbol) + def isImplicitClass: Boolean = + import reflect._ + sym.maybeOwner != Symbol.noSymbol + && sym.maybeOwner.declaredMethods.exists { methodSymbol => + methodSymbol.name == sym.name && methodSymbol.flags.is(Flags.Implicit) && methodSymbol.flags.is(Flags.Method) + } + def packageName: String = if (sym.isPackageDef) sym.fullName else sym.maybeOwner.packageName @@ -91,7 +98,9 @@ object SymOps: Flags.Open -> Modifier.Open, Flags.Override -> Modifier.Override, Flags.Case -> Modifier.Case, - ).collect { case (flag, mod) if sym.flags.is(flag) => mod } + ).collect { + case (flag, mod) if sym.flags.is(flag) => mod + } ++ Seq(Modifier.Implicit).filter(_ => sym.isImplicitClass) def isHiddenByVisibility(using dctx: DocContext): Boolean = import VisibilityScope._ From 32d7099b69aae6de903690370483589ccb910d85 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 13 Aug 2021 17:46:16 +0200 Subject: [PATCH 05/16] Method Types + small API cleanup --- scaladoc-testcases/src/tests/syntaxes.scala | 9 + .../tools/scaladoc/tasty/InkuireSupport.scala | 257 +++++++++--------- 2 files changed, 140 insertions(+), 126 deletions(-) create mode 100644 scaladoc-testcases/src/tests/syntaxes.scala diff --git a/scaladoc-testcases/src/tests/syntaxes.scala b/scaladoc-testcases/src/tests/syntaxes.scala new file mode 100644 index 000000000000..db30eca4e4f3 --- /dev/null +++ b/scaladoc-testcases/src/tests/syntaxes.scala @@ -0,0 +1,9 @@ +package test.syntaxes + +class DoingStuffOps[A](a: A): + def doStuff: Unit = () + +trait DoingStuffSyntax: + implicit def toDoingStuffOps[A](a: A): DoingStuffOps[A] = DoingStuffOps(a) + +object doingstuff extends DoingStuffSyntax diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 99f1d202ca6b..102443a97716 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -22,132 +22,118 @@ trait InkuireSupport: def doInkuireStuff(classDef: ClassDef): Unit = { val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type] - def varName(t: Inkuire.TypeLike): Option[String] = t match { - case tpe: Inkuire.Type => Some(tpe.name.name) - case tl: Inkuire.TypeLambda => varName(tl.result) - case _ => None - } - - val variableNames: Set[String] = classType.params.map(_.typ) - .flatMap(varName(_).toList).toSet + val variableNames: Set[String] = classType.params.map(_.typ) + .flatMap(varName(_).toList).toSet - val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type]) + val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type]) - val isModule = classDef.symbol.flags.is(Flags.Module) + val isModule = classDef.symbol.flags.is(Flags.Module) - if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents))) - - classDef.symbol.declaredTypes - .filter(viableSymbol) - .foreach { - case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) => - val typ = typeSymbol.tree.asInkuire(variableNames) - if typ.isInstanceOf[Inkuire.Type] then { - val t = typ.asInstanceOf[Inkuire.Type] - Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) - } - case typeSymbol: Symbol if !typeSymbol.isClassDef => - val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] - val typ = typeSymbol.tree.asInkuire(variableNames) - if typ.isInstanceOf[Inkuire.Type] then { - val t = typ.asInstanceOf[Inkuire.Type] - val rhsTypeLike = typeDef.rhs.asInkuire(variableNames) - Inkuire.db = Inkuire.db.copy( - typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike), - types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)) - ) - } - if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then - val typJava = typeDef.rhs.asInkuire(variableNames) - if typJava.isInstanceOf[Inkuire.Type] then { - val tJava = typJava.asInstanceOf[Inkuire.Type] - Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) - } - case _ => - } + if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents))) - def viableSymbol(s: Symbol): Boolean = - !s.flags.is(Flags.Private) && - !s.flags.is(Flags.Protected) && - !s.flags.is(Flags.Override) && - !s.flags.is(Flags.Synthetic) - - if classDef.symbol.isImplicitClass then // Implicit classes - classDef.symbol.maybeOwner.declarations - .filter { methodSymbol => - methodSymbol.name == classDef.symbol.name && methodSymbol.flags.is(Flags.Implicit) && methodSymbol.flags.is(Flags.Method) + classDef.symbol.declaredTypes + .filter(viableSymbol) + .foreach { + case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) => + val typ = typeSymbol.tree.asInkuire(variableNames) + if typ.isInstanceOf[Inkuire.Type] then { + val t = typ.asInstanceOf[Inkuire.Type] + Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) } - .foreach(handleImplicitConversion(_, variableNames)) - - classDef.symbol.declaredMethods - .filter(viableSymbol) - .tap { _.foreach { // Loop for implicit conversions - case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) - && classDef.symbol.flags.is(Flags.Module) - && implicitConversion.owner.fullName == ("scala.Predef$") => - handleImplicitConversion(implicitConversion, variableNames) - case _ => - }} - .tap { _.foreach { // Loop for functions and vals - case methodSymbol: Symbol => - val defdef = methodSymbol.tree.asInstanceOf[DefDef] - val methodVars = defdef.paramss.flatMap(_.params).collect { - case TypeDef(name, _) => name - } - val vars = variableNames ++ methodVars - val receiver: Option[Inkuire.TypeLike] = - Some(classType) - .filter(_ => !isModule) - .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) - val (name, ownerName) = nameAndOwnerName(classDef, methodSymbol) - val sgn = Inkuire.ExternalSignature( - signature = Inkuire.Signature( - receiver = receiver, - arguments = methodSymbol.nonExtensionTermParamLists.collect { - case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters - }.flatten.map(_.tpt.asInkuire(vars)), - result = defdef.returnTpt.asInkuire(vars), - context = Inkuire.SignatureContext( - vars = vars.toSet, - constraints = Map.empty //TODO [Inkuire] Type bounds - ) - ), - name = name, - packageName = ownerName, - uri = methodSymbol.dri.externalLink.getOrElse(""), - entryType = "def" + case typeSymbol: Symbol if !typeSymbol.isClassDef => + val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] + val typ = typeSymbol.tree.asInkuire(variableNames) + if typ.isInstanceOf[Inkuire.Type] then { + val t = typ.asInstanceOf[Inkuire.Type] + val rhsTypeLike = typeDef.rhs.asInkuire(variableNames) + Inkuire.db = Inkuire.db.copy( + typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike), + types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)) ) - val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) - Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) - }} + } + if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then + val typJava = typeDef.rhs.asInkuire(variableNames) + if typJava.isInstanceOf[Inkuire.Type] then { + val tJava = typJava.asInstanceOf[Inkuire.Type] + Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) + } + case _ => + } - classDef.symbol.declaredFields - .filter(viableSymbol) - .foreach { - case valSymbol: Symbol => - val valdef = valSymbol.tree.asInstanceOf[ValDef] - val receiver: Option[Inkuire.TypeLike] = - Some(classType) - .filter(_ => !isModule) - val (name, ownerName) = nameAndOwnerName(classDef, valSymbol) - val sgn = Inkuire.ExternalSignature( - signature = Inkuire.Signature( - receiver = receiver, - arguments = Seq.empty, - result = valdef.tpt.asInkuire(variableNames), - context = Inkuire.SignatureContext( - vars = variableNames.toSet, - constraints = Map.empty //TODO [Inkuire] Type bounds - ) - ), - name = name, - packageName = ownerName, - uri = valSymbol.dri.externalLink.getOrElse(""), - entryType = "val" - ) - val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) - Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) + if classDef.symbol.isImplicitClass then // Implicit classes <- synthetic method with the same name + classDef.symbol.maybeOwner.declarations + .filter { methodSymbol => + methodSymbol.name == classDef.symbol.name && methodSymbol.flags.is(Flags.Implicit) && methodSymbol.flags.is(Flags.Method) } + .foreach(handleImplicitConversion(_, variableNames)) + + classDef.symbol.declaredMethods + .filter(viableSymbol) + .tap { _.foreach { // Loop for implicit conversions + case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) => + handleImplicitConversion(implicitConversion, variableNames) + case _ => + }} + .tap { _.foreach { // Loop for functions and vals + case methodSymbol: Symbol => + val defdef = methodSymbol.tree.asInstanceOf[DefDef] + val methodVars = defdef.paramss.flatMap(_.params).collect { + case TypeDef(name, _) => name + } + val vars = variableNames ++ methodVars + val receiver: Option[Inkuire.TypeLike] = + Some(classType) + .filter(_ => !isModule) + .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) + val (name, ownerName) = nameAndOwnerName(classDef, methodSymbol) + val sgn = Inkuire.ExternalSignature( + signature = Inkuire.Signature( + receiver = receiver, + arguments = methodSymbol.nonExtensionTermParamLists.collect { + case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters + }.flatten.map(_.tpt.asInkuire(vars)), + result = defdef.returnTpt.asInkuire(vars), + context = Inkuire.SignatureContext( + vars = vars.toSet, + constraints = Map.empty //TODO [Inkuire] Type bounds + ) + ), + name = name, + packageName = ownerName, + uri = methodSymbol.dri.externalLink.getOrElse(""), + entryType = "def" + ) + val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) + Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) + }} + + classDef.symbol.declaredFields + .filter(viableSymbol) + .foreach { + case valSymbol: Symbol => + val valdef = valSymbol.tree.asInstanceOf[ValDef] + val receiver: Option[Inkuire.TypeLike] = + Some(classType) + .filter(_ => !isModule) + val (name, ownerName) = nameAndOwnerName(classDef, valSymbol) + val sgn = Inkuire.ExternalSignature( + signature = Inkuire.Signature( + receiver = receiver, + arguments = Seq.empty, + result = valdef.tpt.asInkuire(variableNames), + context = Inkuire.SignatureContext( + vars = variableNames.toSet, + constraints = Map.empty //TODO [Inkuire] Type bounds + ) + ), + name = name, + packageName = ownerName, + uri = valSymbol.dri.externalLink.getOrElse(""), + entryType = "val" + ) + val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) + Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) + } } private def handleImplicitConversion(implicitConversion: Symbol, variableNames: Set[String]) = { @@ -161,6 +147,8 @@ trait InkuireSupport: case _ => } + private def hasStaticChild(classDef: ClassDef): Boolean = ??? + private def nameAndOwnerName(classDef: ClassDef, symbol: Symbol): (String, String) = if classDef.symbol.flags.is(Flags.Module) && (classDef.symbol.companionClass != Symbol.noSymbol || (Seq("apply", "unapply").contains(symbol.name))) then @@ -174,7 +162,7 @@ trait InkuireSupport: ownerNameChain(classDef.symbol).mkString(".") ) - def ownerNameChain(sym: Symbol): List[String] = + private def ownerNameChain(sym: Symbol): List[String] = if sym.isNoSymbol then List.empty else if sym == defn.EmptyPackageClass then List.empty else if sym == defn.RootPackage then List.empty @@ -182,6 +170,18 @@ trait InkuireSupport: else if sym.normalizedName.contains("$package") then ownerNameChain(sym.owner) else ownerNameChain(sym.owner) :+ sym.normalizedName + private def viableSymbol(s: Symbol): Boolean = + !s.flags.is(Flags.Private) && + !s.flags.is(Flags.Protected) && + !s.flags.is(Flags.Override) && + !s.flags.is(Flags.Synthetic) + + private def varName(t: Inkuire.TypeLike): Option[String] = t match { + case tpe: Inkuire.Type => Some(tpe.name.name) + case tl: Inkuire.TypeLambda => varName(tl.result) + case _ => None + } + private def paramsForClass(classDef: ClassDef, vars: Set[String]): Seq[Inkuire.Variance] = classDef.getTypeParams.map(mkTypeArgumentInkuire) @@ -190,7 +190,7 @@ trait InkuireSupport: def asInkuire(vars: Set[String]): Inkuire.TypeLike = partialAsInkuire(vars)(tpeTree) - def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.TypeLike] = { + private def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.TypeLike] = { case TypeBoundsTree(low, high) => inner(low.tpe, vars) //TODO [Inkuire] Type bounds case tpeTree: Applied => inner(tpeTree.tpe, vars) @@ -201,7 +201,7 @@ trait InkuireSupport: case typeDef: TypeDef => mkTypeDef(typeDef) } - def mkTypeDef(typeDef: TypeDef): Inkuire.Type = typeDef.rhs match { + private def mkTypeDef(typeDef: TypeDef): Inkuire.Type = typeDef.rhs match { case LambdaTypeTree(paramsDefs, _) => val name = typeDef.symbol.normalizedName val normalizedName = if name.matches("_\\$\\d*") then "_" else name @@ -218,7 +218,7 @@ trait InkuireSupport: ) } - def mkTypeFromClassDef(classDef: ClassDef, vars: Set[String]): Inkuire.Type = { + private def mkTypeFromClassDef(classDef: ClassDef, vars: Set[String]): Inkuire.Type = { Inkuire.Type( name = Inkuire.TypeName(classDef.name), itid = classDef.symbol.itid, @@ -245,7 +245,7 @@ trait InkuireSupport: ) } - def mkTypeArgumentInkuire(argument: TypeDef): Inkuire.Variance = + private def mkTypeArgumentInkuire(argument: TypeDef): Inkuire.Variance = //TODO [Inkuire] Type bounds (other than just HKTs) val name = argument.symbol.normalizedName val normalizedName = if name.matches("_\\$\\d*") then "_" else name @@ -263,7 +263,7 @@ trait InkuireSupport: else if argument.symbol.flags.is(Flags.Contravariant) then Inkuire.Contravariance(t) else Inkuire.Invariance(t) - def typeVariableDeclarationParamsNo(argument: TypeDef): Int = + private def typeVariableDeclarationParamsNo(argument: TypeDef): Int = argument.rhs match case t: TypeTree => t.tpe match case TypeBounds(_, TypeLambda(names, _, _)) => names.size @@ -346,5 +346,10 @@ trait InkuireSupport: inner(m.paramTypes(i), vars) case RecursiveType(tp) => inner(tp, vars) - case MethodType(_, params, resType) => - inner(resType, vars) //TODO [Inkuire] Method type + case m@MethodType(_, typeList, resType) => + val name = s"Function${typeList.size-1}" + Inkuire.Type( + name = Inkuire.TypeName(name), + params = typeList.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(resType, vars)), + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) + ) From d701f3bdd645f7682792f5b2a1923222e97d6a78 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 13 Aug 2021 19:01:35 +0200 Subject: [PATCH 06/16] Implicit syntax test --- scaladoc-testcases/src/tests/syntaxes.scala | 4 +++- scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scaladoc-testcases/src/tests/syntaxes.scala b/scaladoc-testcases/src/tests/syntaxes.scala index db30eca4e4f3..51c929bf0ae3 100644 --- a/scaladoc-testcases/src/tests/syntaxes.scala +++ b/scaladoc-testcases/src/tests/syntaxes.scala @@ -6,4 +6,6 @@ class DoingStuffOps[A](a: A): trait DoingStuffSyntax: implicit def toDoingStuffOps[A](a: A): DoingStuffOps[A] = DoingStuffOps(a) -object doingstuff extends DoingStuffSyntax +trait AllSyntaxes extends DoingStuffSyntax + +object doingstuff extends AllSyntaxes diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 102443a97716..8dcc5575690b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -147,8 +147,6 @@ trait InkuireSupport: case _ => } - private def hasStaticChild(classDef: ClassDef): Boolean = ??? - private def nameAndOwnerName(classDef: ClassDef, symbol: Symbol): (String, String) = if classDef.symbol.flags.is(Flags.Module) && (classDef.symbol.companionClass != Symbol.noSymbol || (Seq("apply", "unapply").contains(symbol.name))) then From a9cd1274eb332dc6035e1c7f11de0d1fcce0c0e5 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 16 Aug 2021 10:22:33 +0200 Subject: [PATCH 07/16] Remove isParsed --- scaladoc/src/dotty/tools/scaladoc/Inkuire.scala | 14 ++++++-------- .../tools/scaladoc/tasty/InkuireSupport.scala | 12 ++++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 85624e8b15d7..6e295f0cbe2a 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -41,7 +41,7 @@ object Inkuire { typeAliases: Map[ITID, TypeLike] ) - case class ITID(uuid: String, isParsed: Boolean) + case class ITID(uuid: String) case class Signature( receiver: Option[Contravariance], @@ -87,7 +87,7 @@ object Inkuire { val uuid = s"external-type-lambda-arg-$name" Inkuire.Type( name = Inkuire.TypeName(name), - itid = Some(Inkuire.ITID(uuid, isParsed = false)), + itid = Some(Inkuire.ITID(uuid)), isVariable = true ) } @@ -98,8 +98,7 @@ object Inkuire { name = TypeName(""), itid = Some( ITID( - uuid = "", - isParsed = false + uuid = "" ) ) ) @@ -107,7 +106,7 @@ object Inkuire { def StarProjection: Type = Type( name = TypeName("_"), - itid = Some(ITID("_", isParsed = false)), + itid = Some(ITID("_")), isStarProjection = true ) } @@ -192,7 +191,7 @@ object Inkuire { } private def serializeAsKey(itid: ITID): String = { - s"""${itid.isParsed}=${itid.uuid}""" + s"${itid.uuid}" } private def serialize(v: (Type, Seq[Type])): JSON = { @@ -242,8 +241,7 @@ object Inkuire { private def serialize(itid: ITID): JSON = { jsonObject( - ("uuid", serialize(itid.uuid)), - ("isParsed", serialize(itid.isParsed)) + ("uuid", serialize(itid.uuid)) ) } diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 8dcc5575690b..a8d9b4c184c4 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -226,7 +226,7 @@ trait InkuireSupport: given SymbolSyntaxInkuire: AnyRef with extension (symbol: Symbol) - def itid(using dctx: DocContext): Option[Inkuire.ITID] = Some(Inkuire.ITID(symbol.dri.symbolUUID, isParsed = false)) + def itid(using dctx: DocContext): Option[Inkuire.ITID] = Some(Inkuire.ITID(symbol.dri.symbolUUID)) given TypeSyntaxInkuire: AnyRef with extension (tpe: TypeRepr) @@ -238,7 +238,7 @@ trait InkuireSupport: val name = s"X$i" Inkuire.Type( name = Inkuire.TypeName(name), - itid = Some(Inkuire.ITID(uuid, isParsed = false)), + itid = Some(Inkuire.ITID(uuid)), isVariable = true ) } @@ -290,7 +290,7 @@ trait InkuireSupport: Inkuire.Type( name = Inkuire.TypeName(constant.toString), params = Seq.empty, - itid = Some(Inkuire.ITID(constant.toString, isParsed = false)) + itid = Some(Inkuire.ITID(constant.toString)) ) case ThisType(tpe) => inner(tpe, vars) case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedAnnotation(annotation) => @@ -310,14 +310,14 @@ trait InkuireSupport: Inkuire.Type( name = Inkuire.TypeName(name), params = typeList.init.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(typeList.last, vars)), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]")) ) else if t.isTupleN then val name = s"Tuple${typeList.size}" Inkuire.Type( name = Inkuire.TypeName(name), params = typeList.map(p => Inkuire.Covariance(inner(p, vars))), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]")) ) else inner(tpe, vars).asInstanceOf[Inkuire.Type].copy( @@ -349,5 +349,5 @@ trait InkuireSupport: Inkuire.Type( name = Inkuire.TypeName(name), params = typeList.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(resType, vars)), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]")) ) From 46e8aa9ae0789f542da5f872bb814cccee82f1c2 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 16 Aug 2021 17:59:29 +0200 Subject: [PATCH 08/16] Better generation of implicit conversions --- scaladoc/src/dotty/tools/scaladoc/Inkuire.scala | 6 +++--- .../dotty/tools/scaladoc/tasty/InkuireSupport.scala | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 6e295f0cbe2a..c512d79ebfe7 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -10,7 +10,7 @@ object Inkuire { db = db.copy( functions = db.functions.sortBy(_.hashCode), types = db.types.toSeq.sortBy(_._1.uuid).toMap, - implicitConversions = db.implicitConversions.sortBy(_._1.uuid) + implicitConversions = db.implicitConversions.sortBy(_._1.hashCode) ) } @@ -37,7 +37,7 @@ object Inkuire { case class InkuireDb( functions: Seq[ExternalSignature], types: Map[ITID, (Type, Seq[Type])], - implicitConversions: Seq[(ITID, Type)], + implicitConversions: Seq[(TypeLike, Type)], typeAliases: Map[ITID, TypeLike] ) @@ -163,7 +163,7 @@ object Inkuire { ) } - private def serializeConversion(conversion: (ITID, Type)): JSON = { + private def serializeConversion(conversion: (TypeLike, Type)): JSON = { jsonList( Seq( serialize(conversion._1), diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index a8d9b4c184c4..5805cd1b0100 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -138,12 +138,16 @@ trait InkuireSupport: private def handleImplicitConversion(implicitConversion: Symbol, variableNames: Set[String]) = { val defdef = implicitConversion.tree.asInstanceOf[DefDef] - val to = defdef.returnTpt.asInkuire(variableNames) + val methodVars = defdef.paramss.flatMap(_.params).collect { + case TypeDef(name, _) => name + } + val vars = variableNames ++ methodVars + val to = defdef.returnTpt.asInkuire(vars) val from = defdef.paramss.flatMap(_.params).collectFirst { - case v: ValDef => v.tpt.asInkuire(variableNames) + case v: ValDef => v.tpt.asInkuire(vars) } (from, to) match - case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) + case (Some(from), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from -> to)) case _ => } From 6c634e5f76d5a4e2ad1c3f64f574eb6a140156ed Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 16 Aug 2021 18:00:06 +0200 Subject: [PATCH 09/16] Revert "Remove isParsed" This reverts commit 2f9e2bad63d223d34142b7a922b23a050038393d. --- scaladoc/src/dotty/tools/scaladoc/Inkuire.scala | 14 ++++++++------ .../tools/scaladoc/tasty/InkuireSupport.scala | 12 ++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index c512d79ebfe7..93c5f8823728 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -41,7 +41,7 @@ object Inkuire { typeAliases: Map[ITID, TypeLike] ) - case class ITID(uuid: String) + case class ITID(uuid: String, isParsed: Boolean) case class Signature( receiver: Option[Contravariance], @@ -87,7 +87,7 @@ object Inkuire { val uuid = s"external-type-lambda-arg-$name" Inkuire.Type( name = Inkuire.TypeName(name), - itid = Some(Inkuire.ITID(uuid)), + itid = Some(Inkuire.ITID(uuid, isParsed = false)), isVariable = true ) } @@ -98,7 +98,8 @@ object Inkuire { name = TypeName(""), itid = Some( ITID( - uuid = "" + uuid = "", + isParsed = false ) ) ) @@ -106,7 +107,7 @@ object Inkuire { def StarProjection: Type = Type( name = TypeName("_"), - itid = Some(ITID("_")), + itid = Some(ITID("_", isParsed = false)), isStarProjection = true ) } @@ -191,7 +192,7 @@ object Inkuire { } private def serializeAsKey(itid: ITID): String = { - s"${itid.uuid}" + s"""${itid.isParsed}=${itid.uuid}""" } private def serialize(v: (Type, Seq[Type])): JSON = { @@ -241,7 +242,8 @@ object Inkuire { private def serialize(itid: ITID): JSON = { jsonObject( - ("uuid", serialize(itid.uuid)) + ("uuid", serialize(itid.uuid)), + ("isParsed", serialize(itid.isParsed)) ) } diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 5805cd1b0100..8bc0891cbe37 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -230,7 +230,7 @@ trait InkuireSupport: given SymbolSyntaxInkuire: AnyRef with extension (symbol: Symbol) - def itid(using dctx: DocContext): Option[Inkuire.ITID] = Some(Inkuire.ITID(symbol.dri.symbolUUID)) + def itid(using dctx: DocContext): Option[Inkuire.ITID] = Some(Inkuire.ITID(symbol.dri.symbolUUID, isParsed = false)) given TypeSyntaxInkuire: AnyRef with extension (tpe: TypeRepr) @@ -242,7 +242,7 @@ trait InkuireSupport: val name = s"X$i" Inkuire.Type( name = Inkuire.TypeName(name), - itid = Some(Inkuire.ITID(uuid)), + itid = Some(Inkuire.ITID(uuid, isParsed = false)), isVariable = true ) } @@ -294,7 +294,7 @@ trait InkuireSupport: Inkuire.Type( name = Inkuire.TypeName(constant.toString), params = Seq.empty, - itid = Some(Inkuire.ITID(constant.toString)) + itid = Some(Inkuire.ITID(constant.toString, isParsed = false)) ) case ThisType(tpe) => inner(tpe, vars) case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedAnnotation(annotation) => @@ -314,14 +314,14 @@ trait InkuireSupport: Inkuire.Type( name = Inkuire.TypeName(name), params = typeList.init.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(typeList.last, vars)), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]")) + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) ) else if t.isTupleN then val name = s"Tuple${typeList.size}" Inkuire.Type( name = Inkuire.TypeName(name), params = typeList.map(p => Inkuire.Covariance(inner(p, vars))), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]")) + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) ) else inner(tpe, vars).asInstanceOf[Inkuire.Type].copy( @@ -353,5 +353,5 @@ trait InkuireSupport: Inkuire.Type( name = Inkuire.TypeName(name), params = typeList.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(resType, vars)), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]")) + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) ) From 3c5502ed6da5444b551e8756cc15a7c0b98e596f Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Wed, 18 Aug 2021 19:47:54 +0200 Subject: [PATCH 10/16] Handle implicit conversions on generation --- .../src/dotty/tools/scaladoc/Inkuire.scala | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 93c5f8823728..8db53524175d 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -8,7 +8,7 @@ object Inkuire { def beforeSave(): Unit = { db = db.copy( - functions = db.functions.sortBy(_.hashCode), + functions = functions.sortBy(_.hashCode), types = db.types.toSeq.sortBy(_._1.uuid).toMap, implicitConversions = db.implicitConversions.sortBy(_._1.hashCode) ) @@ -34,6 +34,48 @@ object Inkuire { case _ => e } + def functions: Seq[ExternalSignature] = Inkuire.db.functions.flatMap { func => + val fromConversions = Inkuire.db.implicitConversions.filter { ic => + func.signature.receiver.nonEmpty && matchingICTypes(ic._2, func.signature.receiver.get.typ) + }.map { ic => + func.copy( + signature = func.signature.copy( + receiver = func.signature.receiver.map { rcvr => + Contravariance( + newReceiver(rcvr.typ, ic._2, ic._1) + ) + } + ) + ) + } + Seq(func) ++ fromConversions + } + .distinct + + def matchingICTypes(a: TypeLike, b: TypeLike): Boolean = (a, b) match { + case (a: Type, b: Type) if a.params.size == 0 && b.params.size == 0 && a.itid == b.itid => true + case (a: Type, b: Type) if a.params.size == 1 && b.params.size == 1 && a.itid == b.itid => + a.params.head.typ.isInstanceOf[Type] && a.params.head.typ.asInstanceOf[Type].isVariable && + b.params.head.typ.isInstanceOf[Type] && b.params.head.typ.asInstanceOf[Type].isVariable + case _ => false + } + + def newReceiver(old: TypeLike, to: TypeLike, from: TypeLike): TypeLike = (old, to) match { + case (a: Type, b: Type) if a.params.size == 0 && b.params.size == 0 && a.itid == b.itid => from + case (a: Type, b: Type) if a.params.size == 1 && b.params.size == 1 && a.itid == b.itid + && a.params.head.typ.isInstanceOf[Type] && a.params.head.typ.asInstanceOf[Type].isVariable && + b.params.head.typ.isInstanceOf[Type] && b.params.head.typ.asInstanceOf[Type].isVariable => + if from.isInstanceOf[Type] && from.asInstanceOf[Type].params.size == 1 && from.asInstanceOf[Type].params.head.typ.isInstanceOf[Type] && from.asInstanceOf[Type].params.head.typ.asInstanceOf[Type].isVariable then + from.asInstanceOf[Type].copy( + params = Seq(Contravariance(a.params.head.typ.asInstanceOf[Type])) + ) + else if from.isInstanceOf[Type] && from.asInstanceOf[Type].isVariable then + a.params.head.typ.asInstanceOf[Type] + else + from + case _ => old + } + case class InkuireDb( functions: Seq[ExternalSignature], types: Map[ITID, (Type, Seq[Type])], From 91726d59d51257a8d869345c4b766954a6db8a13 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Wed, 25 Aug 2021 15:54:37 +0200 Subject: [PATCH 11/16] Sorting --- scaladoc-js/src/searchbar/PageEntry.scala | 3 ++- .../src/searchbar/SearchbarComponent.scala | 15 ++++++++++++++- .../searchbar/engine/InkuireJSSearchEngine.scala | 3 ++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/scaladoc-js/src/searchbar/PageEntry.scala b/scaladoc-js/src/searchbar/PageEntry.scala index 4429965a2060..7b0837e87a95 100644 --- a/scaladoc-js/src/searchbar/PageEntry.scala +++ b/scaladoc-js/src/searchbar/PageEntry.scala @@ -25,7 +25,8 @@ case class InkuireMatch( functionName: String, packageLocation: String, pageLocation: String, - entryType: String + entryType: String, + mq: Int ) object PageEntry { diff --git a/scaladoc-js/src/searchbar/SearchbarComponent.scala b/scaladoc-js/src/searchbar/SearchbarComponent.scala index d45352df3f54..3a264af19a3b 100644 --- a/scaladoc-js/src/searchbar/SearchbarComponent.scala +++ b/scaladoc-js/src/searchbar/SearchbarComponent.scala @@ -40,6 +40,7 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch val wrapper = document.createElement("div").asInstanceOf[html.Div] wrapper.classList.add("scaladoc-searchbar-result") wrapper.classList.add("monospace") + wrapper.setAttribute("mq", m.mq.toString) val resultDiv = document.createElement("div").asInstanceOf[html.Div] resultDiv.classList.add("scaladoc-searchbar-result-row") @@ -132,7 +133,19 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch loading.appendChild(animation) properResultsDiv.appendChild(loading) inkuireEngine.query(query) { (m: InkuireMatch) => - properResultsDiv.appendChild(m.toHTML) + var next: Option[Element] = None + 0.until(properResultsDiv.children.length).foreach { i => + val child = properResultsDiv.children(i) + val attr = child.getAttribute("mq") + if attr != null && attr != "" && Integer.parseInt(attr) > m.mq && next.isEmpty then { + next = Some(child) + } + } + next.fold{ + properResultsDiv.appendChild(m.toHTML) + } { next => + properResultsDiv.insertBefore(m.toHTML, next) + } } { (s: String) => animation.classList.remove("loading") properResultsDiv.appendChild(s.toHTMLError) diff --git a/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala b/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala index 9a1c75947307..f3e7cfd52417 100644 --- a/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala +++ b/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala @@ -22,7 +22,8 @@ class InkuireJSSearchEngine { d.functionName.asInstanceOf[String], d.packageLocation.asInstanceOf[String], d.pageLocation.asInstanceOf[String], - d.entryType.asInstanceOf[String] + d.entryType.asInstanceOf[String], + d.mq.asInstanceOf[Int] ) } From 8fd69bdf42caecb698b17dd484fb65e5ac522a01 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Wed, 25 Aug 2021 16:10:20 +0200 Subject: [PATCH 12/16] Better static method heuristic --- scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 8bc0891cbe37..53c997ea9c80 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -152,8 +152,7 @@ trait InkuireSupport: } private def nameAndOwnerName(classDef: ClassDef, symbol: Symbol): (String, String) = - if classDef.symbol.flags.is(Flags.Module) - && (classDef.symbol.companionClass != Symbol.noSymbol || (Seq("apply", "unapply").contains(symbol.name))) then + if classDef.symbol.flags.is(Flags.Module) || Seq("apply", "unapply").contains(symbol.name) then ( symbol.maybeOwner.normalizedName + "." + symbol.name, ownerNameChain(classDef.symbol.maybeOwner).mkString(".") From 1f472f63617493c865b865105ac0ad51bbf1fb17 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 26 Aug 2021 17:42:11 +0200 Subject: [PATCH 13/16] Handle type aliases with bounds better --- .../src/dotty/tools/scaladoc/Inkuire.scala | 32 ++-- .../tools/scaladoc/tasty/InkuireSupport.scala | 168 ++++++++++-------- 2 files changed, 110 insertions(+), 90 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 8db53524175d..f1b9414c9835 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -5,12 +5,15 @@ import dotty.tools.scaladoc.util._ object Inkuire { var db = InkuireDb(Seq.empty, Map.empty, Seq.empty, Map.empty) + var implicitConversions: Seq[(Option[TypeLike], Type)] = Seq.empty def beforeSave(): Unit = { db = db.copy( functions = functions.sortBy(_.hashCode), types = db.types.toSeq.sortBy(_._1.uuid).toMap, - implicitConversions = db.implicitConversions.sortBy(_._1.hashCode) + implicitConversions = implicitConversions.collect { + case (Some(from), to) => from -> to + }.sortBy(_._1.hashCode) ) } @@ -35,18 +38,25 @@ object Inkuire { } def functions: Seq[ExternalSignature] = Inkuire.db.functions.flatMap { func => - val fromConversions = Inkuire.db.implicitConversions.filter { ic => + val fromConversions = Inkuire.implicitConversions.filter { ic => func.signature.receiver.nonEmpty && matchingICTypes(ic._2, func.signature.receiver.get.typ) - }.map { ic => - func.copy( - signature = func.signature.copy( - receiver = func.signature.receiver.map { rcvr => - Contravariance( - newReceiver(rcvr.typ, ic._2, ic._1) - ) - } + }.map { + case (Some(from), to) => + func.copy( + signature = func.signature.copy( + receiver = func.signature.receiver.map { rcvr => + Contravariance( + newReceiver(rcvr.typ, to, from) + ) + } + ) + ) + case (None, to) => + func.copy( + signature = func.signature.copy( + receiver = None + ) ) - ) } Seq(func) ++ fromConversions } diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 53c997ea9c80..3e1a09574b16 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -46,10 +46,20 @@ trait InkuireSupport: if typ.isInstanceOf[Inkuire.Type] then { val t = typ.asInstanceOf[Inkuire.Type] val rhsTypeLike = typeDef.rhs.asInkuire(variableNames) - Inkuire.db = Inkuire.db.copy( - typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike), + val withType = Inkuire.db.copy( types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)) ) + typeDef.rhs match { + case TypeBoundsTree(_, r) if r.asInkuire(variableNames).isInstanceOf[Inkuire.Type] => + Inkuire.db = Inkuire.db.copy( + types = Inkuire.db.types.updated(t.itid.get, (t, Seq(r.asInkuire(variableNames).asInstanceOf[Inkuire.Type]))) + ) + case _ => + Inkuire.db = withType.copy( + types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)), + typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike) + ) + } } if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then val typJava = typeDef.rhs.asInkuire(variableNames) @@ -70,7 +80,7 @@ trait InkuireSupport: classDef.symbol.declaredMethods .filter(viableSymbol) .tap { _.foreach { // Loop for implicit conversions - case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) => + case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) || implicitConversion.flags.is(Flags.Given) => handleImplicitConversion(implicitConversion, variableNames) case _ => }} @@ -81,15 +91,15 @@ trait InkuireSupport: case TypeDef(name, _) => name } val vars = variableNames ++ methodVars - val receiver: Option[Inkuire.TypeLike] = - Some(classType) - .filter(_ => !isModule) - .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) + val (receiver, preArgs): (Option[Inkuire.TypeLike], Seq[Inkuire.TypeLike]) = Some(classType).filter(_ => !isModule) match { + case None => (methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)), Seq.empty) + case rcvr => (rcvr, methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)).toSeq) + } val (name, ownerName) = nameAndOwnerName(classDef, methodSymbol) val sgn = Inkuire.ExternalSignature( signature = Inkuire.Signature( receiver = receiver, - arguments = methodSymbol.nonExtensionTermParamLists.collect { + arguments = preArgs ++ methodSymbol.nonExtensionTermParamLists.collect { case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters }.flatten.map(_.tpt.asInkuire(vars)), result = defdef.returnTpt.asInkuire(vars), @@ -147,21 +157,17 @@ trait InkuireSupport: case v: ValDef => v.tpt.asInkuire(vars) } (from, to) match - case (Some(from), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from -> to)) + case (from, to: Inkuire.Type) => Inkuire.implicitConversions = Inkuire.implicitConversions :+ (from -> to) case _ => } private def nameAndOwnerName(classDef: ClassDef, symbol: Symbol): (String, String) = if classDef.symbol.flags.is(Flags.Module) || Seq("apply", "unapply").contains(symbol.name) then - ( - symbol.maybeOwner.normalizedName + "." + symbol.name, + symbol.maybeOwner.normalizedName + "." + symbol.name -> ownerNameChain(classDef.symbol.maybeOwner).mkString(".") - ) else - ( - symbol.name, + symbol.name -> ownerNameChain(classDef.symbol).mkString(".") - ) private def ownerNameChain(sym: Symbol): List[String] = if sym.isNoSymbol then List.empty @@ -192,7 +198,7 @@ trait InkuireSupport: partialAsInkuire(vars)(tpeTree) private def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.TypeLike] = { - case TypeBoundsTree(low, high) => inner(low.tpe, vars) //TODO [Inkuire] Type bounds + case tpeTree: TypeBoundsTree => inner(tpeTree.tpe, vars) case tpeTree: Applied => inner(tpeTree.tpe, vars) case tpeTree: TypeTree => @@ -285,72 +291,76 @@ trait InkuireSupport: case _ => false case _ => false - private def inner(tp: TypeRepr, vars: Set[String]): Inkuire.TypeLike = tp match - case OrType(left, right) => Inkuire.OrType(inner(left, vars), inner(right, vars)) - case AndType(left, right) => Inkuire.AndType(inner(left, vars), inner(right, vars)) - case ByNameType(tpe) => inner(tpe, vars) - case ConstantType(constant) => - Inkuire.Type( - name = Inkuire.TypeName(constant.toString), - params = Seq.empty, - itid = Some(Inkuire.ITID(constant.toString, isParsed = false)) - ) - case ThisType(tpe) => inner(tpe, vars) - case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedAnnotation(annotation) => - inner(tpe, vars) //TODO [Inkuire] Repeated types - case AppliedType(repeatedClass, Seq(tpe)) if isRepeated(repeatedClass) => - inner(tpe, vars) //TODO [Inkuire] Repeated types - case AnnotatedType(tpe, _) => - inner(tpe, vars) - case tl @ TypeLambda(paramNames, _, resType) => - Inkuire.TypeLambda(paramNames.map(Inkuire.TypeLambda.argument), inner(resType, vars)) //TODO [Inkuire] Type bounds - case r: Refinement => - inner(r.info, vars) //TODO [Inkuire] Refinements - case t @ AppliedType(tpe, typeList) => - import dotty.tools.dotc.util.Chars._ - if t.isFunctionType then - val name = s"Function${typeList.size-1}" + private def inner(tp: TypeRepr, vars: Set[String]): Inkuire.TypeLike = + tp match + case OrType(left, right) => Inkuire.OrType(inner(left, vars), inner(right, vars)) + case AndType(left, right) => Inkuire.AndType(inner(left, vars), inner(right, vars)) + case ByNameType(tpe) => inner(tpe, vars) + case ConstantType(constant) => Inkuire.Type( - name = Inkuire.TypeName(name), - params = typeList.init.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(typeList.last, vars)), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) + name = Inkuire.TypeName(constant.toString), + params = Seq.empty, + itid = Some(Inkuire.ITID(constant.toString, isParsed = false)) ) - else if t.isTupleN then - val name = s"Tuple${typeList.size}" + case ThisType(tpe) => inner(tpe, vars) + case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedAnnotation(annotation) => + inner(tpe, vars) //TODO [Inkuire] Repeated types + case AppliedType(repeatedClass, Seq(tpe)) if isRepeated(repeatedClass) => + inner(tpe, vars) //TODO [Inkuire] Repeated types + case AnnotatedType(tpe, _) => + inner(tpe, vars) + case tl @ TypeLambda(paramNames, _, resType) => + Inkuire.TypeLambda(paramNames.map(Inkuire.TypeLambda.argument), inner(resType, vars)) //TODO [Inkuire] Type bounds + case r: Refinement => + inner(r.info, vars) //TODO [Inkuire] Refinements + case t @ AppliedType(tpe, typeList) => + import dotty.tools.dotc.util.Chars._ + if t.isFunctionType then + val name = s"Function${typeList.size-1}" + Inkuire.Type( + name = Inkuire.TypeName(name), + params = typeList.init.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(typeList.last, vars)), + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) + ) + else if t.isTupleN then + val name = s"Tuple${typeList.size}" + Inkuire.Type( + name = Inkuire.TypeName(name), + params = typeList.map(p => Inkuire.Covariance(inner(p, vars))), + itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) + ) + else + inner(tpe, vars).asInstanceOf[Inkuire.Type].copy( + params = typeList.map(p => Inkuire.Invariance(inner(p, vars))) + ) + case tp: TypeRef => + Inkuire.Type( + name = Inkuire.TypeName(tp.name), + itid = tp.typeSymbol.itid, + params = Seq.empty, + isVariable = vars.contains(tp.name) + ) + case tr @ TermRef(qual, typeName) => + inner(qual, vars) + case tb@TypeBounds(low, hi) => + if low.typeSymbol != defn.NothingClass || hi.typeSymbol == defn.AnyClass then + inner(low, vars) //TODO [Inkuire] Type bounds + else + inner(hi, vars) + case NoPrefix() => + Inkuire.Type.unresolved //TODO [Inkuire] <- should be handled by Singleton case, but didn't work + case MatchType(bond, sc, cases) => + inner(sc, vars) + case ParamRef(TypeLambda(names, _, _), i) => + Inkuire.TypeLambda.argument(names(i)) + case ParamRef(m: MethodType, i) => + inner(m.paramTypes(i), vars) + case RecursiveType(tp) => + inner(tp, vars) + case m@MethodType(_, typeList, resType) => + val name = s"Function${typeList.size-1}" Inkuire.Type( name = Inkuire.TypeName(name), - params = typeList.map(p => Inkuire.Covariance(inner(p, vars))), + params = typeList.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(resType, vars)), itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) ) - else - inner(tpe, vars).asInstanceOf[Inkuire.Type].copy( - params = typeList.map(p => Inkuire.Invariance(inner(p, vars))) - ) - case tp: TypeRef => - Inkuire.Type( - name = Inkuire.TypeName(tp.name), - itid = tp.typeSymbol.itid, - params = Seq.empty, - isVariable = vars.contains(tp.name) - ) - case tr @ TermRef(qual, typeName) => - inner(qual, vars) - case TypeBounds(low, hi) => - inner(low, vars) //TODO [Inkuire] Type bounds - case NoPrefix() => - Inkuire.Type.unresolved //TODO [Inkuire] <- should be handled by Singleton case, but didn't work - case MatchType(bond, sc, cases) => - inner(sc, vars) - case ParamRef(TypeLambda(names, _, _), i) => - Inkuire.TypeLambda.argument(names(i)) - case ParamRef(m: MethodType, i) => - inner(m.paramTypes(i), vars) - case RecursiveType(tp) => - inner(tp, vars) - case m@MethodType(_, typeList, resType) => - val name = s"Function${typeList.size-1}" - Inkuire.Type( - name = Inkuire.TypeName(name), - params = typeList.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(resType, vars)), - itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) - ) From 10cf3399390ecc8a80b69b5f444c841e817e8473 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 2 Sep 2021 13:23:30 +0200 Subject: [PATCH 14/16] Bump inkuire version --- project/Build.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Build.scala b/project/Build.scala index 9f2e1bc973d7..02ef660048fd 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1327,7 +1327,7 @@ object Build { import _root_.scala.sys.process._ import _root_.scala.concurrent._ import ExecutionContext.Implicits.global - val inkuireVersion = "1.0.0-M2" + val inkuireVersion = "1.0.0-M3" val inkuireLink = s"https://github.com/VirtusLab/Inkuire/releases/download/$inkuireVersion/inkuire.js" val inkuireDestinationFile = (Compile / resourceManaged).value / "dotty_res" / "scripts" / "inkuire.js" sbt.IO.touch(inkuireDestinationFile) From f117898f223f35fb7ddafe590f880572e22acd07 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 2 Sep 2021 14:24:53 +0200 Subject: [PATCH 15/16] fix tests --- scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index 3bc1678bff2b..cd079e8f237a 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -14,7 +14,7 @@ object SymOps: def isImplicitClass: Boolean = import reflect._ - sym.maybeOwner != Symbol.noSymbol + sym.isClassDef && sym.maybeOwner != Symbol.noSymbol && sym.maybeOwner.declaredMethods.exists { methodSymbol => methodSymbol.name == sym.name && methodSymbol.flags.is(Flags.Implicit) && methodSymbol.flags.is(Flags.Method) } From b8fa6d713be60636023442578f1ebb06e3766b6b Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 6 Sep 2021 09:36:40 +0200 Subject: [PATCH 16/16] Review changes --- scaladoc-js/src/searchbar/SearchbarComponent.scala | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/scaladoc-js/src/searchbar/SearchbarComponent.scala b/scaladoc-js/src/searchbar/SearchbarComponent.scala index 3a264af19a3b..c77c8b6b9d83 100644 --- a/scaladoc-js/src/searchbar/SearchbarComponent.scala +++ b/scaladoc-js/src/searchbar/SearchbarComponent.scala @@ -1,6 +1,7 @@ package dotty.tools.scaladoc import org.scalajs.dom._ +import org.scalajs.dom.ext._ import org.scalajs.dom.html.Input import scala.scalajs.js.timers._ import scala.concurrent.duration._ @@ -133,15 +134,12 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch loading.appendChild(animation) properResultsDiv.appendChild(loading) inkuireEngine.query(query) { (m: InkuireMatch) => - var next: Option[Element] = None - 0.until(properResultsDiv.children.length).foreach { i => - val child = properResultsDiv.children(i) - val attr = child.getAttribute("mq") - if attr != null && attr != "" && Integer.parseInt(attr) > m.mq && next.isEmpty then { - next = Some(child) - } + val next = properResultsDiv.children.foldLeft[Option[Element]](None) { + case (acc, child) if !acc.isEmpty => acc + case (_, child) => + Option.when(child.hasAttribute("mq") && Integer.parseInt(child.getAttribute("mq")) > m.mq)(child) } - next.fold{ + next.fold { properResultsDiv.appendChild(m.toHTML) } { next => properResultsDiv.insertBefore(m.toHTML, next)