Skip to content

Commit 1f472f6

Browse files
committed
Handle type aliases with bounds better
1 parent 8fd69bd commit 1f472f6

File tree

2 files changed

+110
-90
lines changed

2 files changed

+110
-90
lines changed

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

Lines changed: 21 additions & 11 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(
1112
functions = functions.sortBy(_.hashCode),
1213
types = db.types.toSeq.sortBy(_._1.uuid).toMap,
13-
implicitConversions = db.implicitConversions.sortBy(_._1.hashCode)
14+
implicitConversions = implicitConversions.collect {
15+
case (Some(from), to) => from -> to
16+
}.sortBy(_._1.hashCode)
1417
)
1518
}
1619

@@ -35,18 +38,25 @@ object Inkuire {
3538
}
3639

3740
def functions: Seq[ExternalSignature] = Inkuire.db.functions.flatMap { func =>
38-
val fromConversions = Inkuire.db.implicitConversions.filter { ic =>
41+
val fromConversions = Inkuire.implicitConversions.filter { ic =>
3942
func.signature.receiver.nonEmpty && matchingICTypes(ic._2, func.signature.receiver.get.typ)
40-
}.map { ic =>
41-
func.copy(
42-
signature = func.signature.copy(
43-
receiver = func.signature.receiver.map { rcvr =>
44-
Contravariance(
45-
newReceiver(rcvr.typ, ic._2, ic._1)
46-
)
47-
}
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+
)
4859
)
49-
)
5060
}
5161
Seq(func) ++ fromConversions
5262
}

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

