Skip to content

Commit b93a9b5

Browse files
committed
And/OrTypes + TypeLambdas
1 parent c885a7c commit b93a9b5

File tree

3 files changed

+111
-53
lines changed

3 files changed

+111
-53
lines changed

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

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ object Inkuire {
3838
}
3939

4040
object Signature {
41-
def apply(receiver: Option[Type], arguments: Seq[Type], result: Type, context: SignatureContext): Signature =
41+
def apply(receiver: Option[TypeLike], arguments: Seq[TypeLike], result: TypeLike, context: SignatureContext): Signature =
4242
Signature(receiver.map(Contravariance(_)), arguments.map(Contravariance(_)), Covariance(result), context)
4343
}
4444

@@ -49,15 +49,32 @@ object Inkuire {
4949
uri: String
5050
)
5151

52+
sealed trait TypeLike
53+
5254
case class Type(
53-
name: TypeName,
54-
params: Seq[Variance] = Seq.empty,
55-
nullable: Boolean = false,
56-
itid: Option[ITID] = None,
57-
isVariable: Boolean = false,
55+
name: TypeName,
56+
params: Seq[Variance] = Seq.empty,
57+
nullable: Boolean = false,
58+
itid: Option[ITID] = None,
59+
isVariable: Boolean = false,
5860
isStarProjection: Boolean = false,
59-
isUnresolved: Boolean = false
60-
)
61+
isUnresolved: Boolean = false
62+
) extends TypeLike
63+
64+
case class AndType(left: TypeLike, right: TypeLike) extends TypeLike
65+
case class OrType(left: TypeLike, right: TypeLike) extends TypeLike
66+
67+
case class TypeLambda(args: Seq[Type], result: TypeLike) extends TypeLike
68+
69+
object TypeLambda {
70+
def argument(name: String): Type =
71+
val uuid = s"external-type-lambda-arg-$name"
72+
Inkuire.Type(
73+
name = Inkuire.TypeName(name),
74+
itid = Some(Inkuire.ITID(uuid, isParsed = false)),
75+
isVariable = true
76+
)
77+
}
6178

