From 6f5593a2558a3ec553b2b66c265e650862939bb7 Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Tue, 12 Apr 2016 15:36:27 -0400 Subject: [PATCH] Minor cleanup of FastTypeTag changes to ensure all tag logic goes through new macro. --- .../pickling/tags/FastTypeTagMacros.scala | 45 ++++++++++++++----- .../pickling/tags/FastTypeTagMacros.scala | 45 ++++++++++++++----- .../src/main/scala/scala/pickling/Tools.scala | 16 ------- .../scala/pickling/generator/sourcegen.scala | 2 +- .../generator/scalasymbols/Compat.scala | 6 +-- .../scalasymbols/TestScalaSymbols.scala | 24 +++++----- 6 files changed, 82 insertions(+), 56 deletions(-) diff --git a/core/src/main/scala-2.10/scala/pickling/tags/FastTypeTagMacros.scala b/core/src/main/scala-2.10/scala/pickling/tags/FastTypeTagMacros.scala index 5cd8aa924b..7aa1cc2269 100644 --- a/core/src/main/scala-2.10/scala/pickling/tags/FastTypeTagMacros.scala +++ b/core/src/main/scala-2.10/scala/pickling/tags/FastTypeTagMacros.scala @@ -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)) => @@ -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) } } \ No newline at end of file diff --git a/core/src/main/scala-2.11/scala/pickling/tags/FastTypeTagMacros.scala b/core/src/main/scala-2.11/scala/pickling/tags/FastTypeTagMacros.scala index 3e4f1215d6..86c51a5001 100644 --- a/core/src/main/scala-2.11/scala/pickling/tags/FastTypeTagMacros.scala +++ b/core/src/main/scala-2.11/scala/pickling/tags/FastTypeTagMacros.scala @@ -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)) => @@ -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) } } \ No newline at end of file diff --git a/core/src/main/scala/scala/pickling/Tools.scala b/core/src/main/scala/scala/pickling/Tools.scala index 05b8b8b762..07142cfb80 100644 --- a/core/src/main/scala/scala/pickling/Tools.scala +++ b/core/src/main/scala/scala/pickling/Tools.scala @@ -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 diff --git a/core/src/main/scala/scala/pickling/generator/sourcegen.scala b/core/src/main/scala/scala/pickling/generator/sourcegen.scala index 97c09a2798..dd409ea8ca 100644 --- a/core/src/main/scala/scala/pickling/generator/sourcegen.scala +++ b/core/src/main/scala/scala/pickling/generator/sourcegen.scala @@ -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 = diff --git a/macro-test/src/main/scala/scala/pickling/generator/scalasymbols/Compat.scala b/macro-test/src/main/scala/scala/pickling/generator/scalasymbols/Compat.scala index e5298c993e..080fb86f58 100644 --- a/macro-test/src/main/scala/scala/pickling/generator/scalasymbols/Compat.scala +++ b/macro-test/src/main/scala/scala/pickling/generator/scalasymbols/Compat.scala @@ -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() } } @@ -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 } } @@ -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) } } diff --git a/macro-test/src/test/scala/scala/pickling/generator/scalasymbols/TestScalaSymbols.scala b/macro-test/src/test/scala/scala/pickling/generator/scalasymbols/TestScalaSymbols.scala index 7344c2e505..64ee1007ff 100644 --- a/macro-test/src/test/scala/scala/pickling/generator/scalasymbols/TestScalaSymbols.scala +++ b/macro-test/src/test/scala/scala/pickling/generator/scalasymbols/TestScalaSymbols.scala @@ -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" )) 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") {