Lines changed: 89 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,20 @@ trait InkuireSupport:
4646
if typ.isInstanceOf[Inkuire.Type] then {
4747
val t = typ.asInstanceOf[Inkuire.Type]
4848
val rhsTypeLike = typeDef.rhs.asInkuire(variableNames)
49-
Inkuire.db = Inkuire.db.copy(
50-
typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike),
49+
val withType = Inkuire.db.copy(
5150
types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty))
5251
)
52+
typeDef.rhs match {
53+
case TypeBoundsTree(_, r) if r.asInkuire(variableNames).isInstanceOf[Inkuire.Type] =>
54+
Inkuire.db = Inkuire.db.copy(
55+
types = Inkuire.db.types.updated(t.itid.get, (t, Seq(r.asInkuire(variableNames).asInstanceOf[Inkuire.Type])))
56+
)
57+
case _ =>
58+
Inkuire.db = withType.copy(
59+
types = Inkuire.db.types.updated(t.itid.get, (t, Seq.empty)),
60+
typeAliases = Inkuire.db.typeAliases.updated(t.itid.get, rhsTypeLike)
61+
)
62+
}
5363
}
5464
if typeDef.rhs.symbol.flags.is(Flags.JavaDefined) then
5565
val typJava = typeDef.rhs.asInkuire(variableNames)
@@ -70,7 +80,7 @@ trait InkuireSupport:
7080
classDef.symbol.declaredMethods
7181
.filter(viableSymbol)
7282
.tap { _.foreach { // Loop for implicit conversions
73-
case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) =>
83+
case implicitConversion: Symbol if implicitConversion.flags.is(Flags.Implicit) || implicitConversion.flags.is(Flags.Given) =>
7484
handleImplicitConversion(implicitConversion, variableNames)
7585
case _ =>
7686
}}
@@ -81,15 +91,15 @@ trait InkuireSupport:
8191
case TypeDef(name, _) => name
8292
}
8393
val vars = variableNames ++ methodVars
84-
val receiver: Option[Inkuire.TypeLike] =
85-
Some(classType)
86-
.filter(_ => !isModule)
87-
.orElse(methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)))
94+
val (receiver, preArgs): (Option[Inkuire.TypeLike], Seq[Inkuire.TypeLike]) = Some(classType).filter(_ => !isModule) match {
95+
case None => (methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)), Seq.empty)
96+
case rcvr => (rcvr, methodSymbol.extendedSymbol.flatMap(s => partialAsInkuire(vars).lift(s.tpt)).toSeq)
97+
}
8898
val (name, ownerName) = nameAndOwnerName(classDef, methodSymbol)
8999
val sgn = Inkuire.ExternalSignature(
90100
signature = Inkuire.Signature(
91101
receiver = receiver,
92-
arguments = methodSymbol.nonExtensionTermParamLists.collect {
102+
arguments = preArgs ++ methodSymbol.nonExtensionTermParamLists.collect {
93103
case tpc@TermParamClause(params) if !tpc.isImplicit && !tpc.isGiven => params //TODO [Inkuire] Implicit parameters
94104
}.flatten.map(_.tpt.asInkuire(vars)),
95105
result = defdef.returnTpt.asInkuire(vars),
@@ -147,21 +157,17 @@ trait InkuireSupport:
147157
case v: ValDef => v.tpt.asInkuire(vars)
148158
}
149159
(from, to) match
150-
case (Some(from), to: Inkuire.Type) => Inkuire.db = Inkuire.db.copy(implicitConversions = Inkuire.db.implicitConversions :+ (from -> to))
160+
case (from, to: Inkuire.Type) => Inkuire.implicitConversions = Inkuire.implicitConversions :+ (from -> to)
151161
case _ =>
152162
}
153163

154164
private def nameAndOwnerName(classDef: ClassDef, symbol: Symbol): (String, String) =
155165
if classDef.symbol.flags.is(Flags.Module) || Seq("apply", "unapply").contains(symbol.name) then
156-
(
157-
symbol.maybeOwner.normalizedName + "." + symbol.name,
166+
symbol.maybeOwner.normalizedName + "." + symbol.name ->
158167
ownerNameChain(classDef.symbol.maybeOwner).mkString(".")
159-
)
160168
else
161-
(
162-
symbol.name,
169+
symbol.name ->
163170
ownerNameChain(classDef.symbol).mkString(".")
164-
)
165171

166172
private def ownerNameChain(sym: Symbol): List[String] =
167173
if sym.isNoSymbol then List.empty
@@ -192,7 +198,7 @@ trait InkuireSupport:
192198
partialAsInkuire(vars)(tpeTree)
193199

194200
private def partialAsInkuire(vars: Set[String]): PartialFunction[Tree, Inkuire.TypeLike] = {
195-
case TypeBoundsTree(low, high) => inner(low.tpe, vars) //TODO [Inkuire] Type bounds
201+
case tpeTree: TypeBoundsTree => inner(tpeTree.tpe, vars)
196202
case tpeTree: Applied =>
197203
inner(tpeTree.tpe, vars)
198204
case tpeTree: TypeTree =>
@@ -285,72 +291,76 @@ trait InkuireSupport:
285291
case _ => false
286292
case _ => false
287293

288-
private def inner(tp: TypeRepr, vars: Set[String]): Inkuire.TypeLike = tp match
289-
case OrType(left, right) => Inkuire.OrType(inner(left, vars), inner(right, vars))
290-
case AndType(left, right) => Inkuire.AndType(inner(left, vars), inner(right, vars))
291-
case ByNameType(tpe) => inner(tpe, vars)
292-
case ConstantType(constant) =>
293-
Inkuire.Type(
294-
name = Inkuire.TypeName(constant.toString),
295-
params = Seq.empty,
296-
itid = Some(Inkuire.ITID(constant.toString, isParsed = false))
297-
)
298-
case ThisType(tpe) => inner(tpe, vars)
299-
case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedAnnotation(annotation) =>
300-
inner(tpe, vars) //TODO [Inkuire] Repeated types
301-
case AppliedType(repeatedClass, Seq(tpe)) if isRepeated(repeatedClass) =>
302-
inner(tpe, vars) //TODO [Inkuire] Repeated types
303-
case AnnotatedType(tpe, _) =>
304-
inner(tpe, vars)
305-
case tl @ TypeLambda(paramNames, _, resType) =>
306-
Inkuire.TypeLambda(paramNames.map(Inkuire.TypeLambda.argument), inner(resType, vars)) //TODO [Inkuire] Type bounds
307-
case r: Refinement =>
308-
inner(r.info, vars) //TODO [Inkuire] Refinements
309-
case t @ AppliedType(tpe, typeList) =>
310-
import dotty.tools.dotc.util.Chars._
311-
if t.isFunctionType then
312-
val name = s"Function${typeList.size-1}"
294+
private def inner(tp: TypeRepr, vars: Set[String]): Inkuire.TypeLike =
295+
tp match
296+
case OrType(left, right) => Inkuire.OrType(inner(left, vars), inner(right, vars))
297+
case AndType(left, right) => Inkuire.AndType(inner(left, vars), inner(right, vars))
298+
case ByNameType(tpe) => inner(tpe, vars)
299+
case ConstantType(constant) =>
313300
Inkuire.Type(
314-
name = Inkuire.TypeName(name),
315-
params = typeList.init.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(typeList.last, vars)),
316-
itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false))
301+
name = Inkuire.TypeName(constant.toString),
302+
params = Seq.empty,
303+
itid = Some(Inkuire.ITID(constant.toString, isParsed = false))
317304
)
318-
else if t.isTupleN then
319-
val name = s"Tuple${typeList.size}"
305+
case ThisType(tpe) => inner(tpe, vars)
306+
case AnnotatedType(AppliedType(_, Seq(tpe)), annotation) if isRepeatedAnnotation(annotation) =>
307+
inner(tpe, vars) //TODO [Inkuire] Repeated types
308+
case AppliedType(repeatedClass, Seq(tpe)) if isRepeated(repeatedClass) =>
309+
inner(tpe, vars) //TODO [Inkuire] Repeated types
310+
case AnnotatedType(tpe, _) =>
311+
inner(tpe, vars)
312+
case tl @ TypeLambda(paramNames, _, resType) =>
313+
Inkuire.TypeLambda(paramNames.map(Inkuire.TypeLambda.argument), inner(resType, vars)) //TODO [Inkuire] Type bounds
314+
case r: Refinement =>
315+
inner(r.info, vars) //TODO [Inkuire] Refinements
316+
case t @ AppliedType(tpe, typeList) =>
317+
import dotty.tools.dotc.util.Chars._
318+
if t.isFunctionType then
319+
val name = s"Function${typeList.size-1}"
320+
Inkuire.Type(
321+
name = Inkuire.TypeName(name),
322+
params = typeList.init.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(typeList.last, vars)),
323+
itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false))
324+
)
325+
else if t.isTupleN then
326+
val name = s"Tuple${typeList.size}"
327+
Inkuire.Type(
328+
name = Inkuire.TypeName(name),
329+
params = typeList.map(p => Inkuire.Covariance(inner(p, vars))),
330+
itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false))
331+
)
332+
else
333+
inner(tpe, vars).asInstanceOf[Inkuire.Type].copy(
334+
params = typeList.map(p => Inkuire.Invariance(inner(p, vars)))
335+
)
336+
case tp: TypeRef =>
337+
Inkuire.Type(
338+
name = Inkuire.TypeName(tp.name),
339+
itid = tp.typeSymbol.itid,
340+
params = Seq.empty,
341+
isVariable = vars.contains(tp.name)
342+
)
343+
case tr @ TermRef(qual, typeName) =>
344+
inner(qual, vars)
345+
case tb@TypeBounds(low, hi) =>
346+
if low.typeSymbol != defn.NothingClass || hi.typeSymbol == defn.AnyClass then
347+
inner(low, vars) //TODO [Inkuire] Type bounds
348+
else
349+
inner(hi, vars)
350+
case NoPrefix() =>
351+
Inkuire.Type.unresolved //TODO [Inkuire] <- should be handled by Singleton case, but didn't work
352+
case MatchType(bond, sc, cases) =>
353+
inner(sc, vars)
354+
case ParamRef(TypeLambda(names, _, _), i) =>
355+
Inkuire.TypeLambda.argument(names(i))
356+
case ParamRef(m: MethodType, i) =>
357+
inner(m.paramTypes(i), vars)
358+
case RecursiveType(tp) =>
359+
inner(tp, vars)
360+
case m@MethodType(_, typeList, resType) =>
361+
val name = s"Function${typeList.size-1}"
320362
Inkuire.Type(
321363
name = Inkuire.TypeName(name),
322-
params = typeList.map(p => Inkuire.Covariance(inner(p, vars))),
364+
params = typeList.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(resType, vars)),
323365
itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false))
324366
)
325-
else
326-
inner(tpe, vars).asInstanceOf[Inkuire.Type].copy(
327-
params = typeList.map(p => Inkuire.Invariance(inner(p, vars)))
328-
)
329-
case tp: TypeRef =>
330-
Inkuire.Type(
331-
name = Inkuire.TypeName(tp.name),
332-
itid = tp.typeSymbol.itid,
333-
params = Seq.empty,
334-
isVariable = vars.contains(tp.name)
335-
)
336-
case tr @ TermRef(qual, typeName) =>
337-
inner(qual, vars)
338-
case TypeBounds(low, hi) =>
339-
inner(low, vars) //TODO [Inkuire] Type bounds
340-
case NoPrefix() =>
341-
Inkuire.Type.unresolved //TODO [Inkuire] <- should be handled by Singleton case, but didn't work
342-
case MatchType(bond, sc, cases) =>
343-
inner(sc, vars)
344-
case ParamRef(TypeLambda(names, _, _), i) =>
345-
Inkuire.TypeLambda.argument(names(i))
346-
case ParamRef(m: MethodType, i) =>
347-
inner(m.paramTypes(i), vars)
348-
case RecursiveType(tp) =>
349-
inner(tp, vars)
350-
case m@MethodType(_, typeList, resType) =>
351-
val name = s"Function${typeList.size-1}"
352-
Inkuire.Type(
353-
name = Inkuire.TypeName(name),
354-
params = typeList.map(p => Inkuire.Contravariance(inner(p, vars))) :+ Inkuire.Covariance(inner(resType, vars)),
355-
itid = Some(Inkuire.ITID(s"${name}scala.${name}//[]", isParsed = false))
356-
)

0 commit comments

Comments
 (0)