Skip to content

Commit

Permalink
Address review
Browse files Browse the repository at this point in the history
  • Loading branch information
liufengyun committed Oct 8, 2022
1 parent 41bcb6a commit a24ff12
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 62 deletions.
31 changes: 8 additions & 23 deletions compiler/src/dotty/tools/dotc/transform/init/Checker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import scala.collection.mutable

import Semantic._

class Checker extends Phase {
class Checker extends Phase:

override def phaseName: String = Checker.name

Expand All @@ -34,19 +34,20 @@ class Checker extends Phase {
val checkCtx = ctx.fresh.setPhase(this.start)
val traverser = new InitTreeTraverser()
units.foreach { unit => traverser.traverse(unit.tpdTree) }
val classes = traverser.getConcreteClasses()
val classes = traverser.getClasses()

Semantic.checkClasses(classes)(using checkCtx)

units

def run(using Context): Unit =
// ignore, we already called `Semantic.check()` in `runOn`
()

class InitTreeTraverser extends TreeTraverser {
private val concreteClasses: mutable.ArrayBuffer[ClassSymbol] = new mutable.ArrayBuffer
class InitTreeTraverser extends TreeTraverser:
private val classes: mutable.ArrayBuffer[ClassSymbol] = new mutable.ArrayBuffer

def getConcreteClasses(): List[ClassSymbol] = concreteClasses.toList
def getClasses(): List[ClassSymbol] = classes.toList

override def traverse(tree: Tree)(using Context): Unit =
traverseChildren(tree)
Expand All @@ -59,28 +60,12 @@ class Checker extends Phase {
mdef match
case tdef: TypeDef if tdef.isClassDef =>
val cls = tdef.symbol.asClass
if isConcreteClass(cls) then concreteClasses.append(cls)
classes.append(cls)
case _ =>

case _ =>
}
}

private def isConcreteClass(cls: ClassSymbol)(using Context) = {
val instantiable: Boolean =
cls.is(Flags.Module) ||
!cls.isOneOf(Flags.AbstractOrTrait) && {
// see `Checking.checkInstantiable` in typer
val tp = cls.appliedRef
val stp = SkolemType(tp)
val selfType = cls.givenSelfType.asSeenFrom(stp, cls)
!selfType.exists || stp <:< selfType
}

// A concrete class may not be instantiated if the self type is not satisfied
instantiable && cls.enclosingPackageClass != defn.StdLibPatchesPackage.moduleClass
}
}
end InitTreeTraverser

object Checker:
val name: String = "initChecker"
Expand Down
86 changes: 47 additions & 39 deletions compiler/src/dotty/tools/dotc/transform/init/Semantic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1206,56 +1206,49 @@ object Semantic:
cls == defn.AnyValClass ||
cls == defn.ObjectClass

// ----- Work list ---------------------------------------------------
class WorkList private[Semantic](tasks: List[ClassSymbol]):
/** Process the worklist until done */
final def work()(using Cache, Context): Unit =
for task <- tasks do doTask(task)

/** Check an individual class
*
* This method should only be called from the work list scheduler.
*/
private def doTask(classSym: ClassSymbol)(using Cache, Context): Unit =
val thisRef = ThisRef(classSym)
val tpl = classSym.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
// ----- API --------------------------------

@tailrec
def iterate(): Unit = {
given Promoted = Promoted.empty(classSym)
given Trace = Trace.empty.add(classSym.defTree)
given reporter: Reporter.BufferedReporter = new Reporter.BufferedReporter
/** Check an individual class
*
* The class to be checked must be an instantiable concrete class.
*/
private def checkClass(classSym: ClassSymbol)(using Cache, Context): Unit =
val thisRef = ThisRef(classSym)
val tpl = classSym.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]

thisRef.ensureFresh()
@tailrec
def iterate(): Unit = {
given Promoted = Promoted.empty(classSym)
given Trace = Trace.empty.add(classSym.defTree)
given reporter: Reporter.BufferedReporter = new Reporter.BufferedReporter

// set up constructor parameters
for param <- tpl.constr.termParamss.flatten do
thisRef.updateField(param.symbol, Hot)
thisRef.ensureFresh()

log("checking " + classSym) { eval(tpl, thisRef, classSym) }
reporter.errors.foreach(_.issue)
// set up constructor parameters
for param <- tpl.constr.termParamss.flatten do
thisRef.updateField(param.symbol, Hot)

if cache.hasChanged && reporter.errors.isEmpty then
// code to prepare cache and heap for next iteration
cache.prepareForNextIteration()
iterate()
else
cache.prepareForNextClass()
}
log("checking " + classSym) { eval(tpl, thisRef, classSym) }
reporter.errors.foreach(_.issue)

iterate()
end doTask
end WorkList
if cache.hasChanged && reporter.errors.isEmpty then
// code to prepare cache and heap for next iteration
cache.prepareForNextIteration()
iterate()
else
cache.prepareForNextClass()
}

// ----- API --------------------------------
iterate()
end checkClass

/**
* Check the specified concrete classes
*/
def checkClasses(concreteClasses: List[ClassSymbol])(using Context): Unit =
val workList = new WorkList(concreteClasses)
val cache = new Cache
workList.work()(using cache, ctx)
def checkClasses(classes: List[ClassSymbol])(using Context): Unit =
given Cache()
for classSym <- classes if isConcreteClass(classSym) do
checkClass(classSym)

// ----- Semantic definition --------------------------------

Expand Down Expand Up @@ -1766,3 +1759,18 @@ object Semantic:
if (sym.isEffectivelyFinal || sym.isConstructor) sym
else sym.matchingMember(cls.appliedRef)
}

private def isConcreteClass(cls: ClassSymbol)(using Context) = {
val instantiable: Boolean =
cls.is(Flags.Module) ||
!cls.isOneOf(Flags.AbstractOrTrait) && {
// see `Checking.checkInstantiable` in typer
val tp = cls.appliedRef
val stp = SkolemType(tp)
val selfType = cls.givenSelfType.asSeenFrom(stp, cls)
!selfType.exists || stp <:< selfType
}

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

0 comments on commit a24ff12

Please sign in to comment.