diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-06-21 00:26:39 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-06-21 00:26:39 -0700 |
commit | 320a32b0b5902781b9fb13ad83083574a36f3e46 (patch) | |
tree | 3155d95602e4d4012f3aaab3abd931bb68b293f0 /src/compiler | |
parent | 6aea0ae85f72594798ec6c96e30cc1aef48c3a99 (diff) | |
parent | 6aa5762fa0333625ec93378e2147649a8bafde34 (diff) | |
download | scala-320a32b0b5902781b9fb13ad83083574a36f3e46.tar.gz scala-320a32b0b5902781b9fb13ad83083574a36f3e46.tar.bz2 scala-320a32b0b5902781b9fb13ad83083574a36f3e46.zip |
Merge pull request #735 from retronym/ticket/4842-2
SI-4842 Forbid access to in-construction this in self-constructor args
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 62 |
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 e5e8acc185..60cc9e5fb8 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 6bd1117689..b12ca4f0b4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1846,16 +1846,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 _ => () } } @@ -1889,7 +1886,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 @@ -2007,11 +2036,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) |