From 609d29f83563afdf31c4e30c80ab85bb939970dc Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Tue, 10 Jun 2025 17:37:20 +0200 Subject: [PATCH 1/3] Remove unnecessary uses of uncheckedNN --- .../dotty/tools/backend/jvm/BCodeSyncAndTry.scala | 13 +++++-------- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- compiler/src/dotty/tools/dotc/core/Contexts.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../dotty/tools/dotc/core/tasty/TreePickler.scala | 6 +++--- .../tools/dotc/sbt/ExtractDependencies.scala | 1 - .../src/dotty/tools/dotc/typer/Implicits.scala | 10 ++++------ .../src/dotty/tools/dotc/util/EqHashSet.scala | 11 ++++------- .../dotty/tools/dotc/util/GenericHashSet.scala | 15 +++++++-------- compiler/src/dotty/tools/dotc/util/HashSet.scala | 11 ++++------- .../src/dotty/tools/dotc/util/ReadOnlyMap.scala | 6 +++--- .../src/dotty/tools/dotc/util/WeakHashSet.scala | 4 ++-- compiler/src/dotty/tools/io/FileExtension.scala | 1 - 13 files changed, 35 insertions(+), 49 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala b/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala index 4e2ea6dd52b8..84d41b5b5751 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeSyncAndTry.scala @@ -213,7 +213,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { val acquiredStack = if needStackStash then stack.acquireFullStack() else null val stashLocals = if acquiredStack == null then null - else acquiredStack.uncheckedNN.filter(_ != UNIT).map(btpe => locals.makeTempLocal(btpe)) + else acquiredStack.filter(_ != UNIT).map(btpe => locals.makeTempLocal(btpe)) val hasFinally = (finalizer != tpd.EmptyTree) @@ -240,9 +240,8 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { */ if stashLocals != null then - val stashLocalsNN = stashLocals.uncheckedNN // why is this necessary? - for i <- (stashLocalsNN.length - 1) to 0 by -1 do - val local = stashLocalsNN(i) + for i <- (stashLocals.length - 1) to 0 by -1 do + val local = stashLocals(i) bc.store(local.idx, local.tk) /* ------ (1) try-block, protected by: @@ -398,8 +397,6 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { */ if stashLocals != null then - val stashLocalsNN = stashLocals.uncheckedNN // why is this necessary? - val resultLoc = if kind == UNIT then null else if tmp != null then locals(tmp) // reuse the same local @@ -407,8 +404,8 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder { if resultLoc != null then bc.store(resultLoc.idx, kind) - for i <- 0 until stashLocalsNN.size do - val local = stashLocalsNN(i) + for i <- 0 until stashLocals.size do + val local = stashLocals(i) bc.load(local.idx, local.tk) if local.tk.isRef then bc.emit(asm.Opcodes.ACONST_NULL) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 2abae103780f..d889a79dc7b9 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -276,7 +276,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val previousParamRefs: ListBuffer[TermRef] = // It is ok to assign `null` here. // If `isParamDependent == false`, the value of `previousParamRefs` is not used. - if isParamDependent then mutable.ListBuffer[TermRef]() else (null: ListBuffer[TermRef] | Null).uncheckedNN + if isParamDependent then mutable.ListBuffer[TermRef]() else null.asInstanceOf[ListBuffer[TermRef]] def valueParam(name: TermName, origInfo: Type, isErased: Boolean): TermSymbol = val maybeImplicit = diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index a867f90b237a..1435550777a4 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -870,7 +870,7 @@ object Contexts { finally ctx.base.comparersInUse = saved end comparing - @sharable val NoContext: Context = new FreshContext((null: ContextBase | Null).uncheckedNN) { + @sharable val NoContext: Context = new FreshContext(null.asInstanceOf[ContextBase]) { override val implicits: ContextualImplicits = new ContextualImplicits(Nil, null, false)(this: @unchecked) setSource(NoSource) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ea4626ac684e..6fe512328755 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5046,7 +5046,7 @@ object Types extends TypeUtils { assert(currentEntry.bounds.contains(tp), i"$origin is constrained to be $currentEntry but attempted to instantiate it to $tp") - if ((ctx.typerState eq owningState.nn.get.uncheckedNN) && !TypeComparer.subtypeCheckInProgress) + if ((ctx.typerState eq owningState.nn.get) && !TypeComparer.subtypeCheckInProgress) setPermanentInst(tp) ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, tp) tp diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 4e63c7e973fe..5583cadca901 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -118,7 +118,7 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { else if label == NoAddr then pickleForwardSymRef(sym) else - writeRef(label.uncheckedNN) // !!! Dotty problem: Not clear why nn or uncheckedNN is needed here + writeRef(label) private def pickleForwardSymRef(sym: Symbol)(using Context) = { val ref = reserveRef(relative = false) @@ -184,7 +184,7 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { } else { writeByte(SHAREDtype) - writeRef(prev.uncheckedNN) + writeRef(prev) } } catch { @@ -260,7 +260,7 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { writeByte(RECthis) val binderAddr: Addr | Null = pickledTypes.lookup(tpe.binder) assert(binderAddr != null, tpe.binder) - writeRef(binderAddr.uncheckedNN) + writeRef(binderAddr) case tpe: SkolemType => pickleType(tpe.info) case tpe: RefinedType => diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 8b3b217cb0fc..20bdda055fd5 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -548,7 +548,6 @@ class DependencyRecorder { * This is backed by a cache which is invalidated when `ctx.owner` changes. */ private def resolveDependencyFromClass(using Context): Symbol = { - import dotty.tools.uncheckedNN if (lastOwner != ctx.owner) { lastOwner = ctx.owner val source = nonLocalEnclosingClass diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 25fed4e62de9..3eaac92b24f6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -2151,12 +2151,10 @@ sealed class TermRefSet(using Context): if !that.isEmpty then that.foreach(+=) def foreach[U](f: TermRef => U): Unit = - def handle(sym: TermSymbol | Null, prefixes: Type | List[Type] | Null): Unit = - // We cannot use `.nn` here due to inference issue. - val prefixes0: Type | List[Type] = prefixes.uncheckedNN - prefixes0 match - case prefix: Type => f(TermRef(prefix, sym.uncheckedNN)) - case prefixes: List[Type] => prefixes.foreach(pre => f(TermRef(pre, sym.uncheckedNN))) + def handle(sym: TermSymbol, prefixes: Type | List[Type]): Unit = + prefixes match + case prefix: Type => f(TermRef(prefix, sym)) + case prefixes: List[Type] => prefixes.foreach(pre => f(TermRef(pre, sym))) elems.forEach(handle) // used only for debugging diff --git a/compiler/src/dotty/tools/dotc/util/EqHashSet.scala b/compiler/src/dotty/tools/dotc/util/EqHashSet.scala index d584441fd00a..917d12ed37d0 100644 --- a/compiler/src/dotty/tools/dotc/util/EqHashSet.scala +++ b/compiler/src/dotty/tools/dotc/util/EqHashSet.scala @@ -1,7 +1,5 @@ package dotty.tools.dotc.util -import dotty.tools.uncheckedNN - object EqHashSet: def from[T](xs: IterableOnce[T]): EqHashSet[T] = @@ -47,7 +45,7 @@ class EqHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - if isEqual(e.uncheckedNN, x) then return e + if isEqual(e, x) then return e idx = nextIndex(idx) e = entryAt(idx) null @@ -66,7 +64,7 @@ class EqHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - if isEqual(e.uncheckedNN, x) then return false // already entered + if isEqual(e, x) then return false // already entered idx = nextIndex(idx) e = entryAt(idx) addEntryAt(idx, x) @@ -77,8 +75,7 @@ class EqHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - // TODO: remove uncheckedNN when explicit-nulls is enabled for regule compiling - if isEqual(e.uncheckedNN, x) then return e.uncheckedNN + if isEqual(e, x) then return e idx = nextIndex(idx) e = entryAt(idx) addEntryAt(idx, x) @@ -101,6 +98,6 @@ class EqHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends var idx = 0 while idx < oldTable.length do val e: T | Null = oldTable(idx).asInstanceOf[T | Null] - if e != null then addOld(e.uncheckedNN) + if e != null then addOld(e) idx += 1 } diff --git a/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala b/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala index 3c30e8e73300..ca23bdb51b1d 100644 --- a/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala +++ b/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala @@ -74,7 +74,7 @@ abstract class GenericHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - if isEqual(e.uncheckedNN, x) then return e + if isEqual(e, x) then return e idx = nextIndex(idx) e = entryAt(idx) null @@ -93,7 +93,7 @@ abstract class GenericHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - if isEqual(e.uncheckedNN, x) then return false // already entered + if isEqual(e, x) then return false // already entered idx = nextIndex(idx) e = entryAt(idx) addEntryAt(idx, x) @@ -104,8 +104,7 @@ abstract class GenericHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - // TODO: remove uncheckedNN when explicit-nulls is enabled for regule compiling - if isEqual(e.uncheckedNN, x) then return e.uncheckedNN + if isEqual(e, x) then return e idx = nextIndex(idx) e = entryAt(idx) addEntryAt(idx, x) @@ -117,20 +116,20 @@ abstract class GenericHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - if isEqual(e.uncheckedNN, x) then + if isEqual(e, x) then var hole = idx while idx = nextIndex(idx) e = entryAt(idx) e != null do - val eidx = index(hash(e.uncheckedNN)) + val eidx = index(hash(e)) if isDense || index(eidx - (hole + 1)) > index(idx - (hole + 1)) // entry `e` at `idx` can move unless `index(hash(e))` is in // the (ring-)interval [hole + 1 .. idx] then - setEntry(hole, e.uncheckedNN) + setEntry(hole, e) hole = idx table(hole) = null used -= 1 @@ -158,7 +157,7 @@ abstract class GenericHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int var idx = 0 while idx < oldTable.length do val e: T | Null = oldTable(idx).asInstanceOf[T | Null] - if e != null then addOld(e.uncheckedNN) + if e != null then addOld(e) idx += 1 protected def growTable(): Unit = diff --git a/compiler/src/dotty/tools/dotc/util/HashSet.scala b/compiler/src/dotty/tools/dotc/util/HashSet.scala index 3a973793d542..70903c1918ca 100644 --- a/compiler/src/dotty/tools/dotc/util/HashSet.scala +++ b/compiler/src/dotty/tools/dotc/util/HashSet.scala @@ -1,7 +1,5 @@ package dotty.tools.dotc.util -import dotty.tools.uncheckedNN - object HashSet: def from[T](xs: IterableOnce[T]): HashSet[T] = @@ -51,7 +49,7 @@ class HashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends Ge var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - if isEqual(e.uncheckedNN, x) then return e + if isEqual(e, x) then return e idx = nextIndex(idx) e = entryAt(idx) null @@ -69,7 +67,7 @@ class HashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends Ge var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - if isEqual(e.uncheckedNN, x) then return false // already entered + if isEqual(e, x) then return false // already entered idx = nextIndex(idx) e = entryAt(idx) addEntryAt(idx, x) @@ -80,8 +78,7 @@ class HashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends Ge var idx = firstIndex(x) var e: T | Null = entryAt(idx) while e != null do - // TODO: remove uncheckedNN when explicit-nulls is enabled for regule compiling - if isEqual(e.uncheckedNN, x) then return e.uncheckedNN + if isEqual(e, x) then return e idx = nextIndex(idx) e = entryAt(idx) addEntryAt(idx, x) @@ -104,6 +101,6 @@ class HashSet[T](initialCapacity: Int = 8, capacityMultiple: Int = 2) extends Ge var idx = 0 while idx < oldTable.length do val e: T | Null = oldTable(idx).asInstanceOf[T | Null] - if e != null then addOld(e.uncheckedNN) + if e != null then addOld(e) idx += 1 } diff --git a/compiler/src/dotty/tools/dotc/util/ReadOnlyMap.scala b/compiler/src/dotty/tools/dotc/util/ReadOnlyMap.scala index 020303c18bc2..05d83070f75f 100644 --- a/compiler/src/dotty/tools/dotc/util/ReadOnlyMap.scala +++ b/compiler/src/dotty/tools/dotc/util/ReadOnlyMap.scala @@ -17,17 +17,17 @@ abstract class ReadOnlyMap[Key, Value]: def get(key: Key): Option[Value] = lookup(key) match case null => None - case v => Some(v.uncheckedNN) + case v => Some(v) def getOrElse(key: Key, value: => Value) = lookup(key) match case null => value - case v => v.uncheckedNN + case v => v def contains(key: Key): Boolean = lookup(key) != null def apply(key: Key): Value = lookup(key) match case null => throw new NoSuchElementException(s"$key") - case v => v.uncheckedNN + case v => v def toArray: Array[(Key, Value)] = val result = new Array[(Key, Value)](size) diff --git a/compiler/src/dotty/tools/dotc/util/WeakHashSet.scala b/compiler/src/dotty/tools/dotc/util/WeakHashSet.scala index d93505f6f3c2..1423cb5d278d 100644 --- a/compiler/src/dotty/tools/dotc/util/WeakHashSet.scala +++ b/compiler/src/dotty/tools/dotc/util/WeakHashSet.scala @@ -178,7 +178,7 @@ abstract class WeakHashSet[A <: AnyRef](initialCapacity: Int = 8, loadFactor: Do case null => addEntryAt(bucket, elem, h, oldHead) case _ => val entryElem = entry.get - if entryElem != null && isEqual(elem, entryElem) then entryElem.uncheckedNN + if entryElem != null && isEqual(elem, entryElem) then entryElem else linkedListLoop(entry.tail) } @@ -296,7 +296,7 @@ abstract class WeakHashSet[A <: AnyRef](initialCapacity: Int = 8, loadFactor: Do assert(entry.get != null, s"$entry had a null value indicated that gc activity was happening during diagnostic validation or that a null value was inserted") computedCount += 1 val cachedHash = entry.hash - val realHash = hash(entry.get.uncheckedNN) + val realHash = hash(entry.get) assert(cachedHash == realHash, s"for $entry cached hash was $cachedHash but should have been $realHash") val computedBucket = index(realHash) assert(computedBucket == bucket, s"for $entry the computed bucket was $computedBucket but should have been $bucket") diff --git a/compiler/src/dotty/tools/io/FileExtension.scala b/compiler/src/dotty/tools/io/FileExtension.scala index 3aeef5b902ce..c7c4143dc977 100644 --- a/compiler/src/dotty/tools/io/FileExtension.scala +++ b/compiler/src/dotty/tools/io/FileExtension.scala @@ -1,6 +1,5 @@ package dotty.tools.io -import dotty.tools.uncheckedNN import dotty.tools.dotc.util.EnumFlags.FlagSet enum FileExtension(val toLowerCase: String): From c5cd3aeb51556d7aa45571619f89c4fb08f06581 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 12 Jun 2025 19:23:05 +0200 Subject: [PATCH 2/3] Fix bootstrapped compiler tests --- compiler/test/dotty/tools/vulpix/TestConfiguration.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/test/dotty/tools/vulpix/TestConfiguration.scala b/compiler/test/dotty/tools/vulpix/TestConfiguration.scala index e97ef47e6fef..d231627551c7 100644 --- a/compiler/test/dotty/tools/vulpix/TestConfiguration.scala +++ b/compiler/test/dotty/tools/vulpix/TestConfiguration.scala @@ -73,7 +73,7 @@ object TestConfiguration { val bestEffortBaselineOptions = TestFlags(basicClasspath, noCheckOptions) val unindentOptions = TestFlags(basicClasspath, Array("-no-indent") ++ checkOptions ++ noCheckOptions ++ yCheckOptions) val withCompilerOptions = - defaultOptions.withClasspath(withCompilerClasspath).withRunClasspath(withCompilerClasspath) + defaultOptions.and("-Yexplicit-nulls").withClasspath(withCompilerClasspath).withRunClasspath(withCompilerClasspath) lazy val withStagingOptions = defaultOptions.withClasspath(withStagingClasspath).withRunClasspath(withStagingClasspath) lazy val withTastyInspectorOptions = @@ -89,7 +89,7 @@ object TestConfiguration { "-Yprint-pos-syms" ) val picklingWithCompilerOptions = - picklingOptions.withClasspath(withCompilerClasspath).withRunClasspath(withCompilerClasspath) + picklingOptions.and("-Yexplicit-nulls").withClasspath(withCompilerClasspath).withRunClasspath(withCompilerClasspath) val explicitNullsOptions = defaultOptions and "-Yexplicit-nulls" From f7db381ba93533087112e8d5fffe20191f6ea6d8 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 12 Jun 2025 19:30:02 +0200 Subject: [PATCH 3/3] Update tests --- tests/pos-with-compiler/Patterns.scala | 2 +- tests/pos-with-compiler/lazyValsSepComp.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pos-with-compiler/Patterns.scala b/tests/pos-with-compiler/Patterns.scala index 6492ce6f8c72..4b4dfcccea2b 100644 --- a/tests/pos-with-compiler/Patterns.scala +++ b/tests/pos-with-compiler/Patterns.scala @@ -2,7 +2,7 @@ import dotty.tools.dotc.ast.Trees.* import dotty.tools.dotc.core.Types.* object Patterns { - val d: Object = null + val d: Object = Object() private def rebase(tp: NamedType): Type = { def rebaseFrom(prefix: Type): Type = ??? tp.prefix match { diff --git a/tests/pos-with-compiler/lazyValsSepComp.scala b/tests/pos-with-compiler/lazyValsSepComp.scala index c7e97dc12142..43bd8575feb3 100644 --- a/tests/pos-with-compiler/lazyValsSepComp.scala +++ b/tests/pos-with-compiler/lazyValsSepComp.scala @@ -10,7 +10,7 @@ import dotty.tools.dotc.core.Contexts.* /** A test to trigger issue with separate compilation and lazy vals */ object Foo { - val definitions: Definitions = null + val definitions: Definitions = null.asInstanceOf[Definitions] def defn = definitions def go = defn.ScalaBoxedClasses }