6279
object Type {
6380
def unresolved: Type =
@@ -94,7 +111,7 @@ object Inkuire {
94111

95112
case class SignatureContext(
96113
vars: Set[String],
97-
constraints: Map[String, Seq[Type]]
114+
constraints: Map[String, Seq[TypeLike]]
98115
) {
99116
override def hashCode: Int = vars.size.hashCode
100117

@@ -110,16 +127,16 @@ object Inkuire {
110127
}
111128

112129
sealed abstract class Variance {
113-
val typ: Type
130+
val typ: TypeLike
114131
}
115132

116-
case class Covariance(typ: Type) extends Variance
133+
case class Covariance(typ: TypeLike) extends Variance
117134

118-
case class Contravariance(typ: Type) extends Variance
135+
case class Contravariance(typ: TypeLike) extends Variance
119136

120-
case class Invariance(typ: Type) extends Variance
137+
case class Invariance(typ: TypeLike) extends Variance
121138

122-
case class UnresolvedVariance(typ: Type) extends Variance
139+
case class UnresolvedVariance(typ: TypeLike) extends Variance
123140

124141
object EngineModelSerializers {
125142
def serialize(db: InkuireDb): JSON = {
@@ -161,16 +178,36 @@ object Inkuire {
161178
)
162179
}
163180

164-
private def serialize(t: Type): JSON = {
165-
jsonObject(
166-
("name", serialize(t.name)),
167-
("params", jsonList(t.params.map(serialize))),
168-
("nullable", serialize(t.nullable)),
169-
("itid", serialize(t.itid.get)),
170-
("isVariable", serialize(t.isVariable)),
171-
("isStarProjection", serialize(t.isStarProjection)),
172-
("isUnresolved", serialize(t.isUnresolved))
173-
)
181+
private def serialize(t: TypeLike): JSON = t match {
182+
case t: Type =>
183+
jsonObject(
184+
("name", serialize(t.name)),
185+
("params", jsonList(t.params.map(serialize))),
186+
("nullable", serialize(t.nullable)),
187+
("itid", serialize(t.itid.get)),
188+
("isVariable", serialize(t.isVariable)),
189+
("isStarProjection", serialize(t.isStarProjection)),
190+
("isUnresolved", serialize(t.isUnresolved)),
191+
("typelikekind", serialize("type"))
192+
)
193+
case t: OrType =>
194+
jsonObject(
195+
("left", serialize(t.left)),
196+
("right", serialize(t.right)),
197+
("typelikekind", serialize("ortype"))
198+
)
199+
case t: AndType =>
200+
jsonObject(
201+
("left", serialize(t.left)),
202+
("right", serialize(t.right)),
203+
("typelikekind", serialize("andtype"))
204+
)
205+
case t: TypeLambda =>
206+
jsonObject(
207+
("args", jsonList(t.args.map(serialize))),
208+
("result", serialize(t.result)),
209+
("typelikekind", serialize("typelambda"))
210+
)
174211
}
175212

176213
private def serialize(b: Boolean): JSON = {
@@ -248,7 +285,7 @@ object Inkuire {
248285
)
249286
}
250287

251-
private def serializeConstraints(constraints: Map[String, Seq[Type]]): JSON = {
288+
private def serializeConstraints(constraints: Map[String, Seq[TypeLike]]): JSON = {
252289
jsonObject((
253290
constraints.toList.map {
254291
case (name, vs) =>

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

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,18 @@ trait ClassLikeSupport:
9696

9797
if summon[DocContext].args.generateInkuire then {
9898

99-
val classType = classDef.asInkuire(Set.empty)
100-
val variableNames = classType.params.map(_.typ.name.name).toSet
99+
val classType: Inkuire.Type = classDef.asInkuire(Set.empty).asInstanceOf[Inkuire.Type]
101100

102-
val parents = classDef.parents.map(_.asInkuire(variableNames))
101+
def varName(t: Inkuire.TypeLike): Option[String] = t match {
102+
case tpe: Inkuire.Type => Some(tpe.name.name)
103+
case tl: Inkuire.TypeLambda => varName(tl.result)
104+
case _ => None
105+
}
106+
107+
val variableNames: Set[String] = classType.params.map(_.typ)
108+
.flatMap(varName(_).toList).toSet
109+
110+
val parents: Seq[Inkuire.Type] = classDef.parents.map(_.asInkuire(variableNames).asInstanceOf[Inkuire.Type])
103111

104112
val isModule = classDef.symbol.flags.is(Flags.Module)
105113

@@ -111,8 +119,12 @@ trait ClassLikeSupport:
111119
if typeDef.rhs.symbol.fullName.contains("java") then
112120
val t = typeSymbol.tree.asInkuire(variableNames) // TODO [Inkuire] Hack until type aliases are supported
113121
val tJava = typeDef.rhs.symbol.tree.asInkuire(variableNames)
114-
Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))) // TODO [Inkuire] Hack until type aliases are supported
115-
Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty)))
122+
t match
123+
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
124+
case _ =>
125+
tJava match
126+
case tJava: Inkuire.Type => Inkuire.db = Inkuire.db.copy(types = Inkuire.db.types.updated(tJava.itid.get, (tJava, Seq.empty)))
127+
case _ =>
116128
}
117129

118130
classDef.symbol.declaredMethods
@@ -130,17 +142,17 @@ trait ClassLikeSupport:
130142
val from = defdef.paramss.flatMap(_.params).collectFirst {
131143
case v: ValDef => v.tpt.asInkuire(variableNames)
132144
}
133-
from match
134-
case Some(from) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to))
135-
case None =>
145+
(from, to) match
146+
case (Some(from: Inkuire.Type), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from.itid.get -> to))
147+
case _ =>
136148

137149
case methodSymbol: Symbol =>
138150
val defdef = methodSymbol.tree.asInstanceOf[DefDef]
139151
val methodVars = defdef.paramss.flatMap(_.params).collect {
140152
case TypeDef(name, _) => name
141153
}
142154
val vars = variableNames ++ methodVars
143-
val receiver: Option[Inkuire.Type] =
155+
val receiver: Option[Inkuire.TypeLike] =
144156
Some(classType)
145157
.filter(_ => !isModule)
146158
.orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)))

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

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import dotty.tools.scaladoc._
55
import dotty.tools.scaladoc.{Signature => DSignature}
66
import dotty.tools.scaladoc.Inkuire
77

8+
import scala.util.Random
89
import scala.quoted._
910

1011
import SymOps._
@@ -22,15 +23,13 @@ trait InkuireSupport:
2223

2324
given TreeSyntaxInkuire: AnyRef with
2425
extension (tpeTree: Tree)
25-
def asInkuire(vars: Set[String]): Inkuire.Type =
26+
def asInkuire(vars: Set[String]): Inkuire.TypeLike =
2627
partialAsInkuire(vars)(tpeTree)
2728

