Skip to content

Commit c25dfdc

Browse files
committed
Deprecate nested class shadowing in "override" position
Fixes scala/bug#8353 This deprecates nested class shadowing in "override" position for Dotty compatibility. In general Scala does not implement override of classes where "new Status" might take on different meaning based on what the subtypes are doing. To avoid the confusion, we are deprecating the nested class shadow another nested class if it was introduced by a parent class.
1 parent d1b3235 commit c25dfdc

17 files changed

+100
-61
lines changed

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ abstract class RefChecks extends Transform {
272272
* that are not implemented in a subclass.
273273
* 4. Check that every member with an `override` modifier
274274
* overrides some other member.
275+
* 5. Check that the nested class do not shadow other nested classes from outer class's parent.
275276
*/
276277
private def checkAllOverrides(clazz: Symbol, typesOnly: Boolean = false): Unit = {
277278
val self = clazz.thisType
@@ -832,7 +833,21 @@ abstract class RefChecks extends Transform {
832833
}
833834
member resetFlag (OVERRIDE | ABSOVERRIDE) // Any Override
834835
}
835-
}
836+
837+
// 5. Check that the nested class do not shadow other nested classes from outer class's parent
838+
def checkNestedClassShadow(): Unit =
839+
if (clazz.isNestedClass) {
840+
val overridden = clazz.owner.ancestors
841+
.map(a => clazz.matchingSymbol(a, clazz.owner.thisType))
842+
.filter(c => c.exists && c.isClass)
843+
overridden foreach { sym2 =>
844+
def msg(what: String) = s"shadowing a nested class of a parent is $what but class ${clazz.name} shadows $sym2 defined in ${sym2.owner}; rename the class to something else"
845+
if (currentRun.isScala300) reporter.error(clazz.pos, msg("unsupported"))
846+
else currentRun.reporting.deprecationWarning(clazz.pos, clazz, msg("deprecated"), "2.13.2")
847+
}
848+
}
849+
checkNestedClassShadow()
850+
} // end checkAllOverrides
836851

