Skip to content

Commit 68ce658

Browse files
authored
Merge pull request #12567 from dotty-staging/fix-11028
Reject references to self in super constructor calls
2 parents af0de81 + b9701ac commit 68ce658

File tree

8 files changed

+84
-14
lines changed

8 files changed

+84
-14
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class Compiler {
121121
new ElimStaticThis, // Replace `this` references to static objects by global identifiers
122122
new CountOuterAccesses) :: // Identify outer accessors that can be dropped
123123
List(new DropOuterAccessors, // Drop unused outer accessors
124+
new CheckNoSuperThis, // Check that supercalls don't contain references to `this`
124125
new Flatten, // Lift all inner classes to package scope
125126
new RenameLifted, // Renames lifted classes to local numbering scheme
126127
new TransformWildcards, // Replace wildcards with default values
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core.*
5+
import MegaPhase.MiniPhase
6+
import Contexts.*, Types.*, Symbols.*, SymDenotations.*, Flags.*
7+
import ast.*
8+
import Trees.*
9+
import Decorators.*
10+
11+
import annotation.threadUnsafe
12+
13+
object CheckNoSuperThis:
14+
val name: String = "checkNoSuperThis"
15+
16+
/** Checks that super and this calls do not pass `this` as (part of) an argument. */
17+
class CheckNoSuperThis extends MiniPhase:
18+
thisPhase =>
19+
import tpd._
20+
21+
override def phaseName: String = CheckNoSuperThis.name
22+
23+
override def runsAfterGroupsOf: Set[String] = Set(Constructors.name)
24+
25+
override def transformDefDef(mdef: DefDef)(using Context): DefDef =
26+
if mdef.symbol.isClassConstructor then
27+
mdef.rhs match
28+
case Block(stats, _) => splitAtSuper(stats) match
29+
case (Apply(_, superArgs) :: _, _) =>
30+
val cls = mdef.symbol.owner
31+
def fail(t: Tree) =
32+
report.error(em"super constructor cannot be passed a self reference $t unless parameter is declared by-name", t.srcPos)
33+
for arg <- superArgs do
34+
arg.foreachSubTree {
35+
case t: This if t.symbol == cls =>
36+
fail(t)
37+
case t: RefTree => t.tpe match
38+
case tpe @ TermRef(prefix, _)
39+
if (prefix == cls.thisType
40+
|| cls.is(Module)
41+
&& (prefix.termSymbol == cls.sourceModule || tpe.symbol == cls.sourceModule)
42+
) && !tpe.symbol.is(JavaStatic) => fail(t)
43+
case _ =>
44+
case _ =>
45+
}
46+
case _ =>
47+
case _ =>
48+
mdef
49+
50+
end CheckNoSuperThis

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -991,18 +991,6 @@ trait Checking {
991991
report.error(i"""$called is already implemented by super${caller.superClass},
992992
|its constructor cannot be called again""", call.srcPos)
993993

994-
if (caller.is(Module)) {
995-
val traverser = new TreeTraverser {
996-
def traverse(tree: Tree)(using Context) = tree match {
997-
case tree: RefTree if tree.isTerm && (tree.tpe.classSymbol eq caller) =>
998-
report.error("super constructor cannot be passed a self reference", tree.srcPos)
999-
case _ =>
1000-
traverseChildren(tree)
1001-
}
1002-
}
1003-
traverser.traverse(call)
1004-
}
1005-
1006994
// Check that constructor call is of the form _.<init>(args1)...(argsN).
1007995
// This guards against calls resulting from inserted implicits or applies.
1008996
def checkLegalConstructorCall(tree: Tree, encl: Tree, kind: String): Unit = tree match {

tests/neg/i11045.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
abstract class Foo(x: Any)
2+
class Boom(var x: Unit, y: Unit) extends Foo((x: Int) => x) // error: super constructor cannot be passed a self reference
3+
@main def Test =
4+
Boom((), ())
5+

tests/neg/i11208.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.reflect.ClassTag
2+
3+
@main def run = println(Foo)
4+
5+
abstract class Bar[T](implicit val thisClassTag: ClassTag[T])
6+
7+
class Foo
8+
object Foo extends Bar[Foo] // error

tests/neg/i11208a.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Foo(implicit val foo: Foo)
2+
3+
object Test extends App {
4+
implicit object Bar extends Foo // error
5+
Bar.foo
6+
}

tests/neg/i12557.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package example
2+
3+
abstract class X[P <: Product](using val m: scala.deriving.Mirror.ProductOf[P]) {
4+
def unapply(p: P): m.MirroredElemTypes = ???
5+
}
6+
7+
case class A(a: Int)
8+
object A extends X[A] // error
9+
10+
object Main {
11+
def main(args: Array[String]): Unit = {
12+
A.unapply(A(2))
13+
}
14+
}

tests/pos/i11045.scala

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)