Skip to content

Commit 96d7e16

Browse files
authored
Merge pull request scala#5864 from retronym/faster/subst
Optimize symbol substitution
2 parents e5be62d + 2b59f58 commit 96d7e16

File tree

2 files changed

+50
-18
lines changed

2 files changed

+50
-18
lines changed

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ trait Types
147147
override def termSymbol = underlying.termSymbol
148148
override def termSymbolDirect = underlying.termSymbolDirect
149149
override def typeParams = underlying.typeParams
150+
@deprecated("No longer used in the compiler implementation", since = "2.12.3")
150151
override def boundSyms = underlying.boundSyms
151152
override def typeSymbol = underlying.typeSymbol
152153
override def typeSymbolDirect = underlying.typeSymbolDirect
@@ -468,8 +469,9 @@ trait Types
468469
* the empty list for all other types */
469470
def typeParams: List[Symbol] = List()
470471

471-
/** For a (potentially wrapped) poly or existential type, its bound symbols,
472-
* the empty list for all other types */
472+
/** For a (potentially wrapped) poly, method or existential type, its directly bound symbols,
473+
* the empty set for all other types */
474+
@deprecated("No longer used in the compiler implementation", since = "2.12.3")
473475
def boundSyms: immutable.Set[Symbol] = emptySymbolSet
474476

475477
/** Replace formal type parameter symbols with actual type arguments. ErrorType on arity mismatch.
@@ -1085,7 +1087,7 @@ trait Types
10851087
override def baseTypeSeq: BaseTypeSeq = supertype.baseTypeSeq
10861088
override def baseTypeSeqDepth: Depth = supertype.baseTypeSeqDepth
10871089
override def baseClasses: List[Symbol] = supertype.baseClasses
1088-
}
1090+
}
10891091

10901092
/** A base class for types that represent a single value
10911093
* (single-types and this-types).
@@ -1106,13 +1108,8 @@ trait Types
11061108
if (pre.isOmittablePrefix) pre.fullName + ".type"
11071109
else prefixString + "type"
11081110
}
1109-
/*
1110-
override def typeOfThis: Type = typeSymbol.typeOfThis
1111-
override def bounds: TypeBounds = TypeBounds(this, this)
1112-
override def prefix: Type = NoType
1113-
override def typeArgs: List[Type] = List()
1114-
override def typeParams: List[Symbol] = List()
1115-
*/
1111+
@deprecated("No longer used in the compiler implementation", since = "2.12.3")
1112+
override def boundSyms: Set[Symbol] = emptySymbolSet
11161113
}
11171114

11181115
/** An object representing an erroneous type */
@@ -2505,6 +2502,7 @@ trait Types
25052502

25062503
override def paramTypes = mapList(params)(symTpe) // OPT use mapList rather than .map
25072504

2505+
@deprecated("No longer used in the compiler implementation", since = "2.12.3")
25082506
override def boundSyms = resultType.boundSyms ++ params
25092507

25102508
override def resultType(actuals: List[Type]) =
@@ -2562,6 +2560,7 @@ trait Types
25622560
override def baseTypeSeqDepth: Depth = resultType.baseTypeSeqDepth
25632561
override def baseClasses: List[Symbol] = resultType.baseClasses
25642562
override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
2563+
@deprecated("No longer used in the compiler implementation", since = "2.12.3")
25652564
override def boundSyms = resultType.boundSyms
25662565
override def safeToString: String = "=> "+ resultType
25672566
override def kind = "NullaryMethodType"
@@ -2594,6 +2593,7 @@ trait Types
25942593
override def decls: Scope = resultType.decls
25952594
override def termSymbol: Symbol = resultType.termSymbol
25962595
override def typeSymbol: Symbol = resultType.typeSymbol
2596+
@deprecated("No longer used in the compiler implementation", since = "2.12.3")
25972597
override def boundSyms = immutable.Set[Symbol](typeParams ++ resultType.boundSyms: _*)
25982598
override def prefix: Type = resultType.prefix
25992599
override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq
@@ -2650,6 +2650,7 @@ trait Types
26502650
override def isTrivial = false
26512651
override def bounds = TypeBounds(maybeRewrap(underlying.bounds.lo), maybeRewrap(underlying.bounds.hi))
26522652
override def parents = underlying.parents map maybeRewrap
2653+
@deprecated("No longer used in the compiler implementation", since = "2.12.3")
26532654
override def boundSyms = quantified.toSet
26542655
override def prefix = maybeRewrap(underlying.prefix)
26552656
override def typeArgs = underlying.typeArgs map maybeRewrap

