summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-01-25 09:06:08 -0800
committerPaul Phillips <paulp@improving.org>2013-01-25 09:06:08 -0800
commitdacab70646561159b4c34c2d751e03b61eeee369 (patch)
tree985c157d370b2af30987ff0bfa5ab885a9e4f4b0 /src
parentb49eaefd816a80ad7d04b150c16f8e76cfbdb03e (diff)
parent1a7de4314ac72bca81e31ad3ac0af7bee7eed26b (diff)
downloadscala-dacab70646561159b4c34c2d751e03b61eeee369.tar.gz
scala-dacab70646561159b4c34c2d751e03b61eeee369.tar.bz2
scala-dacab70646561159b4c34c2d751e03b61eeee369.zip
Merge pull request #1938 from retronym/ticket/6666
SI-6666 Restrict hidden `this` access in self/super calls.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala38
1 files changed, 31 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 4a23e65ad2..a4f75f424f 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -320,12 +320,24 @@ abstract class LambdaLift extends InfoTransform {
private def memberRef(sym: Symbol) = {
val clazz = sym.owner.enclClass
//Console.println("memberRef from "+currentClass+" to "+sym+" in "+clazz)
- val qual = if (clazz == currentClass) gen.mkAttributedThis(clazz)
- else {
- sym resetFlag(LOCAL | PRIVATE)
- if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType)
- else outerPath(outerValue, currentClass.outerClass, clazz)
- }
+ def prematureSelfReference() {
+ val what =
+ if (clazz.isStaticOwner) clazz.fullLocationString
+ else s"the unconstructed `this` of ${clazz.fullLocationString}"
+ val msg = s"Implementation restriction: access of ${sym.fullLocationString} from ${currentClass.fullLocationString}, would require illegal premature access to $what"
+ currentUnit.error(curTree.pos, msg)
+ }
+ val qual =
+ if (clazz == currentClass) gen.mkAttributedThis(clazz)
+ else {
+ sym resetFlag (LOCAL | PRIVATE)
+ if (selfOrSuperCalls exists (_.owner == clazz)) {
+ prematureSelfReference()
+ EmptyTree
+ }
+ else if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType)
+ else outerPath(outerValue, currentClass.outerClass, clazz)
+ }
Select(qual, sym) setType sym.tpe
}
@@ -495,13 +507,25 @@ abstract class LambdaLift extends InfoTransform {
private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe)
+ /** The stack of constructor symbols in which a call to this() or to the super
+ * constructor is active.
+ */
+ private val selfOrSuperCalls = mutable.Stack[Symbol]()
+ @inline private def inSelfOrSuperCall[A](sym: Symbol)(a: => A) = try {
+ selfOrSuperCalls push sym
+ a
+ } finally selfOrSuperCalls.pop()
+
override def transform(tree: Tree): Tree = tree match {
case Select(ReferenceToBoxed(idt), elem) if elem == nme.elem =>
postTransform(preTransform(idt), isBoxedRef = false)
case ReferenceToBoxed(idt) =>
postTransform(preTransform(idt), isBoxedRef = true)
case _ =>
- postTransform(preTransform(tree))
+ def transformTree = postTransform(preTransform(tree))
+ if (treeInfo isSelfOrSuperConstrCall tree)
+ inSelfOrSuperCall(currentOwner)(transformTree)
+ else transformTree
}
/** Transform statements and add lifted definitions to them. */