Skip to content

Commit af9594d

Browse files
authored
Merge pull request #13472 from dotty-staging/fix-init-soundness
Fix init soundness
2 parents ba43eb1 + e905cd5 commit af9594d

File tree

14 files changed

+601
-204
lines changed

14 files changed

+601
-204
lines changed

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

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package init
55

66
import dotty.tools.dotc._
77
import ast.tpd
8+
import tpd._
89

910
import dotty.tools.dotc.core._
1011
import Contexts._
@@ -15,51 +16,54 @@ import StdNames._
1516
import dotty.tools.dotc.transform._
1617
import Phases._
1718

18-
1919
import scala.collection.mutable
2020

21+
import Semantic._
2122

2223
class Checker extends Phase {
23-
import tpd._
2424

2525
val phaseName = "initChecker"
2626

27-
private val semantic = new Semantic
28-
2927
override val runsAfter = Set(Pickler.name)
3028

3129
override def isEnabled(using Context): Boolean =
3230
super.isEnabled && ctx.settings.YcheckInit.value
3331

3432
override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
35-
units.foreach { unit => traverser.traverse(unit.tpdTree) }
36-
super.runOn(units)
33+
val checkCtx = ctx.fresh.setPhase(this.start)
34+
Semantic.withInitialState {
35+
val traverser = new InitTreeTraverser()
36+
units.foreach { unit => traverser.traverse(unit.tpdTree) }
37+
given Context = checkCtx
38+
Semantic.check()
39+
super.runOn(units)
40+
}
41+
42+
def run(using Context): Unit = {
43+
// ignore, we already called `Semantic.check()` in `runOn`
44+
}
3745

38-
val traverser = new TreeTraverser {
46+
class InitTreeTraverser(using WorkList) extends TreeTraverser {
3947
override def traverse(tree: Tree)(using Context): Unit =
4048
traverseChildren(tree)
4149
tree match {
42-
case tdef: MemberDef =>
50+
case mdef: MemberDef =>
4351
// self-type annotation ValDef has no symbol
44-
if tdef.name != nme.WILDCARD then
45-
tdef.symbol.defTree = tree
46-
case _ =>
47-
}
48-
}
52+
if mdef.name != nme.WILDCARD then
53+
mdef.symbol.defTree = tree
4954

50-
override def run(using Context): Unit = {
51-
val unit = ctx.compilationUnit
52-
unit.tpdTree.foreachSubTree {
53-
case tdef: TypeDef if tdef.isClassDef =>
54-
transformTypeDef(tdef)
55+
mdef match
56+
case tdef: TypeDef if tdef.isClassDef =>
57+
val cls = tdef.symbol.asClass
58+
val thisRef = ThisRef(cls)
59+
if shouldCheckClass(cls) then Semantic.addTask(thisRef)
60+
case _ =>
5561

56-
case _ =>
57-
}
62+
case _ =>
63+
}
5864
}
5965

60-
61-
private def transformTypeDef(tree: TypeDef)(using Context): tpd.Tree = {
62-
val cls = tree.symbol.asClass
66+
private def shouldCheckClass(cls: ClassSymbol)(using Context) = {
6367
val instantiable: Boolean =
6468
cls.is(Flags.Module) ||
6569
!cls.isOneOf(Flags.AbstractOrTrait) && {
@@ -71,21 +75,6 @@ class Checker extends Phase {
7175
}
7276

7377
// A concrete class may not be instantiated if the self type is not satisfied
74-
if (instantiable && cls.enclosingPackageClass != defn.StdLibPatchesPackage.moduleClass) {
75-
import semantic._
76-
val tpl = tree.rhs.asInstanceOf[Template]
77-
val thisRef = ThisRef(cls).ensureExists
78-
79-
val paramValues = tpl.constr.termParamss.flatten.map(param => param.symbol -> Hot).toMap
80-
81-
given Promoted = Promoted.empty
82-
given Trace = Trace.empty
83-
given Env = Env(paramValues)
84-
85-
val res = eval(tpl, thisRef, cls)
86-
res.errors.foreach(_.issue)
87-
}
88-
89-
tree
78+
instantiable && cls.enclosingPackageClass != defn.StdLibPatchesPackage.moduleClass
9079
}
9180
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ object Errors {
5555
case unsafe: UnsafePromotion => unsafe.errors.flatMap(_.flatten)
5656
case _ => this :: Nil
5757
}
58+
59+
override def toString() = this.getClass.getName
5860
}
5961

6062
/** Access non-initialized field */

0 commit comments

Comments
 (0)