Skip to content

Commit

Permalink
airframe-surface: Scala3 higher-kind type support (#2395)
Browse files Browse the repository at this point in the history
airframe=surface: Scala3 higher-kind type support
  • Loading branch information
xerial committed Sep 5, 2022
1 parent ab39f24 commit a1ce684
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 24 deletions.
@@ -1,6 +1,5 @@
package wvlet.airframe.surface
import scala.quoted._
import dotty.tools.dotc.core.{Types as DottyTypes}

private[surface] object CompileTimeSurfaceFactory {

Expand Down Expand Up @@ -91,19 +90,23 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q) {
} else {
seen += t
// For debugging
// println(s"[${typeNameOf(t)}]\n ${t}")
// println(s"[${typeNameOf(t)}]\n ${t}\nfull type name: ${fullTypeNameOf(t)}\nclass: ${t.getClass}")
val generator = factory.andThen { expr =>
val cacheKey =
if (typeNameOf(t) == "scala.Any" && classOf[DottyTypes.TypeBounds].isAssignableFrom(t.getClass)) {
// Distinguish scala.Any and type bounds (such as _)
s"${fullTypeNameOf(t)} for ${t}"
} else if (typeNameOf(t) == "scala.Any" && classOf[DottyTypes.TypeParamRef].isAssignableFrom(t.getClass)) {
// This ensure different cache key for each Type Parameter (such as T and U).
// This is required because fullTypeNameOf of every Type Parameters is `scala.Any`.
s"${fullTypeNameOf(t)} for ${t}"
} else {
fullTypeNameOf(t)
val cacheKey = if (typeNameOf(t) == "scala.Any") {
t match {
case ParamRef(TypeLambda(typeNames, _, _), _) =>
// Distinguish scala.Any and type bounds (such as _)
s"${fullTypeNameOf(t)} for ${t}"
case TypeBounds(_, _) =>
// This ensures different cache key for each Type Parameter (such as T and U).
// This is required because fullTypeNameOf of every Type Parameters is `scala.Any`.
s"${fullTypeNameOf(t)} for ${t}"
case _ =>
fullTypeNameOf(t)
}
} else {
fullTypeNameOf(t)
}
'{
val key = ${ Expr(cacheKey) }
if (!wvlet.airframe.surface.surfaceCache.contains(key)) {
Expand All @@ -130,7 +133,6 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q) {
javaEnumFactory orElse
exisitentialTypeFactory orElse
genericTypeWithConstructorFactory orElse
typeParameterFactory orElse
genericTypeFactory
}

Expand Down Expand Up @@ -208,15 +210,16 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q) {
val args = a.args.map(surfaceOf(_))
// TODO support type erasure instead of using AnyRefSurface
'{ HigherKindedTypeSurface(${ Expr(name) }, ${ Expr(fullName) }, AnyRefSurface, ${ Expr.ofSeq(args) }) }
case p @ ParamRef(TypeLambda(typeNames, _, _), _) =>
val name = typeNames.mkString(",")
val fullName = fullTypeNameOf(p)
'{ HigherKindedTypeSurface(${ Expr(name) }, ${ Expr(fullName) }, AnyRefSurface, Seq.empty) }
}

private def typeArgsOf(t: TypeRepr): List[TypeRepr] = {
t match {
case a: AppliedType =>
a.args
// TODO: Dealiasing should be done before ?
case DottyTypes.TypeAlias(DottyTypes.HKTypeLambda(_, a: AppliedType)) =>
a.args
case other =>
List.empty
}
Expand Down Expand Up @@ -401,12 +404,6 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q) {
})
}

private def typeParameterFactory: Factory = {
case p: DottyTypes.ParamRef if (fullTypeNameOf(p) == "Any") =>
val paramName = Expr(p.paramName.toString)
'{ HigherKindedTypeSurface(${ paramName }, ${ paramName }, AnyRefSurface, Nil) }
}

private def genericTypeFactory: Factory = {
case a: AppliedType =>
val typeArgs = a.args.map(surfaceOf(_))
Expand Down
Expand Up @@ -37,8 +37,6 @@ class RecursiveHigherKindTypeTest extends SurfaceSpec {
import Holder.BySkinny

test("support recursive higher kind types") {
// ....

val s = Surface.of[Holder[BySkinny]]
assertEquals(s.name, "Holder[BySkinny]")
assertEquals(s.isAlias, false)
Expand Down

0 comments on commit a1ce684

Please sign in to comment.