diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 95875bfedcc1..51067cea38f3 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -841,6 +841,9 @@ object Contexts { def uniquesSizes: Map[String, (Int, Int, Int)] = uniqueSets.transform((_, s) => (s.size, s.accesses, s.misses)) + var emptyTypeBounds: TypeBounds = null + var emptyWildcardBounds: WildcardType = null + /** Number of findMember calls on stack */ private[core] var findMemberCount: Int = 0 @@ -894,6 +897,8 @@ object Contexts { def reset(): Unit = { for ((_, set) <- uniqueSets) set.clear() + emptyTypeBounds = null + emptyWildcardBounds = null errorTypeMsg.clear() sources.clear() sourceNamed.clear() diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index 0306b16537dc..af55456df539 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -229,23 +229,32 @@ class OrderingConstraint(private val boundsMap: ParamBounds, * and to handle them separately is for efficiency, so that type expressions * used as bounds become smaller. * + * TODO: try to do without stripping? It would mean it is more efficient + * to pull out full bounds from a constraint. + * * @param isUpper If true, `bound` is an upper bound, else a lower bound. */ - private def stripParams(tp: Type, paramBuf: mutable.ListBuffer[TypeParamRef], + private def stripParams( + tp: Type, + todos: mutable.ListBuffer[(OrderingConstraint, TypeParamRef) => OrderingConstraint], isUpper: Boolean)(using Context): Type = tp match { case param: TypeParamRef if contains(param) => - if (!paramBuf.contains(param)) paramBuf += param + todos += (if isUpper then order(_, _, param) else order(_, param, _)) NoType + case tp: TypeBounds => + val lo1 = stripParams(tp.lo, todos, !isUpper).orElse(defn.NothingType) + val hi1 = stripParams(tp.hi, todos, isUpper).orElse(defn.AnyKindType) + tp.derivedTypeBounds(lo1, hi1) case tp: AndType if isUpper => - val tp1 = stripParams(tp.tp1, paramBuf, isUpper) - val tp2 = stripParams(tp.tp2, paramBuf, isUpper) + val tp1 = stripParams(tp.tp1, todos, isUpper) + val tp2 = stripParams(tp.tp2, todos, isUpper) if (tp1.exists) if (tp2.exists) tp.derivedAndType(tp1, tp2) else tp1 else tp2 case tp: OrType if !isUpper => - val tp1 = stripParams(tp.tp1, paramBuf, isUpper) - val tp2 = stripParams(tp.tp2, paramBuf, isUpper) + val tp1 = stripParams(tp.tp1, todos, isUpper) + val tp2 = stripParams(tp.tp2, todos, isUpper) if (tp1.exists) if (tp2.exists) tp.derivedOrType(tp1, tp2) else tp1 @@ -254,17 +263,6 @@ class OrderingConstraint(private val boundsMap: ParamBounds, tp } - /** The bound type `tp` without clearly dependent parameters. - * A top or bottom type if type consists only of dependent parameters. - * TODO: try to do without normalization? It would mean it is more efficient - * to pull out full bounds from a constraint. - * @param isUpper If true, `bound` is an upper bound, else a lower bound. - */ - private def normalizedType(tp: Type, paramBuf: mutable.ListBuffer[TypeParamRef], - isUpper: Boolean)(using Context): Type = - stripParams(tp, paramBuf, isUpper) - .orElse(if (isUpper) defn.AnyKindType else defn.NothingType) - def add(poly: TypeLambda, tvars: List[TypeVar])(using Context): This = { assert(!contains(poly)) val nparams = poly.paramNames.length @@ -280,18 +278,15 @@ class OrderingConstraint(private val boundsMap: ParamBounds, */ private def init(poly: TypeLambda)(using Context): This = { var current = this - val loBuf, hiBuf = new mutable.ListBuffer[TypeParamRef] + val todos = new mutable.ListBuffer[(OrderingConstraint, TypeParamRef) => OrderingConstraint] var i = 0 while (i < poly.paramNames.length) { val param = poly.paramRefs(i) - val bounds = nonParamBounds(param) - val lo = normalizedType(bounds.lo, loBuf, isUpper = false) - val hi = normalizedType(bounds.hi, hiBuf, isUpper = true) - current = updateEntry(current, param, bounds.derivedTypeBounds(lo, hi)) - current = loBuf.foldLeft(current)(order(_, _, param)) - current = hiBuf.foldLeft(current)(order(_, param, _)) - loBuf.clear() - hiBuf.clear() + val stripped = stripParams(nonParamBounds(param), todos, isUpper = true) + current = updateEntry(current, param, stripped) + while todos.nonEmpty do + current = todos.head(current, param) + todos.dropInPlace(1) i += 1 } current.checkNonCyclic() diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 53c6638387d6..91dc9281c29a 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -263,13 +263,15 @@ object Types { /** Is this type exactly Nothing (no vars, aliases, refinements etc allowed)? */ def isBottomType(using Context): Boolean = this match { - case tp: TypeRef => tp.symbol eq defn.NothingClass + case tp: TypeRef => + tp.name == tpnme.Nothing && (tp.symbol eq defn.NothingClass) case _ => false } /** Is this type exactly Any (no vars, aliases, refinements etc allowed)? */ def isTopType(using Context): Boolean = this match { - case tp: TypeRef => tp.symbol eq defn.AnyClass + case tp: TypeRef => + tp.name == tpnme.Any && (tp.symbol eq defn.AnyClass) case _ => false } @@ -4647,7 +4649,13 @@ object Types { object TypeBounds { def apply(lo: Type, hi: Type)(using Context): TypeBounds = unique(new RealTypeBounds(lo, hi)) - def empty(using Context): TypeBounds = apply(defn.NothingType, defn.AnyType) + def empty(using Context): TypeBounds = + val result = ctx.base.emptyTypeBounds + if result == null then + ctx.base.emptyTypeBounds = apply(defn.NothingType, defn.AnyType) + empty + else + result def emptyPolyKind(using Context): TypeBounds = apply(defn.NothingType, defn.AnyKindType) def upper(hi: Type)(using Context): TypeBounds = apply(defn.NothingType, hi) def lower(lo: Type)(using Context): TypeBounds = apply(lo, defn.AnyType) @@ -4790,7 +4798,15 @@ object Types { final class CachedWildcardType(optBounds: Type) extends WildcardType(optBounds) @sharable object WildcardType extends WildcardType(NoType) { - def apply(bounds: TypeBounds)(using Context): WildcardType = unique(new CachedWildcardType(bounds)) + def apply(bounds: TypeBounds)(using Context): WildcardType = + if bounds eq TypeBounds.empty then + val result = ctx.base.emptyWildcardBounds + if result == null then + ctx.base.emptyWildcardBounds = unique(CachedWildcardType(bounds)) + apply(bounds) + else + result + else unique(CachedWildcardType(bounds)) } /** An extractor for single abstract method types. diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 78fe1bd1b297..fe466c5b2836 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -21,6 +21,7 @@ import NameKinds._ import NamerOps._ import ContextOps._ import Variances.Invariant +import TastyUnpickler.NameTable import typer.ConstFold import typer.Checking.checkNonCyclic import util.Spans._ @@ -51,7 +52,7 @@ import scala.annotation.internal.sharable * @param commentUnpicklerOpt the unpickler for comments, if it exists */ class TreeUnpickler(reader: TastyReader, - nameAtRef: NameRef => TermName, + nameAtRef: NameTable, posUnpicklerOpt: Option[PositionUnpickler], commentUnpicklerOpt: Option[CommentUnpickler]) { import TreeUnpickler._ @@ -557,7 +558,7 @@ class TreeUnpickler(reader: TastyReader, val rhsStart = currentAddr val rhsIsEmpty = nothingButMods(end) if (!rhsIsEmpty) skipTree() - val (givenFlags, annotFns, privateWithin) = readModifiers(end, readTypedAnnot, readTypedWithin, NoSymbol) + val (givenFlags, annotFns, privateWithin) = readModifiers(end) pickling.println(i"creating symbol $name at $start with flags $givenFlags") val flags = normalizeFlags(tag, givenFlags, name, isAbsType, rhsIsEmpty) def adjustIfModule(completer: LazyType) = @@ -608,12 +609,10 @@ class TreeUnpickler(reader: TastyReader, /** Read modifier list into triplet of flags, annotations and a privateWithin * boundary symbol. */ - def readModifiers[WithinType, AnnotType] - (end: Addr, readAnnot: Context ?=> Symbol => AnnotType, readWithin: Context ?=> WithinType, defaultWithin: WithinType) - (using Context): (FlagSet, List[Symbol => AnnotType], WithinType) = { + def readModifiers(end: Addr)(using Context): (FlagSet, List[Symbol => Annotation], Symbol) = { var flags: FlagSet = EmptyFlags - var annotFns: List[Symbol => AnnotType] = Nil - var privateWithin = defaultWithin + var annotFns: List[Symbol => Annotation] = Nil + var privateWithin: Symbol = NoSymbol while (currentAddr.index != end.index) { def addFlag(flag: FlagSet) = { flags |= flag @@ -676,9 +675,9 @@ class TreeUnpickler(reader: TastyReader, (flags, annotFns.reverse, privateWithin) } - private val readTypedWithin: Context ?=> Symbol = readType().typeSymbol + private def readWithin(using Context): Symbol = readType().typeSymbol - private val readTypedAnnot: Context ?=> Symbol => Annotation = + private def readAnnot(using Context): Symbol => Annotation = readByte() val end = readEnd() val tp = readType() diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index b517e6d17481..437963af9161 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -202,7 +202,8 @@ abstract class Reporter extends interfaces.ReporterResult { /** Issue all error messages in this reporter to next outer one, or make sure they are written. */ def flush()(using Context): Unit = - removeBufferedMessages.foreach(ctx.reporter.report) + val msgs = removeBufferedMessages + if msgs.nonEmpty then msgs.foreach(ctx.reporter.report) /** If this reporter buffers messages, all buffered messages, otherwise Nil */ def pendingMessages(using Context): List[Diagnostic] = Nil