Skip to content

Commit 09ef873

Browse files
4e6xeno-by
authored andcommitted
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
1 parent 9164c2a commit 09ef873

21 files changed

+165
-20
lines changed

src/compiler/scala/reflect/reify/codegen/GenSymbols.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ trait GenSymbols {
100100
reifyIntoSymtab(binding.symbol) { sym =>
101101
if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym + "(" + sym.accurateKindString + ")")
102102
val name = newTermName(nme.REIFY_FREE_PREFIX + sym.name + (if (sym.isType) nme.REIFY_FREE_THIS_SUFFIX else ""))
103+
// Flag <stable> is set here to make reified free value pass stability test during reflective compilation
104+
if (!sym.isMutable) sym setFlag reflect.internal.Flags.STABLE
103105
if (sym.isCapturedVariable) {
104106
assert(binding.isInstanceOf[Ident], showRaw(binding))
105107
val capturedBinding = referenceCapturedVariable(sym)

src/compiler/scala/reflect/reify/codegen/GenTrees.scala

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,11 @@ trait GenTrees {
163163
}
164164
}
165165

166-
private def reifyBoundType(tree: Tree): Tree = {
166+
private def reifyBoundType(tree: RefTree): Tree = {
167167
val sym = tree.symbol
168168
val tpe = tree.tpe
169169

170-
def reifyBoundType(tree: Tree): Tree = {
170+
def reifyBoundType(tree: RefTree): Tree = {
171171
assert(tpe != null, "unexpected: bound type that doesn't have a tpe: " + showRaw(tree))
172172

173173
// if a symbol or a type of the scrutinee are local to reifee
@@ -196,13 +196,19 @@ trait GenTrees {
196196
mirrorBuildCall(nme.TypeTree, spliced)
197197
}
198198
}
199-
else if (sym.isLocatable) {
200-
if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym))
201-
mirrorBuildCall(nme.Ident, reify(sym))
202-
}
203-
else {
204-
if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe))
205-
mirrorBuildCall(nme.TypeTree, reify(tpe))
199+
else tree match {
200+
case Select(qual, name) if !qual.symbol.isPackage && !qual.symbol.isPackageObject && qual.symbol != definitions.PredefModule =>
201+
if (reifyDebug) println(s"reifying Select($qual, $name)")
202+
mirrorCall(nme.Select, reify(qual), reify(name))
203+
case SelectFromTypeTree(qual, name) =>
204+
if (reifyDebug) println(s"reifying SelectFromTypeTree($qual, $name)")
205+
mirrorCall(nme.SelectFromTypeTree, reify(qual), reify(name))
206+
case _ if sym.isLocatable =>
207+
if (reifyDebug) println(s"tpe is locatable: reify as Ident($sym)")
208+
mirrorBuildCall(nme.Ident, reify(sym))
209+
case _ =>
210+
if (reifyDebug) println(s"tpe is not locatable: reify as TypeTree($tpe)")
211+
mirrorBuildCall(nme.TypeTree, reify(tpe))
206212
}
207213
}
208214
}

src/compiler/scala/reflect/reify/utils/Extractors.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,12 @@ trait Extractors {
263263
}
264264

265265
object BoundType {
266-
def unapply(tree: Tree): Option[Tree] = tree match {
267-
case Select(_, name) if name.isTypeName =>
266+
def unapply(tree: Tree): Option[RefTree] = tree match {
267+
case tree @ Select(_, name) if name.isTypeName =>
268268
Some(tree)
269-
case SelectFromTypeTree(_, name) if name.isTypeName =>
269+
case tree @ SelectFromTypeTree(_, _) =>
270270
Some(tree)
271-
case Ident(name) if name.isTypeName =>
271+
case tree @ Ident(name) if name.isTypeName =>
272272
Some(tree)
273273
case _ =>
274274
None

src/compiler/scala/tools/reflect/ToolBoxFactory.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
212212
val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName))
213213
def makeParam(schema: (FreeTermSymbol, TermName)) = {
214214
val (fv, name) = schema
215-
meth.newValueParameter(name) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType))
215+
/* Free term symbol `fv` can contain flag <stable> which was set by
216+
* `scala.reflect.reify.codegen.GenSymbols.reifyFreeTerm` method.
217+
* It is recovered here, so value parameter can pass `isExprSafeToInline`
218+
* test in `scala.reflect.internal.TreeInfo`. */
219+
meth.newValueParameter(name, newFlags = if (fv.hasStableFlag) Flags.STABLE else 0) setInfo appliedType(definitions.FunctionClass(0).tpe, List(fv.tpe.resultType))
216220
}
217221
meth setInfo MethodType(freeTerms.map(makeParam).toList, AnyClass.tpe)
218222
minfo.decls enter meth
@@ -418,4 +422,3 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
418422
def eval(tree: u.Tree): Any = compile(tree)()
419423
}
420424
}
421-

src/reflect/scala/reflect/internal/Flags.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ class Flags extends ModifierFlags {
274274
* from Modifiers. Others which may be applied at creation time are:
275275
* SYNTHETIC.
276276
*/
277-
final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM
277+
final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM | STABLE
278278
final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC
279279
final val VarianceFlags = COVARIANT | CONTRAVARIANT
280280

src/reflect/scala/reflect/internal/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ trait StdNames {
607607
val RootPackage: NameType = "RootPackage"
608608
val RootClass: NameType = "RootClass"
609609
val Select: NameType = "Select"
610+
val SelectFromTypeTree: NameType = "SelectFromTypeTree"
610611
val StringContext: NameType = "StringContext"
611612
val This: NameType = "This"
612613
val ThisType: NameType = "ThisType"

src/reflect/scala/reflect/internal/TreeInfo.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ abstract class TreeInfo {
8989
tree.symbol.isStable && isExprSafeToInline(qual)
9090
case TypeApply(fn, _) =>
9191
isExprSafeToInline(fn)
92+
/* Special case for reified free terms. During reflective compilation,
93+
* reified value recovered flag <stable> from free term and wrapped into a
94+
* Function object, so it can pass stability check here to become a stable
95+
* identifier.*/
96+
case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
97+
free.symbol.hasStableFlag && isExprSafeToInline(free)
9298
case Apply(fn, List()) =>
9399
/* Note: After uncurry, field accesses are represented as Apply(getter, Nil),
94100
* so an Apply can also be pure.
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
List(2)
1+
reflective toolbox has failed:
2+
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
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import scala.reflect.runtime.universe._
2-
import scala.tools.reflect.ToolBox
2+
import scala.tools.reflect.{ ToolBox, ToolBoxError }
33
import scala.tools.reflect.Eval
44

55
object Test extends App {
@@ -9,9 +9,10 @@ object Test extends App {
99
val code = reify {
1010
List[C#T](2)
1111
}
12-
println(code.eval)
12+
try { println(code.eval) }
13+
catch { case e: ToolBoxError => println(e.getMessage) }
1314
}
1415

1516
new C
1617
}
17-
}
18+
}

test/files/run/t6591_1.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Block(List(ValDef(Modifiers(), newTermName("v"), Select(Ident(A), newTypeName("I")), Select(Ident(A), newTermName("impl")))), Ident(newTermName("v")))

0 commit comments

Comments
 (0)