Skip to content

Fix init soundness #13472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 51 commits into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
857cc74
Update tests
EnzeXing Aug 25, 2021
ef43eb5
Add worklist and refactor definition for ThisRef
liufengyun Sep 4, 2021
5d1fe86
Rename Addr to Ref
liufengyun Sep 4, 2021
7279f73
Refactor: make state explicit
liufengyun Sep 5, 2021
20ff7ca
Add constructor to Warm
liufengyun Sep 5, 2021
f5651b5
Revert ThisRef to previous version
liufengyun Sep 5, 2021
6763285
Refactor constructor call
liufengyun Sep 5, 2021
ab09fd2
Make cache part of state
liufengyun Sep 5, 2021
98f9f7e
Handle cache in work list
liufengyun Sep 5, 2021
fb0c347
Don't iterate if errors found
liufengyun Sep 5, 2021
69e314e
Revert heap changes if cache has changed
liufengyun Sep 5, 2021
db11295
Restore cacheResult option for eval
liufengyun Sep 5, 2021
111ac87
Handle callConstructor
liufengyun Sep 6, 2021
29bdb5d
Reset Cache.changed after each iteration
liufengyun Sep 6, 2021
0b1b21f
Tweak log printing of errors
liufengyun Sep 6, 2021
c5daf1d
Fix context for init check
liufengyun Sep 6, 2021
4a71470
Introduce global cache which holds fixed point value
liufengyun Sep 6, 2021
375e0e5
Update tests
liufengyun Sep 7, 2021
6188e8e
Avoid asInstanceOf in logging
liufengyun Sep 7, 2021
5bdd898
Refactor cache
liufengyun Sep 8, 2021
9ea3624
Cache default value in the input cache
liufengyun Sep 8, 2021
d0e71a2
Rename global cache to stable cache
liufengyun Sep 8, 2021
fe3930d
Better encapsulate Cache.assume
liufengyun Sep 8, 2021
5bd83ae
Rename in/out to last/current
liufengyun Sep 8, 2021
2589824
Mark arguments as constructor only
liufengyun Sep 8, 2021
2849052
Add note for tempting but unsound optimization
liufengyun Sep 8, 2021
8a4fe78
Commit cache to stable on error
liufengyun Sep 8, 2021
5b00b1f
Make sure the object of a reference assumption value exists
liufengyun Sep 8, 2021
04aa72b
Add back arguments to ThisRef
liufengyun Sep 8, 2021
ad503fc
Populate parameters of Warm objects by reusing init
liufengyun Sep 8, 2021
fb3b6ca
Make sure the class parameters and outers of warm objects are populated
liufengyun Sep 8, 2021
bc98ce8
Use correct trace
liufengyun Sep 8, 2021
b27d58b
Populate class parameters for warm objects in a heap prepare step
liufengyun Sep 8, 2021
99df102
Try to check warm values immediately
liufengyun Sep 9, 2021
4163fd3
Fix crash: make sure object fresh before calling init
liufengyun Sep 9, 2021
683d537
Be more sensitive for values Warm(outer = ThisRef)
liufengyun Sep 9, 2021
ccbb355
Fix non-determinism in test
liufengyun Sep 9, 2021
fc76549
Make isPopulatingParams a flag in Warm
liufengyun Sep 15, 2021
191877a
Make heap as part of cache
liufengyun Sep 16, 2021
f5540f5
Update test
liufengyun Sep 20, 2021
a15a06c
Add more debugging information
liufengyun Sep 20, 2021
46793f1
Lazily populate warm objects
liufengyun Sep 20, 2021
8bbe384
Add comment
liufengyun Sep 20, 2021
dab8181
Fix non-termination
liufengyun Sep 21, 2021
1ab5316
Fix pickling test
liufengyun Sep 22, 2021
1e802c9
Remove unused parameters of ThisRef
liufengyun Sep 22, 2021
8088217
Fix compilation of scodec
liufengyun Sep 22, 2021
6566756
Apply suggestions from code review
liufengyun Oct 7, 2021
15a51d7
Address review comments
liufengyun Oct 7, 2021
7ee58a3
Address review: Add comment to populateParams
liufengyun Oct 7, 2021
e905cd5
Fix compilation
liufengyun Oct 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 28 additions & 39 deletions compiler/src/dotty/tools/dotc/transform/init/Checker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package init

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

import dotty.tools.dotc.core._
import Contexts._
Expand All @@ -15,51 +16,54 @@ import StdNames._
import dotty.tools.dotc.transform._
import Phases._


import scala.collection.mutable

import Semantic._

class Checker extends Phase {
import tpd._

val phaseName = "initChecker"

private val semantic = new Semantic

override val runsAfter = Set(Pickler.name)

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

override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] =
units.foreach { unit => traverser.traverse(unit.tpdTree) }
super.runOn(units)
val checkCtx = ctx.fresh.setPhase(this.start)
Semantic.withInitialState {
val traverser = new InitTreeTraverser()
units.foreach { unit => traverser.traverse(unit.tpdTree) }
given Context = checkCtx
Semantic.check()
super.runOn(units)
}

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

val traverser = new TreeTraverser {
class InitTreeTraverser(using WorkList) extends TreeTraverser {
override def traverse(tree: Tree)(using Context): Unit =
traverseChildren(tree)
tree match {
case tdef: MemberDef =>
case mdef: MemberDef =>
// self-type annotation ValDef has no symbol
if tdef.name != nme.WILDCARD then
tdef.symbol.defTree = tree
case _ =>
}
}
if mdef.name != nme.WILDCARD then
mdef.symbol.defTree = tree

override def run(using Context): Unit = {
val unit = ctx.compilationUnit
unit.tpdTree.foreachSubTree {
case tdef: TypeDef if tdef.isClassDef =>
transformTypeDef(tdef)
mdef match
case tdef: TypeDef if tdef.isClassDef =>
val cls = tdef.symbol.asClass
val thisRef = ThisRef(cls)
if shouldCheckClass(cls) then Semantic.addTask(thisRef)
case _ =>

case _ =>
}
case _ =>
}
}


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

// A concrete class may not be instantiated if the self type is not satisfied
if (instantiable && cls.enclosingPackageClass != defn.StdLibPatchesPackage.moduleClass) {
import semantic._
val tpl = tree.rhs.asInstanceOf[Template]
val thisRef = ThisRef(cls).ensureExists

val paramValues = tpl.constr.termParamss.flatten.map(param => param.symbol -> Hot).toMap

given Promoted = Promoted.empty
given Trace = Trace.empty
given Env = Env(paramValues)

val res = eval(tpl, thisRef, cls)
res.errors.foreach(_.issue)
}

tree
instantiable && cls.enclosingPackageClass != defn.StdLibPatchesPackage.moduleClass
}
}
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/init/Errors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ object Errors {
case unsafe: UnsafePromotion => unsafe.errors.flatMap(_.flatten)
case _ => this :: Nil
}

override def toString() = this.getClass.getName
}

/** Access non-initialized field */
Expand Down
Loading