summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames Iry <jamesiry@gmail.com>2013-02-08 07:34:11 -0800
committerJames Iry <jamesiry@gmail.com>2013-02-08 07:34:11 -0800
commitc0d1bc4cc4cb2958af69305d286ff684306617a5 (patch)
treeaf67a07ac877e3e34fa4e227bf48786d300352d9 /src
parentabc87e25d9a8030ed65677df9b41f302025c1717 (diff)
parent81fa8316092e295c1a893b6fcf65568c11fffb58 (diff)
downloadscala-c0d1bc4cc4cb2958af69305d286ff684306617a5.tar.gz
scala-c0d1bc4cc4cb2958af69305d286ff684306617a5.tar.bz2
scala-c0d1bc4cc4cb2958af69305d286ff684306617a5.zip
Merge pull request #2017 from retronym/ticket/6666
Booking more progress on SI-6666
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala64
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala25
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala9
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala1
4 files changed, 63 insertions, 36 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 78c120c1ad..2f28a16416 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -8,6 +8,7 @@ package transform
import symtab._
import Flags.{ CASE => _, _ }
+import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import matching.{ Patterns, ParallelMatching }
import scala.tools.nsc.settings.ScalaVersion
@@ -210,6 +211,8 @@ abstract class ExplicitOuter extends InfoTransform
/** The first outer selection from currently transformed tree.
* The result is typed but not positioned.
+ *
+ * Will return `EmptyTree` if there is no outer accessor because of a premature self reference.
*/
protected def outerValue: Tree =
if (outerParam != NoSymbol) ID(outerParam)
@@ -219,25 +222,34 @@ abstract class ExplicitOuter extends InfoTransform
* The result is typed but not positioned.
* If the outer access is from current class and current class is final
* take outer field instead of accessor
+ *
+ * Will return `EmptyTree` if there is no outer accessor because of a premature self reference.
*/
private def outerSelect(base: Tree): Tree = {
- val outerAcc = outerAccessor(base.tpe.typeSymbol.toInterface)
- val currentClass = this.currentClass //todo: !!! if this line is removed, we get a build failure that protected$currentClass need an override modifier
- // outerFld is the $outer field of the current class, if the reference can
- // use it (i.e. reference is allowed to be of the form this.$outer),
- // otherwise it is NoSymbol
- val outerFld =
- if (outerAcc.owner == currentClass &&
+ val baseSym = base.tpe.typeSymbol.toInterface
+ val outerAcc = outerAccessor(baseSym)
+ if (outerAcc == NoSymbol && baseSym.ownersIterator.exists(isUnderConstruction)) {
+ // e.g neg/t6666.scala
+ // The caller will report the error with more information.
+ EmptyTree
+ } else {
+ val currentClass = this.currentClass //todo: !!! if this line is removed, we get a build failure that protected$currentClass need an override modifier
+ // outerFld is the $outer field of the current class, if the reference can
+ // use it (i.e. reference is allowed to be of the form this.$outer),
+ // otherwise it is NoSymbol
+ val outerFld =
+ if (outerAcc.owner == currentClass &&
base.tpe =:= currentClass.thisType &&
outerAcc.owner.isEffectivelyFinal)
- outerField(currentClass) suchThat (_.owner == currentClass)
- else
- NoSymbol
- val path =
- if (outerFld != NoSymbol) Select(base, outerFld)
- else Apply(Select(base, outerAcc), Nil)
-
- localTyper typed path
+ outerField(currentClass) suchThat (_.owner == currentClass)
+ else
+ NoSymbol
+ val path =
+ if (outerFld != NoSymbol) Select(base, outerFld)
+ else Apply(Select(base, outerAcc), Nil)
+
+ localTyper typed path
+ }
}
/** The path
@@ -257,6 +269,17 @@ abstract class ExplicitOuter extends InfoTransform
else outerPath(outerSelect(base), from.outerClass, to)
}
+
+ /** The stack of class symbols in which a call to this() or to the super
+ * constructor, or early definition is active
+ */
+ protected def isUnderConstruction(clazz: Symbol) = selfOrSuperCalls contains clazz
+ protected val selfOrSuperCalls = mutable.Stack[Symbol]()
+ @inline protected def inSelfOrSuperCall[A](sym: Symbol)(a: => A) = {
+ selfOrSuperCalls push sym
+ try a finally selfOrSuperCalls.pop()
+ }
+
override def transform(tree: Tree): Tree = {
val savedOuterParam = outerParam
try {
@@ -270,7 +293,10 @@ abstract class ExplicitOuter extends InfoTransform
}
case _ =>
}
- super.transform(tree)
+ if ((treeInfo isSelfOrSuperConstrCall tree) || (treeInfo isEarlyDef tree))
+ inSelfOrSuperCall(currentOwner.owner)(super.transform(tree))
+ else
+ super.transform(tree)
}
finally outerParam = savedOuterParam
}
@@ -336,7 +362,8 @@ abstract class ExplicitOuter extends InfoTransform
/** The definition tree of the outer accessor of current class
*/
- def outerFieldDef: Tree = VAL(outerField(currentClass)) === EmptyTree
+ def outerFieldDef: Tree =
+ VAL(outerField(currentClass)) === EmptyTree
/** The definition tree of the outer accessor of current class
*/
@@ -484,6 +511,9 @@ abstract class ExplicitOuter extends InfoTransform
val clazz = sym.owner
val vparamss1 =
if (isInner(clazz)) { // (4)
+ if (isUnderConstruction(clazz.outerClass)) {
+ reporter.error(tree.pos, s"Implementation restriction: ${clazz.fullLocationString} requires premature access to ${clazz.outerClass}.")
+ }
val outerParam =
sym.newValueParameter(nme.OUTER, sym.pos) setInfo clazz.outerClass.thisType
((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 845843e9d6..631468dd0c 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -317,7 +317,7 @@ abstract class LambdaLift extends InfoTransform {
else searchIn(currentOwner)
}
- private def memberRef(sym: Symbol) = {
+ private def memberRef(sym: Symbol): Tree = {
val clazz = sym.owner.enclClass
//Console.println("memberRef from "+currentClass+" to "+sym+" in "+clazz)
def prematureSelfReference() {
@@ -331,12 +331,17 @@ abstract class LambdaLift extends InfoTransform {
if (clazz == currentClass) gen.mkAttributedThis(clazz)
else {
sym resetFlag (LOCAL | PRIVATE)
- if (selfOrSuperCalls exists (_.owner == clazz)) {
+ if (isUnderConstruction(clazz)) {
prematureSelfReference()
EmptyTree
}
else if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType)
- else outerPath(outerValue, currentClass.outerClass, clazz)
+ else {
+ outerValue match {
+ case EmptyTree => prematureSelfReference(); return EmptyTree
+ case o => outerPath(o, currentClass.outerClass, clazz)
+ }
+ }
}
Select(qual, sym) setType sym.tpe
}
@@ -533,25 +538,13 @@ 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 _ =>
- def transformTree = postTransform(preTransform(tree))
- if (treeInfo isSelfOrSuperConstrCall tree)
- inSelfOrSuperCall(currentOwner)(transformTree)
- else transformTree
+ postTransform(preTransform(tree))
}
/** Transform statements and add lifted definitions to them. */
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index ab338447c9..341dbfbe1f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -134,9 +134,12 @@ trait Namers extends MethodSynthesis {
def setPrivateWithin(tree: MemberDef, sym: Symbol): Symbol =
setPrivateWithin(tree, sym, tree.mods)
- def inConstructorFlag: Long =
- if (owner.isConstructor && !context.inConstructorSuffix || owner.isEarlyInitialized) INCONSTRUCTOR
- else 0l
+ def inConstructorFlag: Long = {
+ val termOwnedContexts: List[Context] = context.enclosingContextChain.takeWhile(_.owner.isTerm)
+ val constructorNonSuffix = termOwnedContexts exists (c => c.owner.isConstructor && !c.inConstructorSuffix)
+ val earlyInit = termOwnedContexts exists (_.owner.isEarlyInitialized)
+ if (constructorNonSuffix || earlyInit) INCONSTRUCTOR else 0L
+ }
def moduleClassFlags(moduleFlags: Long) =
(moduleFlags & ModuleToClassFlags) | inConstructorFlag
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 4ffd198dc4..d9eb48ff2d 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -2911,6 +2911,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final override def isNonClassType = false
final override def isAbstractType = false
final override def isAliasType = false
+ final override def isContravariant = false
override def isAbstractClass = this hasFlag ABSTRACT
override def isCaseClass = this hasFlag CASE