Skip to content

Extend whitelist in global initialization checker #20290

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 2 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
23 changes: 18 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/init/Objects.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import scala.collection.mutable
import scala.annotation.tailrec
import scala.annotation.constructorOnly
import dotty.tools.dotc.core.Flags.AbstractOrTrait
import Decorators.*

/** Check initialization safety of static objects
*
Expand Down Expand Up @@ -68,11 +69,21 @@ import dotty.tools.dotc.core.Flags.AbstractOrTrait
*
*/
class Objects(using Context @constructorOnly):
val immutableHashSetBuider: Symbol = requiredClass("scala.collection.immutable.HashSetBuilder")
val immutableHashSetNode: Symbol = requiredClass("scala.collection.immutable.SetNode")
// TODO: this should really be an annotation on the rhs of the field initializer rather than the field itself.
val HashSetBuilder_rootNode: Symbol = immutableHashSetBuider.requiredValue("rootNode")

val whiteList = Set(HashSetBuilder_rootNode)
val SetNode_EmptySetNode: Symbol = Denotations.staticRef("scala.collection.immutable.SetNode.EmptySetNode".toTermName).symbol
val immutableHashSet: Symbol = requiredModule("scala.collection.immutable.HashSet")
val HashSet_EmptySet: Symbol = Denotations.staticRef("scala.collection.immutable.HashSet.EmptySet".toTermName).symbol
val immutableVector: Symbol = requiredModule("scala.collection.immutable.Vector")
val Vector_EmptyIterator: Symbol = immutableVector.requiredValue("emptyIterator")
val immutableMapNode: Symbol = requiredModule("scala.collection.immutable.MapNode")
val MapNode_EmptyMapNode: Symbol = immutableMapNode.requiredValue("EmptyMapNode")
val immutableHashMap: Symbol = requiredModule("scala.collection.immutable.HashMap")
val HashMap_EmptyMap: Symbol = immutableHashMap.requiredValue("EmptyMap")
val immutableLazyList: Symbol = requiredModule("scala.collection.immutable.LazyList")
val LazyList_empty: Symbol = immutableLazyList.requiredValue("_empty")

val whiteList: Set[Symbol] = Set()

// ----------------------------- abstract domain -----------------------------

Expand Down Expand Up @@ -162,7 +173,7 @@ class Objects(using Context @constructorOnly):
extends Ref(valsMap = mutable.Map.empty, varsMap = mutable.Map.empty, outersMap = mutable.Map.empty):
val owner = klass

def show(using Context) = "ObjectRef(" + klass.show + ")"
def show(using Context) = "ObjectRef(" + klass.show + ")" + "valMap = " + vals + "varMap = " + vars

/**
* Represents values that are instances of the specified class.
Expand Down Expand Up @@ -821,6 +832,7 @@ class Objects(using Context @constructorOnly):
errorReadOtherStaticObject(State.currentObject, addr)
Bottom
else if ref.isObjectRef && ref.klass.hasSource then
println(s"Uninitialized field Position 2, ref = $ref, target = $target")
report.warning("Access uninitialized field " + field.show + ". " + Trace.show, Trace.position)
Bottom
else
Expand All @@ -829,6 +841,7 @@ class Objects(using Context @constructorOnly):
else if ref.hasVal(target) then
ref.valValue(target)
else if ref.isObjectRef && ref.klass.hasSource then
println(s"Uninitialized field Position 2, ref = $ref, target = $target")
report.warning("Access uninitialized field " + field.show + ". " + Trace.show, Trace.position)
Bottom
else
Expand Down
6 changes: 6 additions & 0 deletions tests/init-global/pos/EmptyMap.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import scala.collection.immutable.HashMap

object O {
val emptyMap: HashMap[Int, Int] = HashMap.empty
val key = emptyMap.get(0)
}
4 changes: 4 additions & 0 deletions tests/init-global/pos/EmptyMap2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import scala.collection.immutable.HashMap

object A:
val a = HashMap.empty[Int, Int].updated(1, 2)
6 changes: 6 additions & 0 deletions tests/init-global/pos/EmptySet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import scala.collection.immutable.HashSet

object O {
val emptySet = HashSet.empty
val emptySetSize = emptySet.size
}
4 changes: 4 additions & 0 deletions tests/init-global/pos/EmptySet2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import scala.collection.immutable.HashSet

object A:
val a = HashSet.empty[Int] + 1
7 changes: 7 additions & 0 deletions tests/init-global/pos/EmptyVectorIterator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.collection.immutable.Vector

object O {
val emptyVector = Vector.empty
val emptyVectorIterator = emptyVector.iterator
val hasNext = emptyVectorIterator.hasNext
}
4 changes: 4 additions & 0 deletions tests/init-global/pos/LazyList.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import scala.collection.immutable.LazyList

object A:
val a = LazyList.empty[Int] :+ 1
Loading