summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-12-10 00:33:30 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-14 14:09:14 +0100
commitb0176294060c9ce8b86d71e7bc8a7a13cef15b1e (patch)
treefb68701eda408edfd8d347d22ca97f36eb70df45
parent51b16e421ddd4e6c7e90ba945addf39ffcb4fa41 (diff)
downloadscala-b0176294060c9ce8b86d71e7bc8a7a13cef15b1e.tar.gz
scala-b0176294060c9ce8b86d71e7bc8a7a13cef15b1e.tar.bz2
scala-b0176294060c9ce8b86d71e7bc8a7a13cef15b1e.zip
SI-6484 adds Universe.typeOf[T](x: T)
This is a nice addition to Universe.typeOf[T], quite frequently useful for inspecting ad-hoc types. As promised by https://github.com/scala/scala/pull/1741, which represented my previous stab at adding this API, I ran into problems when trying to introduce the API naively. def typeOf[T](implicit ttag: TypeTag[T]): Type def typeOf[T: TypeTag](x: T): Type The first problem came from the fact that even though they don't look ambiguous, under certain circumstances, the couple of typeOf overloads can become ambiguous. Concretely, ambiguity happens when T <: TypeTag[T], which makes the compiler uncapable to choose an overload to typecheck `typeOf[T](<materialized>: TypeTag[T])`. Luckily, defining x as a by-name parameter fixes the problem. def typeOf[T](implicit ttag: TypeTag[T]): Type def typeOf[T: TypeTag](x: => T): Type The second problem manifested itself in reification of snippets that contained calls to typeOf. Apparently, materialized tags get rolled back by reify as products of macro expansion, becoming replaced with `implicitly[TypeTag[T]]`. Afterwards, subsequent rollback of TypeTree's strips the replacement of its type argument, producing bare `implicitly`. Back then when typeOf wasn't overloaded, this abomination typechecked and worked correctly, but now, due to some weird reason, it stopped. I have worked around this by performing the rollback on a larger scale - instead of hunting down materialized tags, this commit detects calls to typeOf and removes their implicit argument lists altogether.
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenUtils.scala4
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reshape.scala26
-rw-r--r--src/reflect/scala/reflect/api/TypeTags.scala16
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/macros/Aliases.scala12
-rw-r--r--test/files/run/reify_typeof.check10
-rw-r--r--test/files/run/reify_typeof.scala14
-rw-r--r--test/files/run/typetags_typeof_x.check8
-rw-r--r--test/files/run/typetags_typeof_x.scala14
9 files changed, 101 insertions, 5 deletions
diff --git a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
index de9fec0df5..4512b2cb6f 100644
--- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
@@ -5,6 +5,10 @@ trait GenUtils {
self: Reifier =>
import global._
+ import treeInfo._
+ import definitions._
+ private val runDefinitions = currentRun.runDefinitions
+ import runDefinitions._
def reifyList(xs: List[Any]): Tree =
mkList(xs map reify)
diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala
index 6c073c0b4c..9a54632796 100644
--- a/src/compiler/scala/reflect/reify/phases/Reshape.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala
@@ -78,7 +78,7 @@ trait Reshape {
super.transform(preTyper)
}
- private def undoMacroExpansion(tree: Tree): Tree =
+ private def undoMacroExpansion(tree: Tree): Tree = {
tree.attachments.get[analyzer.MacroExpansionAttachment] match {
case Some(analyzer.MacroExpansionAttachment(original, _)) =>
def mkImplicitly(tp: Type) = atPos(tree.pos)(
@@ -96,8 +96,30 @@ trait Reshape {
case Apply(TypeApply(_, List(tt)), List(pre)) if sym == materializeTypeTag => mkImplicitly(typeRef(pre.tpe, TypeTagClass, List(tt.tpe)))
case _ => original
}
- case _ => tree
+ case None =>
+ // `typeOf[T]` calls get translated into `typeOf[T](Predef.implicitly)` by Reshape
+ // unfortunately, this doesn't work well with the recently introduced `def typeOf[T: TypeTag](x: T)` overload
+ // somehow the typechecker is now longer able to make sense of targless implicitly failing with:
+ // ambiguous implicit values:
+ // both value StringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String]
+ // and method conforms in object Predef of type [A]=> <:<[A,A]
+ // match expected type T
+ // could not find implicit value for parameter e: T
+ // overloaded method value typeOf with alternatives:
+ // (x: => List[Int])(implicit evidence$2: ru.TypeTag[List[Int]])ru.Type <and>
+ // (implicit ttag: ru.TypeTag[List[Int]])ru.Type
+ // cannot be applied to (Unit)
+ // therefore here we give the calls to `weakTypeOf` and `typeOf` a bit of extra helping
+ // erasing synthetic implicit arguments altogether, so that this weird tree shape doesn't appear in the reifee in the first place
+ def isTypeOf(sym: Symbol): Boolean = {
+ sym != null && (sym.name == nme.typeOf || sym.name == nme.weakTypeOf) && sym.owner == TypeTagsClass
+ }
+ tree match {
+ case Apply(fun, args) if !tree.tpe.isInstanceOf[MethodType] && isTypeOf(fun.symbol) => fun
+ case _ => tree
+ }
}
+ }
override def transformModifiers(mods: Modifiers) = {
val mods1 = toPreTyperModifiers(mods, currentSymbol)
diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala
index be76758224..d6af68f923 100644
--- a/src/reflect/scala/reflect/api/TypeTags.scala
+++ b/src/reflect/scala/reflect/api/TypeTags.scala
@@ -326,13 +326,25 @@ trait TypeTags { self: Universe =>
* Shortcut for `implicitly[WeakTypeTag[T]].tpe`
* @group TypeTags
*/
- def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe
+ def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = if (attag != null) attag.tpe else typeOf[Null]
+
+ /**
+ * Type of `x` as derived from a weak type tag.
+ * @group TypeTags
+ */
+ def weakTypeOf[T: WeakTypeTag](x: => T): Type = weakTypeOf[T]
/**
* Shortcut for `implicitly[TypeTag[T]].tpe`
* @group TypeTags
*/
- def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
+ def typeOf[T](implicit ttag: TypeTag[T]): Type = if (ttag != null) ttag.tpe else typeOf[Null]
+
+ /**
+ * Type of `x` as derived from a type tag.
+ * @group TypeTags
+ */
+ def typeOf[T: TypeTag](x: => T): Type = typeOf[T]
}
private[scala] class SerializedTypeTag(var tpec: TypeCreator, var concrete: Boolean) extends Serializable {
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 679186f938..71c4009a62 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -768,6 +768,7 @@ trait StdNames {
val tree : NameType = "tree"
val true_ : NameType = "true"
val typedProductIterator: NameType = "typedProductIterator"
+ val typeOf: NameType = "typeOf"
val TypeName: NameType = "TypeName"
val typeTagToManifest: NameType = "typeTagToManifest"
val unapply: NameType = "unapply"
@@ -782,6 +783,7 @@ trait StdNames {
val valueOf : NameType = "valueOf"
val values : NameType = "values"
val wait_ : NameType = "wait"
+ val weakTypeOf: NameType = "weakTypeOf"
val withFilter: NameType = "withFilter"
val zero: NameType = "zero"
diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala
index d2b878d081..8651661c63 100644
--- a/src/reflect/scala/reflect/macros/Aliases.scala
+++ b/src/reflect/scala/reflect/macros/Aliases.scala
@@ -110,10 +110,20 @@ trait Aliases {
/**
* Shortcut for `implicitly[WeakTypeTag[T]].tpe`
*/
- def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe
+ def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = if (attag != null) attag.tpe else typeOf[Null]
+
+ /**
+ * Type of `x` as derived from a weak type tag.
+ */
+ def weakTypeOf[T: WeakTypeTag](x: => T): Type = weakTypeOf[T]
/**
* Shortcut for `implicitly[TypeTag[T]].tpe`
*/
def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
+
+ /**
+ * Type of `x` as derived from a type tag.
+ */
+ def typeOf[T: TypeTag](x: => T): Type = typeOf[T]
}
diff --git a/test/files/run/reify_typeof.check b/test/files/run/reify_typeof.check
new file mode 100644
index 0000000000..670f76faa4
--- /dev/null
+++ b/test/files/run/reify_typeof.check
@@ -0,0 +1,10 @@
+Expr[Unit]({
+ val ru = `package`.universe;
+ val tpe1: ru.Type = ru.typeOf[`package`.List[Int]];
+ Predef.println(tpe1);
+ val tpe2: ru.Type = ru.typeOf(List.apply(1, 2, 3));
+ Predef.println(tpe2)
+})
+scala.List[Int]
+List[Int]
+()
diff --git a/test/files/run/reify_typeof.scala b/test/files/run/reify_typeof.scala
new file mode 100644
index 0000000000..985c57b9ab
--- /dev/null
+++ b/test/files/run/reify_typeof.scala
@@ -0,0 +1,14 @@
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.Eval
+
+object Test extends App {
+ val reified = reify {
+ val ru = scala.reflect.runtime.universe
+ val tpe1: ru.Type = ru.typeOf[List[Int]]
+ println(tpe1)
+ val tpe2: ru.Type = ru.typeOf(List(1, 2, 3))
+ println(tpe2)
+ }
+ println(reified)
+ println(reified.eval)
+} \ No newline at end of file
diff --git a/test/files/run/typetags_typeof_x.check b/test/files/run/typetags_typeof_x.check
new file mode 100644
index 0000000000..832a8bc63c
--- /dev/null
+++ b/test/files/run/typetags_typeof_x.check
@@ -0,0 +1,8 @@
+List[T]
+C
+Int
+List[Any]
+AnyRef{def x: Int}
+Null
+Nothing
+Null
diff --git a/test/files/run/typetags_typeof_x.scala b/test/files/run/typetags_typeof_x.scala
new file mode 100644
index 0000000000..08be6d4527
--- /dev/null
+++ b/test/files/run/typetags_typeof_x.scala
@@ -0,0 +1,14 @@
+import scala.reflect.runtime.universe._
+
+object Test extends App {
+ def foo[T](x: T) = weakTypeOf(List(x))
+ println(foo(2))
+ locally { class C; println(weakTypeOf(new C)) }
+
+ println(typeOf(2))
+ println(typeOf(List(1, "1")))
+ println(typeOf(new { def x = 2 }))
+ println(typeOf[Null])
+ println(typeOf[Nothing])
+ println(typeOf(null))
+} \ No newline at end of file