Skip to content

Commit aab0062

Browse files
committed
Check abstract classes
1 parent 4e2c8d5 commit aab0062

File tree

5 files changed

+37
-27
lines changed

5 files changed

+37
-27
lines changed

compiler/src/dotty/tools/dotc/transform/init/Checker.scala

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import scala.collection.mutable
1919

2020
import Semantic._
2121

22-
class Checker extends Phase {
22+
class Checker extends Phase:
2323

2424
override def phaseName: String = Checker.name
2525

@@ -34,7 +34,7 @@ class Checker extends Phase {
3434
val checkCtx = ctx.fresh.setPhase(this.start)
3535
val traverser = new InitTreeTraverser()
3636
units.foreach { unit => traverser.traverse(unit.tpdTree) }
37-
val classes = traverser.getConcreteClasses()
37+
val classes = traverser.getClasses()
3838

3939
ParamOverridingCheck.checkClasses(classes)(using checkCtx)
4040
Semantic.checkClasses(classes)(using checkCtx)
@@ -45,10 +45,10 @@ class Checker extends Phase {
4545
// ignore, we already called `Semantic.check()` in `runOn`
4646
()
4747

48-
class InitTreeTraverser extends TreeTraverser {
49-
private val concreteClasses: mutable.ArrayBuffer[ClassSymbol] = new mutable.ArrayBuffer
48+
class InitTreeTraverser extends TreeTraverser:
49+
private val classes: mutable.ArrayBuffer[ClassSymbol] = new mutable.ArrayBuffer
5050

51-
def getConcreteClasses(): List[ClassSymbol] = concreteClasses.toList
51+
def getClasses(): List[ClassSymbol] = classes.toList
5252

5353
override def traverse(tree: Tree)(using Context): Unit =
5454
traverseChildren(tree)
@@ -61,28 +61,13 @@ class Checker extends Phase {
6161
mdef match
6262
case tdef: TypeDef if tdef.isClassDef =>
6363
val cls = tdef.symbol.asClass
64-
if isConcreteClass(cls) then concreteClasses.append(cls)
64+
classes.append(cls)
6565
case _ =>
6666

6767
case _ =>
6868
}
69-
}
70-
71-
private def isConcreteClass(cls: ClassSymbol)(using Context) = {
72-
val instantiable: Boolean =
73-
cls.is(Flags.Module) ||
74-
!cls.isOneOf(Flags.AbstractOrTrait) && {
75-
// see `Checking.checkInstantiable` in typer
76-
val tp = cls.appliedRef
77-
val stp = SkolemType(tp)
78-
val selfType = cls.givenSelfType.asSeenFrom(stp, cls)
79-
!selfType.exists || stp <:< selfType
80-
}
69+
end InitTreeTraverser
8170

82-
// A concrete class may not be instantiated if the self type is not satisfied
83-
instantiable && cls.enclosingPackageClass != defn.StdLibPatchesPackage.moduleClass
84-
}
85-
}
8671

8772
object Checker:
8873
val name: String = "initChecker"

compiler/src/dotty/tools/dotc/transform/init/ParamOverridingCheck.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ object ParamOverridingCheck:
145145
/**
146146
* Check the specified concrete classes
147147
*/
148-
def checkClasses(concreteClasses: List[ClassSymbol])(using Context): Unit =
149-
for classSym <- concreteClasses do
148+
def checkClasses(classes: List[ClassSymbol])(using Context): Unit =
149+
for classSym <- classes if !classSym.is(Flags.Trait) do
150150
val thisRef = ThisRef(classSym, fields = mutable.Map.empty)
151151
val tpl = classSym.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
152152
for param <- tpl.constr.termParamss.flatten yield
@@ -331,8 +331,7 @@ object ParamOverridingCheck:
331331
// check parameter access semantics
332332
for
333333
paramSym <- klass.paramGetters
334-
subClass <- thisV.klass.baseClasses if subClass.isSubClass(klass) && subClass != klass
335-
overridingSym = paramSym.overridingSymbol(subClass) if overridingSym.exists
334+
overridingSym = paramSym.overridingSymbol(thisV.klass) if overridingSym.exists
336335
do
337336
// println(paramSym.show + " is overridden in " + thisV.klass)
338337
if !overridingSym.is(Flags.ParamAccessor) then

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ object Semantic:
12101210
class WorkList private[Semantic](tasks: List[ClassSymbol]):
12111211
/** Process the worklist until done */
12121212
final def work()(using Cache, Context): Unit =
1213-
for task <- tasks do doTask(task)
1213+
for task <- tasks if isConcreteClass(task) do doTask(task)
12141214

12151215
/** Check an individual class
12161216
*
@@ -1766,3 +1766,18 @@ object Semantic:
17661766
if (sym.isEffectivelyFinal || sym.isConstructor) sym
17671767
else sym.matchingMember(cls.appliedRef)
17681768
}
1769+
1770+
private def isConcreteClass(cls: ClassSymbol)(using Context) = {
1771+
val instantiable: Boolean =
1772+
cls.is(Flags.Module) ||
1773+
!cls.isOneOf(Flags.AbstractOrTrait) && {
1774+
// see `Checking.checkInstantiable` in typer
1775+
val tp = cls.appliedRef
1776+
val stp = SkolemType(tp)
1777+
val selfType = cls.givenSelfType.asSeenFrom(stp, cls)
1778+
!selfType.exists || stp <:< selfType
1779+
}
1780+
1781+
// A concrete class may not be instantiated if the self type is not satisfied
1782+
instantiable && cls.enclosingPackageClass != defn.StdLibPatchesPackage.moduleClass
1783+
}

tests/init/neg/i15764d.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ class A(val y: Int)
33
abstract class B(override val y: Int) extends A(10) // error
44

55
class C extends B(7)
6+
7+
class X(val y: Int)
8+
9+
abstract class Y(override val y: Int) extends A(10) // error

tests/init/pos/i15764e.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait X(val x: Int, y: Int, z: Int)
2+
trait Y(override val x: Int, y: Int, z: Int) extends X
3+
class Z(override val x: Int, y: Int, z: Int) extends Y(x, y, z) with X(x, y, z)
4+
5+
trait A(val x: Int, y: Int, z: Int)
6+
trait B(override val x: Int, y: Int, z: Int) extends A
7+
class C extends B(1, 2, 3) with A(1, 2, 3)

0 commit comments

Comments
 (0)