summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Bushev <bushevdv@gmail.com>2012-12-14 17:09:55 +0400
committerEugene Burmako <xeno.by@gmail.com>2013-02-08 12:53:14 +0100
commit09ef8730d13eff1cf200bbfb0f6fda7f6d72524a (patch)
tree85c49426a77eb415678fdea5eee12522ca16e276
parent9164c2af4183e04986eb652e09081daba3d0d279 (diff)
downloadscala-09ef8730d13eff1cf200bbfb0f6fda7f6d72524a.tar.gz
scala-09ef8730d13eff1cf200bbfb0f6fda7f6d72524a.tar.bz2
scala-09ef8730d13eff1cf200bbfb0f6fda7f6d72524a.zip
SI-6591 Reify and path-dependent types
Reification scheme changed. Now Select an SelectFromTypeTree trees reified appropriately, as Select and SelectFromTypeTree accordingly. Packages and Predef object was excluded in order not to break the existing reification scheme and not to break tests which rely on it. Reified free terms can contain flag <stable> to make reified values become stable identifiers. For example in the case of reify_newimpl_15.scala class C { type T reify { val v: List[T] = List(2) } } class C reified as free term C$value, and List[C.T] becomes List[C$value().T], so C$value.apply() need to pass stability test isExprSafeToInline at scala.reflect.internal.TreeInfo. For this purpose special case for reified free terms was added to isExprSafeToInline function. test run/reify_newipl_30 disabled due to SI-7082 test t6591_4 moved to pending due to SI-7083
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenSymbols.scala2
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenTrees.scala24
-rw-r--r--src/compiler/scala/reflect/reify/utils/Extractors.scala8
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala7
-rw-r--r--src/reflect/scala/reflect/internal/Flags.scala2
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala6
-rw-r--r--test/files/run/reify_newimpl_30.check3
-rw-r--r--test/files/run/reify_newimpl_30.scala7
-rw-r--r--test/files/run/t6591_1.check1
-rw-r--r--test/files/run/t6591_1.scala19
-rw-r--r--test/files/run/t6591_2.check1
-rw-r--r--test/files/run/t6591_2.scala19
-rw-r--r--test/files/run/t6591_3.check1
-rw-r--r--test/files/run/t6591_3.scala17
-rw-r--r--test/files/run/t6591_5.check1
-rw-r--r--test/files/run/t6591_5.scala23
-rw-r--r--test/files/run/t6591_6.check1
-rw-r--r--test/files/run/t6591_6.scala24
-rw-r--r--test/pending/run/t6591_4.check1
-rw-r--r--test/pending/run/t6591_4.scala17
21 files changed, 165 insertions, 20 deletions
diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
index 22a834d2e4..0d795e3783 100644
--- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
@@ -100,6 +100,8 @@ trait GenSymbols {
reifyIntoSymtab(binding.symbol) { sym =>
if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym + "(" + sym.accurateKindString + ")")
val name = newTermName(nme.REIFY_FREE_PREFIX + sym.name + (if (sym.isType) nme.REIFY_FREE_THIS_SUFFIX else ""))
+ // Flag <stable> is set here to make reified free value pass stability test during reflective compilation
+ if (!sym.isMutable) sym setFlag reflect.internal.Flags.STABLE
if (sym.isCapturedVariable) {
assert(binding.isInstanceOf[Ident], showRaw(binding))
val capturedBinding = referenceCapturedVariable(sym)
diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala
index 06e287f62f..7c7a79e774 100644
--- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala
@@ -163,11 +163,11 @@ trait GenTrees {
}
}
- private def reifyBoundType(tree: Tree): Tree = {
+ private def reifyBoundType(tree: RefTree): Tree = {
val sym = tree.symbol
val tpe = tree.tpe
- def reifyBoundType(tree: Tree): Tree = {
+ def reifyBoundType(tree: RefTree): 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
@@ -196,13 +196,19 @@ trait GenTrees {
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 tree match {
+ case Select(qual, name) if !qual.symbol.isPackage && !qual.symbol.isPackageObject && qual.symbol != definitions.PredefModule =>
+ if (reifyDebug) println(s"reifying Select($qual, $name)")
+ mirrorCall(nme.Select, reify(qual), reify(name))
+ case SelectFromTypeTree(qual, name) =>
+ if (reifyDebug) println(s"reifying SelectFromTypeTree($qual, $name)")
+ mirrorCall(nme.SelectFromTypeTree, reify(qual), reify(name))
+ case _ if sym.isLocatable =>
+ if (reifyDebug) println(s"tpe is locatable: reify as Ident($sym)")
+ mirrorBuildCall(nme.Ident, reify(sym))
+ case _ =>
+ if (reifyDebug) println(s"tpe is not locatable: reify as TypeTree($tpe)")
+ mirrorBuildCall(nme.TypeTree, reify(tpe))
}
}
}
diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala
index ebbcb95481..134ae13890 100644
--- a/src/compiler/scala/reflect/reify/utils/Extractors.scala
+++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala
@@ -263,12 +263,12 @@ trait Extractors {
}
object BoundType {
- def unapply(tree: Tree): Option[Tree] = tree match {
- case Select(_, name) if name.isTypeName =>
+ def unapply(tree: Tree): Option[RefTree] = tree match {
+ case tree @ Select(_, name) if name.isTypeName =>
Some(tree)
- case SelectFromTypeTree(_, name) if name.isTypeName =>
+ case tree @ SelectFromTypeTree(_, _) =>
Some(tree)
- case Ident(name) if name.isTypeName =>
+ case tree @ Ident(name) if name.isTypeName =>
Some(tree)
case _ =>
None
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 95135b84e0..fdc790a920 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -212,7 +212,11 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName))
def makeParam(schema: (FreeTermSymbol, TermName)) = {
val (fv, name) = schema
- meth.newValueParameter(name) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType))
+ /* Free term symbol `fv` can contain flag <stable> which was set by
+ * `scala.reflect.reify.codegen.GenSymbols.reifyFreeTerm` method.
+ * It is recovered here, so value parameter can pass `isExprSafeToInline`
+ * test in `scala.reflect.internal.TreeInfo`. */
+ meth.newValueParameter(name, newFlags = if (fv.hasStableFlag) Flags.STABLE else 0) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType))
}
meth setInfo MethodType(freeTerms.map(makeParam).toList, AnyClass.tpe)
minfo.decls enter meth
@@ -418,4 +422,3 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
def eval(tree: u.Tree): Any = compile(tree)()
}
}
-
diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala
index a0362c8921..5853315479 100644
--- a/src/reflect/scala/reflect/internal/Flags.scala
+++ b/src/reflect/scala/reflect/internal/Flags.scala
@@ -274,7 +274,7 @@ class Flags extends ModifierFlags {
* from Modifiers. Others which may be applied at creation time are:
* SYNTHETIC.
*/
- final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM
+ final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM | STABLE
final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC
final val VarianceFlags = COVARIANT | CONTRAVARIANT
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index ddc5d94e70..bcda2bc1ae 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -607,6 +607,7 @@ trait StdNames {
val RootPackage: NameType = "RootPackage"
val RootClass: NameType = "RootClass"
val Select: NameType = "Select"
+ val SelectFromTypeTree: NameType = "SelectFromTypeTree"
val StringContext: NameType = "StringContext"
val This: NameType = "This"
val ThisType: NameType = "ThisType"
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 8b5dc80c83..f83106aaef 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -89,6 +89,12 @@ abstract class TreeInfo {
tree.symbol.isStable && isExprSafeToInline(qual)
case TypeApply(fn, _) =>
isExprSafeToInline(fn)
+ /* Special case for reified free terms. During reflective compilation,
+ * reified value recovered flag <stable> from free term and wrapped into a
+ * Function object, so it can pass stability check here to become a stable
+ * identifier.*/
+ case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
+ free.symbol.hasStableFlag && isExprSafeToInline(free)
case Apply(fn, List()) =>
/* Note: After uncurry, field accesses are represented as Apply(getter, Nil),
* so an Apply can also be pure.
diff --git a/test/files/run/reify_newimpl_30.check b/test/files/run/reify_newimpl_30.check
index c23af69b08..29baac911e 100644
--- a/test/files/run/reify_newimpl_30.check
+++ b/test/files/run/reify_newimpl_30.check
@@ -1 +1,2 @@
-List(2)
+reflective toolbox has failed:
+unresolved free type variables (namely: C defined by <local Test> in reify_newimpl_30.scala:7:11). have you forgot to use TypeTag annotations for type parameters external to a reifee? if you have troubles tracking free type variables, consider using -Xlog-free-types
diff --git a/test/files/run/reify_newimpl_30.scala b/test/files/run/reify_newimpl_30.scala
index 573d05a630..bc34f1bb6c 100644
--- a/test/files/run/reify_newimpl_30.scala
+++ b/test/files/run/reify_newimpl_30.scala
@@ -1,5 +1,5 @@
import scala.reflect.runtime.universe._
-import scala.tools.reflect.ToolBox
+import scala.tools.reflect.{ ToolBox, ToolBoxError }
import scala.tools.reflect.Eval
object Test extends App {
@@ -9,9 +9,10 @@ object Test extends App {
val code = reify {
List[C#T](2)
}
- println(code.eval)
+ try { println(code.eval) }
+ catch { case e: ToolBoxError => println(e.getMessage) }
}
new C
}
-} \ No newline at end of file
+}
diff --git a/test/files/run/t6591_1.check b/test/files/run/t6591_1.check
new file mode 100644
index 0000000000..b6cb6c286d
--- /dev/null
+++ b/test/files/run/t6591_1.check
@@ -0,0 +1 @@
+Block(List(ValDef(Modifiers(), newTermName("v"), Select(Ident(A), newTypeName("I")), Select(Ident(A), newTermName("impl")))), Ident(newTermName("v")))
diff --git a/test/files/run/t6591_1.scala b/test/files/run/t6591_1.scala
new file mode 100644
index 0000000000..6dd9a1d9fb
--- /dev/null
+++ b/test/files/run/t6591_1.scala
@@ -0,0 +1,19 @@
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.ToolBox
+import scala.tools.reflect.Eval
+
+trait O { trait I }
+
+object A extends O {
+ val impl = new I {}
+}
+
+object Test extends App {
+ val code = reify {
+ val v: A.I = A.impl
+ v
+ }
+ println(showRaw(code.tree))
+
+ val v: A.I = code.eval
+}
diff --git a/test/files/run/t6591_2.check b/test/files/run/t6591_2.check
new file mode 100644
index 0000000000..b2d5797cbf
--- /dev/null
+++ b/test/files/run/t6591_2.check
@@ -0,0 +1 @@
+Block(List(ValDef(Modifiers(), newTermName("v"), SelectFromTypeTree(Ident(A), newTypeName("I")), Select(Apply(Select(New(Ident(A)), nme.CONSTRUCTOR), List()), newTermName("impl")))), Ident(newTermName("v")))
diff --git a/test/files/run/t6591_2.scala b/test/files/run/t6591_2.scala
new file mode 100644
index 0000000000..6214308dab
--- /dev/null
+++ b/test/files/run/t6591_2.scala
@@ -0,0 +1,19 @@
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.ToolBox
+import scala.tools.reflect.Eval
+
+trait O { trait I }
+
+class A extends O {
+ val impl = new I {}
+}
+
+object Test extends App {
+ val code = reify {
+ val v: A#I = (new A).impl
+ v
+ }
+ println(showRaw(code.tree))
+
+ val v: A#I = code.eval
+}
diff --git a/test/files/run/t6591_3.check b/test/files/run/t6591_3.check
new file mode 100644
index 0000000000..a7b594ba65
--- /dev/null
+++ b/test/files/run/t6591_3.check
@@ -0,0 +1 @@
+Block(List(ValDef(Modifiers(), newTermName("v"), Select(This(newTypeName("A")), newTypeName("I")), Apply(Select(New(Select(This(newTypeName("A")), newTypeName("I"))), nme.CONSTRUCTOR), List()))), Ident(newTermName("v")))
diff --git a/test/files/run/t6591_3.scala b/test/files/run/t6591_3.scala
new file mode 100644
index 0000000000..b73a7baf48
--- /dev/null
+++ b/test/files/run/t6591_3.scala
@@ -0,0 +1,17 @@
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.ToolBox
+import scala.tools.reflect.Eval
+
+class O { class I }
+
+object A extends O {
+ val code = reify {
+ val v: I = new I
+ v
+ }
+ println(showRaw(code.tree))
+}
+
+object Test extends App {
+ val v: A.I = A.code.eval
+}
diff --git a/test/files/run/t6591_5.check b/test/files/run/t6591_5.check
new file mode 100644
index 0000000000..8f1c2b3ede
--- /dev/null
+++ b/test/files/run/t6591_5.check
@@ -0,0 +1 @@
+Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(This(newTypeName("A")), newTermName("x")), newTypeName("I")), Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v"))))
diff --git a/test/files/run/t6591_5.scala b/test/files/run/t6591_5.scala
new file mode 100644
index 0000000000..18d6f90a9b
--- /dev/null
+++ b/test/files/run/t6591_5.scala
@@ -0,0 +1,23 @@
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.ToolBox
+import scala.tools.reflect.Eval
+import java.lang.reflect.InvocationTargetException
+
+class O { class I }
+
+object A extends O {
+ val x = new O
+ val code = reify {
+ val v: x.I = ???
+ v
+ }
+ println(showRaw(code))
+}
+
+object Test extends App {
+ try {
+ val v: A.x.I = A.code.eval
+ } catch {
+ case ex: InvocationTargetException if ex.getCause.isInstanceOf[NotImplementedError] =>
+ }
+}
diff --git a/test/files/run/t6591_6.check b/test/files/run/t6591_6.check
new file mode 100644
index 0000000000..5ddf7600f1
--- /dev/null
+++ b/test/files/run/t6591_6.check
@@ -0,0 +1 @@
+Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Select(Ident(newTermName("A")), newTermName("x")), newTypeName("I")), Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("$qmark$qmark$qmark")))), Ident(newTermName("v"))))
diff --git a/test/files/run/t6591_6.scala b/test/files/run/t6591_6.scala
new file mode 100644
index 0000000000..2eee87928d
--- /dev/null
+++ b/test/files/run/t6591_6.scala
@@ -0,0 +1,24 @@
+import scala.language.existentials
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.ToolBox
+import scala.tools.reflect.Eval
+import java.lang.reflect.InvocationTargetException
+
+class O { class I }
+
+class A extends O {
+ val x = new O
+ val code = reify {
+ val v: x.I = ???
+ v
+ }
+ println(showRaw(code))
+}
+
+object Test extends App {
+ try {
+ val v = (new A).code.eval
+ } catch {
+ case ex: InvocationTargetException if ex.getCause.isInstanceOf[NotImplementedError] =>
+ }
+}
diff --git a/test/pending/run/t6591_4.check b/test/pending/run/t6591_4.check
new file mode 100644
index 0000000000..0f1c0489e9
--- /dev/null
+++ b/test/pending/run/t6591_4.check
@@ -0,0 +1 @@
+Expr(Block(List(ValDef(Modifiers(), newTermName("v"), Select(Ident(newTermName("A")), newTypeName("I")), Apply(Select(New(Select(Ident(newTermName("A")), newTypeName("I"))), nme.CONSTRUCTOR), List()))), Ident(newTermName("v"))))
diff --git a/test/pending/run/t6591_4.scala b/test/pending/run/t6591_4.scala
new file mode 100644
index 0000000000..f20c8e6127
--- /dev/null
+++ b/test/pending/run/t6591_4.scala
@@ -0,0 +1,17 @@
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.ToolBox
+import scala.tools.reflect.Eval
+
+class O { class I }
+
+class A extends O {
+ val code = reify {
+ val v: I = new I
+ v
+ }
+ println(showRaw(code))
+}
+
+object Test extends App {
+ val v: A#I = (new A).code.eval
+}