From 286abfc4cf6ed41c1622f4964aae321b0b9b6c6d Mon Sep 17 00:00:00 2001 From: Andriy Polishchuk Date: Thu, 6 Dec 2012 11:59:05 +0200 Subject: SI-5841 reification of renamed imports Reification of renamed imports is done by catching Selects with name != their tree.symbol.name, replacing this name with tree.symbol.name, and then doing reifyProduct in case of renamed terms and reifyBoundType (inner) in case of renamed types. --- .../scala/reflect/reify/codegen/GenTrees.scala | 7 +++++++ .../scala/reflect/reify/utils/Extractors.scala | 2 ++ test/files/run/reify_renamed_term_basic.check | 1 + test/files/run/reify_renamed_term_basic.scala | 20 ++++++++++++++++++ .../run/reify_renamed_term_local_to_reifee.check | 1 + .../run/reify_renamed_term_local_to_reifee.scala | 20 ++++++++++++++++++ .../run/reify_renamed_term_overloaded_method.check | 1 + .../run/reify_renamed_term_overloaded_method.scala | 17 +++++++++++++++ test/files/run/reify_renamed_term_si5841.check | 1 + test/files/run/reify_renamed_term_si5841.scala | 7 +++++++ test/files/run/reify_renamed_type_basic.check | 1 + test/files/run/reify_renamed_type_basic.scala | 16 +++++++++++++++ .../run/reify_renamed_type_local_to_reifee.check | 1 + .../run/reify_renamed_type_local_to_reifee.scala | 24 ++++++++++++++++++++++ test/files/run/reify_renamed_type_spliceable.check | 1 + test/files/run/reify_renamed_type_spliceable.scala | 21 +++++++++++++++++++ 16 files changed, 141 insertions(+) create mode 100644 test/files/run/reify_renamed_term_basic.check create mode 100644 test/files/run/reify_renamed_term_basic.scala create mode 100644 test/files/run/reify_renamed_term_local_to_reifee.check create mode 100644 test/files/run/reify_renamed_term_local_to_reifee.scala create mode 100644 test/files/run/reify_renamed_term_overloaded_method.check create mode 100644 test/files/run/reify_renamed_term_overloaded_method.scala create mode 100644 test/files/run/reify_renamed_term_si5841.check create mode 100644 test/files/run/reify_renamed_term_si5841.scala create mode 100644 test/files/run/reify_renamed_type_basic.check create mode 100644 test/files/run/reify_renamed_type_basic.scala create mode 100644 test/files/run/reify_renamed_type_local_to_reifee.check create mode 100644 test/files/run/reify_renamed_type_local_to_reifee.scala create mode 100644 test/files/run/reify_renamed_type_spliceable.check create mode 100644 test/files/run/reify_renamed_type_spliceable.scala diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 918aedce51..f489476e96 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -147,6 +147,11 @@ trait GenTrees { } case tree @ Ident(_) if tree.symbol.isLocalToReifee => mirrorCall(nme.Ident, reify(tree.name)) + case Select(qual, name) => + if (tree.symbol != NoSymbol && tree.symbol.name != name) + reifyProduct(Select(qual, tree.symbol.name)) + else + reifyProduct(tree) case _ => throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) } @@ -196,6 +201,8 @@ trait GenTrees { } tree match { + case Select(qual, name) if (name != tree.symbol.name) => + reifyBoundType(Select(qual, tree.symbol.name)) case Select(_, _) => reifyBoundType(tree) case SelectFromTypeTree(_, _) => 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 -- cgit v1.2.3 From c5ffa03f19758173a8cdb03e8ae18d91c72c000d Mon Sep 17 00:00:00 2001 From: Andriy Polishchuk Date: Thu, 6 Dec 2012 12:01:34 +0200 Subject: Cleanups of reifyBoundTerm and reifyBoundType Cases in reifyBoundTerm are merged by constructors; conditions in reifyBoundType are linearized; also, in latter, or-patterns are used to merge some cases; and some minor stuff not worth mentioning. --- .../scala/reflect/reify/codegen/GenTrees.scala | 131 +++++++++++---------- 1 file changed, 69 insertions(+), 62 deletions(-) diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index f489476e96..31974b5b76 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -120,95 +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 Select(qual, name) => - if (tree.symbol != NoSymbol && tree.symbol.name != name) - reifyProduct(Select(qual, tree.symbol.name)) - else - reifyProduct(tree) - 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(qual, name) if (name != tree.symbol.name) => - reifyBoundType(Select(qual, tree.symbol.name)) - 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)) } -- cgit v1.2.3