diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-12-10 00:33:30 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-02-14 14:09:14 +0100 |
commit | b0176294060c9ce8b86d71e7bc8a7a13cef15b1e (patch) | |
tree | fb68701eda408edfd8d347d22ca97f36eb70df45 /src/compiler | |
parent | 51b16e421ddd4e6c7e90ba945addf39ffcb4fa41 (diff) | |
download | scala-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.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/reflect/reify/codegen/GenUtils.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/reflect/reify/phases/Reshape.scala | 26 |
2 files changed, 28 insertions, 2 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) |