Skip to content
This repository has been archived by the owner on Feb 20, 2019. It is now read-only.

Minor cleanup of FastTypeTag changes to ensure all tag logic goes thr… #405

Merged
merged 1 commit into from
Apr 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import scala.language.experimental.macros
* with type tags generated from raw java reflection.
*/
trait FastTypeTagMacros extends Macro {
// TODO(joshuasuereth): This is may duplicate functionality with the `.tag` extension method on `Type`.
def impl[T: c.WeakTypeTag]: c.Tree = {

/** Extracts 'simple' types from complex ones.
* here, simple means type constructors (and arguments).
* This method will decompose these, while dropping anything fancy on the floor
* (like existential types)
*/
def extractSimpleTypes[T](t: c.Type)(handler: (String, List[c.Type]) => T): T = {
import c.universe._
import compat._
val T = weakTypeOf[T]
if (T.typeSymbol.isParameter)
c.abort(c.enclosingPosition, s"cannot generate FastTypeTag for type parameter $T, FastTypeTag can only be generated for concrete types")
def handleType(t: c.Type): c.Tree =
def handleType(t: c.Type): T =
t.normalize match {
case ExistentialType(tparams, TypeRef(pre, sym, targs))
if targs.nonEmpty && targs.forall(targ => tparams.contains(targ.typeSymbol)) =>
Expand All @@ -28,12 +30,31 @@ trait FastTypeTagMacros extends Macro {
case RefinedType(first :: tail, scope) => handleType(first)
// TODO - Special handling for inner-classes of classes
case TypeRef(pre, sym, targs) if pre.typeSymbol.isModuleClass =>
val name = sym.fullName + (if (sym.isModuleClass) ".type" else "")
val targSrcs = targs.map(t => q"_root_.scala.Predef.implicitly[_root_.scala.pickling.tags.FastTypeTag[${t}]]")
q"_root_.scala.pickling.tags.FastTypeTag[$T]($name, _root_.scala.List.apply(..$targSrcs))"
case _ =>
q"_root_.scala.pickling.tags.FastTypeTag[$T](${T.toString}, _root_.scala.Nil)"
val name = sym.fullName + (if (sym.isModuleClass) ".type" else "")
handler(name, targs)
case _ => handler(t.toString, Nil)
}
handleType(t)
}
// TODO - Ideally this is uneeded, but for now there are a few places where we want the "string key" of
// a fast type tag, so we duplicate the functionality of runtime in a compile-time method here.
def typeKey(t: c.Type): String = {
extractSimpleTypes(t) { (tcons, targs) =>
if (targs.isEmpty) tcons
else s"$tcons[${targs.map(typeKey).mkString(",")}]"
}
}

// TODO(joshuasuereth): This is may duplicate functionality with the `.tag` extension method on `Type`.
def impl[T: c.WeakTypeTag]: c.Tree = {
import c.universe._
import compat._
val T = weakTypeOf[T]
if (T.typeSymbol.isParameter)
c.abort(c.enclosingPosition, s"cannot generate FastTypeTag for type parameter $T, FastTypeTag can only be generated for concrete types")
extractSimpleTypes(T) { (tcons, targs) =>
val targSrcs = targs.map(t => q"_root_.scala.Predef.implicitly[_root_.scala.pickling.tags.FastTypeTag[${t}]]")
q"_root_.scala.pickling.tags.FastTypeTag[$T]($tcons, _root_.scala.List.apply(..$targSrcs))"
}
handleType(T)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import scala.language.experimental.macros
* with type tags generated from raw java reflection.
*/
trait FastTypeTagMacros extends Macro {
// TODO(joshuasuereth): This is may duplicate functionality with the `.tag` extension method on `Type`.
def impl[T: c.WeakTypeTag]: c.Tree = {

/** Extracts 'simple' types from complex ones.
* here, simple means type constructors (and arguments).
* This method will decompose these, while dropping anything fancy on the floor
* (like existential types)
*/
def extractSimpleTypes[T](t: c.Type)(handler: (String, List[c.Type]) => T): T = {
import c.universe._
import compat._
val T = weakTypeOf[T]
if (T.typeSymbol.isParameter)
c.abort(c.enclosingPosition, s"cannot generate FastTypeTag for type parameter $T, FastTypeTag can only be generated for concrete types")
def handleType(t: c.Type): c.Tree =
def handleType(t: c.Type): T =
t.normalize match {
case ExistentialType(tparams, TypeRef(pre, sym, targs))
if targs.nonEmpty && targs.forall(targ => tparams.contains(targ.typeSymbol)) =>
Expand All @@ -28,12 +30,31 @@ trait FastTypeTagMacros extends Macro {
case RefinedType(first :: tail, scope) => handleType(first)
// TODO - Special handling for inner-classes of classes
case TypeRef(pre, sym, targs) if pre.typeSymbol.isModuleClass =>
val name = sym.fullName + (if (sym.isModuleClass) ".type" else "")
val targSrcs = targs.map(t => q"_root_.scala.Predef.implicitly[_root_.scala.pickling.tags.FastTypeTag[${t}]]")
q"_root_.scala.pickling.tags.FastTypeTag[$T]($name, _root_.scala.List.apply(..$targSrcs))"
case _ =>
q"_root_.scala.pickling.tags.FastTypeTag[$T](${T.toString}, _root_.scala.Nil)"
val name = sym.fullName + (if (sym.isModuleClass) ".type" else "")
handler(name, targs)
case _ => handler(t.toString, Nil)
}
handleType(t)
}
// TODO - Ideally this is uneeded, but for now there are a few places where we want the "string key" of
// a fast type tag, so we duplicate the functionality of runtime in a compile-time method here.
def typeKey(t: c.Type): String = {
extractSimpleTypes(t) { (tcons, targs) =>
if (targs.isEmpty) tcons
else s"$tcons[${targs.map(typeKey).mkString(",")}]"
}
}

// TODO(joshuasuereth): This is may duplicate functionality with the `.tag` extension method on `Type`.
def impl[T: c.WeakTypeTag]: c.Tree = {
import c.universe._
import compat._
val T = weakTypeOf[T]
if (T.typeSymbol.isParameter)
c.abort(c.enclosingPosition, s"cannot generate FastTypeTag for type parameter $T, FastTypeTag can only be generated for concrete types")
extractSimpleTypes(T) { (tcons, targs) =>
val targSrcs = targs.map(t => q"_root_.scala.Predef.implicitly[_root_.scala.pickling.tags.FastTypeTag[${t}]]")
q"_root_.scala.pickling.tags.FastTypeTag[$T]($tcons, _root_.scala.List.apply(..$targSrcs))"
}
handleType(T)
}
}
16 changes: 0 additions & 16 deletions core/src/main/scala/scala/pickling/Tools.scala
Original file line number Diff line number Diff line change
Expand Up @@ -211,22 +211,6 @@ trait RichTypes {
import compat._

implicit class RichType(tpe: scala.reflect.api.Universe#Type) {
// TODO - Remove this. First we need to alter sourcegen so
// that it loads subclass picklers as members of the generated pickler/unpickler and
// pulls tag-key comparison from the string generated by FastTypeTag macro.
def key: String = {
tpe.normalize match {
case ExistentialType(tparams, TypeRef(pre, sym, targs))
if targs.nonEmpty && targs.forall(targ => tparams.contains(targ.typeSymbol)) =>
TypeRef(pre, sym, Nil).key
case TypeRef(pre, sym, targs) if pre.typeSymbol.isModuleClass =>
sym.fullName +
(if (sym.isModuleClass) ".type" else "") +
(if (targs.isEmpty) "" else targs.map(_.key).mkString("[", ",", "]"))
case RefinedType(hd :: tail, scope) => hd.key
case t => t.toString
}
}

def isEffectivelyPrimitive: Boolean = tpe match {
case TypeRef(_, sym: ClassSymbol, _) if sym.isPrimitive => true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ private[pickling] trait SourceGenerator extends Macro with tags.FastTypeTagMacr
val subClassCases =
x.subClasses.toList map { sc =>
val stpe = sc.tpe[c.universe.type](c.universe)
val skey = stpe.key
val skey = typeKey(stpe)
CaseDef(Literal(Constant(skey)), EmptyTree, createUnpickler(stpe))
}
val subClass =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ trait SymbolTestMacros extends Macro {
val tpe = weakTypeOf[T]
val cls = symbols.newClass(tpe)
cls.primaryConstructor match {
case Some(x) => x.parameterTypes[c.universe.type](c.universe).toList.flatMap(_.map(_.key))
case Some(x) => x.parameterTypes[c.universe.type](c.universe).toList.flatMap(_.map(_.toString))
case None => Seq()
}
}
Expand All @@ -28,7 +28,7 @@ trait SymbolTestMacros extends Macro {
val mthds = IrSymbol.allDeclaredMethodIncludingSubclasses(cls)
mthds.filter(_.isVar).map { x =>
//System.err.println(s" - $x, ${x.returnType(c.universe)} from ${x.owner}")
x.returnType[c.universe.type](c.universe).key
x.returnType[c.universe.type](c.universe).toString
}
}

Expand Down Expand Up @@ -75,7 +75,7 @@ trait SymbolTestMacros extends Macro {
def parentClasses[T: WeakTypeTag]: Seq[String] = {
val tpe = weakTypeOf[T]
val cls = symbols.newClass(tpe)
cls.parentClasses.map(_.tpe[c.universe.type](c.universe).key)
cls.parentClasses.map(_.tpe[c.universe.type](c.universe).toString)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,34 +54,34 @@ class TestScalaSymbols extends FunSuite {

test("fieldTypesWithTypeArgs") {
assert(Compat.varTypes[ParentTag.Foo[String, Int]].toSet == Set(
"scala.Tuple2[java.lang.String,scala.Int]", "scala.Int"
"(String, Int)", "Int"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the above representation scala.Tuple2[java.lang.String,scala.Int] is more accurate than (String, Int). Is this happening because you're now using toString of the type implementation? I'm not sure if this human-friendly display name should be taken seriously.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is literally just a test. The macro is ONLY used to test that symbols are pulled out.

Not meant to be human friendly, so no, it's not meant to be taken seriously. It's only so we can test if things inside the macro are working.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. varTypes is used only for your tests.

))
assert(Compat.varTypes[ParentTag.Baz[String]].toSet == Set(
"scala.Tuple2[java.lang.String,scala.Float]",
"scala.Tuple2[java.lang.String,scala.Int]",
"scala.Int"
"(String, Float)",
"(String, Int)",
"Int"
))
assert(Compat.varTypes[ParentTag.Biz].toSet == Set(
"scala.Tuple2[java.lang.String,scala.Float]",
"scala.Tuple2[java.lang.String,scala.Int]",
"scala.Int"
"(String, Float)",
"(String, Int)",
"Int"

))
}

test("constructorParamWithTypeArgs") {
assert(Compat.constructorParamTypes[ParentTag.Foo2] ==
Seq("scala.Tuple2[scala.Int,java.lang.String]")
Seq("(Int, String)")
)
}

test("parentClassesWithTypeArgs") {
val parentClassKeys = Compat.parentClassTags[ParentTag.Biz].toSet
assert(parentClassKeys == Set(
"scala.pickling.generator.scalasymbols.ParentTag.Foo[java.lang.String,scala.Int]",
"scala.pickling.generator.scalasymbols.ParentTag.Baz[java.lang.String]",
"scala.Any",
"java.lang.Object"))
"scala.pickling.generator.scalasymbols.ParentTag.Foo[String,Int]",
"scala.pickling.generator.scalasymbols.ParentTag.Baz[String]",
"Any",
"Object"))
}

test("detectTransient") {
Expand Down