Skip to content

Commit

Permalink
Merge pull request #7789 from dotty-staging/init-dotty
Browse files Browse the repository at this point in the history
Safe initialization for Scala
  • Loading branch information
anatoliykmetyuk committed Feb 13, 2020
2 parents a71e099 + 6a4d06a commit 228b61e
Show file tree
Hide file tree
Showing 166 changed files with 5,080 additions and 4 deletions.
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ class Compiler {
new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars
new ElimPackagePrefixes, // Eliminate references to package prefixes in Select nodes
new CookComments, // Cook the comments: expand variables, doc, etc.
new CheckStatic) :: // Check restrictions that apply to @static members
new CheckStatic, // Check restrictions that apply to @static members
new init.Checker) :: // Check initialization of objects
List(new CompleteJavaEnums, // Fill in constructors for Java enums
new ElimRepeated, // Rewrite vararg parameters and arguments
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
/** An extractor for def of a closure contained the block of the closure. */
object closureDef {
def unapply(tree: Tree)(implicit ctx: Context): Option[DefDef] = tree match {
case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, closure: Closure) =>
case Block((meth : DefDef) :: Nil, closure: Closure) if meth.symbol == closure.meth.symbol =>
Some(meth)
case Block(Nil, expr) =>
unapply(expr)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ object Printers {
val implicits: Printer = noPrinter
val implicitsDetailed: Printer = noPrinter
val lexical: Printer = noPrinter
val init: Printer = noPrinter
val inlining: Printer = noPrinter
val interactiv: Printer = noPrinter
val nullables: Printer = noPrinter
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ class ScalaSettings extends Settings.SettingGroup {
val YnoKindPolymorphism: Setting[Boolean] = BooleanSetting("-Yno-kind-polymorphism", "Enable kind polymorphism (see https://dotty.epfl.ch/docs/reference/kind-polymorphism.html). Potentially unsound.")
val YexplicitNulls: Setting[Boolean] = BooleanSetting("-Yexplicit-nulls", "Make reference types non-nullable. Nullable types can be expressed with unions: e.g. String|Null.")
val YerasedTerms: Setting[Boolean] = BooleanSetting("-Yerased-terms", "Allows the use of erased terms.")
val YcheckInit: Setting[Boolean] = BooleanSetting("-Ycheck-init", "Check initialization of objects")

/** Area-specific debug output */
val YexplainLowlevel: Setting[Boolean] = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")
Expand Down
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,9 @@ object Symbols {
*/
def retainsDefTree(implicit ctx: Context): Boolean =
ctx.settings.YretainTrees.value ||
denot.owner.isTerm || // no risk of leaking memory after a run for these
denot.isOneOf(InlineOrProxy) // need to keep inline info
denot.owner.isTerm || // no risk of leaking memory after a run for these
denot.isOneOf(InlineOrProxy) || // need to keep inline info
ctx.settings.YcheckInit.value // initialization check

/** The last denotation of this symbol */
private var lastDenot: SymDenotation = _
Expand Down
63 changes: 63 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/init/Checker.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dotty.tools.dotc
package transform
package init


import dotty.tools.dotc._
import ast.tpd

import dotty.tools.dotc.core._
import Contexts.Context
import Types._

import dotty.tools.dotc.transform._
import MegaPhase._


import scala.collection.mutable


class Checker extends MiniPhase {
import tpd._

val phaseName = "initChecker"

// cache of class summary
private val baseEnv = Env(null, mutable.Map.empty)

override val runsAfter = Set(Pickler.name)

override def isEnabled(implicit ctx: Context): Boolean =
super.isEnabled && ctx.settings.YcheckInit.value

override def transformTypeDef(tree: TypeDef)(implicit ctx: Context): tpd.Tree = {
if (!tree.isClassDef) return tree

val cls = tree.symbol.asClass
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
if (instantiable) {
implicit val state = Checking.State(
visited = mutable.Set.empty,
path = Vector.empty,
thisClass = cls,
fieldsInited = mutable.Set.empty,
parentsInited = mutable.Set.empty,
env = baseEnv.withCtx(ctx)
)

Checking.checkClassBody(tree)
}

tree
}
}
Loading

0 comments on commit 228b61e

Please sign in to comment.