diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index f3fba2e83fa7..2b3854d4478b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -73,9 +73,9 @@ object Trees { /** The type of the tree. In case of an untyped tree, * an UnAssignedTypeException is thrown. (Overridden by empty trees) */ - final def tpe: T = - if myTpe == null then throw UnAssignedTypeException(this) - myTpe.uncheckedNN + final def tpe: T = myTpe match + case null => throw UnAssignedTypeException(this) + case t => t /** Copy `tpe` attribute from tree `from` into this tree, independently * whether it is null or not. @@ -292,10 +292,11 @@ object Trees { trait DefTree[+T <: Untyped] extends DenotingTree[T] { type ThisTree[+T <: Untyped] <: DefTree[T] - private var myMods: untpd.Modifiers | Null = uninitialized + private var myMods: untpd.Modifiers | Null = null - private[dotc] def rawMods: untpd.Modifiers = - if (myMods == null) untpd.EmptyModifiers else myMods.uncheckedNN + private[dotc] def rawMods: untpd.Modifiers = myMods match + case null => untpd.EmptyModifiers + case mods => mods def withAnnotations(annots: List[untpd.Tree]): ThisTree[Untyped] = withMods(rawMods.withAnnotations(annots)) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 13d70408d7db..83fa7727f3f0 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -15,7 +15,6 @@ import Spans.* import scala.annotation.tailrec import scala.collection.{immutable, mutable} -import scala.compiletime.uninitialized /** Some creators for typed trees */ object tpd extends Trees.Instance[Type] with TypedTreeInfo { @@ -1373,13 +1372,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { trait TreeProvider { protected def computeRootTrees(using Context): List[Tree] - private var myTrees: List[Tree] | Null = uninitialized + private var myTrees: List[Tree] | Null = null /** Get trees defined by this provider. Cache them if -Yretain-trees is set. */ def rootTrees(using Context): List[Tree] = if (ctx.settings.YretainTrees.value) { - if (myTrees == null) myTrees = computeRootTrees - myTrees.uncheckedNN + initialize(myTrees, myTrees = _, computeRootTrees) } else computeRootTrees diff --git a/compiler/src/dotty/tools/dotc/cc/Capability.scala b/compiler/src/dotty/tools/dotc/cc/Capability.scala index 171a62e6b8d8..02190188db4a 100644 --- a/compiler/src/dotty/tools/dotc/cc/Capability.scala +++ b/compiler/src/dotty/tools/dotc/cc/Capability.scala @@ -9,7 +9,6 @@ import util.common.alwaysTrue import scala.collection.mutable import CCState.* import Periods.{NoRunId, RunId, RunWidth} -import compiletime.uninitialized import StdNames.nme import CaptureSet.{Refs, emptyRefs, VarState} import Annotations.Annotation @@ -341,7 +340,7 @@ object Capabilities: */ trait Capability extends Showable: - private var myCaptureSet: CaptureSet | Null = uninitialized + private var myCaptureSet: CaptureSet | Null = null private var captureSetValid: Validity = invalid private var mySingletonCaptureSet: CaptureSet.Const | Null = null private var myDerived: List[DerivedCapability] = Nil @@ -602,9 +601,7 @@ object Capabilities: /** The capture set consisting of exactly this reference */ def singletonCaptureSet(using Context): CaptureSet.Const = - if mySingletonCaptureSet == null then - mySingletonCaptureSet = CaptureSet(this) - mySingletonCaptureSet.uncheckedNN + initialize(mySingletonCaptureSet, mySingletonCaptureSet = _, CaptureSet(this)) /** The capture set of the type underlying this reference */ def captureSetOfInfo(using Context): CaptureSet = diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintRunInfo.scala b/compiler/src/dotty/tools/dotc/core/ConstraintRunInfo.scala index 8ec38d52e725..323db4eb8a09 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintRunInfo.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintRunInfo.scala @@ -7,7 +7,7 @@ import scala.compiletime.uninitialized trait ConstraintRunInfo { self: Run => private var maxSize = 0 - private var maxConstraint: Constraint | Null = uninitialized + private var maxConstraint: Constraint | Null = null def recordConstraintSize(c: Constraint, size: Int): Unit = if (size > maxSize) { maxSize = size diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index cfbc4d6078f7..077056766a54 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -895,7 +895,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) } @@ -913,7 +913,7 @@ object Contexts { val initialCtx: Context = FreshContext.initial(this: @unchecked, settings) /** The platform, initialized by `initPlatform()`. */ - private var _platform: Platform | Null = uninitialized + private var _platform: Platform | Null = null /** The platform */ def platform: Platform = { diff --git a/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala b/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala index 75c23bb003b5..10263afe4fd7 100644 --- a/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/GadtConstraint.scala @@ -123,7 +123,9 @@ class GadtConstraint private ( def apply(tp: Type): Type = externalize(tp, this)(using mapCtx) def tvarOrError(sym: Symbol)(using Context): TypeVar = - mapping(sym).ensuring(_ != null, i"not a constrainable symbol: $sym").uncheckedNN + mapping(sym) match + case null => throw new AssertionError(i"not a constrainable symbol: $sym") + case m => m @tailrec final def stripInternalTypeVar(tp: Type): Type = tp match case tv: TypeVar => diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index b239c092f1df..5392393c9fc3 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -888,22 +888,23 @@ class OrderingConstraint(private val boundsMap: ParamBounds, i += 1 } - private var myUninstVars: mutable.ArrayBuffer[TypeVar] | Null = uninitialized + private var myUninstVars: mutable.ArrayBuffer[TypeVar] | Null = null /** The uninstantiated typevars of this constraint */ - def uninstVars: collection.Seq[TypeVar] = { - if (myUninstVars == null || myUninstVars.uncheckedNN.exists(_.isPermanentlyInstantiated)) { - myUninstVars = new mutable.ArrayBuffer[TypeVar] - boundsMap.foreachBinding { (poly, entries) => - for (i <- 0 until paramCount(entries)) - typeVar(entries, i) match { - case tv: TypeVar if !tv.isPermanentlyInstantiated && isBounds(entries(i)) => myUninstVars.uncheckedNN += tv - case _ => - } - } - } - myUninstVars.uncheckedNN - } + def uninstVars: collection.Seq[TypeVar] = + myUninstVars match + case uv: mutable.ArrayBuffer[TypeVar] if !uv.exists(_.isPermanentlyInstantiated) => uv + case _ => + val res = new mutable.ArrayBuffer[TypeVar] + myUninstVars = res + boundsMap.foreachBinding { (poly, entries) => + for (i <- 0 until paramCount(entries)) + typeVar(entries, i) match { + case tv: TypeVar if !tv.isPermanentlyInstantiated && isBounds(entries(i)) => res += tv + case _ => + } + } + res // ---------- Checking ----------------------------------------------- diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 7e2fea6cb2fd..63ed60419dff 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -19,7 +19,6 @@ import printing.Printer import SymDenotations.NoDenotation import collection.mutable -import scala.compiletime.uninitialized object Scopes { @@ -31,7 +30,7 @@ object Scopes { * This value must be a power of two, so that the index of an element can * be computed as element.hashCode & (hashTable.length - 1) */ - inline val MinHashedScopeSize = 8 + private inline val MinHashedScopeSize = 8 /** The maximal permissible number of recursions when creating * a hashtable @@ -42,7 +41,7 @@ object Scopes { * the given name in the given context. Returns `NoSymbol` if the * no symbol should be synthesized for the given name. */ - type SymbolSynthesizer = Name => Context ?=> Symbol + private type SymbolSynthesizer = Name => Context ?=> Symbol class ScopeEntry private[Scopes] (val name: Name, _sym: Symbol, val owner: Scope) { @@ -135,7 +134,11 @@ object Scopes { final def lookupAll(name: Name)(using Context): Iterator[Symbol] = new Iterator[Symbol] { var e = lookupEntry(name) def hasNext: Boolean = e != null - def next(): Symbol = { val r = e.nn.sym; e = lookupNextEntry(e.uncheckedNN); r } + def next(): Symbol = e match + case null => throw new NoSuchElementException() + case ee => + e = lookupNextEntry(ee) + ee.sym } /** Does this scope contain a reference to `sym` when looking up `name`? */ @@ -179,8 +182,10 @@ object Scopes { result.nn.enter(newName, sym) else drop() - // TODO: improve flow typing to handle this case - if result == null then this else result.uncheckedNN + // TODO: `if result == null then this else result` should work here, improve flow typing to handle it + result match + case null => this + case r => r def implicitDecls(using Context): List[TermRef] = Nil @@ -257,7 +262,7 @@ object Scopes { /** create and enter a scope entry with given name and symbol */ protected def newScopeEntry(name: Name, sym: Symbol)(using Context): ScopeEntry = { - ensureCapacity(if (hashTable != null) hashTable.uncheckedNN.length else MinHashedScopeSize) + ensureCapacity(hashTable match { case null => MinHashedScopeSize; case ht => ht.length }) val e = new ScopeEntry(name, sym, this) e.prev = lastEntry lastEntry = e @@ -383,21 +388,24 @@ object Scopes { while ((e != null) && e.name != name) e = e.prev } - if ((e == null) && (synthesize != null)) { - val sym = synthesize.uncheckedNN(name) - if (sym.exists) newScopeEntry(sym.name, sym) else e - } - else e + if e != null then e + else synthesize match + case null => null + case s => + val sym = s(name) + if (sym.exists) newScopeEntry(sym.name, sym) else e } /** lookup next entry with same name as this one */ override final def lookupNextEntry(entry: ScopeEntry)(using Context): ScopeEntry | Null = { - var e: ScopeEntry | Null = entry - if (hashTable != null) - while ({ e = e.nn.tail ; (e != null) && e.uncheckedNN.name != entry.name }) () + if hashTable != null then + var e: ScopeEntry | Null = entry.tail + while e != null && e.name != entry.name do e = e.tail + e else - while ({ e = e.nn.prev ; (e != null) && e.uncheckedNN.name != entry.name }) () - e + var e: ScopeEntry | Null = entry.prev + while e != null && e.name != entry.name do e = e.prev + e } /** Returns all symbols as a list in the order they were entered in this scope. @@ -418,7 +426,7 @@ object Scopes { override def implicitDecls(using Context): List[TermRef] = { ensureComplete() - var irefs = new mutable.ListBuffer[TermRef] + val irefs = new mutable.ListBuffer[TermRef] var e = lastEntry while (e != null) { if (e.sym.isOneOf(GivenOrImplicitVal)) { diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index c33ad458b0d5..35d9b720bb42 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1917,7 +1917,9 @@ object SymDenotations { invalidateMemberNamesCache() def invalidateMemberCachesFor(sym: Symbol)(using Context): Unit = - if myMemberCache != null then myMemberCache.uncheckedNN.remove(sym.name) + myMemberCache match + case null => () + case mc => mc.remove(sym.name) if !sym.flagsUNSAFE.is(Private) then invalidateMemberNamesCache() if sym.isWrappedToplevelDef then @@ -2165,7 +2167,9 @@ object SymDenotations { */ def replace(prev: Symbol, replacement: Symbol)(using Context): Unit = { unforcedDecls.openForMutations.replace(prev, replacement) - if (myMemberCache != null) myMemberCache.uncheckedNN.remove(replacement.name) + myMemberCache match + case null => () + case mc => mc.remove(replacement.name) } /** Delete symbol from current scope. @@ -2176,7 +2180,9 @@ object SymDenotations { val scope = info.decls.openForMutations scope.unlink(sym, sym.name) if sym.name != sym.originalName then scope.unlink(sym, sym.originalName) - if (myMemberCache != null) myMemberCache.uncheckedNN.remove(sym.name) + myMemberCache match + case null => () + case mc => mc.remove(sym.name) if (!sym.flagsUNSAFE.is(Private)) invalidateMemberNamesCache() } @@ -3073,17 +3079,18 @@ object SymDenotations { : (List[ClassSymbol], BaseClassSet) = { assert(isValid) CyclicReference.trace("compute the base classes of ", clsd.symbol): - if cache != null then cache.uncheckedNN - else - if (locked) throw CyclicReference(clsd) - locked = true - provisional = false - val computed = - try clsd.computeBaseData(using this, ctx) - finally locked = false - if (!provisional) cache = computed - else onBehalf.signalProvisional() - computed + cache match + case null => + if (locked) throw CyclicReference(clsd) + locked = true + provisional = false + val computed = + try clsd.computeBaseData(using this, ctx) + finally locked = false + if (!provisional) cache = computed + else onBehalf.signalProvisional() + computed + case mc => mc } def sameGroup(p1: Phase, p2: Phase) = p1.sameParentsStartId == p2.sameParentsStartId diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index c6888c045a74..ab2c273ecaed 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -212,7 +212,7 @@ object Symbols extends SymUtils { /** The symbol's signature if it is completed or a method, NotAMethod otherwise. */ final def signature(using Context): Signature = - if lastDenot.uncheckedNN.isCompleted || lastDenot.uncheckedNN.is(Method) then + if lastDenot.isCompleted || lastDenot.is(Method) then denot.signature else Signature.NotAMethod diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index e8c05f7bc6c0..661ca9f75f01 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -108,7 +108,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling override def checkReset() = super.checkReset() - assert(pendingSubTypes == null || pendingSubTypes.uncheckedNN.isEmpty) + pendingSubTypes match + case null => () + case ps => assert(ps.isEmpty) assert(canCompareAtoms == true) assert(successCount == 0) assert(totalCount == 0) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 49ba10388705..93427ffb048e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -110,15 +110,12 @@ object TypeErasure: case tp: TypeVar if !tp.isInstantiated => -2 case _ => -1 - def normalizeClass(cls: ClassSymbol)(using Context): ClassSymbol = { - if (defn.specialErasure.contains(cls)) - return defn.specialErasure(cls).uncheckedNN - if (cls.owner == defn.ScalaPackageClass) { - if (cls == defn.UnitClass) - return defn.BoxedUnitClass - } - cls - } + def normalizeClass(cls: ClassSymbol)(using Context): ClassSymbol = + defn.specialErasure.get(cls) match + case Some(se) => se + case None => + if cls.owner == defn.ScalaPackageClass && cls == defn.UnitClass then defn.BoxedUnitClass + else cls /** A predicate that tests whether a type is a legal erased type. Only asInstanceOf and * isInstanceOf may have types that do not satisfy the predicate. diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 069cca698d31..12c2577dd7bf 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -823,29 +823,32 @@ object TypeOps: var prefixTVar: Type | Null = null def apply(tp: Type): Type = tp match { case tp: TermRef if singletons.contains(tp.symbol) => - prefixTVar = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out - prefixTVar.uncheckedNN + val v = singletons(tp.symbol) // e.g. tests/pos/i19031.ci-reg2.scala, keep out + prefixTVar = v + v case ThisType(tref) if !tref.symbol.isStaticOwner => val symbol = tref.symbol val compatibleSingleton = singletons.valuesIterator.find(_.underlying.derivesFrom(symbol)) if singletons.contains(symbol) then - prefixTVar = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this - prefixTVar.uncheckedNN + val v = singletons(symbol) // e.g. tests/pos/i16785.scala, keep Outer.this + prefixTVar = v + v else if compatibleSingleton.isDefined then - prefixTVar = compatibleSingleton.get - prefixTVar.uncheckedNN + val v = compatibleSingleton.get + prefixTVar = v + v else if symbol.is(Module) then TermRef(this(tref.prefix), symbol.sourceModule) else if (prefixTVar != null) this(tref.applyIfParameterized(tref.typeParams.map(_ => WildcardType))) - else { + else prefixTVar = WildcardType // prevent recursive call from assigning it // e.g. tests/pos/i15029.more.scala, create a TypeVar for `Instances`' B, so we can disregard `Ints` val tvars = tref.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds, DepParamName.fresh(tparam.paramName)) } val tref2 = this(tref.applyIfParameterized(tvars)) - prefixTVar = newTypeVar(TypeBounds.upper(tref2), DepParamName.fresh(tref.name)) - prefixTVar.uncheckedNN - } + val v = newTypeVar(TypeBounds.upper(tref2), DepParamName.fresh(tref.name)) + prefixTVar = v + v case tp => mapOver(tp) } } diff --git a/compiler/src/dotty/tools/dotc/core/TyperState.scala b/compiler/src/dotty/tools/dotc/core/TyperState.scala index ddc5e36520a2..312756b614da 100644 --- a/compiler/src/dotty/tools/dotc/core/TyperState.scala +++ b/compiler/src/dotty/tools/dotc/core/TyperState.scala @@ -50,7 +50,7 @@ class TyperState() { private var myId: Int = uninitialized def id: Int = myId - private var previous: TyperState | Null = uninitialized + private var previous: TyperState | Null = null private var myReporter: Reporter = uninitialized @@ -80,7 +80,9 @@ class TyperState() { this def isGlobalCommittable: Boolean = - isCommittable && (previous == null || previous.uncheckedNN.isGlobalCommittable) + isCommittable && (previous match + case null => true + case p => p.isGlobalCommittable) private var isCommitted: Boolean = uninitialized @@ -139,7 +141,10 @@ class TyperState() { * which is not yet committed, or which does not have a parent. */ def uncommittedAncestor: TyperState = - if (isCommitted && previous != null) previous.uncheckedNN.uncommittedAncestor else this + previous match + case null => this + case p if isCommitted => p.uncommittedAncestor + case _ => this /** Commit `this` typer state by copying information into the current typer state, * where "current" means contextual, so meaning `ctx.typerState`. @@ -279,7 +284,9 @@ class TyperState() { ownedVars += tvar private def isOwnedAnywhere(ts: TyperState, tvar: TypeVar): Boolean = - ts.ownedVars.contains(tvar) || ts.previous != null && isOwnedAnywhere(ts.previous.uncheckedNN, tvar) + ts.ownedVars.contains(tvar) || (ts.previous match + case null => false + case tp => isOwnedAnywhere(tp, tvar)) /** Make type variable instances permanent by assigning to `inst` field if * type variable instantiation cannot be retracted anymore. Then, remove @@ -304,9 +311,9 @@ class TyperState() { override def toString: String = { def ids(state: TyperState): List[String] = s"${state.id}${if (state.isCommittable) "" else "X"}" :: - (if (state.previous == null) Nil else ids(state.previous.uncheckedNN)) + (state.previous match { case null => Nil; case sp => ids(sp) }) s"TS[${ids(this).mkString(", ")}]" } - def stateChainStr: String = s"$this${if (previous == null) "" else previous.uncheckedNN.stateChainStr}" + def stateChainStr: String = s"$this${previous match { case null => ""; case p => p.stateChainStr }}" } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 56f3e2599f10..dec3d8b63c17 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2430,7 +2430,9 @@ object Types extends TypeUtils { * current run. */ def denotationIsCurrent(using Context): Boolean = - lastDenotation != null && lastDenotation.uncheckedNN.validFor.runId == ctx.runId + lastDenotation match + case null => false + case ld => ld.validFor.runId == ctx.runId /** If the reference is symbolic or the denotation is current, its symbol, otherwise NoDenotation. * @@ -5064,11 +5066,13 @@ object Types extends TypeUtils { private[core] def permanentInst = inst private[core] def setPermanentInst(tp: Type): Unit = inst = tp - if tp.exists && owningState != null then - val owningState1 = owningState.uncheckedNN.get - if owningState1 != null then - owningState1.ownedVars -= this - owningState = null // no longer needed; null out to avoid a memory leak + owningState match + case os: WeakReference[TyperState] if tp.exists => + val owningState1 = os.get + if owningState1 != null then + owningState1.ownedVars -= this + owningState = null // no longer needed; null out to avoid a memory leak + case _ => () private[core] def resetInst(ts: TyperState): Unit = assert(inst.exists) @@ -5125,7 +5129,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 @@ -6116,7 +6120,7 @@ object Types extends TypeUtils { val args1 = args.zipWithConserve(tparams): case (arg @ TypeBounds(lo, hi), tparam) => val v = vmap.computedVariance(tparam) - if v.uncheckedNN < 0 then lo + if v != null && v < 0 then lo else hi case (arg, _) => arg tp.derivedAppliedType(tycon, args1) diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala index 69b77fdc8ec3..e1994c40401e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -23,25 +23,34 @@ class StoreReporter(outer: Reporter | Null = Reporter.NoReporter, fromTyperState override def doReport(dia: Diagnostic)(using Context): Unit = { typr.println(s">>>> StoredError: ${dia.message}") // !!! DEBUG - if (infos == null) infos = new mutable.ListBuffer - infos.uncheckedNN += dia + val infos1 = initialize(infos, infos = _, new mutable.ListBuffer) + infos1 += dia } override def hasUnreportedErrors: Boolean = - outer != null && infos != null && infos.uncheckedNN.exists(_.isInstanceOf[Error]) + outer != null && (infos match + case null => false + case is => is.exists(_.isInstanceOf[Error])) override def hasStickyErrors: Boolean = - infos != null && infos.uncheckedNN.exists(_.isInstanceOf[StickyError]) + infos match + case null => false + case is => is.exists(_.isInstanceOf[StickyError]) override def removeBufferedMessages(using Context): List[Diagnostic] = - if (infos != null) try infos.uncheckedNN.toList finally infos = null - else Nil + infos match + case null => Nil + case is => try is.toList finally infos = null override def mapBufferedMessages(f: Diagnostic => Diagnostic)(using Context): Unit = - if infos != null then infos.uncheckedNN.mapInPlace(f) + infos match + case null => () + case is => is.mapInPlace(f) override def pendingMessages(using Context): List[Diagnostic] = - if (infos != null) infos.uncheckedNN.toList else Nil + infos match + case null => Nil + case is => is.toList override def errorsReported: Boolean = hasErrors || (outer != null && outer.errorsReported) diff --git a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala index 2bf164f4b2a3..dc949237141b 100644 --- a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala +++ b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala @@ -12,9 +12,8 @@ import core.Names.* import core.NameKinds.TempResultName import core.Constants.* import util.Store -import dotty.tools.uncheckedNN +import dotty.tools.initialize import ast.tpd.* -import compiletime.uninitialized /** This phase translates variables that are captured in closures to * heap-allocated refs. @@ -47,10 +46,8 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer: } private var myRefInfo: RefInfo | Null = null - private def refInfo(using Context): RefInfo = { - if (myRefInfo == null) myRefInfo = new RefInfo() - myRefInfo.uncheckedNN - } + private def refInfo(using Context): RefInfo = + initialize(myRefInfo, myRefInfo = _, new RefInfo()) override def prepareForUnit(tree: Tree)(using Context): Context = captured.clear() diff --git a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala index f7302d65ec58..c1034bb707f6 100644 --- a/compiler/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/compiler/src/dotty/tools/dotc/transform/LazyVals.scala @@ -49,7 +49,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer { val containerFlagsMask: FlagSet = Method | Lazy | Accessor | Module /** A map of lazy values to the fields they should null after initialization. */ - private var lazyValNullables: IdentityHashMap[Symbol, mutable.ListBuffer[Symbol]] | Null = uninitialized + private var lazyValNullables: IdentityHashMap[Symbol, mutable.ListBuffer[Symbol]] | Null = null private def nullableFor(sym: Symbol)(using Context) = { // optimisation: value only used once, we can remove the value from the map val nullables = lazyValNullables.nn.remove(sym) diff --git a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala index 16c50b9cd474..4a6ade34c5c9 100644 --- a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -137,13 +137,14 @@ object OverridingPairs: */ private def nextOverriding(): Unit = { @tailrec def loop(): Unit = - if (curEntry != null) { - overriding = curEntry.uncheckedNN.sym - if (visited.contains(overriding)) { - curEntry = curEntry.uncheckedNN.prev - loop() - } - } + curEntry match + case null => () + case ce => + overriding = ce.sym + if visited.contains(overriding) then + curEntry = ce.prev + loop() + loop() nextEntry = curEntry } @@ -154,22 +155,26 @@ object OverridingPairs: * overridden = overridden member of the pair, provided hasNext is true */ @tailrec final def next(): Unit = - if nextEntry != null then - nextEntry = decls.lookupNextEntry(nextEntry.uncheckedNN) - if nextEntry != null then - try - overridden = nextEntry.uncheckedNN.sym - if overriding.owner != overridden.owner && matches(overriding, overridden) then - visited += overridden - if !isHandledByParent(overriding, overridden) then return - catch case ex: TypeError => - // See neg/i1750a for an example where a cyclic error can arise. - // The root cause in this example is an illegal "override" of an inner trait - report.error(ex, base.srcPos) - else - curEntry = curEntry.nn.prev - nextOverriding() - next() + nextEntry match + case null => () + case ne => + decls.lookupNextEntry(ne) match + case null => + nextEntry = null + curEntry = curEntry.nn.prev + nextOverriding() + case ne => + nextEntry = ne + try + overridden = ne.sym + if overriding.owner != overridden.owner && matches(overriding, overridden) then + visited += overridden + if !isHandledByParent(overriding, overridden) then return + catch case ex: TypeError => + // See neg/i1750a for an example where a cyclic error can arise. + // The root cause in this example is an illegal "override" of an inner trait + report.error(ex, base.srcPos) + next() nextOverriding() next() diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index d8750dc2e21d..6381848b2dfd 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -11,9 +11,7 @@ import StdNames.nme import reporting.* import transform.MegaPhase.MiniPhase import util.LinearSet -import dotty.tools.uncheckedNN - -import scala.compiletime.uninitialized +import dotty.tools.initialize /** A Tail Rec Transformer. * @@ -236,12 +234,9 @@ class TailRec extends MiniPhase { var failureReported: Boolean = false /** The `tailLabelN` label symbol, used to encode a `continue` from the infinite `while` loop. */ - private var myContinueLabel: Symbol | Null = uninitialized - def continueLabel(using Context): Symbol = { - if (myContinueLabel == null) - myContinueLabel = newSymbol(method, TailLabelName.fresh(), Label, defn.UnitType) - myContinueLabel.uncheckedNN - } + private var myContinueLabel: Symbol | Null = null + def continueLabel(using Context): Symbol = + initialize(myContinueLabel, myContinueLabel = _, newSymbol(method, TailLabelName.fresh(), Label, defn.UnitType)) /** The local `var` that replaces `this`, if it is modified in at least one recursive call. */ var varForRewrittenThis: Option[Symbol] = None diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index a03a2f5cf4c6..e40cfba6e07e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1156,8 +1156,9 @@ trait Applications extends Compatibility { override def liftFun(): Unit = if (liftedDefs == null) { - liftedDefs = new mutable.ListBuffer[Tree] - myNormalizedFun = lifter.liftApp(liftedDefs.uncheckedNN, myNormalizedFun) + val lds = new mutable.ListBuffer[Tree] + liftedDefs = lds + myNormalizedFun = lifter.liftApp(lds, myNormalizedFun) } /** The index of the first difference between lists of trees `xs` and `ys` diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 509b5a43d227..a70699da4a62 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -113,9 +113,9 @@ object Implicits: /** Widen type so that it is neither a singleton type nor a type that inherits from scala.Singleton. */ private def widenSingleton(tp: Type)(using Context): Type = { - if (mySingletonClass == null) mySingletonClass = defn.SingletonClass + val sc = initialize(mySingletonClass, mySingletonClass = _, defn.SingletonClass) val wtp = tp.widenSingleton - if (wtp.derivesFrom(mySingletonClass.uncheckedNN)) defn.AnyType else wtp + if (wtp.derivesFrom(sc)) defn.AnyType else wtp } protected def isAccessible(ref: TermRef)(using Context): Boolean @@ -315,15 +315,13 @@ object Implicits: * Scala2 mode, since we do not want to change the implicit disambiguation then. */ override val level: Int = - def isSameOwner = irefCtx.owner eq outerImplicits.uncheckedNN.irefCtx.owner - def isSameScope = irefCtx.scope eq outerImplicits.uncheckedNN.irefCtx.scope def isLazyImplicit = refs.head.implicitName.is(LazyImplicitName) - if outerImplicits == null then 1 - else if migrateTo3(using irefCtx) - || isSameOwner && (isImport || isSameScope && !isLazyImplicit) - then outerImplicits.uncheckedNN.level - else outerImplicits.uncheckedNN.level + 1 + outerImplicits match + case null => 1 + case oi if migrateTo3(using irefCtx) + || (irefCtx.owner eq oi.irefCtx.owner) && (isImport || (irefCtx.scope eq oi.irefCtx.scope) && !isLazyImplicit) => oi.level + case oi => oi.level + 1 end level /** Is this the outermost implicits? This is the case if it either the implicits @@ -951,8 +949,8 @@ trait Implicits: case fail @ SearchFailure(failed) => if fail.isAmbiguous then failed else - if synthesizer == null then synthesizer = Synthesizer(this) - val (tree, errors) = synthesizer.uncheckedNN.tryAll(formal, span) + val synth = initialize(synthesizer, synthesizer = _, Synthesizer(this)) + val (tree, errors) = synth.tryAll(formal, span) if errors.nonEmpty then SearchFailure(new SynthesisFailure(errors, formal), span).tree else @@ -2021,9 +2019,7 @@ final class SearchRoot extends SearchHistory: /** The dictionary of recursive implicit types and corresponding terms for this search. */ var myImplicitDictionary: mutable.Map[Type, (TermRef, tpd.Tree)] | Null = null private def implicitDictionary = - if myImplicitDictionary == null then - myImplicitDictionary = mutable.Map.empty[Type, (TermRef, tpd.Tree)] - myImplicitDictionary.uncheckedNN + initialize(myImplicitDictionary, myImplicitDictionary = _, mutable.Map.empty[Type, (TermRef, tpd.Tree)]) /** * Link a reference to an under-construction implicit for the provided type to its @@ -2209,12 +2205,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/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 0054b53e4b13..f48678f8237d 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -58,14 +58,9 @@ class ImportInfo(symf: Context ?=> Symbol, case _ => None } - def importSym(using Context): Symbol = { - if (mySym == null) { - mySym = symf - assert(mySym != null) - } - mySym.uncheckedNN - } - private var mySym: Symbol | Null = uninitialized + private var mySym: Symbol | Null = null + def importSym(using Context): Symbol = + initialize(mySym, mySym = _, symf) /** The (TermRef) type of the qualifier of the import clause */ def site(using Context): Type = importSym.info match { @@ -99,8 +94,8 @@ class ImportInfo(symf: Context ?=> Symbol, /** Compute info relating to the selector list */ private def ensureInitialized(): Unit = if myExcluded == null then myExcluded = Set() - myForwardMapping = SimpleIdentityMap.empty - myReverseMapping = SimpleIdentityMap.empty + var forwardMapping: SimpleIdentityMap[TermName, TermName] = SimpleIdentityMap.empty + var reverseMapping: SimpleIdentityMap[TermName, TermName] = SimpleIdentityMap.empty for sel <- selectors do if sel.isWildcard then myWildcardImport = true @@ -109,8 +104,10 @@ class ImportInfo(symf: Context ?=> Symbol, if sel.rename != sel.name then myExcluded = myExcluded.nn + sel.name if !sel.isUnimport then - myForwardMapping = myForwardMapping.uncheckedNN.updated(sel.name, sel.rename) - myReverseMapping = myReverseMapping.uncheckedNN.updated(sel.rename, sel.name) + forwardMapping = forwardMapping.updated(sel.name, sel.rename) + reverseMapping = reverseMapping.updated(sel.rename, sel.name) + myForwardMapping = forwardMapping + myReverseMapping = reverseMapping /** The upper bound for `given` wildcards, or `Nothing` if there are none */ def givenBound(using Context) = @@ -166,20 +163,18 @@ class ImportInfo(symf: Context ?=> Symbol, * override import java.lang.{} // disables all imports */ def unimported(using Context): Symbol = - if myUnimported == null then + initialize(myUnimported, myUnimported = _, { lazy val sym = site.termSymbol def maybeShadowsRoot = symNameOpt match case Some(symName) => defn.ShadowableImportNames.contains(symName) case None => false - myUnimported = - if maybeShadowsRoot && defn.rootImportTypes.exists(_.symbol == sym) then sym - else NoSymbol - assert(myUnimported != null) - myUnimported.uncheckedNN + if maybeShadowsRoot && defn.rootImportTypes.exists(_.symbol == sym) then sym + else NoSymbol + }) private val isLanguageImport: Boolean = untpd.languageImport(qualifier).isDefined - private var myUnimported: Symbol | Null = uninitialized + private var myUnimported: Symbol | Null = null private var featureCache: SimpleIdentityMap[TermName, java.lang.Boolean] = SimpleIdentityMap.empty diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 562465d5c651..cfc5de9b176f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -600,7 +600,7 @@ class Namer { typer: Typer => if (tree == modCls) { val fromTempl = fromCls.rhs.asInstanceOf[Template] val modTempl = modCls.rhs.asInstanceOf[Template] - res = cpy.TypeDef(modCls)( + val r = cpy.TypeDef(modCls)( rhs = cpy.Template(modTempl)( derived = if (fromTempl.derived.nonEmpty) fromTempl.derived else modTempl.derived, body = fromTempl.body.filter { @@ -611,10 +611,10 @@ class Namer { typer: Typer => if (fromTempl.derived.nonEmpty) { if (modTempl.derived.nonEmpty) report.error(em"a class and its companion cannot both have `derives` clauses", mdef.srcPos) - // `res` is inside a closure, so the flow-typing doesn't work here. - res.uncheckedNN.putAttachment(desugar.DerivingCompanion, fromTempl.srcPos.startPos) + r.putAttachment(desugar.DerivingCompanion, fromTempl.srcPos.startPos) } - res.uncheckedNN + res = r + r } else tree } @@ -936,8 +936,9 @@ class Namer { typer: Typer => completedTypeParamSyms = tparams override def completerTypeParams(sym: Symbol)(using Context): List[TypeSymbol] = - if completedTypeParamSyms != null then completedTypeParamSyms.uncheckedNN - else Nil + completedTypeParamSyms match + case null => Nil + case cpts => cpts protected def addAnnotations(sym: Symbol): Unit = original match { case original: untpd.MemberDef => @@ -1099,10 +1100,11 @@ class Namer { typer: Typer => } override def completerTypeParams(sym: Symbol)(using Context): List[TypeSymbol] = - if myTypeParams == null then + initialize(myTypeParams, myTypeParams = _, { //println(i"completing type params of $sym in ${sym.owner}") - nestedCtx = localContext(sym).setNewScope - given Context = nestedCtx.uncheckedNN + val newScope = localContext(sym).setNewScope + nestedCtx = newScope + given Context = newScope def typeParamTrees(tdef: Tree): List[TypeDef] = tdef match case TypeDef(_, original) => @@ -1114,10 +1116,11 @@ class Namer { typer: Typer => val tparams = typeParamTrees(original) index(tparams) - myTypeParams = tparams.map(symbolOfTree(_).asType) + val res = tparams.map(symbolOfTree(_).asType) + myTypeParams = res for param <- tparams do typedAheadExpr(param) - end if - myTypeParams.uncheckedNN + res + }) end completerTypeParams override final def typeSig(sym: Symbol): Type = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index d88c2a2f837c..4f355cbd87e2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -311,14 +311,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer * @param using_Context the outer context of `precCtx` */ def checkImportAlternatives(previous: Type, prevPrec: BindingPrec, prevCtx: Context)(using Context): Type = - - def addAltImport(altImp: TermRef) = - if !TypeComparer.isSameRef(previous, altImp) - && !altImports.uncheckedNN.exists(TypeComparer.isSameRef(_, altImp)) - then - altImports.uncheckedNN += altImp - if altImports != null && ctx.isImportContext then + def addAltImport(altImp: TermRef) = + if !TypeComparer.isSameRef(previous, altImp) + && !altImports.exists(TypeComparer.isSameRef(_, altImp)) + then + altImports += altImp + val curImport = ctx.importInfo.uncheckedNN namedImportRef(curImport) match case altImp: TermRef => @@ -558,12 +557,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer if (curImport.nn.unimported ne NoSymbol) unimported += curImport.nn.unimported if (curOwner.is(Package) && curImport != null && curImport.isRootImport && previous.exists) previous // no more conflicts possible in this case - else if (isPossibleImport(NamedImport) && (curImport ne outer.importInfo)) { - val namedImp = namedImportRef(curImport.uncheckedNN) + else if (isPossibleImport(NamedImport) && curImport != null && (curImport ne outer.importInfo)) { + val namedImp = namedImportRef(curImport) if (namedImp.exists) checkImportAlternatives(namedImp, NamedImport, ctx)(using outer) - else if (isPossibleImport(WildImport) && !curImport.nn.importSym.isCompleting) { - val wildImp = wildImportRef(curImport.uncheckedNN) + else if (isPossibleImport(WildImport) && !curImport.importSym.isCompleting) { + val wildImp = wildImportRef(curImport) if (wildImp.exists) checkImportAlternatives(wildImp, WildImport, ctx)(using outer) else { diff --git a/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala b/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala index ca23bdb51b1d..5ab69a85bc1a 100644 --- a/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala +++ b/compiler/src/dotty/tools/dotc/util/GenericHashSet.scala @@ -1,7 +1,5 @@ package dotty.tools.dotc.util -import dotty.tools.uncheckedNN - import scala.compiletime.uninitialized object GenericHashSet: @@ -176,7 +174,11 @@ abstract class GenericHashSet[T](initialCapacity: Int = 8, capacityMultiple: Int idx < table.length def next() = require(hasNext) - try entry(idx).uncheckedNN finally idx += 1 + entry(idx) match + case null => throw new NoSuchElementException() + case e => + idx += 1 + e def iterator: Iterator[T] = new EntryIterator(): def entry(idx: Int) = entryAt(idx) diff --git a/compiler/src/dotty/tools/package.scala b/compiler/src/dotty/tools/package.scala index 475befce3807..fee51df7c8a5 100644 --- a/compiler/src/dotty/tools/package.scala +++ b/compiler/src/dotty/tools/package.scala @@ -22,6 +22,18 @@ package object tools { transparent inline def uncheckedNN: T = x.asInstanceOf[T] end extension + /** + * Allows one to lazily initialize values without explicit `.nn`. + * This is useful for values that need a Context and thus can't be `lazy val`s. + */ + inline def initialize[T](getter: T | Null, inline setter: T => Unit, inline value: => T): T = + if getter != null then + getter + else + val res = value + setter(res) + res + /** * Infrastructure to shorten method calls by not requiring a lambda. * Instead of `def f(x: ... => ...)` that must be called as, e.g., `f(x => x + 1)`,