Skip to content

Commit fb0347e

Browse files
authored
Merge pull request #5108 from dotty-staging/fix-5083
Fix #5083: Disallow using trait parameters as prefix for its parents
2 parents 0fd4e6a + 35083fd commit fb0347e

File tree

4 files changed

+80
-0
lines changed

4 files changed

+80
-0
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,20 @@ object RefChecks {
108108
case _ =>
109109
}
110110

111+
/** Disallow using trait parameters as prefix for its parents.
112+
*
113+
* The rationale is to ensure outer-related NPE never happen in Scala.
114+
* Otherwise, outer NPE may happen, see tests/neg/i5083.scala
115+
*/
116+
private def checkParentPrefix(cls: Symbol, parent: Tree)(implicit ctx: Context): Unit =
117+
parent.tpe.typeConstructor match {
118+
case TypeRef(ref: TermRef, _) =>
119+
val paramRefs = ref.namedPartsWith(ntp => ntp.symbol.enclosingClass == cls)
120+
if (paramRefs.nonEmpty)
121+
ctx.error("trait parameters cannot be used as parent prefixes", parent.pos)
122+
case _ =>
123+
}
124+
111125
/** Check that a class and its companion object to not both define
112126
* a class or module with same name
113127
*/
@@ -961,6 +975,7 @@ class RefChecks extends MiniPhase { thisPhase =>
961975
val cls = ctx.owner
962976
checkOverloadedRestrictions(cls)
963977
checkParents(cls)
978+
if (cls.is(Trait)) tree.parents.foreach(checkParentPrefix(cls, _))
964979
checkCompanionNameClashes(cls)
965980
checkAllOverrides(cls)
966981
tree

tests/neg/i5083.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class A(a: Int) {
2+
abstract class X {
3+
def f: Int
4+
val x = a + f // NPE: the outer for `Y` is not yet set
5+
}
6+
7+
trait Y {
8+
val y = a
9+
def f: Int = A.this.a // NPE: the outer for `Y` is not yet set
10+
}
11+
12+
trait Z(val o: A) extends o.Y { // error
13+
val z = a
14+
}
15+
16+
class B extends X with Z(new A(4))
17+
}
18+
19+
20+
object Test {
21+
def main(args: Array[String]): Unit = {
22+
val a = new A(3)
23+
new a.B
24+
}
25+
}

tests/neg/i5083b.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class A(a: Int) {
2+
class X {
3+
val x = a
4+
}
5+
6+
trait Y {
7+
val y = a
8+
}
9+
10+
val z: Z = ???
11+
12+
trait Z(val o: A) extends z.o.Y // error: cyclic reference `z`
13+
14+
class B extends X with Z(new A(4))
15+
}

tests/neg/i5083c.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class A(a: Int) {
2+
trait X {
3+
def f: Int
4+
val x = a + f // NPE: the outer for `Y` is not yet set
5+
}
6+
7+
trait Y {
8+
val y = a
9+
def f: Int = A.this.a // NPE: the outer for `Y` is not yet set
10+
}
11+
12+
class Z(o: A) extends m.Y { // error
13+
val m = o
14+
}
15+
16+
class B extends Z(new A(4))
17+
}
18+
19+
20+
object Test {
21+
def main(args: Array[String]): Unit = {
22+
val a = new A(3)
23+
new a.B
24+
}
25+
}

0 commit comments

Comments
 (0)