Skip to content

Commit 02642db

Browse files
Merge pull request scala#13454 from KacperFKorban/scaladoc/inkuire-M3
Scaladoc/Inkuire-M3
2 parents a47a81a + b8fa6d7 commit 02642db

File tree

12 files changed

+354
-200
lines changed

12 files changed

+354
-200
lines changed

project/Build.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,7 @@ object Build {
13271327
import _root_.scala.sys.process._
13281328
import _root_.scala.concurrent._
13291329
import ExecutionContext.Implicits.global
1330-
val inkuireVersion = "1.0.0-M2"
1330+
val inkuireVersion = "1.0.0-M3"
13311331
val inkuireLink = s"https://github.com/VirtusLab/Inkuire/releases/download/$inkuireVersion/inkuire.js"
13321332
val inkuireDestinationFile = (Compile / resourceManaged).value / "dotty_res" / "scripts" / "inkuire.js"
13331333
sbt.IO.touch(inkuireDestinationFile)

scaladoc-js/src/searchbar/PageEntry.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ case class InkuireMatch(
2525
functionName: String,
2626
packageLocation: String,
2727
pageLocation: String,
28-
entryType: String
28+
entryType: String,
29+
mq: Int
2930
)
3031

3132
object PageEntry {

scaladoc-js/src/searchbar/SearchbarComponent.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dotty.tools.scaladoc
22

33
import org.scalajs.dom._
4+
import org.scalajs.dom.ext._
45
import org.scalajs.dom.html.Input
56
import scala.scalajs.js.timers._
67
import scala.concurrent.duration._
@@ -40,6 +41,7 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch
4041
val wrapper = document.createElement("div").asInstanceOf[html.Div]
4142
wrapper.classList.add("scaladoc-searchbar-result")
4243
wrapper.classList.add("monospace")
44+
wrapper.setAttribute("mq", m.mq.toString)
4345

4446
val resultDiv = document.createElement("div").asInstanceOf[html.Div]
4547
resultDiv.classList.add("scaladoc-searchbar-result-row")
@@ -132,7 +134,16 @@ class SearchbarComponent(engine: SearchbarEngine, inkuireEngine: InkuireJSSearch
132134
loading.appendChild(animation)
133135
properResultsDiv.appendChild(loading)
134136
inkuireEngine.query(query) { (m: InkuireMatch) =>
135-
properResultsDiv.appendChild(m.toHTML)
137+
val next = properResultsDiv.children.foldLeft[Option[Element]](None) {
138+
case (acc, child) if !acc.isEmpty => acc
139+
case (_, child) =>
140+
Option.when(child.hasAttribute("mq") && Integer.parseInt(child.getAttribute("mq")) > m.mq)(child)
141+
}
142+
next.fold {
143+
properResultsDiv.appendChild(m.toHTML)
144+
} { next =>
145+
properResultsDiv.insertBefore(m.toHTML, next)
146+
}
136147
} { (s: String) =>
137148
animation.classList.remove("loading")
138149
properResultsDiv.appendChild(s.toHTMLError)

scaladoc-js/src/searchbar/engine/InkuireJSSearchEngine.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class InkuireJSSearchEngine {
2222
d.functionName.asInstanceOf[String],
2323
d.packageLocation.asInstanceOf[String],
2424
d.pageLocation.asInstanceOf[String],
25-
d.entryType.asInstanceOf[String]
25+
d.entryType.asInstanceOf[String],
26+
d.mq.asInstanceOf[Int]
2627
)
2728
}
2829

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package tests.anImplicitClass
2+
3+
implicit class AddingOps(n: Int):
4+
def inc: Int = n + 1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package tests.caseClassesWithVars
2+
3+
case class Sheep(var numberOfLegs: Int):
4+
var name: String = "Lawrence"
5+
6+
class Goat(var numberOfLegs: Int)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package tests.justmethods
2+
3+
trait Animal
4+
5+
def whatSoundDoIMake(animal: Animal): String = "IoIo"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package test.syntaxes
2+
3+
class DoingStuffOps[A](a: A):
4+
def doStuff: Unit = ()
5+
6+
trait DoingStuffSyntax:
7+
implicit def toDoingStuffOps[A](a: A): DoingStuffOps[A] = DoingStuffOps(a)
8+
9+
trait AllSyntaxes extends DoingStuffSyntax
10+
11+
object doingstuff extends AllSyntaxes

scaladoc/src/dotty/tools/scaladoc/Inkuire.scala

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import dotty.tools.scaladoc.util._
55
object Inkuire {
66

77
var db = InkuireDb(Seq.empty, Map.empty, Seq.empty, Map.empty)
8+
var implicitConversions: Seq[(Option[TypeLike], Type)] = Seq.empty
89

910
def beforeSave(): Unit = {
1011
db = db.copy(
11-
functions = db.functions.sortBy(_.hashCode),
12+
functions = functions.sortBy(_.hashCode),
1213
types = db.types.toSeq.sortBy(_._1.uuid).toMap,
13-
implicitConversions = db.implicitConversions.sortBy(_._1.uuid)
14+
implicitConversions = implicitConversions.collect {
15+
case (Some(from), to) => from -> to
16+
}.sortBy(_._1.hashCode)
1417
)
1518
}
1619

@@ -34,10 +37,59 @@ object Inkuire {
3437
case _ => e
3538
}
3639

40+
def functions: Seq[ExternalSignature] = Inkuire.db.functions.flatMap { func =>
41+
val fromConversions = Inkuire.implicitConversions.filter { ic =>
42+
func.signature.receiver.nonEmpty && matchingICTypes(ic._2, func.signature.receiver.get.typ)
43+
}.map {
44+
case (Some(from), to) =>
45+
func.copy(
46+
signature = func.signature.copy(
47+
receiver = func.signature.receiver.map { rcvr =>
48+
Contravariance(
49+
newReceiver(rcvr.typ, to, from)
50+
)
51+
}
52+
)
53+
)
54+
case (None, to) =>
55+
func.copy(
56+
signature = func.signature.copy(
57+
receiver = None
58+
)
59+
)
60+
}
61+
Seq(func) ++ fromConversions
62+
}
63+
.distinct
64+
65+
def matchingICTypes(a: TypeLike, b: TypeLike): Boolean = (a, b) match {
66+
case (a: Type, b: Type) if a.params.size == 0 && b.params.size == 0 && a.itid == b.itid => true
67+
case (a: Type, b: Type) if a.params.size == 1 && b.params.size == 1 && a.itid == b.itid =>
68+
a.params.head.typ.isInstanceOf[Type] && a.params.head.typ.asInstanceOf[Type].isVariable &&
69+
b.params.head.typ.isInstanceOf[Type] && b.params.head.typ.asInstanceOf[Type].isVariable
70+
case _ => false
71+
}
72+
73+
def newReceiver(old: TypeLike, to: TypeLike, from: TypeLike): TypeLike = (old, to) match {
74+
case (a: Type, b: Type) if a.params.size == 0 && b.params.size == 0 && a.itid == b.itid => from
75+
case (a: Type, b: Type) if a.params.size == 1 && b.params.size == 1 && a.itid == b.itid
76+
&& a.params.head.typ.isInstanceOf[Type] && a.params.head.typ.asInstanceOf[Type].isVariable &&
77+
b.params.head.typ.isInstanceOf[Type] && b.params.head.typ.asInstanceOf[Type].isVariable =>
78+
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
79+
from.asInstanceOf[Type].copy(
80+
params = Seq(Contravariance(a.params.head.typ.asInstanceOf[Type]))
81+
)
82+
else if from.isInstanceOf[Type] && from.asInstanceOf[Type].isVariable then
83+
a.params.head.typ.asInstanceOf[Type]
84+
else
85+
from
86+
case _ => old
87+
}
88+
3789
case class InkuireDb(
3890
functions: Seq[ExternalSignature],
3991
types: Map[ITID, (Type, Seq[Type])],
40-
implicitConversions: Seq[(ITID, Type)],
92+
implicitConversions: Seq[(TypeLike, Type)],
4193
typeAliases: Map[ITID, TypeLike]
4294
)
4395

@@ -164,7 +216,7 @@ object Inkuire {
164216
)
165217
}
166218

167-
private def serializeConversion(conversion: (ITID, Type)): JSON = {
219+
private def serializeConversion(conversion: (TypeLike, Type)): JSON = {
168220
jsonList(
169221
Seq(
170222
serialize(conversion._1),

scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala

Lines changed: 1 addition & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -100,133 +100,7 @@ trait ClassLikeSupport:
100100
deprecated = classDef.symbol.isDeprecated()
101101
)
102102

103-
if summon[DocContext].args.generateInkuire then {
104-
105-
val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type]
106-
107-
def varName(t: Inkuire.TypeLike): Option[String] = t match {
108-
case tpe: Inkuire.Type => Some(tpe.name.name)
109-
case tl: Inkuire.TypeLambda => varName(tl.result)
110-
case _ => None
111-
}
112-
113-
val variableNames: Set[String] = classType.params.map(_.typ)
114-
.flatMap(varName(_).toList).toSet
115-
116-
val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type])
117-
118-
val isModule = classDef.symbol.flags.is(Flags.Module)
119-
120-
if !isModule then Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(classType.itid.get, (classType, parents)))
121-
122-
classDef.symbol.declaredTypes
123-
.filter(viableSymbol)
124-
.foreach {
125-
case typeSymbol: Symbol if typeSymbol.flags.is(Flags.Opaque) =>
126-
val typ = typeSymbol.tree.asInkuire(variableNames)
127-
if typ.isInstanceOf[Inkuire.Type] then {
128-
val t = typ.asInstanceOf[Inkuire.Type]
129-
Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)))
130-
}
131-
case typeSymbol: Symbol if !typeSymbol.isClassDef =>
132-
val typeDef = typeSymbol.tree.asInstanceOf[TypeDef]
133-
val typ = typeSymbol.tree.asInkuire(variableNames)
134-
if typ.isInstanceOf[Inkuire.Type] then {
135-
val t = typ.asInstanceOf[Inkuire.Type]
136-
val rhsTypeLike = typeDef.rhs.asInkuire(variableNames)
137-
Inkuire.db = Inkuire.db.copy(
138-
typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike),
139-
types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))
140-
)
141-
}
142-
if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then
143-
val typJava = typeDef.rhs.asInkuire(variableNames)
144-
if typJava.isInstanceOf[Inkuire.Type] then {
145-
val tJava = typJava.asInstanceOf[Inkuire.Type]
146-
Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty)))
147-
}
148-
case _ =>
149-
}
150-
151-
def viableSymbol(s: Symbol): Boolean =
152-
!s.flags.is(Flags.Private) &&
153-
!s.flags.is(Flags.Protected) &&
154-
!s.flags.is(Flags.Override) &&
155-
!s.flags.is(Flags.Synthetic)
156-
157-
classDef.symbol.declaredMethods
158-
.filter(viableSymbol)
159-
.foreach {
160-
case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit)
161-
&& classDef.symbol.flags.is(Flags.Module)
162-
&& implicitConversion.owner.fullName == ("scala.Predef$") =>
163-
val defdef = implicitConversion.tree.asInstanceOf[DefDef]
164-
val to = defdef.returnTpt.asInkuire(variableNames)
165-
val from = defdef.paramss.flatMap(_.params).collectFirst {
166-
case v: ValDef => v.tpt.asInkuire(variableNames)
167-
}
168-
(from, to) match
169-
case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to))
170-
case _ =>
171-
172-
case methodSymbol: Symbol =>
173-
val defdef = methodSymbol.tree.asInstanceOf[DefDef]
174-
val methodVars = defdef.paramss.flatMap(_.params).collect {
175-
case TypeDef(name, _) => name
176-
}
177-
val vars = variableNames ++ methodVars
178-
val receiver: Option[Inkuire.TypeLike] =
179-
Some(classType)
180-
.filter(_ => !isModule)
181-
.orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)))
182-
val sgn = Inkuire.ExternalSignature(
183-
signature = Inkuire.Signature(
184-
receiver = receiver,
185-
arguments = methodSymbol.nonExtensionTermParamLists.collect {
186-
case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters
187-
}.flatten.map(_.tpt.asInkuire(vars)),
188-
result = defdef.returnTpt.asInkuire(vars),
189-
context = Inkuire.SignatureContext(
190-
vars = vars.toSet,
191-
constraints = Map.empty //TODO [Inkuire] Type bounds
192-
)
193-
),
194-
name = methodSymbol.name,
195-
packageName = methodSymbol.dri.location,
196-
uri = methodSymbol.dri.externalLink.getOrElse(""),
197-
entryType = "def"
198-
)
199-
val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature))
200-
Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn)
201-
}
202-
203-
classDef.symbol.declaredFields
204-
.filter(viableSymbol)
205-
.foreach {
206-
case valSymbol: Symbol =>
207-
val valdef = valSymbol.tree.asInstanceOf[ValDef]
208-
val receiver: Option[Inkuire.TypeLike] =
209-
Some(classType)
210-
.filter(_ => !isModule)
211-
val sgn = Inkuire.ExternalSignature(
212-
signature = Inkuire.Signature(
213-
receiver = receiver,
214-
arguments = Seq.empty,
215-
result = valdef.tpt.asInkuire(variableNames),
216-
context = Inkuire.SignatureContext(
217-
vars = variableNames.toSet,
218-
constraints = Map.empty //TODO [Inkuire] Type bounds
219-
)
220-
),
221-
name = valSymbol.name,
222-
packageName = valSymbol.dri.location,
223-
uri = valSymbol.dri.externalLink.getOrElse(""),
224-
entryType = "val"
225-
)
226-
val curriedSgn = sgn.copy(signature = Inkuire.curry(sgn.signature))
227-
Inkuire.db = Inkuire.db.copy(functions = Inkuire.db.functions :+ curriedSgn)
228-
}
229-
}
103+
if summon[DocContext].args.generateInkuire then doInkuireStuff(classDef)
230104

231105
if signatureOnly then baseMember else baseMember.copy(
232106
members = classDef.extractPatchedMembers.sortBy(m => (m.name, m.kind.name)),

0 commit comments

Comments
 (0)