From 6aa5762fa0333625ec93378e2147649a8bafde34 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 17 Jun 2012 23:23:49 +0200 Subject: 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. --- .../tools/nsc/typechecker/ContextErrors.scala | 8 ++- .../scala/tools/nsc/typechecker/Typers.scala | 62 ++++++++++++++++------ 2 files changed, 54 insertions(+), 16 deletions(-) (limited to 'src') 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) -- cgit v1.2.3