From d220fe347b19e6d550ea80ad4ac8d5602aa52bfd Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Wed, 14 Jul 2021 13:58:16 +0200 Subject: [PATCH 01/18] Remove isVariable flag --- .../scaladoc/tasty/ClassLikeSupport.scala | 18 +++++++------- .../tools/scaladoc/tasty/InkuireSupport.scala | 24 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 53cf0ced6fbb..0e99d353a736 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -96,10 +96,10 @@ trait ClassLikeSupport: if summon[DocContext].args.generateInkuire then { - val classType = classDef.asInkuire(Set.empty, true) + val classType = classDef.asInkuire(Set.empty) val variableNames = classType.params.map(_.typ.name.name).toSet - val parents = classDef.parents.map(_.asInkuire(variableNames, false)) + val parents = classDef.parents.map(_.asInkuire(variableNames)) val isModule = classDef.symbol.flags.is(Flags.Module) @@ -109,8 +109,8 @@ trait ClassLikeSupport: case typeSymbol: Symbol => val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] if typeDef.rhs.symbol.fullName.contains("java") then - val t = typeSymbol.tree.asInkuire(variableNames, false) // TODO [Inkuire] Hack until type aliases are supported - val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames, false) + val t = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported + val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames) Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) // TODO [Inkuire] Hack until type aliases are supported Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) } @@ -126,9 +126,9 @@ trait ClassLikeSupport: && classDef.symbol.flags.is(Flags.Module) && implicitConversion.owner.fullName == ("scala.Predef$") => val defdef = implicitConversion.tree.asInstanceOf[DefDef] - val to = defdef.returnTpt.asInkuire(variableNames, false) + val to = defdef.returnTpt.asInkuire(variableNames) val from = defdef.paramss.flatMap(_.params).collectFirst { - case v: ValDef => v.tpt.asInkuire(variableNames, false) + case v: ValDef => v.tpt.asInkuire(variableNames) } from match case Some(from) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) @@ -143,14 +143,14 @@ trait ClassLikeSupport: val receiver: Option[Inkuire.Type] = Some(classType) .filter(_ => !isModule) - .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars, false).lift(s.tpt))) + .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) val sgn = Inkuire.ExternalSignature( signature = Inkuire.Signature( receiver = receiver, arguments = methodSymbol.nonExtensionParamLists.flatMap(_.params).collect { - case ValDef(_, tpe, _) => tpe.asInkuire(vars, false) + case ValDef(_, tpe, _) => tpe.asInkuire(vars) }, - result = defdef.returnTpt.asInkuire(vars, false), + result = defdef.returnTpt.asInkuire(vars), context = Inkuire.SignatureContext( vars = vars.toSet, constraints = Map.empty //TODO [Inkuire] Type bounds diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index fbb466ffc1e6..3b83ff06d652 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -17,24 +17,24 @@ trait InkuireSupport: private given qctx.type = qctx - private def paramsForClass(classDef: ClassDef, vars: Set[String], isVariable: Boolean): Seq[Inkuire.Variance] = - classDef.getTypeParams.map(mkTypeArgumentInkuire(_, vars, isVariable)) + private def paramsForClass(classDef: ClassDef, vars: Set[String]): Seq[Inkuire.Variance] = + classDef.getTypeParams.map(mkTypeArgumentInkuire(_, vars)) given TreeSyntaxInkuire: AnyRef with extension (tpeTree: Tree) - def asInkuire(vars: Set[String], isVariable: Boolean): Inkuire.Type = - partialAsInkuire(vars, isVariable)(tpeTree) + def asInkuire(vars: Set[String]): Inkuire.Type = + partialAsInkuire(vars)(tpeTree) - def partialAsInkuire(vars: Set[String], isVariable: Boolean): PartialFunction[Tree, Inkuire.Type] = { + def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.Type] = { case TypeBoundsTree(low, high) => inner(low.tpe, vars) //TODO [Inkuire] Type bounds case tpeTree: Applied => inner(tpeTree.tpe, vars).copy( - params = tpeTree.args.map(p => Inkuire.Invariance(p.asInkuire(vars, isVariable))) + params = tpeTree.args.map(p => Inkuire.Invariance(p.asInkuire(vars))) ) case tpeTree: TypeTree => inner(tpeTree.tpe, vars) case term: Term => inner(term.tpe, vars) - case classDef: ClassDef => mkTypeFromClassDef(classDef, vars, isVariable) + case classDef: ClassDef => mkTypeFromClassDef(classDef, vars) case typeDef: TypeDef => Inkuire.Type( name = Inkuire.TypeName(typeDef.name), @@ -42,11 +42,11 @@ trait InkuireSupport: ) } - def mkTypeFromClassDef(classDef: ClassDef, vars: Set[String], isVariable: Boolean): Inkuire.Type = { + def mkTypeFromClassDef(classDef: ClassDef, vars: Set[String]): Inkuire.Type = { Inkuire.Type( name = Inkuire.TypeName(classDef.name), itid = classDef.symbol.itid, - params = paramsForClass(classDef, vars, isVariable) + params = paramsForClass(classDef, vars) ) } @@ -58,13 +58,13 @@ trait InkuireSupport: extension (tpe: TypeRepr) def asInkuire(vars: Set[String]): Inkuire.Type = inner(tpe, vars) - def mkTypeArgumentInkuire(argument: TypeDef, vars: Set[String] = Set.empty, isVariable: Boolean = false): Inkuire.Variance = + def mkTypeArgumentInkuire(argument: TypeDef, vars: Set[String] = Set.empty): Inkuire.Variance = val name = argument.symbol.normalizedName val normalizedName = if name.matches("_\\$\\d*") then "_" else name val t = Inkuire.Type( name = Inkuire.TypeName(normalizedName), itid = argument.symbol.itid, - isVariable = vars.contains(normalizedName) || isVariable, + isVariable = true, params = Seq.empty //TODO [Inkuire] Type Lambdas ) if argument.symbol.flags.is(Flags.Covariant) then Inkuire.Covariance(t) @@ -141,7 +141,7 @@ trait InkuireSupport: 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, _, resType), i) => + case ParamRef(TypeLambda(names, _, _), i) => Inkuire.Type( name = Inkuire.TypeName(names(i)), itid = Some(Inkuire.ITID(s"external-itid-${names(i)}", isParsed = false)), From c885a7c5cb209bc75a41d2eac832300a4802d0bc Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Wed, 14 Jul 2021 14:38:06 +0200 Subject: [PATCH 02/18] Encode HKT class type parameters (semi) correctly --- scaladoc/src/dotty/tools/scaladoc/Inkuire.scala | 7 +++++++ .../tools/scaladoc/tasty/InkuireSupport.scala | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 2a96a0b8cc85..11662b08f0b1 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -70,6 +70,13 @@ object Inkuire { ) ) ) + + def StarProjection: Type = + Type( + name = TypeName("_"), + itid = Some(ITID("_", isParsed = false)), + isStarProjection = true + ) } case class TypeName(name: String) { diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 3b83ff06d652..d220e112e0ad 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -18,7 +18,7 @@ trait InkuireSupport: private given qctx.type = qctx private def paramsForClass(classDef: ClassDef, vars: Set[String]): Seq[Inkuire.Variance] = - classDef.getTypeParams.map(mkTypeArgumentInkuire(_, vars)) + classDef.getTypeParams.map(mkTypeArgumentInkuire) given TreeSyntaxInkuire: AnyRef with extension (tpeTree: Tree) @@ -58,19 +58,28 @@ trait InkuireSupport: extension (tpe: TypeRepr) def asInkuire(vars: Set[String]): Inkuire.Type = inner(tpe, vars) - def mkTypeArgumentInkuire(argument: TypeDef, vars: Set[String] = Set.empty): Inkuire.Variance = + 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 + val params = 1.to(typeVariableDeclarationParamsNo(argument)).map(_ => Inkuire.Type.StarProjection) val t = Inkuire.Type( name = Inkuire.TypeName(normalizedName), itid = argument.symbol.itid, isVariable = true, - params = Seq.empty //TODO [Inkuire] Type Lambdas + params = params.map(Inkuire.Invariance(_)) ) if argument.symbol.flags.is(Flags.Covariant) then Inkuire.Covariance(t) else if argument.symbol.flags.is(Flags.Contravariant) then Inkuire.Contravariance(t) else Inkuire.Invariance(t) + def typeVariableDeclarationParamsNo(argument: TypeDef): Int = + argument.rhs match + case t: TypeTree => t.tpe match + case TypeBounds(_, TypeLambda(names, _, _)) => names.size + case _ => 0 + case _ => 0 + private def isRepeatedAnnotation(term: Term) = term.tpe match case t: TypeRef => t.name == "Repeated" && t.qualifier.match From b93a9b5069eb19b754a4ecbc4eaf3773b4227e71 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 15 Jul 2021 16:03:11 +0200 Subject: [PATCH 03/18] And/OrTypes + TypeLambdas --- .../src/dotty/tools/scaladoc/Inkuire.scala | 87 +++++++++++++------ .../scaladoc/tasty/ClassLikeSupport.scala | 30 +++++-- .../tools/scaladoc/tasty/InkuireSupport.scala | 47 ++++++---- 3 files changed, 111 insertions(+), 53 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 11662b08f0b1..8ec57877f964 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -38,7 +38,7 @@ object Inkuire { } object Signature { - def apply(receiver: Option[Type], arguments: Seq[Type], result: Type, context: SignatureContext): Signature = + def apply(receiver: Option[TypeLike], arguments: Seq[TypeLike], result: TypeLike, context: SignatureContext): Signature = Signature(receiver.map(Contravariance(_)), arguments.map(Contravariance(_)), Covariance(result), context) } @@ -49,15 +49,32 @@ object Inkuire { uri: String ) + sealed trait TypeLike + case class Type( - name: TypeName, - params: Seq[Variance] = Seq.empty, - nullable: Boolean = false, - itid: Option[ITID] = None, - isVariable: Boolean = false, + name: TypeName, + params: Seq[Variance] = Seq.empty, + nullable: Boolean = false, + itid: Option[ITID] = None, + isVariable: Boolean = false, isStarProjection: Boolean = false, - isUnresolved: Boolean = false - ) + isUnresolved: Boolean = false + ) extends TypeLike + + case class AndType(left: TypeLike, right: TypeLike) extends TypeLike + case class OrType(left: TypeLike, right: TypeLike) extends TypeLike + + case class TypeLambda(args: Seq[Type], result: TypeLike) extends TypeLike + + object TypeLambda { + def argument(name: String): Type = + val uuid = s"external-type-lambda-arg-$name" + Inkuire.Type( + name = Inkuire.TypeName(name), + itid = Some(Inkuire.ITID(uuid, isParsed = false)), + isVariable = true + ) + } object Type { def unresolved: Type = @@ -94,7 +111,7 @@ object Inkuire { case class SignatureContext( vars: Set[String], - constraints: Map[String, Seq[Type]] + constraints: Map[String, Seq[TypeLike]] ) { override def hashCode: Int = vars.size.hashCode @@ -110,16 +127,16 @@ object Inkuire { } sealed abstract class Variance { - val typ: Type + val typ: TypeLike } - case class Covariance(typ: Type) extends Variance + case class Covariance(typ: TypeLike) extends Variance - case class Contravariance(typ: Type) extends Variance + case class Contravariance(typ: TypeLike) extends Variance - case class Invariance(typ: Type) extends Variance + case class Invariance(typ: TypeLike) extends Variance - case class UnresolvedVariance(typ: Type) extends Variance + case class UnresolvedVariance(typ: TypeLike) extends Variance object EngineModelSerializers { def serialize(db: InkuireDb): JSON = { @@ -161,16 +178,36 @@ object Inkuire { ) } - private def serialize(t: Type): JSON = { - jsonObject( - ("name", serialize(t.name)), - ("params", jsonList(t.params.map(serialize))), - ("nullable", serialize(t.nullable)), - ("itid", serialize(t.itid.get)), - ("isVariable", serialize(t.isVariable)), - ("isStarProjection", serialize(t.isStarProjection)), - ("isUnresolved", serialize(t.isUnresolved)) - ) + private def serialize(t: TypeLike): JSON = t match { + case t: Type => + jsonObject( + ("name", serialize(t.name)), + ("params", jsonList(t.params.map(serialize))), + ("nullable", serialize(t.nullable)), + ("itid", serialize(t.itid.get)), + ("isVariable", serialize(t.isVariable)), + ("isStarProjection", serialize(t.isStarProjection)), + ("isUnresolved", serialize(t.isUnresolved)), + ("typelikekind", serialize("type")) + ) + case t: OrType => + jsonObject( + ("left", serialize(t.left)), + ("right", serialize(t.right)), + ("typelikekind", serialize("ortype")) + ) + case t: AndType => + jsonObject( + ("left", serialize(t.left)), + ("right", serialize(t.right)), + ("typelikekind", serialize("andtype")) + ) + case t: TypeLambda => + jsonObject( + ("args", jsonList(t.args.map(serialize))), + ("result", serialize(t.result)), + ("typelikekind", serialize("typelambda")) + ) } private def serialize(b: Boolean): JSON = { @@ -248,7 +285,7 @@ object Inkuire { ) } - private def serializeConstraints(constraints: Map[String, Seq[Type]]): JSON = { + private def serializeConstraints(constraints: Map[String, Seq[TypeLike]]): JSON = { jsonObject(( constraints.toList.map { case (name, vs) => diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 0e99d353a736..3fed75b1e304 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -96,10 +96,18 @@ trait ClassLikeSupport: if summon[DocContext].args.generateInkuire then { - val classType = classDef.asInkuire(Set.empty) - val variableNames = classType.params.map(_.typ.name.name).toSet + val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type] - val parents = classDef.parents.map(_.asInkuire(variableNames)) + 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) @@ -111,8 +119,12 @@ trait ClassLikeSupport: if typeDef.rhs.symbol.fullName.contains("java") then val t = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames) - Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) // TODO [Inkuire] Hack until type aliases are supported - Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) + t match + case t: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) // TODO [Inkuire] Hack until type aliases are supported + case _ => + tJava match + case tJava: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) + case _ => } classDef.symbol.declaredMethods @@ -130,9 +142,9 @@ trait ClassLikeSupport: val from = defdef.paramss.flatMap(_.params).collectFirst { case v: ValDef => v.tpt.asInkuire(variableNames) } - from match - case Some(from) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to)) - case None => + (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 methodSymbol: Symbol => val defdef = methodSymbol.tree.asInstanceOf[DefDef] @@ -140,7 +152,7 @@ trait ClassLikeSupport: case TypeDef(name, _) => name } val vars = variableNames ++ methodVars - val receiver: Option[Inkuire.Type] = + val receiver: Option[Inkuire.TypeLike] = Some(classType) .filter(_ => !isModule) .orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt))) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index d220e112e0ad..81a107548c5f 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -5,6 +5,7 @@ import dotty.tools.scaladoc._ import dotty.tools.scaladoc.{Signature => DSignature} import dotty.tools.scaladoc.Inkuire +import scala.util.Random import scala.quoted._ import SymOps._ @@ -22,15 +23,13 @@ trait InkuireSupport: given TreeSyntaxInkuire: AnyRef with extension (tpeTree: Tree) - def asInkuire(vars: Set[String]): Inkuire.Type = + def asInkuire(vars: Set[String]): Inkuire.TypeLike = partialAsInkuire(vars)(tpeTree) - def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.Type] = { + 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).copy( - params = tpeTree.args.map(p => Inkuire.Invariance(p.asInkuire(vars))) - ) + inner(tpeTree.tpe, vars) case tpeTree: TypeTree => inner(tpeTree.tpe, vars) case term: Term => inner(term.tpe, vars) @@ -56,19 +55,33 @@ trait InkuireSupport: given TypeSyntaxInkuire: AnyRef with extension (tpe: TypeRepr) - def asInkuire(vars: Set[String]): Inkuire.Type = inner(tpe, vars) + def asInkuire(vars: Set[String]): Inkuire.TypeLike = inner(tpe, vars) + + private def genDummyTypeArgs(n: Int) = + 1.to(n).map { i => + val uuid = s"dummy-arg$i${Random.nextString(10)}" + val name = s"X$i" + Inkuire.Type( + name = Inkuire.TypeName(name), + itid = Some(Inkuire.ITID(uuid, isParsed = false)), + isVariable = true + ) + } 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 - val params = 1.to(typeVariableDeclarationParamsNo(argument)).map(_ => Inkuire.Type.StarProjection) - val t = Inkuire.Type( + val params = genDummyTypeArgs(typeVariableDeclarationParamsNo(argument)) + val res = Inkuire.Type( name = Inkuire.TypeName(normalizedName), itid = argument.symbol.itid, isVariable = true, params = params.map(Inkuire.Invariance(_)) ) + val t = params.toList match + case Nil => res + case _ => Inkuire.TypeLambda(params, res) if argument.symbol.flags.is(Flags.Covariant) then Inkuire.Covariance(t) else if argument.symbol.flags.is(Flags.Contravariant) then Inkuire.Contravariance(t) else Inkuire.Invariance(t) @@ -94,9 +107,9 @@ trait InkuireSupport: case _ => false case _ => false - private def inner(tp: TypeRepr, vars: Set[String]): Inkuire.Type = tp match - case OrType(left, right) => inner(left, vars) //TODO [Inkuire] Or/AndTypes - case AndType(left, right) => inner(left, vars) //TODO [Inkuire] Or/AndTypes + 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( @@ -111,8 +124,8 @@ trait InkuireSupport: inner(tpe, vars) //TODO [Inkuire] Repeated types case AnnotatedType(tpe, _) => inner(tpe, vars) - case tl @ TypeLambda(params, paramBounds, resType) => - inner(resType, vars) //TODO [Inkuire] Type lambdas + 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) => @@ -132,7 +145,7 @@ trait InkuireSupport: itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false)) ) else - inner(tpe, vars).copy( + inner(tpe, vars).asInstanceOf[Inkuire.Type].copy( params = typeList.map(p => Inkuire.Invariance(inner(p, vars))) ) case tp: TypeRef => @@ -151,11 +164,7 @@ trait InkuireSupport: case MatchType(bond, sc, cases) => inner(sc, vars) case ParamRef(TypeLambda(names, _, _), i) => - Inkuire.Type( - name = Inkuire.TypeName(names(i)), - itid = Some(Inkuire.ITID(s"external-itid-${names(i)}", isParsed = false)), - isVariable = true - ) + Inkuire.TypeLambda.argument(names(i)) case ParamRef(m: MethodType, i) => inner(m.paramTypes(i), vars) case RecursiveType(tp) => From 439c60c18be931444e0317314e43821fa403d87a Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 15 Jul 2021 20:06:57 +0200 Subject: [PATCH 04/18] Change synthetic type lambda argument itid generation --- .../src/dotty/tools/scaladoc/tasty/InkuireSupport.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 81a107548c5f..f478fae220f3 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -57,9 +57,9 @@ trait InkuireSupport: extension (tpe: TypeRepr) def asInkuire(vars: Set[String]): Inkuire.TypeLike = inner(tpe, vars) - private def genDummyTypeArgs(n: Int) = + private def genSyntheticTypeArgs(n: Int) = 1.to(n).map { i => - val uuid = s"dummy-arg$i${Random.nextString(10)}" + val uuid = s"synthetic-arg$i${Random.nextString(10)}" val name = s"X$i" Inkuire.Type( name = Inkuire.TypeName(name), @@ -72,7 +72,7 @@ trait InkuireSupport: //TODO [Inkuire] Type bounds (other than just HKTs) val name = argument.symbol.normalizedName val normalizedName = if name.matches("_\\$\\d*") then "_" else name - val params = genDummyTypeArgs(typeVariableDeclarationParamsNo(argument)) + val params = genSyntheticTypeArgs(typeVariableDeclarationParamsNo(argument)) val res = Inkuire.Type( name = Inkuire.TypeName(normalizedName), itid = argument.symbol.itid, From cf508b6c3ba37c1ab5cfd174560d04bdeb08cacc Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 16 Jul 2021 11:13:40 +0200 Subject: [PATCH 05/18] Do not generate entries for synthetic methods --- scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 3fed75b1e304..378561d213b5 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -131,7 +131,8 @@ trait ClassLikeSupport: .filter { (s: Symbol) => !s.flags.is(Flags.Private) && !s.flags.is(Flags.Protected) && - !s.flags.is(Flags.Override) + !s.flags.is(Flags.Override) && + !s.flags.is(Flags.Synthetic) } .foreach { case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) From f67089a65a406d42d5db1c8a51ba71ef8829d6d7 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 16 Jul 2021 11:27:46 +0200 Subject: [PATCH 06/18] More sane Java classes hack --- scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 378561d213b5..962bf3a6465d 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -116,7 +116,7 @@ trait ClassLikeSupport: classDef.symbol.declaredTypes.foreach { case typeSymbol: Symbol => val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] - if typeDef.rhs.symbol.fullName.contains("java") then + if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then val t = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames) t match From 715ffe284703ed8ae652a2f69ef86d4d9e368fee Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 16 Jul 2021 13:49:26 +0200 Subject: [PATCH 07/18] Better loading animation --- scaladoc/resources/dotty_res/styles/search-bar.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scaladoc/resources/dotty_res/styles/search-bar.css b/scaladoc/resources/dotty_res/styles/search-bar.css index f778bf43c186..c00e341bea59 100644 --- a/scaladoc/resources/dotty_res/styles/search-bar.css +++ b/scaladoc/resources/dotty_res/styles/search-bar.css @@ -77,7 +77,7 @@ border-radius: 5px; background-color: var(--shadow); color: var(--shadow); - animation: dotFlashing 1s infinite alternate; + animation: dotFlashing .4s infinite alternate; display: inline-block; position: absolute; top: 0; @@ -86,7 +86,7 @@ .loading { left: 50%; position: relative; - animation-delay: .5s; + animation-delay: .2s; } .loading::before { @@ -96,7 +96,7 @@ .loading::after { left: 15px; - animation-delay: 1s; + animation-delay: .4s; } @keyframes dotFlashing { From de0f6a3d1707881ea1bdbf592c5bd79de8391af9 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 16 Jul 2021 16:40:42 +0200 Subject: [PATCH 08/18] Opaque types --- .../tools/scaladoc/tasty/ClassLikeSupport.scala | 5 +++++ .../tools/scaladoc/tasty/InkuireSupport.scala | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 962bf3a6465d..82f34b444340 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -114,6 +114,11 @@ trait ClassLikeSupport: if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents))) classDef.symbol.declaredTypes.foreach { + case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) => + val t = typeSymbol.tree.asInkuire(variableNames) + t match + case t: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) + case _ => case typeSymbol: Symbol => val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index f478fae220f3..761c52e28fb2 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -34,7 +34,20 @@ trait InkuireSupport: inner(tpeTree.tpe, vars) case term: Term => inner(term.tpe, vars) case classDef: ClassDef => mkTypeFromClassDef(classDef, vars) - case typeDef: TypeDef => + case typeDef: TypeDef => mkTypeDef(typeDef) + } + + 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 + val params = paramsDefs.map(_.name).map(Inkuire.TypeLambda.argument) + Inkuire.Type( + name = Inkuire.TypeName(normalizedName), + itid = typeDef.symbol.itid, + params = params.map(Inkuire.Invariance(_)) + ) + case _ => Inkuire.Type( name = Inkuire.TypeName(typeDef.name), itid = typeDef.symbol.itid From fb25987a443e756334a9db0f8464f1d9110d566a Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 16 Jul 2021 16:56:44 +0200 Subject: [PATCH 09/18] Make error handling readable --- .../scaladoc/tasty/ClassLikeSupport.scala | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 82f34b444340..4ce5e85a8779 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -115,21 +115,24 @@ trait ClassLikeSupport: classDef.symbol.declaredTypes.foreach { case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) => - val t = typeSymbol.tree.asInkuire(variableNames) - t match - case t: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) - case _ => + 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 => val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then - val t = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported - val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames) - t match - case t: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) // TODO [Inkuire] Hack until type aliases are supported - case _ => - tJava match - case tJava: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty))) - case _ => + val typ = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported + val typJava = typeDef.rhs.symbol.tree.asInkuire(variableNames) + if typ.isInstanceOf[Inkuire.Type] then { // TODO [Inkuire] Hack until type aliases are supported + val t = typ.asInstanceOf[Inkuire.Type] + Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) + } + 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))) + } } classDef.symbol.declaredMethods From cf0cfd3832795f8b205a0cfa2302aba8a21a1dcb Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 19 Jul 2021 11:11:31 +0200 Subject: [PATCH 10/18] Type aliases --- .../src/dotty/tools/scaladoc/Inkuire.scala | 17 +++++-- .../scaladoc/tasty/ClassLikeSupport.scala | 49 ++++++++++--------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 8ec57877f964..b0da461370eb 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -5,7 +5,7 @@ import scala.collection.mutable.{ Map => MMap} object Inkuire { - var db = InkuireDb(Seq.empty, Map.empty, Seq.empty) + var db = InkuireDb(Seq.empty, Map.empty, Seq.empty, Map.empty) def beforeSave(): Unit = { db = db.copy( @@ -23,7 +23,8 @@ object Inkuire { case class InkuireDb( functions: Seq[ExternalSignature], types: Map[ITID, (Type, Seq[Type])], - implicitConversions: Seq[(ITID, Type)] + implicitConversions: Seq[(ITID, Type)], + typeAliases: Map[ITID, TypeLike] ) case class ITID(uuid: String, isParsed: Boolean) @@ -143,7 +144,8 @@ object Inkuire { jsonObject( ("types", serialize(db.types)), ("functions", jsonList(db.functions.map(serialize))), - ("implicitConversions", jsonList(db.implicitConversions.map(serializeConversion))) + ("implicitConversions", jsonList(db.implicitConversions.map(serializeConversion))), + ("typeAliases", serializeTypeAliases(db.typeAliases)) ) } @@ -165,6 +167,15 @@ object Inkuire { )*) } + private def serializeTypeAliases(types: Map[ITID, TypeLike]): JSON = { + jsonObject(( + types.toList.map { + case (itid, v) => + (serializeAsKey(itid), serialize(v)) + } + )*) + } + private def serializeAsKey(itid: ITID): String = { s"""${itid.isParsed}=${itid.uuid}""" } diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 4ce5e85a8779..831628cac409 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -113,35 +113,40 @@ trait ClassLikeSupport: if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents))) - classDef.symbol.declaredTypes.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 => - val typeDef = typeSymbol.tree.asInstanceOf[TypeDef] - if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then - val typ = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported - val typJava = typeDef.rhs.symbol.tree.asInkuire(variableNames) - if typ.isInstanceOf[Inkuire.Type] then { // TODO [Inkuire] Hack until type aliases are supported + 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))) } - 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 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)) } + 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 { (s: Symbol) => - !s.flags.is(Flags.Private) && - !s.flags.is(Flags.Protected) && - !s.flags.is(Flags.Override) && - !s.flags.is(Flags.Synthetic) - } + .filter(viableSymbol) .foreach { case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) && classDef.symbol.flags.is(Flags.Module) From a8164c452aef4e020b5f28f1e8e8b8da04d89686 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 19 Jul 2021 11:21:37 +0200 Subject: [PATCH 11/18] Generate type entries for type alias lhs --- .../src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 831628cac409..60e9790d5284 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -128,7 +128,10 @@ trait ClassLikeSupport: 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)) + 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) From 649a97735076e7a8d4c49eab1d74621127e5cf46 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Wed, 21 Jul 2021 11:06:46 +0200 Subject: [PATCH 12/18] Ignore implicit parameter lists --- .../src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 60e9790d5284..ff7d2988c048 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -176,9 +176,9 @@ trait ClassLikeSupport: val sgn = Inkuire.ExternalSignature( signature = Inkuire.Signature( receiver = receiver, - arguments = methodSymbol.nonExtensionParamLists.flatMap(_.params).collect { - case ValDef(_, tpe, _) => tpe.asInkuire(vars) - }, + arguments = methodSymbol.nonExtensionParamLists.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, From 3aece075dbc04ccbe78c0e93c5323510b919395d Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 22 Jul 2021 16:44:04 +0200 Subject: [PATCH 13/18] Add serializing vals --- .../engine/InkuireJSSearchEngine.scala | 2 +- .../src/dotty/tools/scaladoc/Inkuire.scala | 6 ++-- .../scaladoc/tasty/ClassLikeSupport.scala | 28 ++++++++++++++++++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala b/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala index 5b91512a46f7..f89a6498aa90 100644 --- a/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala +++ b/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala @@ -22,7 +22,7 @@ class InkuireJSSearchEngine { d.prettifiedSignature.asInstanceOf[String], d.pageLocation.asInstanceOf[String], d.functionName.asInstanceOf[String], - "def", + d.entryType.asInstanceOf[String], List.empty ) } diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index b0da461370eb..926911a2ae2d 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -47,7 +47,8 @@ object Inkuire { signature: Signature, name: String, packageName: String, - uri: String + uri: String, + entryType: String ) sealed trait TypeLike @@ -266,7 +267,8 @@ object Inkuire { ("signature", serialize(e.signature)), ("name", serialize(e.name)), ("packageName", serialize(e.packageName)), - ("uri", serialize(e.uri)) + ("uri", serialize(e.uri)), + ("entryType", serialize(e.entryType)) ) } diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index ff7d2988c048..e06075fc383e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -187,11 +187,37 @@ trait ClassLikeSupport: ), name = methodSymbol.name, packageName = methodSymbol.dri.location, - uri = methodSymbol.dri.externalLink.getOrElse("") + uri = methodSymbol.dri.externalLink.getOrElse(""), + entryType = "def" ) Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ sgn) } + 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" + ) + Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ sgn) + } } if signatureOnly then baseMember else baseMember.copy( From 60369fb2a836888ad5e264f8c0015646a89e280f Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Thu, 22 Jul 2021 21:06:38 +0200 Subject: [PATCH 14/18] Add currying signatures --- scaladoc-testcases/src/tests/inkuire.scala | 5 +++++ scaladoc/src/dotty/tools/scaladoc/Inkuire.scala | 13 ++++++++++++- .../tools/scaladoc/tasty/ClassLikeSupport.scala | 6 ++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/scaladoc-testcases/src/tests/inkuire.scala b/scaladoc-testcases/src/tests/inkuire.scala index 1f50fc63858c..2d70a70fb6f5 100644 --- a/scaladoc-testcases/src/tests/inkuire.scala +++ b/scaladoc-testcases/src/tests/inkuire.scala @@ -13,3 +13,8 @@ class JustAClass { class JustAnotherClass extends JustAClass { def method(i: InType2): OutType2 = ??? } + +object InkuireObject { + def function(i: InType1): OutType1 = ??? + val value: InType1 => OutType1 = ??? +} \ No newline at end of file diff --git a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala index 926911a2ae2d..fa663d5af5f9 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Inkuire.scala @@ -1,7 +1,6 @@ package dotty.tools.scaladoc import dotty.tools.scaladoc.util._ -import scala.collection.mutable.{ Map => MMap} object Inkuire { @@ -20,6 +19,18 @@ object Inkuire { jsonObject(("inkuirePaths", jsonList(paths))).toString } + def curry(e: Signature): Signature = { + e.result.typ match + case t: Type if t.name.name == s"Function${t.params.size-1}" => + curry( + e.copy( + arguments = e.arguments ++ t.params.init.map(_.typ).map(Contravariance(_)), + result = Covariance(t.params.last.typ) + ) + ) + case _ => e + } + case class InkuireDb( functions: Seq[ExternalSignature], types: Map[ITID, (Type, Seq[Type])], diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index e06075fc383e..bcc0d1a47039 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -190,7 +190,8 @@ trait ClassLikeSupport: uri = methodSymbol.dri.externalLink.getOrElse(""), entryType = "def" ) - Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ sgn) + val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) + Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) } classDef.symbol.declaredFields @@ -216,7 +217,8 @@ trait ClassLikeSupport: uri = valSymbol.dri.externalLink.getOrElse(""), entryType = "val" ) - Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ sgn) + val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature)) + Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn) } } From 4c98e1168b3f16deb5f7c1cf5ec28808194dd3ff Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 23 Jul 2021 19:10:42 +0200 Subject: [PATCH 15/18] Better loading animation --- .../resources/dotty_res/styles/search-bar.css | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scaladoc/resources/dotty_res/styles/search-bar.css b/scaladoc/resources/dotty_res/styles/search-bar.css index c00e341bea59..1ca364ee2c72 100644 --- a/scaladoc/resources/dotty_res/styles/search-bar.css +++ b/scaladoc/resources/dotty_res/styles/search-bar.css @@ -66,7 +66,7 @@ /* Loading */ .loading-wrapper { - align-self: center; + text-align: center; padding: 4px; } @@ -75,16 +75,19 @@ width: 10px; height: 10px; border-radius: 5px; - background-color: var(--shadow); - color: var(--shadow); - animation: dotFlashing .4s infinite alternate; + background-color: var(--leftbar-bg); + color: var(--leftbar-bg); + animation-name: dotFlashing; + animation-duration: 1.6s; + animation-iteration-count: infinite; + animation-direction: normal; + animation-timing-function: ease-in-out; display: inline-block; position: absolute; top: 0; } .loading { - left: 50%; position: relative; animation-delay: .2s; } @@ -103,7 +106,10 @@ 0% { background-color: var(--leftbar-bg); } - 100% { + 25% { background-color: var(--shadow); } + 50% { + background-color: var(--leftbar-bg); + } } \ No newline at end of file From 1031d33e75d91652c3379c686a2fa4879c62140e Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 23 Jul 2021 20:47:32 +0200 Subject: [PATCH 16/18] Better inkuire results display --- scaladoc-js/resources/scaladoc-searchbar.css | 5 +- scaladoc-js/src/searchbar/PageEntry.scala | 8 +++ .../src/searchbar/SearchbarComponent.scala | 55 +++++++++++++++++-- .../engine/InkuireJSSearchEngine.scala | 17 +++--- .../src/searchbar/engine/QueryParser.scala | 2 +- .../resources/dotty_res/styles/search-bar.css | 16 +++++- 6 files changed, 85 insertions(+), 18 deletions(-) diff --git a/scaladoc-js/resources/scaladoc-searchbar.css b/scaladoc-js/resources/scaladoc-searchbar.css index a248eeb5c328..7c81c3fa75b6 100644 --- a/scaladoc-js/resources/scaladoc-searchbar.css +++ b/scaladoc-js/resources/scaladoc-searchbar.css @@ -80,10 +80,13 @@ background-color: var(--leftbar-bg); color: var(--leftbar-fg); line-height: 24px; - display: flex; padding: 4px 10px 4px 10px; } +.scaladoc-searchbar-result-row { + display: flex; +} + .scaladoc-searchbar-result .micon { height: 16px; width: 16px; diff --git a/scaladoc-js/src/searchbar/PageEntry.scala b/scaladoc-js/src/searchbar/PageEntry.scala index 8caaf8c9d806..4429965a2060 100644 --- a/scaladoc-js/src/searchbar/PageEntry.scala +++ b/scaladoc-js/src/searchbar/PageEntry.scala @@ -20,6 +20,14 @@ case class PageEntry( tokens: List[String] ) +case class InkuireMatch( + prettifiedSignature: String, + functionName: String, + packageLocation: String, + pageLocation: String, + entryType: String +) + object PageEntry { def apply(jsObj: PageEntryJS): PageEntry = PageEntry( jsObj.t, diff --git a/scaladoc-js/src/searchbar/SearchbarComponent.scala b/scaladoc-js/src/searchbar/SearchbarComponent.scala index 16fe6a22f662..d45352df3f54 100644 --- a/scaladoc-js/src/searchbar/SearchbarComponent.scala +++ b/scaladoc-js/src/searchbar/SearchbarComponent.scala @@ -8,9 +8,10 @@ import scala.concurrent.duration._ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearchEngine, parser: QueryParser): val resultsChunkSize = 100 extension (p: PageEntry) - def toHTML(inkuire: Boolean = false) = + def toHTML = val wrapper = document.createElement("div").asInstanceOf[html.Div] wrapper.classList.add("scaladoc-searchbar-result") + wrapper.classList.add("scaladoc-searchbar-result-row") wrapper.classList.add("monospace") val icon = document.createElement("span").asInstanceOf[html.Span] @@ -18,7 +19,7 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch icon.classList.add(p.kind.take(2)) val resultA = document.createElement("a").asInstanceOf[html.Anchor] - resultA.href = if inkuire then p.location else Globals.pathToRoot + p.location + resultA.href = Globals.pathToRoot + p.location resultA.text = s"${p.fullName}" val location = document.createElement("span") @@ -34,8 +35,52 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch }) wrapper + extension (m: InkuireMatch) + def toHTML = + val wrapper = document.createElement("div").asInstanceOf[html.Div] + wrapper.classList.add("scaladoc-searchbar-result") + wrapper.classList.add("monospace") + + val resultDiv = document.createElement("div").asInstanceOf[html.Div] + resultDiv.classList.add("scaladoc-searchbar-result-row") + + val icon = document.createElement("span").asInstanceOf[html.Span] + icon.classList.add("micon") + icon.classList.add(m.entryType.take(2)) + + val resultA = document.createElement("a").asInstanceOf[html.Anchor] + resultA.href = m.pageLocation + resultA.text = m.functionName + + val packageDiv = document.createElement("div").asInstanceOf[html.Div] + packageDiv.classList.add("scaladoc-searchbar-inkuire-package") + + val packageIcon = document.createElement("span").asInstanceOf[html.Span] + packageIcon.classList.add("micon") + packageIcon.classList.add("pa") + + val packageSpan = document.createElement("span").asInstanceOf[html.Span] + packageSpan.textContent = m.packageLocation + + val signature = document.createElement("span") + signature.classList.add("pull-right") + signature.classList.add("scaladoc-searchbar-inkuire-signature") + signature.textContent = m.prettifiedSignature + + wrapper.appendChild(resultDiv) + resultDiv.appendChild(icon) + resultDiv.appendChild(resultA) + resultA.appendChild(signature) + wrapper.appendChild(packageDiv) + packageDiv.appendChild(packageIcon) + packageDiv.appendChild(packageSpan) + wrapper.addEventListener("mouseover", { + case e: MouseEvent => handleHover(wrapper) + }) + wrapper + def handleNewFluffQuery(matchers: List[Matchers]) = - val result = engine.query(matchers).map(_.toHTML(inkuire = false)) + val result = engine.query(matchers).map(_.toHTML) resultsDiv.scrollTop = 0 while (resultsDiv.hasChildNodes()) resultsDiv.removeChild(resultsDiv.lastChild) val fragment = document.createDocumentFragment() @@ -86,8 +131,8 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch animation.classList.add("loading") loading.appendChild(animation) properResultsDiv.appendChild(loading) - inkuireEngine.query(query) { (p: PageEntry) => - properResultsDiv.appendChild(p.toHTML(inkuire = true)) + inkuireEngine.query(query) { (m: InkuireMatch) => + properResultsDiv.appendChild(m.toHTML) } { (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 f89a6498aa90..9a1c75947307 100644 --- a/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala +++ b/scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala @@ -16,20 +16,18 @@ class InkuireJSSearchEngine { val scriptPath = Globals.pathToRoot + "scripts/" val worker: Worker = new Worker(scriptPath + "inkuire-worker.js") - def dynamicToPageEntry(d: Dynamic): PageEntry = { - PageEntry( - d.functionName.asInstanceOf[String], + def dynamicToMatch(d: Dynamic): InkuireMatch = { + InkuireMatch( d.prettifiedSignature.asInstanceOf[String], - d.pageLocation.asInstanceOf[String], d.functionName.asInstanceOf[String], - d.entryType.asInstanceOf[String], - List.empty + d.packageLocation.asInstanceOf[String], + d.pageLocation.asInstanceOf[String], + d.entryType.asInstanceOf[String] ) } - def query(s: String)(callback: PageEntry => Unit)(endCallback: String => Unit): List[PageEntry] = { + def query(s: String)(callback: InkuireMatch => Unit)(endCallback: String => Unit): Unit = { worker.onmessage = _ => () - val res = ListBuffer[PageEntry]() val func = (msg: MessageEvent) => { msg.data.asInstanceOf[String] match { case "engine_ready" => @@ -38,13 +36,12 @@ class InkuireJSSearchEngine { endCallback(endMsg.drop("query_ended".length)) case q => val matches = JSON.parse(q).matches - val actualMatches = matches.asInstanceOf[js.Array[Dynamic]].map(dynamicToPageEntry) + val actualMatches = matches.asInstanceOf[js.Array[Dynamic]].map(dynamicToMatch) actualMatches.foreach(callback) } } worker.onmessage = func worker.postMessage(s) - res.toList } } \ No newline at end of file diff --git a/scaladoc-js/src/searchbar/engine/QueryParser.scala b/scaladoc-js/src/searchbar/engine/QueryParser.scala index 56c40c0003ef..c03becb0026e 100644 --- a/scaladoc-js/src/searchbar/engine/QueryParser.scala +++ b/scaladoc-js/src/searchbar/engine/QueryParser.scala @@ -19,7 +19,7 @@ class QueryParser: val kindRegex = ("(?i)" + kinds.mkString("(","|",")") + " (.*)").r val restRegex = raw"(.*)".r val escapedRegex = raw"`(.*)`".r - val signatureRegex = raw"([^=>]+=>.*)".r + val signatureRegex = raw"(.*=>.*)".r def parseMatchers(query: String): List[Matchers] = query match { case escapedRegex(rest) => List(ByName(rest)) diff --git a/scaladoc/resources/dotty_res/styles/search-bar.css b/scaladoc/resources/dotty_res/styles/search-bar.css index 1ca364ee2c72..9662db3f90e7 100644 --- a/scaladoc/resources/dotty_res/styles/search-bar.css +++ b/scaladoc/resources/dotty_res/styles/search-bar.css @@ -112,4 +112,18 @@ 50% { background-color: var(--leftbar-bg); } -} \ No newline at end of file +} + +.scaladoc-searchbar-inkuire-package { + display: none; + color: var(--symbol-fg) +} + +div[selected] > .scaladoc-searchbar-inkuire-package { + display: flex; +} + +.scaladoc-searchbar-inkuire-package > .micon { + float: right; + margin-left: auto !important; +} From 7f9629152ab182bf0ee6aa8a1107df98c1e445c0 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 26 Jul 2021 10:16:51 +0200 Subject: [PATCH 17/18] Bump Inkuire version --- scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala index 99051b20645d..6b38dd5f4f57 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala @@ -90,7 +90,7 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: ).map(Resource.URL.apply) val urlToPathMappings = List( - ("https://github.com/VirtusLab/Inkuire/releases/download/1.0.0-M1/inkuire.js", "scripts/inkuire.js"), + ("https://github.com/VirtusLab/Inkuire/releases/download/1.0.0-M2/inkuire.js", "scripts/inkuire.js"), ).map { case (url, path) => Resource.URLToCopy(url, path) } From 4e4c3e830e93795ea9ec04289902c3156e17d41e Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Mon, 26 Jul 2021 11:26:00 +0200 Subject: [PATCH 18/18] Deterministic synthetic itids --- .../src/dotty/tools/scaladoc/tasty/InkuireSupport.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala index 761c52e28fb2..2b34ba633b0e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/InkuireSupport.scala @@ -70,9 +70,9 @@ trait InkuireSupport: extension (tpe: TypeRepr) def asInkuire(vars: Set[String]): Inkuire.TypeLike = inner(tpe, vars) - private def genSyntheticTypeArgs(n: Int) = + private def genSyntheticTypeArgs(n: Int, resSymbol: Symbol) = 1.to(n).map { i => - val uuid = s"synthetic-arg$i${Random.nextString(10)}" + val uuid = s"synthetic-arg$i${resSymbol.hashCode}" val name = s"X$i" Inkuire.Type( name = Inkuire.TypeName(name), @@ -85,7 +85,7 @@ trait InkuireSupport: //TODO [Inkuire] Type bounds (other than just HKTs) val name = argument.symbol.normalizedName val normalizedName = if name.matches("_\\$\\d*") then "_" else name - val params = genSyntheticTypeArgs(typeVariableDeclarationParamsNo(argument)) + val params = genSyntheticTypeArgs(typeVariableDeclarationParamsNo(argument), argument.symbol) val res = Inkuire.Type( name = Inkuire.TypeName(normalizedName), itid = argument.symbol.itid,