837852
// Basetype Checking --------------------------------------------------------
838853

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
nested-class-shadowing-removal.scala:9: error: shadowing a nested class of a parent is unsupported but class Status shadows class Status defined in trait Core; rename the class to something else
2+
class Status extends super.Status
3+
^
4+
1 error
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// scalac: -Werror -Xlint:deprecation -Xsource:3.0
2+
//
3+
4+
trait Core {
5+
class Status
6+
}
7+
8+
trait Ext extends Core {
9+
class Status extends super.Status
10+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
nested-class-shadowing.scala:9: warning: shadowing a nested class of a parent is deprecated but class Status shadows class Status defined in trait Core; rename the class to something else
2+
class Status extends super.Status
3+
^
4+
error: No warnings can be incurred under -Werror.
5+
1 warning
6+
1 error
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// scalac: -Werror -Xlint:deprecation
2+
//
3+
4+
trait Core {
5+
class Status
6+
}
7+
8+
trait Ext extends Core {
9+
class Status extends super.Status
10+
}

test/files/res/t597.check

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2-
nsc>
3-
nsc>
2+
nsc> warning: 2 deprecations (since 2.13.2); re-run with -deprecation for details
3+
4+
nsc> warning: 1 deprecation (since 2.13.2); re-run with -deprecation for details
5+
46
nsc>

test/files/res/t743.check

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2-
nsc>
2+
nsc> warning: 1 deprecation (since 2.13.2); re-run with -deprecation for details
3+
34
nsc>
45
nsc>

test/files/res/t831.check

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2-
nsc>
2+
nsc> warning: 3 deprecations (since 2.13.2); re-run with -deprecation for details
3+
34
nsc>
45
nsc>

test/files/run/bugs.check

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,6 @@ hello
8484
<<< bug 328
8585
>>> bug 328
8686

87-
<<< bug 396
88-
A
89-
B
90-
C
91-
>>> bug 396
92-
9387
<<< bug 399
9488
a
9589
>>> bug 399

test/files/run/bugs.scala

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// scalac: -Werror -Xlint:deprecation
2+
//
3+
14
//############################################################################
25
// Bugs
36
//############################################################################
@@ -394,29 +397,6 @@ object Bug328Test {
394397
def test(args: Array[String]): Unit = test0(args);
395398
}
396399

397-
//############################################################################
398-
// Bug 396
399-
400-
trait Bug396A {
401-
class I {
402-
def run = Console.println("A");
403-
}
404-
}
405-
trait Bug396B extends Bug396A {
406-
class I extends super.I {
407-
override def run = { super.run; Console.println("B"); }
408-
}
409-
}
410-
trait Bug396C extends Bug396A {
411-
trait I extends super.I {
412-
override def run = { super.run; Console.println("C"); }
413-
}
414-
}
415-
object Bug396Test extends Bug396B with Bug396C {
416-
class I2 extends super[Bug396B].I with super[Bug396C].I;
417-
def test(args: Array[String]): Unit = (new I2).run
418-
}
419-
420400
//############################################################################
421401
// Bug 399
422402

@@ -476,7 +456,6 @@ object Test {
476456
test(266, Bug266Test.test(args));
477457
test(316, Bug316Test.test(args));
478458
test(328, Bug328Test.test(args));
479-
test(396, Bug396Test.test(args));
480459
test(399, Bug399Test.test(args));
481460

482461
if (errors > 0) {

test/files/run/t6146b.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
t6146b.scala:15: warning: match may not be exhaustive.
1+
t6146b.scala:18: warning: match may not be exhaustive.
22
It would fail on the following inputs: S2(), S3()
33
def foo(f: F[Int]) = f match { case X.S1 => }
44
^

test/files/run/t6146b.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
// scalac: -Xlint:deprecation
2+
//
3+
14
import scala.tools.partest.ReplTest
25

36
class A {
4-
sealed trait F[A]
7+
// sealed trait F[A]
58
}
69

710
class C[T] extends A {

test/files/run/t657.scala

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,55 @@
1+
// scalac: -Werror -Xlint:deprecation
2+
//
13

24
import scala.language.{ implicitConversions }
35
abstract class BaseList {
4-
type Node <: NodeImpl;
5-
implicit def convertNode(ni : NodeImpl) = ni.asInstanceOf[Node];
6-
abstract class NodeImpl;
6+
type Node <: BaseNodeImpl
7+
implicit def convertNode(ni : BaseNodeImpl) = ni.asInstanceOf[Node];
8+
abstract class BaseNodeImpl
79
}
810
abstract class LinkedList extends BaseList {
9-
type Node <: NodeImpl;
10-
trait NodeImpl extends super.NodeImpl;
11+
type Node <: NodeImpl0
12+
trait NodeImpl0 extends super.BaseNodeImpl;
1113
}
1214
trait OffsetList extends LinkedList {
13-
type Node <: NodeImpl;
14-
trait NodeImpl extends super.NodeImpl;
15+
type Node <: NodeImpl1
16+
trait NodeImpl1 extends super.NodeImpl0
1517
}
1618

1719
trait PriorityTree extends BaseList {
18-
type Node <: NodeImpl;
19-
trait NodeImpl extends super.NodeImpl {
20-
def chop : Node = this;
20+
type Node <: NodeImpl2
21+
trait NodeImpl2 extends super.BaseNodeImpl {
22+
def chop : Node = this
2123
}
2224
}
2325

2426
trait PrecedenceParser extends LinkedList with PriorityTree {
25-
type Node <: NodeImpl;
26-
trait NodeImpl extends super[LinkedList].NodeImpl with super[PriorityTree].NodeImpl;
27+
type Node <: NodeImpl3
28+
trait NodeImpl3 extends super[LinkedList].NodeImpl0 with super[PriorityTree].NodeImpl2
2729
}
2830

2931
trait Matcher extends PrecedenceParser {
30-
type Node <: NodeImpl;
31-
trait NodeImpl extends super.NodeImpl;
32+
type Node <: NodeImpl4
33+
trait NodeImpl4 extends super.NodeImpl3
3234

33-
type Matchable <: Node with MatchableImpl;
34-
implicit def convertMatchable(m : MatchableImpl) = m.asInstanceOf[Matchable];
35-
trait MatchableImpl extends NodeImpl {
35+
type Matchable <: Node with MatchableImpl0
36+
implicit def convertMatchable(m : MatchableImpl0) = m.asInstanceOf[Matchable]
37+
trait MatchableImpl0 extends NodeImpl4 {
3638
override def chop : Node = {
3739
Console.println("passed"); super.chop;
3840
}
3941
}
4042
}
4143

4244
class Test1 extends OffsetList with Matcher {
43-
type Node = NodeImpl;
44-
trait NodeImpl extends super[OffsetList].NodeImpl with super[Matcher].NodeImpl;
45-
class MatchableImpl extends super.MatchableImpl with NodeImpl;
46-
type Matchable = MatchableImpl;
45+
type Node = NodeImpl5
46+
trait NodeImpl5 extends super[OffsetList].NodeImpl1 with super[Matcher].NodeImpl4
47+
class MatchableImpl1 extends super.MatchableImpl0 with NodeImpl5
48+
type Matchable = MatchableImpl1
4749
}
4850

4951
object Test extends App {
50-
val test = new Test1;
51-
val m = new test.MatchableImpl;
52-
m.chop;
52+
val test = new Test1
53+
val m = new test.MatchableImpl1
54+
m.chop
5355
}

test/files/run/t6677b.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
t6677b.scala:15: warning: shadowing a nested class of a parent is deprecated but class X shadows class X defined in trait U1; rename the class to something else
2+
class U11 extends U1 { class X extends super.X { foo } } // refer to foo to add $outer pointer
3+
^

test/files/run/t6677b.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// scalac: -Xlint:deprecation
2+
//
3+
14
trait U {
25
trait U1 {
36
class X

test/files/run/t744.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
t744.scala:12: warning: shadowing a nested class of a parent is deprecated but class FileImpl shadows trait FileImpl defined in trait Linked; rename the class to something else
2+
trait FileImpl extends super.FileImpl {
3+
^
14
BEGIN
25
Hello from linked
36
END

test/files/run/t744.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// scalac: -Xlint:deprecation
2+
//
3+
14
trait Linked {
25
type File <: FileImpl;
36
trait FileImpl {

0 commit comments

Comments
 (0)