diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2012-12-11 07:40:50 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2012-12-11 07:40:50 -0800 |
commit | c9bca57781ffa64e0d081facf668775f6eaff2e8 (patch) | |
tree | 5abdc9f3674348023f580e5f15f9809e8cae2e73 | |
parent | 7fe7d2537963dd24ea1cca7b0c4b96f96b773c4a (diff) | |
parent | c5ffa03f19758173a8cdb03e8ae18d91c72c000d (diff) | |
download | scala-c9bca57781ffa64e0d081facf668775f6eaff2e8.tar.gz scala-c9bca57781ffa64e0d081facf668775f6eaff2e8.tar.bz2 scala-c9bca57781ffa64e0d081facf668775f6eaff2e8.zip |
Merge pull request #1752 from scalamacros/ticket/5841
Ticket/5841
16 files changed, 203 insertions, 55 deletions
diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 918aedce51..31974b5b76 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -120,88 +120,102 @@ trait GenTrees { // unlike in `reifyBoundType` we can skip checking for `tpe` being local or not local w.r.t the reifee // a single check for a symbol of the bound term should be enough // that's because only Idents and Thises can be bound terms, and they cannot host complex types - private def reifyBoundTerm(tree: Tree): Tree = tree match { - case tree @ This(_) if tree.symbol == NoSymbol => - throw new Error("unexpected: bound term that doesn't have a symbol: " + showRaw(tree)) - case tree @ This(_) if tree.symbol.isClass && !tree.symbol.isModuleClass && !tree.symbol.isLocalToReifee => - val sym = tree.symbol - if (reifyDebug) println("This for %s, reified as freeVar".format(sym)) - if (reifyDebug) println("Free: " + sym) - mirrorBuildCall(nme.Ident, reifyFreeTerm(This(sym))) - case tree @ This(_) if !tree.symbol.isLocalToReifee => - if (reifyDebug) println("This for %s, reified as This".format(tree.symbol)) - mirrorBuildCall(nme.This, reify(tree.symbol)) - case tree @ This(_) if tree.symbol.isLocalToReifee => - mirrorCall(nme.This, reify(tree.qual)) - case tree @ Ident(_) if tree.symbol == NoSymbol => - // this sometimes happens, e.g. for binds that don't have a body - // or for untyped code generated during previous phases - // (see a comment in Reifiers about the latter, starting with "why do we resetAllAttrs?") - mirrorCall(nme.Ident, reify(tree.name)) - case tree @ Ident(_) if !tree.symbol.isLocalToReifee => - if (tree.symbol.isVariable && tree.symbol.owner.isTerm) { - captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reification here. - mirrorCall(nme.Select, mirrorBuildCall(nme.Ident, reify(tree.symbol)), reify(nme.elem)) - } else { - mirrorBuildCall(nme.Ident, reify(tree.symbol)) - } - case tree @ Ident(_) if tree.symbol.isLocalToReifee => - mirrorCall(nme.Ident, reify(tree.name)) - case _ => - throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) + private def reifyBoundTerm(tree: Tree): Tree = { + val sym = tree.symbol + + tree match { + case This(qual) => + assert(sym != NoSymbol, "unexpected: bound term that doesn't have a symbol: " + showRaw(tree)) + if (sym.isLocalToReifee) + mirrorCall(nme.This, reify(qual)) + else if (sym.isClass && !sym.isModuleClass) { + if (reifyDebug) println("This for %s, reified as freeVar".format(sym)) + if (reifyDebug) println("Free: " + sym) + mirrorBuildCall(nme.Ident, reifyFreeTerm(This(sym))) + } + else { + if (reifyDebug) println("This for %s, reified as This".format(sym)) + mirrorBuildCall(nme.This, reify(sym)) + } + + case Ident(name) => + if (sym == NoSymbol) { + // this sometimes happens, e.g. for binds that don't have a body + // or for untyped code generated during previous phases + // (see a comment in Reifiers about the latter, starting with "why do we resetAllAttrs?") + mirrorCall(nme.Ident, reify(name)) + } + else if (!sym.isLocalToReifee) { + if (sym.isVariable && sym.owner.isTerm) { + captureVariable(sym) // Note order dependency: captureVariable needs to come before reification here. + mirrorCall(nme.Select, mirrorBuildCall(nme.Ident, reify(sym)), reify(nme.elem)) + } + else mirrorBuildCall(nme.Ident, reify(sym)) + } + else mirrorCall(nme.Ident, reify(name)) + + case Select(qual, name) => + if (sym == NoSymbol || sym.name == name) + reifyProduct(tree) + else + reifyProduct(Select(qual, sym.name)) + + case _ => + throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) + } } private def reifyBoundType(tree: Tree): Tree = { + val sym = tree.symbol + val tpe = tree.tpe + def reifyBoundType(tree: Tree): Tree = { - if (tree.tpe == null) - throw new Error("unexpected: bound type that doesn't have a tpe: " + showRaw(tree)) + assert(tpe != null, "unexpected: bound type that doesn't have a tpe: " + showRaw(tree)) // if a symbol or a type of the scrutinee are local to reifee // (e.g. point to a locally declared class or to a path-dependent thingie that depends on a local variable) // then we can reify the scrutinee as a symless AST and that will definitely be hygienic // why? because then typechecking of a scrutinee doesn't depend on the environment external to the quasiquote // otherwise we need to reify the corresponding type - if (tree.symbol.isLocalToReifee || tree.tpe.isLocalToReifee) + if (sym.isLocalToReifee || tpe.isLocalToReifee) reifyProduct(tree) else { - val sym = tree.symbol - val tpe = tree.tpe if (reifyDebug) println("reifying bound type %s (underlying type is %s)".format(sym, tpe)) if (tpe.isSpliceable) { val spliced = spliceType(tpe) + if (spliced == EmptyTree) { if (reifyDebug) println("splicing failed: reify as is") mirrorBuildCall(nme.TypeTree, reify(tpe)) - } else { - spliced match { - case TypeRefToFreeType(freeType) => - if (reifyDebug) println("splicing returned a free type: " + freeType) - Ident(freeType) - case _ => - if (reifyDebug) println("splicing succeeded: " + spliced) - mirrorBuildCall(nme.TypeTree, spliced) - } } - } else { - if (sym.isLocatable) { - if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym)) - mirrorBuildCall(nme.Ident, reify(sym)) - } else { - if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe)) - mirrorBuildCall(nme.TypeTree, reify(tpe)) + else spliced match { + case TypeRefToFreeType(freeType) => + if (reifyDebug) println("splicing returned a free type: " + freeType) + Ident(freeType) + case _ => + if (reifyDebug) println("splicing succeeded: " + spliced) + mirrorBuildCall(nme.TypeTree, spliced) } } + else if (sym.isLocatable) { + if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym)) + mirrorBuildCall(nme.Ident, reify(sym)) + } + else { + if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe)) + mirrorBuildCall(nme.TypeTree, reify(tpe)) + } } } tree match { - case Select(_, _) => - reifyBoundType(tree) - case SelectFromTypeTree(_, _) => - reifyBoundType(tree) - case Ident(_) => + case Select(qual, name) if name != sym.name => + reifyBoundType(Select(qual, sym.name)) + + case Select(_, _) | SelectFromTypeTree(_, _) | Ident(_) => reifyBoundType(tree) + case _ => throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) } diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index b60d15c1d4..ebbcb95481 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -251,6 +251,8 @@ trait Extractors { object BoundTerm { def unapply(tree: Tree): Option[Tree] = tree match { + case Select(_, name) if name.isTermName => + Some(tree) case Ident(name) if name.isTermName => Some(tree) case This(_) => diff --git a/test/files/run/reify_renamed_term_basic.check b/test/files/run/reify_renamed_term_basic.check new file mode 100644 index 0000000000..e78f94fffd --- /dev/null +++ b/test/files/run/reify_renamed_term_basic.check @@ -0,0 +1 @@ +((),(),()) diff --git a/test/files/run/reify_renamed_term_basic.scala b/test/files/run/reify_renamed_term_basic.scala new file mode 100644 index 0000000000..cd76def395 --- /dev/null +++ b/test/files/run/reify_renamed_term_basic.scala @@ -0,0 +1,20 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object A { + object B { + val c = () + } +} + +object Test extends App { + import A.{B => X} + import A.B.{c => y} + import X.{c => z} + + val expr = reify ( + X.c, y, z + ) + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_term_local_to_reifee.check b/test/files/run/reify_renamed_term_local_to_reifee.check new file mode 100644 index 0000000000..e78f94fffd --- /dev/null +++ b/test/files/run/reify_renamed_term_local_to_reifee.check @@ -0,0 +1 @@ +((),(),()) diff --git a/test/files/run/reify_renamed_term_local_to_reifee.scala b/test/files/run/reify_renamed_term_local_to_reifee.scala new file mode 100644 index 0000000000..1860316a5b --- /dev/null +++ b/test/files/run/reify_renamed_term_local_to_reifee.scala @@ -0,0 +1,20 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object A { + object B { + val c = () + } +} + +object Test extends App { + val expr = reify { + import A.{B => X} + import A.B.{c => y} + import X.{c => z} + + (X.c, y, z) + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_term_overloaded_method.check b/test/files/run/reify_renamed_term_overloaded_method.check new file mode 100644 index 0000000000..48082f72f0 --- /dev/null +++ b/test/files/run/reify_renamed_term_overloaded_method.check @@ -0,0 +1 @@ +12 diff --git a/test/files/run/reify_renamed_term_overloaded_method.scala b/test/files/run/reify_renamed_term_overloaded_method.scala new file mode 100644 index 0000000000..3ef442d203 --- /dev/null +++ b/test/files/run/reify_renamed_term_overloaded_method.scala @@ -0,0 +1,17 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object O { + def show(i: Int) = i.toString + def show(s: String) = s +} + +object Test extends App { + import O.{show => s} + + val expr = reify { + s("1") + s(2) + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_term_si5841.check b/test/files/run/reify_renamed_term_si5841.check new file mode 100644 index 0000000000..6031277b76 --- /dev/null +++ b/test/files/run/reify_renamed_term_si5841.check @@ -0,0 +1 @@ +class scala.reflect.runtime.JavaUniverse diff --git a/test/files/run/reify_renamed_term_si5841.scala b/test/files/run/reify_renamed_term_si5841.scala new file mode 100644 index 0000000000..ef18d650bf --- /dev/null +++ b/test/files/run/reify_renamed_term_si5841.scala @@ -0,0 +1,7 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{universe => ru} +import scala.tools.reflect.Eval + +object Test extends App { + println(reify{ru}.eval.getClass) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_type_basic.check b/test/files/run/reify_renamed_type_basic.check new file mode 100644 index 0000000000..6a452c185a --- /dev/null +++ b/test/files/run/reify_renamed_type_basic.check @@ -0,0 +1 @@ +() diff --git a/test/files/run/reify_renamed_type_basic.scala b/test/files/run/reify_renamed_type_basic.scala new file mode 100644 index 0000000000..23729e5c54 --- /dev/null +++ b/test/files/run/reify_renamed_type_basic.scala @@ -0,0 +1,16 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object O { + type A = Unit +} + +object Test extends App { + import O.{A => X} + + def expr = reify { + val a: X = () + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_type_local_to_reifee.check b/test/files/run/reify_renamed_type_local_to_reifee.check new file mode 100644 index 0000000000..6a452c185a --- /dev/null +++ b/test/files/run/reify_renamed_type_local_to_reifee.check @@ -0,0 +1 @@ +() diff --git a/test/files/run/reify_renamed_type_local_to_reifee.scala b/test/files/run/reify_renamed_type_local_to_reifee.scala new file mode 100644 index 0000000000..ed1bad239e --- /dev/null +++ b/test/files/run/reify_renamed_type_local_to_reifee.scala @@ -0,0 +1,24 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object O { + type A = Unit +} + +object Test extends App { + val expr = reify { + import O.{A => X} + + val a: X = () + + object P { + type B = Unit + } + + import P.{B => Y} + + val b: Y = () + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_type_spliceable.check b/test/files/run/reify_renamed_type_spliceable.check new file mode 100644 index 0000000000..6a452c185a --- /dev/null +++ b/test/files/run/reify_renamed_type_spliceable.check @@ -0,0 +1 @@ +() diff --git a/test/files/run/reify_renamed_type_spliceable.scala b/test/files/run/reify_renamed_type_spliceable.scala new file mode 100644 index 0000000000..9c2cff5199 --- /dev/null +++ b/test/files/run/reify_renamed_type_spliceable.scala @@ -0,0 +1,21 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +abstract class C { + type T >: Null +} + +object Test extends App { + def foo(c: C) = { + import c.{T => U} + reify { + val x: U = null + } + } + + val expr = foo(new C { + type T = AnyRef + }) + + println(expr.eval) +}
\ No newline at end of file |