28-
def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.Type] = {
29+
def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.TypeLike] = {
2930
case TypeBoundsTree(low, high) => inner(low.tpe, vars) //TODO [Inkuire] Type bounds
3031
case tpeTree: Applied =>
31-
inner(tpeTree.tpe, vars).copy(
32-
params = tpeTree.args.map(p => Inkuire.Invariance(p.asInkuire(vars)))
33-
)
32+
inner(tpeTree.tpe, vars)
3433
case tpeTree: TypeTree =>
3534
inner(tpeTree.tpe, vars)
3635
case term: Term => inner(term.tpe, vars)
@@ -56,19 +55,33 @@ trait InkuireSupport:
5655

5756
given TypeSyntaxInkuire: AnyRef with
5857
extension (tpe: TypeRepr)
59-
def asInkuire(vars: Set[String]): Inkuire.Type = inner(tpe, vars)
58+
def asInkuire(vars: Set[String]): Inkuire.TypeLike = inner(tpe, vars)
59+
60+
private def genDummyTypeArgs(n: Int) =
61+
1.to(n).map { i =>
62+
val uuid = s"dummy-arg$i${Random.nextString(10)}"
63+
val name = s"X$i"
64+
Inkuire.Type(
65+
name = Inkuire.TypeName(name),
66+
itid = Some(Inkuire.ITID(uuid, isParsed = false)),
67+
isVariable = true
68+
)
69+
}
6070

6171
def mkTypeArgumentInkuire(argument: TypeDef): Inkuire.Variance =
6272
//TODO [Inkuire] Type bounds (other than just HKTs)
6373
val name = argument.symbol.normalizedName
6474
val normalizedName = if name.matches("_\\$\\d*") then "_" else name
65-
val params = 1.to(typeVariableDeclarationParamsNo(argument)).map(_ => Inkuire.Type.StarProjection)
66-
val t = Inkuire.Type(
75+
val params = genDummyTypeArgs(typeVariableDeclarationParamsNo(argument))
76+
val res = Inkuire.Type(
6777
name = Inkuire.TypeName(normalizedName),
6878
itid = argument.symbol.itid,
6979
isVariable = true,
7080
params = params.map(Inkuire.Invariance(_))
7181
)
82+
val t = params.toList match
83+
case Nil => res
84+
case _ => Inkuire.TypeLambda(params, res)
7285
if argument.symbol.flags.is(Flags.Covariant) then Inkuire.Covariance(t)
7386
else if argument.symbol.flags.is(Flags.Contravariant) then Inkuire.Contravariance(t)
7487
else Inkuire.Invariance(t)
@@ -94,9 +107,9 @@ trait InkuireSupport:
94107
case _ => false
95108
case _ => false
96109

97-
private def inner(tp: TypeRepr, vars: Set[String]): Inkuire.Type = tp match
98-
case OrType(left, right) => inner(left, vars) //TODO [Inkuire] Or/AndTypes
99-
case AndType(left, right) => inner(left, vars) //TODO [Inkuire] Or/AndTypes
110+
private def inner(tp: TypeRepr, vars: Set[String]): Inkuire.TypeLike = tp match
111+
case OrType(left, right) => Inkuire.OrType(inner(left, vars), inner(right, vars))
112+
case AndType(left, right) => Inkuire.AndType(inner(left, vars), inner(right, vars))
100113
case ByNameType(tpe) => inner(tpe, vars)
101114
case ConstantType(constant) =>
102115
Inkuire.Type(
@@ -111,8 +124,8 @@ trait InkuireSupport:
111124
inner(tpe, vars) //TODO [Inkuire] Repeated types
112125
case AnnotatedType(tpe, _) =>
113126
inner(tpe, vars)
114-
case tl @ TypeLambda(params, paramBounds, resType) =>
115-
inner(resType, vars) //TODO [Inkuire] Type lambdas
127+
case tl @ TypeLambda(paramNames, _, resType) =>
128+
Inkuire.TypeLambda(paramNames.map(Inkuire.TypeLambda.argument), inner(resType, vars)) //TODO [Inkuire] Type bounds
116129
case r: Refinement =>
117130
inner(r.info, vars) //TODO [Inkuire] Refinements
118131
case t @ AppliedType(tpe, typeList) =>
@@ -132,7 +145,7 @@ trait InkuireSupport:
132145
itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false))
133146
)
134147
else
135-
inner(tpe, vars).copy(
148+
inner(tpe, vars).asInstanceOf[Inkuire.Type].copy(
136149
params = typeList.map(p => Inkuire.Invariance(inner(p, vars)))
137150
)
138151
case tp: TypeRef =>
@@ -151,11 +164,7 @@ trait InkuireSupport:
151164
case MatchType(bond, sc, cases) =>
152165
inner(sc, vars)
153166
case ParamRef(TypeLambda(names, _, _), i) =>
154-
Inkuire.Type(
155-
name = Inkuire.TypeName(names(i)),
156-
itid = Some(Inkuire.ITID(s"external-itid-${names(i)}", isParsed = false)),
157-
isVariable = true
158-
)
167+
Inkuire.TypeLambda.argument(names(i))
159168
case ParamRef(m: MethodType, i) =>
160169
inner(m.paramTypes(i), vars)
161170
case RecursiveType(tp) =>

0 commit comments

Comments
 (0)