[FIXED] Scala 3 Manifest-Ersatz

Ausgabe

Meine Aufgabe ist es, Typinformationen in Java-ähnlicher Notation auszugeben (unter Verwendung von <, >für die Notation von Typargumenten). In Scala 2 habe ich diese kleine Methode scala.reflect.Manifestals Quelle für das Typsymbol und seine Parameter:

def typeOf[T](implicit manifest: Manifest[T]): String = {
  def loop[T0](m: Manifest[T0]): String =
    if (m.typeArguments.isEmpty) m.runtimeClass.getSimpleName
    else {
      val typeArguments = m.typeArguments.map(loop(_)).mkString(",")
      raw"""${m.runtimeClass.getSimpleName}<$typeArguments>"""
    }
  loop(manifest)
}

Leider sind in Scala 3 Manifeste nicht verfügbar. Gibt es eine Scala 3-native Möglichkeit, dies umzuschreiben? Ich bin offen für einige Inline-Makros. Was ich bisher probiert habe ist

inline def typeOf[T]: String = ${typeOfImpl}

private def typeOfImpl[T: Type](using Quotes): Expr[String] =
  import quotes.reflect.*

  val tree = TypeTree.of[T]
  tree.show 
  //    ^^ call is parameterized with Printer but AFAIK there's no way
  //       to provide your own implementation for it. You can to chose
  //       from predefined ones. So how do I proceed from here?

Ich weiß, dass Scala-Typen nicht alle als Java-Typen dargestellt werden können. Ich beabsichtige, nur einfache abzudecken, die die ursprüngliche Methode abdecken konnte. Keine Wildcards oder Existentials, nur vollständig aufgelöste Typen wie:

  • List[String]Auflösung:List<String>
  • List[Option[String]]Auflösung:List<Option<String>>
  • Map[String,Option[Int]]Auflösung:Map<String,Option<Int>>

Lösung

Die letzte funktionierende Lösung, die ich mir ausgedacht habe, war:

def typeOfImpl[T: Type](using Quotes): Expr[String] = {
  import quotes.reflect.*

  TypeRepr.of[T] match {
    case AppliedType(tpr, args) =>
      val typeName   = Expr(tpr.show)
      val typeArguments = Expr.ofList(args.map {
        _.asType match {
          case '[t] => typeOfImpl[t]
        }
      })
      '{
        val tpeName = ${ typeName }
        val typeArgs  = ${ typeArguments }
        typeArgs.mkString(tpeName + "<", ", ", ">")
      }
    case tpr: TypeRef => Expr(tpr.show)
    case other =>
        report.errorAndAbort(s"unsupported type: ${other.show}", Position.ofMacroExpansion)
  }
}


Beantwortet von –
SimY4


Antwort geprüft von –
Clifford M. (FixError Volunteer)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like