Skip to content

Commit cf9b7ae

Browse files
oderskygkossakowski
authored andcommitted
Compilespeed improvements: Exists arguments and others
It turns out that exists is not inlinable, even if put into List. We try to eliminate or hoist most closures passed to exists in Types. There are some other small improvements as well. -- (@gkossakowski): This commit contains also a fix to crasher prepared by @paulp. I squashed that commit and kept the test-case that came with it.
1 parent c32b189 commit cf9b7ae

File tree

6 files changed

+111
-38
lines changed

6 files changed

+111
-38
lines changed

src/compiler/scala/tools/nsc/typechecker/Infer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ trait Infer {
240240
def normalize(tp: Type): Type = tp match {
241241
case mt @ MethodType(params, restpe) if mt.isImplicit =>
242242
normalize(restpe)
243-
case mt @ MethodType(params, restpe) if !restpe.isDependent =>
243+
case mt @ MethodType(params, restpe) if !mt.isDependentMethodType =>
244244
functionType(params map (_.tpe), normalize(restpe))
245245
case NullaryMethodType(restpe) =>
246246
normalize(restpe)

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
124124

125125
defaultMethodNames.toList.distinct foreach { name =>
126126
val methods = clazz.info.findMember(name, 0L, METHOD, false).alternatives
127-
val haveDefaults = methods filter (sym => sym.hasParamWhich(_.hasDefault) && !nme.isProtectedAccessorName(sym.name))
127+
def hasDefaultParam(tpe: Type): Boolean = tpe match {
128+
case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe)
129+
case _ => false
130+
}
131+
val haveDefaults = methods filter (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name))
128132

129133
if (haveDefaults.lengthCompare(1) > 0) {
130134
val owners = haveDefaults map (_.owner)

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ trait Typers extends Modes with Adaptations with Tags {
352352
if (formals exists (isRepeatedParamType(_)))
353353
error(pos, "methods with `*`-parameters cannot be converted to function values");
354354
*/
355-
if (restpe.isDependent)
355+
if (tpe.isDependentMethodType)
356356
DependentMethodTpeConversionToFunctionError(tree, tpe)
357357
checkParamsConvertible(tree, restpe)
358358
case _ =>

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,8 +1378,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
13781378
/** The value parameter sections of this symbol.
13791379
*/
13801380
def paramss: List[List[Symbol]] = info.paramss
1381-
def hasParamWhich(cond: Symbol => Boolean) = mexists(paramss)(cond)
1382-
1381+
13831382
/** The least proper supertype of a class; includes all parent types
13841383
* and refinement where needed. You need to compute that in a situation like this:
13851384
* {

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

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ trait Types extends api.Types { self: SymbolTable =>
293293
case SuperType(_, _) => false
294294
case SingleType(pre, sym) => notConcreteSym(sym)
295295
case ConstantType(_) => false
296-
case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists (arg => notConcreteTpe(arg)))
296+
case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists notConcreteTpe)
297297
case RefinedType(_, _) => false
298298
case ExistentialType(_, _) => false
299299
case AnnotatedType(_, tp, _) => notConcreteTpe(tp)
@@ -343,9 +343,9 @@ trait Types extends api.Types { self: SymbolTable =>
343343
*/
344344
def isImmediatelyDependent: Boolean = false
345345

346-
/** Does this depend on an enclosing method parameter? */
347-
def isDependent: Boolean = IsDependentCollector.collect(this)
348-
346+
/** Is this type a dependent method type? */
347+
def isDependentMethodType: Boolean = false
348+
349349
/** True for WildcardType or BoundedWildcardType. */
350350
def isWildcard = false
351351

@@ -1579,10 +1579,10 @@ trait Types extends api.Types { self: SymbolTable =>
15791579
}
15801580

15811581
override def narrow: Type = typeSymbol.thisType
1582-
override def isNotNull: Boolean = parents exists (_.isNotNull)
1582+
override def isNotNull: Boolean = parents exists typeIsNotNull
15831583

15841584
override def isStructuralRefinement: Boolean =
1585-
typeSymbol.isAnonOrRefinementClass && decls.exists(_.isPossibleInRefinement)
1585+
typeSymbol.isAnonOrRefinementClass && (decls exists symbolIsPossibleInRefinement)
15861586

15871587
// override def isNullable: Boolean =
15881588
// parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
@@ -1598,7 +1598,7 @@ trait Types extends api.Types { self: SymbolTable =>
15981598
if (period != currentPeriod) {
15991599
tpe.baseTypeSeqPeriod = currentPeriod
16001600
if (!isValidForBaseClasses(period)) {
1601-
if (tpe.parents.exists(_.exists(_.isInstanceOf[TypeVar]))) {
1601+
if (tpe.parents exists typeContainsTypeVar) {
16021602
// rename type vars to fresh type params, take base type sequence of
16031603
// resulting type, and rename back all the entries in that sequence
16041604
var tvs = Set[TypeVar]()
@@ -2399,7 +2399,7 @@ trait Types extends api.Types { self: SymbolTable =>
23992399
private def needsPreString = (
24002400
settings.debug.value
24012401
|| !shorthands(sym.fullName)
2402-
|| sym.ownerChain.exists(s => !s.isClass)
2402+
|| (sym.ownersIterator exists (s => !s.isClass))
24032403
)
24042404
private def preString = if (needsPreString) pre.prefixString else ""
24052405
private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]")
@@ -2530,7 +2530,7 @@ trait Types extends api.Types { self: SymbolTable =>
25302530
resultType.isTrivial && (resultType eq resultType.withoutAnnotations)
25312531

25322532
private def isTrivialParam(p: Symbol) =
2533-
p.tpe.isTrivial && !(params.exists(_.tpe contains p) || (resultType contains p))
2533+
p.tpe.isTrivial && !typesContain(paramTypes, p) && !(resultType contains p)
25342534

25352535
def isImplicit = params.nonEmpty && params.head.isImplicit
25362536
def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized?
@@ -2546,13 +2546,15 @@ trait Types extends api.Types { self: SymbolTable =>
25462546

25472547
override def resultType(actuals: List[Type]) =
25482548
if (isTrivial || phase.erasedTypes) resultType
2549-
else if (sameLength(actuals, params)) {
2549+
else if (/*isDependentMethodType && */sameLength(actuals, params)) {
25502550
val idm = new InstantiateDependentMap(params, actuals)
25512551
val res = idm(resultType)
25522552
existentialAbstraction(idm.existentialsNeeded, res)
25532553
}
25542554
else existentialAbstraction(params, resultType)
25552555

2556+
override lazy val isDependentMethodType: Boolean = IsDependentCollector.collect(resultType)
2557+
25562558
// implicit args can only be depended on in result type:
25572559
//TODO this may be generalised so that the only constraint is dependencies are acyclic
25582560
def approximate: MethodType = MethodType(params, resultApprox)
@@ -2567,7 +2569,7 @@ trait Types extends api.Types { self: SymbolTable =>
25672569
}
25682570

25692571
override def atOwner(owner: Symbol) =
2570-
if ((params exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
2572+
if (!allSymbolsHaveOwner(params, owner) || (resultType.atOwner(owner) ne resultType))
25712573
cloneInfo(owner)
25722574
else
25732575
this
@@ -2655,7 +2657,7 @@ trait Types extends api.Types { self: SymbolTable =>
26552657
}
26562658

26572659
override def atOwner(owner: Symbol) =
2658-
if ((typeParams exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
2660+
if (!allSymbolsHaveOwner(typeParams, owner) || (resultType.atOwner(owner) ne resultType))
26592661
cloneInfo(owner)
26602662
else
26612663
this
@@ -2759,7 +2761,7 @@ trait Types extends api.Types { self: SymbolTable =>
27592761
createFromClonedSymbolsAtOwner(quantified, owner, underlying)(newExistentialType)
27602762

27612763
override def atOwner(owner: Symbol) =
2762-
if (quantified exists (_.owner != owner)) cloneInfo(owner) else this
2764+
if (!allSymbolsHaveOwner(quantified, owner)) cloneInfo(owner) else this
27632765

27642766
override def kind = "ExistentialType"
27652767

@@ -2870,7 +2872,7 @@ trait Types extends api.Types { self: SymbolTable =>
28702872
* any results.
28712873
*/
28722874
if (propagateParameterBoundsToTypeVars) {
2873-
val exclude = bounds.isEmptyBounds || bounds.exists(_.typeSymbolDirect.isNonClassType)
2875+
val exclude = bounds.isEmptyBounds || (bounds exists typeIsNonClassType)
28742876

28752877
if (exclude) new TypeConstraint
28762878
else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(new TypeConstraint(bounds))
@@ -2916,13 +2918,12 @@ trait Types extends api.Types { self: SymbolTable =>
29162918
if (tp == NoType) tp
29172919
else existentialAbstraction(existentialsInType(tp), tp)
29182920
)
2921+
29192922
def containsExistential(tpe: Type) =
2920-
tpe exists (_.typeSymbol.isExistentiallyBound)
2923+
tpe exists typeIsExistentiallyBound
29212924

2922-
def existentialsInType(tpe: Type) = (
2923-
for (tp <- tpe ; if tp.typeSymbol.isExistentiallyBound) yield
2924-
tp.typeSymbol
2925-
)
2925+
def existentialsInType(tpe: Type) =
2926+
tpe withFilter typeIsExistentiallyBound map typeSymbolOfType
29262927

29272928
/** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.)
29282929
*/
@@ -4479,7 +4480,7 @@ trait Types extends api.Types { self: SymbolTable =>
44794480
if (sameLength(basesym.typeParams, baseargs))
44804481
instParam(basesym.typeParams, baseargs)
44814482
else
4482-
if (symclazz.tpe.parents.exists(_.isErroneous))
4483+
if (symclazz.tpe.parents exists typeIsErroneous)
44834484
ErrorType // don't be to overzealous with throwing exceptions, see #2641
44844485
else
44854486
throw new Error(
@@ -4530,7 +4531,7 @@ trait Types extends api.Types { self: SymbolTable =>
45304531
else subst(tp, sym, from.tail, to.tail)
45314532

45324533
val boundSyms = tp0.boundSyms
4533-
val tp1 = if (boundSyms exists from.contains) renameBoundSyms(tp0) else tp0
4534+
val tp1 = if (boundSyms.nonEmpty && (boundSyms exists from.contains)) renameBoundSyms(tp0) else tp0
45344535
val tp = mapOver(tp1)
45354536

45364537
tp match {
@@ -4671,6 +4672,8 @@ trait Types extends api.Types { self: SymbolTable =>
46714672
else mapOver(tp)
46724673
}
46734674

4675+
/** Note: This map is needed even for non-dependent method types, despite what the name might imply.
4676+
*/
46744677
class InstantiateDependentMap(params: List[Symbol], actuals0: List[Type]) extends TypeMap with KeepOnlyTypeConstraints {
46754678
private val actuals = actuals0.toIndexedSeq
46764679
private val existentials = new Array[Symbol](actuals.size)
@@ -5897,9 +5900,17 @@ trait Types extends api.Types { self: SymbolTable =>
58975900

58985901
def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean =
58995902
tp.typeSymbol == NothingClass ||
5900-
tp.typeSymbol == NullClass && containsNull(sym.owner) ||
5901-
(tp.nonPrivateMember(sym.name).alternatives exists
5902-
(alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth)))
5903+
tp.typeSymbol == NullClass && containsNull(sym.owner) || {
5904+
def specializedBy(membr: Symbol): Boolean =
5905+
membr == sym || specializesSym(tp.narrow, membr, sym.owner.thisType, sym, depth)
5906+
val member = tp.nonPrivateMember(sym.name)
5907+
if (member eq NoSymbol) false
5908+
else if (member.isOverloaded) member.alternatives exists specializedBy
5909+
else specializedBy(member)
5910+
// was
5911+
// (tp.nonPrivateMember(sym.name).alternatives exists
5912+
// (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth)))
5913+
}
59035914

59045915
/** Does member `sym1` of `tp1` have a stronger type
59055916
* than member `sym2` of `tp2`?
@@ -6145,9 +6156,9 @@ trait Types extends api.Types { self: SymbolTable =>
61456156
*/
61466157
def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = {
61476158
var bounds = instantiatedBounds(pre, owner, tparams, targs)
6148-
if (targs.exists(_.annotations.nonEmpty))
6159+
if (targs exists typeHasAnnotations)
61496160
bounds = adaptBoundsToAnnotations(bounds, tparams, targs)
6150-
(bounds corresponds targs)(_ containsType _)
6161+
(bounds corresponds targs)(boundsContainType)
61516162
}
61526163

61536164
def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] =
@@ -6225,7 +6236,7 @@ trait Types extends api.Types { self: SymbolTable =>
62256236
def loop(tsBts: List[List[Type]]): List[Type] = {
62266237
lubListDepth += 1
62276238

6228-
if (tsBts.isEmpty || tsBts.exists(_.isEmpty)) Nil
6239+
if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) Nil
62296240
else if (tsBts.tail.isEmpty) tsBts.head
62306241
else {
62316242
// ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts.
@@ -6307,10 +6318,12 @@ trait Types extends api.Types { self: SymbolTable =>
63076318
* of some other element of the list. */
63086319
private def elimSuper(ts: List[Type]): List[Type] = ts match {
63096320
case List() => List()
6321+
case List(t) => List(t)
63106322
case t :: ts1 =>
63116323
val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
63126324
if (rest exists (t1 => t1 <:< t)) rest else t :: rest
63136325
}
6326+
63146327
def elimAnonymousClass(t: Type) = t match {
63156328
case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass =>
63166329
clazz.classBound.asSeenFrom(pre, clazz.owner)
@@ -6327,6 +6340,7 @@ trait Types extends api.Types { self: SymbolTable =>
63276340
private def elimSub(ts: List[Type], depth: Int): List[Type] = {
63286341
def elimSub0(ts: List[Type]): List[Type] = ts match {
63296342
case List() => List()
6343+
case List(t) => List(t)
63306344
case t :: ts1 =>
63316345
val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, decr(depth))))
63326346
if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest
@@ -6360,7 +6374,7 @@ trait Types extends api.Types { self: SymbolTable =>
63606374

63616375
def weakLub(ts: List[Type]) =
63626376
if (ts.nonEmpty && (ts forall isNumericValueType)) (numericLub(ts), true)
6363-
else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty)))
6377+
else if (ts exists typeHasAnnotations)
63646378
(annotationsLub(lub(ts map (_.withoutAnnotations)), ts), true)
63656379
else (lub(ts), false)
63666380

@@ -6369,7 +6383,7 @@ trait Types extends api.Types { self: SymbolTable =>
63696383
val nglb = numericGlb(ts)
63706384
if (nglb != NoType) (nglb, true)
63716385
else (glb(ts), false)
6372-
} else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) {
6386+
} else if (ts exists typeHasAnnotations) {
63736387
(annotationsGlb(glb(ts map (_.withoutAnnotations)), ts), true)
63746388
} else (glb(ts), false)
63756389
}
@@ -6554,7 +6568,7 @@ trait Types extends api.Types { self: SymbolTable =>
65546568
indent = indent stripSuffix " "
65556569
println(indent + "lub of " + ts + " is " + res)//debug
65566570
}
6557-
if (ts forall (_.isNotNull)) res.notNull else res
6571+
if (ts forall typeIsNotNull) res.notNull else res
65586572
}
65596573

65606574
val GlbFailure = new Throwable
@@ -6700,7 +6714,7 @@ trait Types extends api.Types { self: SymbolTable =>
67006714

67016715
// if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
67026716

6703-
if (ts exists (_.isNotNull)) res.notNull else res
6717+
if (ts exists typeIsNotNull) res.notNull else res
67046718
}
67056719

67066720
/** A list of the typevars in a type. */
@@ -6742,7 +6756,7 @@ trait Types extends api.Types { self: SymbolTable =>
67426756
// special treatment for lubs of array types after erasure:
67436757
// if argss contain one value type and some other type, the lub is Object
67446758
// if argss contain several reference types, the lub is an array over lub of argtypes
6745-
if (argss exists (_.isEmpty)) {
6759+
if (argss exists typeListIsEmpty) {
67466760
None // something is wrong: an array without a type arg.
67476761
} else {
67486762
val args = argss map (_.head)
@@ -6935,7 +6949,7 @@ trait Types extends api.Types { self: SymbolTable =>
69356949
}
69366950
// Add serializable to a list of parents, unless one of them already is
69376951
def addSerializable(ps: Type*): List[Type] = (
6938-
if (ps exists (_ <:< SerializableClass.tpe)) ps.toList
6952+
if (ps exists typeIsSubTypeOfSerializable) ps.toList
69396953
else (ps :+ SerializableClass.tpe).toList
69406954
)
69416955

@@ -6976,6 +6990,33 @@ trait Types extends api.Types { self: SymbolTable =>
69766990
tostringRecursions -= 1
69776991
}
69786992

6993+
// ----- Hoisted closures and convenience methods, for compile time reductions -------
6994+
6995+
private val typeIsNotNull = (tp: Type) => tp.isNotNull
6996+
private val symbolIsPossibleInRefinement = (sym: Symbol) => sym.isPossibleInRefinement
6997+
private val isTypeVar = (tp: Type) => tp.isInstanceOf[TypeVar]
6998+
private val typeContainsTypeVar = (tp: Type) => tp exists isTypeVar
6999+
private val typeIsNonClassType = (tp: Type) => tp.typeSymbolDirect.isNonClassType
7000+
private val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound
7001+
private val typeSymbolOfType = (tp: Type) => tp.typeSymbol
7002+
private val typeIsErroneous = (tp: Type) => tp.isErroneous
7003+
private val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty
7004+
private val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp
7005+
private val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty
7006+
private val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableClass.tpe
7007+
7008+
@tailrec private def typesContain(tps: List[Type], sym: Symbol): Boolean = tps match {
7009+
case tp :: rest => (tp contains sym) || typesContain(rest, sym)
7010+
case _ => false
7011+
}
7012+
7013+
@tailrec private def allSymbolsHaveOwner(syms: List[Symbol], owner: Symbol): Boolean = syms match {
7014+
case sym :: rest => sym.owner == owner && allSymbolsHaveOwner(rest, owner)
7015+
case _ => true
7016+
}
7017+
7018+
// -------------- Classtags --------------------------------------------------------
7019+
69797020
implicit val AnnotatedTypeTag = ClassTag[AnnotatedType](classOf[AnnotatedType])
69807021
implicit val BoundedWildcardTypeTag = ClassTag[BoundedWildcardType](classOf[BoundedWildcardType])
69817022
implicit val ClassInfoTypeTag = ClassTag[ClassInfoType](classOf[ClassInfoType])
@@ -6994,7 +7035,10 @@ trait Types extends api.Types { self: SymbolTable =>
69947035
implicit val TypeRefTag = ClassTag[TypeRef](classOf[TypeRef])
69957036
implicit val TypeTagg = ClassTag[Type](classOf[Type])
69967037

7038+
// -------------- Statistics --------------------------------------------------------
7039+
69977040
Statistics.newView("#unique types") { if (uniques == null) 0 else uniques.size }
7041+
69987042
}
69997043

70007044
object TypesStats {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import scala.collection._
2+
3+
trait Foo[+A,
4+
+Coll,
5+
+This <: GenSeqView[A, Coll] with GenSeqViewLike[A, Coll, This]]
6+
extends GenSeq[A] with GenSeqLike[A, This] with GenIterableView[A, Coll] with GenIterableViewLike[A, Coll, This] {
7+
self =>
8+
9+
trait Transformed[+B] extends GenSeqView[B, Coll] with super.Transformed[B] {
10+
def length: Int
11+
def apply(idx: Int): B
12+
override def toString = viewToString
13+
}
14+
trait Reversed extends Transformed[A] {
15+
override def iterator: Iterator[A] = createReversedIterator
16+
def length: Int = self.length
17+
def apply(idx: Int): A = self.apply(length - 1 - idx)
18+
final override protected[this] def viewIdentifier = "R"
19+
20+
private def createReversedIterator = {
21+
var lst = List[A]()
22+
for (elem <- self) lst ::= elem
23+
lst.iterator
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)