From 87b2ddb5327f1b51faeab206439ee76683971739 Mon Sep 17 00:00:00 2001 From: EnzeXing Date: Mon, 29 Apr 2024 22:19:18 +0800 Subject: [PATCH 1/2] Extend whitelist and add tests --- .../tools/dotc/transform/init/Objects.scala | 23 +++++++++++++++---- tests/init-global/pos/EmptyMap.scala | 6 +++++ tests/init-global/pos/EmptyMap2.scala | 4 ++++ tests/init-global/pos/EmptySet.scala | 6 +++++ tests/init-global/pos/EmptySet2.scala | 4 ++++ .../init-global/pos/EmptyVectorIterator.scala | 7 ++++++ tests/init-global/pos/LazyList.scala | 4 ++++ 7 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 tests/init-global/pos/EmptyMap.scala create mode 100644 tests/init-global/pos/EmptyMap2.scala create mode 100644 tests/init-global/pos/EmptySet.scala create mode 100644 tests/init-global/pos/EmptySet2.scala create mode 100644 tests/init-global/pos/EmptyVectorIterator.scala create mode 100644 tests/init-global/pos/LazyList.scala diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 793d4b41b174..1f06023ae892 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -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 * @@ -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 ----------------------------- @@ -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. @@ -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 @@ -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 diff --git a/tests/init-global/pos/EmptyMap.scala b/tests/init-global/pos/EmptyMap.scala new file mode 100644 index 000000000000..776fa81763d6 --- /dev/null +++ b/tests/init-global/pos/EmptyMap.scala @@ -0,0 +1,6 @@ +import scala.collection.immutable.HashMap + +object O { + val emptyMap: HashMap[Int, Int] = HashMap.empty + val key = emptyMap.get(0) +} diff --git a/tests/init-global/pos/EmptyMap2.scala b/tests/init-global/pos/EmptyMap2.scala new file mode 100644 index 000000000000..b66c92f449da --- /dev/null +++ b/tests/init-global/pos/EmptyMap2.scala @@ -0,0 +1,4 @@ +import scala.collection.immutable.HashMap + +object A: + val a = HashMap.empty[Int, Int].updated(1, 2) diff --git a/tests/init-global/pos/EmptySet.scala b/tests/init-global/pos/EmptySet.scala new file mode 100644 index 000000000000..7966d01a0aac --- /dev/null +++ b/tests/init-global/pos/EmptySet.scala @@ -0,0 +1,6 @@ +import scala.collection.immutable.HashSet + +object O { + val emptySet = HashSet.empty + val emptySetSize = emptySet.size +} diff --git a/tests/init-global/pos/EmptySet2.scala b/tests/init-global/pos/EmptySet2.scala new file mode 100644 index 000000000000..f2945c050eba --- /dev/null +++ b/tests/init-global/pos/EmptySet2.scala @@ -0,0 +1,4 @@ +import scala.collection.immutable.HashSet + +object A: + val a = HashSet.empty[Int] + 1 diff --git a/tests/init-global/pos/EmptyVectorIterator.scala b/tests/init-global/pos/EmptyVectorIterator.scala new file mode 100644 index 000000000000..40fcce8d7d3e --- /dev/null +++ b/tests/init-global/pos/EmptyVectorIterator.scala @@ -0,0 +1,7 @@ +import scala.collection.immutable.Vector + +object O { + val emptyVector = Vector.empty + val emptyVectorIterator = emptyVector.iterator + val hasNext = emptyVectorIterator.hasNext +} diff --git a/tests/init-global/pos/LazyList.scala b/tests/init-global/pos/LazyList.scala new file mode 100644 index 000000000000..fea70b5a8a54 --- /dev/null +++ b/tests/init-global/pos/LazyList.scala @@ -0,0 +1,4 @@ +import scala.collection.immutable.LazyList + +object A: + val a = LazyList.empty[Int] :+ 1 \ No newline at end of file From 34280669af67b12c67de84ea34304622f922d4f6 Mon Sep 17 00:00:00 2001 From: EnzeXing Date: Tue, 30 Apr 2024 10:25:50 +0800 Subject: [PATCH 2/2] Correction --- compiler/src/dotty/tools/dotc/transform/init/Objects.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala index 1f06023ae892..8c0a34092330 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Objects.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Objects.scala @@ -83,7 +83,7 @@ class Objects(using Context @constructorOnly): val immutableLazyList: Symbol = requiredModule("scala.collection.immutable.LazyList") val LazyList_empty: Symbol = immutableLazyList.requiredValue("_empty") - val whiteList: Set[Symbol] = Set() + val whiteList: Set[Symbol] = Set(SetNode_EmptySetNode, HashSet_EmptySet, Vector_EmptyIterator, MapNode_EmptyMapNode, HashMap_EmptyMap, LazyList_empty) // ----------------------------- abstract domain ----------------------------- @@ -173,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 + ")" + "valMap = " + vals + "varMap = " + vars + def show(using Context) = "ObjectRef(" + klass.show + ")" /** * Represents values that are instances of the specified class. @@ -832,7 +832,6 @@ 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 @@ -841,7 +840,6 @@ 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