src/reflect/scala/reflect/internal/tpe/TypeMaps.scala

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -698,18 +698,32 @@ private[internal] trait TypeMaps {
698698
// OPT this check was 2-3% of some profiles, demoted to -Xdev
699699
if (isDeveloper) assert(sameLength(from, to), "Unsound substitution from "+ from +" to "+ to)
700700

701+
private[this] var fromHasTermSymbol = false
702+
private[this] var fromMin = Int.MaxValue
703+
private[this] var fromMax = Int.MinValue
704+
private[this] var fromSize = 0
705+
from.foreach {
706+
sym =>
707+
fromMin = math.min(fromMin, sym.id)
708+
fromMax = math.max(fromMax, sym.id)
709+
fromSize += 1
710+
if (sym.isTerm) fromHasTermSymbol = true
711+
}
712+
701713
/** Are `sym` and `sym1` the same? Can be tuned by subclasses. */
702714
protected def matches(sym: Symbol, sym1: Symbol): Boolean = sym eq sym1
703715

704716
/** Map target to type, can be tuned by subclasses */
705717
protected def toType(fromtp: Type, tp: T): Type
706718

719+
// We don't need to recurse into the `restpe` below because we will encounter
720+
// them in the next level of recursion, when the result of this method is passed to `mapOver`.
707721
protected def renameBoundSyms(tp: Type): Type = tp match {
708-
case MethodType(ps, restp) =>
709-
createFromClonedSymbols(ps, restp)((ps1, tp1) => copyMethodType(tp, ps1, renameBoundSyms(tp1)))
710-
case PolyType(bs, restp) =>
711-
createFromClonedSymbols(bs, restp)((ps1, tp1) => PolyType(ps1, renameBoundSyms(tp1)))
712-
case ExistentialType(bs, restp) =>
722+
case MethodType(ps, restp) if fromHasTermSymbol && fromContains(ps) =>
723+
createFromClonedSymbols(ps, restp)((ps1, tp1) => copyMethodType(tp, ps1, tp1))
724+
case PolyType(bs, restp) if fromContains(bs) =>
725+
createFromClonedSymbols(bs, restp)((ps1, tp1) => PolyType(ps1, tp1))
726+
case ExistentialType(bs, restp) if fromContains(bs) =>
713727
createFromClonedSymbols(bs, restp)(newExistentialType)
714728
case _ =>
715729
tp
@@ -722,10 +736,27 @@ private[internal] trait TypeMaps {
722736
else subst(tp, sym, from.tail, to.tail)
723737
)
724738

739+
private def fromContains(syms: List[Symbol]): Boolean = {
740+
def fromContains(sym: Symbol): Boolean = {
741+
// OPT Try cheap checks based on the range of symbol ids in from first.
742+
// Equivalent to `from.contains(sym)`
743+
val symId = sym.id
744+
val fromMightContainSym = symId >= fromMin && symId <= fromMax
745+
fromMightContainSym && (
746+
symId == fromMin || symId == fromMax || (fromSize > 2 && from.contains(sym))
747+
)
748+
}
749+
var syms1 = syms
750+
while (syms1 ne Nil) {
751+
val sym = syms1.head
752+
if (fromContains(sym)) return true
753+
syms1 = syms1.tail
754+
}
755+
false
756+
}
757+
725758
def apply(tp0: Type): Type = if (from.isEmpty) tp0 else {
726-
val boundSyms = tp0.boundSyms
727-
val tp1 = if (boundSyms.nonEmpty && (boundSyms exists from.contains)) renameBoundSyms(tp0) else tp0
728-
val tp = mapOver(tp1)
759+
val tp = mapOver(renameBoundSyms(tp0))
729760
def substFor(sym: Symbol) = subst(tp, sym, from, to)
730761

731762
tp match {

0 commit comments

Comments
 (0)