summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-06-17 23:23:49 +0200
committerJason Zaugg <jzaugg@gmail.com>2012-06-17 23:48:42 +0200
commit6aa5762fa0333625ec93378e2147649a8bafde34 (patch)
tree52c6c9c7d608e20d3c628d5f325977f834866a20 /src/compiler
parent277dc7cf43566f8294bde4143107d9bfaa59e8e3 (diff)
downloadscala-6aa5762fa0333625ec93378e2147649a8bafde34.tar.gz
scala-6aa5762fa0333625ec93378e2147649a8bafde34.tar.bz2
scala-6aa5762fa0333625ec93378e2147649a8bafde34.zip
SI-4842 Forbid access to in-construction this in self-constructor args
The check was already in place for direct calls to the super constructor. Without this additional check, ExplicitOuter crashes, as it doesn't create an $outer pointer for the constructor-arg scoped inner object, but expects one to exist when transforming the Outer.this reference.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala62
2 files changed, 54 insertions, 16 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index bcf2ba6b71..fcb73f5947 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -222,7 +222,13 @@ trait ContextErrors {
NormalTypeError(tree, "super constructor cannot be passed a self reference unless parameter is declared by-name")
def SuperConstrArgsThisReferenceError(tree: Tree) =
- NormalTypeError(tree, "super constructor arguments cannot reference unconstructed `this`")
+ ConstrArgsThisReferenceError("super", tree)
+
+ def SelfConstrArgsThisReferenceError(tree: Tree) =
+ ConstrArgsThisReferenceError("self", tree)
+
+ private def ConstrArgsThisReferenceError(prefix: String, tree: Tree) =
+ NormalTypeError(tree, s"$prefix constructor arguments cannot reference unconstructed `this`")
def TooManyArgumentListsForConstructor(tree: Tree) = {
issueNormalTypeError(tree, "too many argument lists for constructor invocation")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 2bdae4164a..b58a7832ac 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1841,16 +1841,13 @@ trait Typers extends Modes with Adaptations with Tags {
val pending = ListBuffer[AbsTypeError]()
// an object cannot be allowed to pass a reference to itself to a superconstructor
// because of initialization issues; bug #473
- for (arg <- superArgs ; tree <- arg) {
- val sym = tree.symbol
- if (sym != null && (sym.info.baseClasses contains clazz)) {
- if (sym.isModule)
- pending += SuperConstrReferenceError(tree)
- tree match {
- case This(qual) =>
- pending += SuperConstrArgsThisReferenceError(tree)
- case _ => ()
- }
+ foreachSubTreeBoundTo(superArgs, clazz) { tree =>
+ if (tree.symbol.isModule)
+ pending += SuperConstrReferenceError(tree)
+ tree match {
+ case This(qual) =>
+ pending += SuperConstrArgsThisReferenceError(tree)
+ case _ => ()
}
}
@@ -1884,7 +1881,39 @@ trait Typers extends Modes with Adaptations with Tags {
pending.foreach(ErrorUtils.issueTypeError)
}
- /** Check if a structurally defined method violates implementation restrictions.
+ // Check for SI-4842.
+ private def checkSelfConstructorArgs(ddef: DefDef, clazz: Symbol) {
+ val pending = ListBuffer[AbsTypeError]()
+ ddef.rhs match {
+ case Block(stats, expr) =>
+ val selfConstructorCall = stats.headOption.getOrElse(expr)
+ foreachSubTreeBoundTo(List(selfConstructorCall), clazz) {
+ case tree @ This(qual) =>
+ pending += SelfConstrArgsThisReferenceError(tree)
+ case _ => ()
+ }
+ case _ =>
+ }
+ pending.foreach(ErrorUtils.issueTypeError)
+ }
+
+ /**
+ * Run the provided function for each sub tree of `trees` that
+ * are bound to a symbol with `clazz` as a base class.
+ *
+ * @param f This function can assume that `tree.symbol` is non null
+ */
+ private def foreachSubTreeBoundTo[A](trees: List[Tree], clazz: Symbol)(f: Tree => Unit): Unit =
+ for {
+ tree <- trees
+ subTree <- tree
+ } {
+ val sym = subTree.symbol
+ if (sym != null && sym.info.baseClasses.contains(clazz))
+ f(subTree)
+ }
+
+ /** Check if a structurally defined method violates implementation restrictions.
* A method cannot be called if it is a non-private member of a refinement type
* and if its parameter's types are any of:
* - the self-type of the refinement
@@ -2002,11 +2031,14 @@ trait Typers extends Modes with Adaptations with Tags {
transformedOrTyped(ddef.rhs, EXPRmode, tpt1.tpe)
}
- if (meth.isPrimaryConstructor && meth.isClassConstructor && !isPastTyper && !reporter.hasErrors && !meth.owner.isSubClass(AnyValClass)) {
- // At this point in AnyVal there is no supercall, which will blow up
- // in computeParamAliases; there's nothing to be computed for Anyval anyway.
+ if (meth.isClassConstructor && !isPastTyper && !reporter.hasErrors && !meth.owner.isSubClass(AnyValClass)) {
+ // At this point in AnyVal there is no supercall, which will blow up
+ // in computeParamAliases; there's nothing to be computed for Anyval anyway.
+ if (meth.isPrimaryConstructor)
computeParamAliases(meth.owner, vparamss1, rhs1)
- }
+ else
+ checkSelfConstructorArgs(ddef, meth.owner)
+ }
if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen && rhs1.tpe.typeSymbol != NothingClass)
rhs1 = checkDead(rhs1)