summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2012-08-20 08:10:34 +0100
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2012-08-20 08:10:38 +0100
commitcf9b7ae0867f594aba39984ac732fbd26ed12f51 (patch)
tree3d4035fda41f8f2bd84361fbca312693c8d2b6f2
parentc32b189a2a2575512d0dc8d91a400d773b53a7f0 (diff)
downloadscala-cf9b7ae0867f594aba39984ac732fbd26ed12f51.tar.gz
scala-cf9b7ae0867f594aba39984ac732fbd26ed12f51.tar.bz2
scala-cf9b7ae0867f594aba39984ac732fbd26ed12f51.zip
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.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala110
-rw-r--r--test/files/pos/specializes-sym-crash.scala26
6 files changed, 111 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index b502af4a7f..9e324194e6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -240,7 +240,7 @@ trait Infer {
def normalize(tp: Type): Type = tp match {
case mt @ MethodType(params, restpe) if mt.isImplicit =>
normalize(restpe)
- case mt @ MethodType(params, restpe) if !restpe.isDependent =>
+ case mt @ MethodType(params, restpe) if !mt.isDependentMethodType =>
functionType(params map (_.tpe), normalize(restpe))
case NullaryMethodType(restpe) =>
normalize(restpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 601ceaaa53..9d0c5f400e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -124,7 +124,11 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
defaultMethodNames.toList.distinct foreach { name =>
val methods = clazz.info.findMember(name, 0L, METHOD, false).alternatives
- val haveDefaults = methods filter (sym => sym.hasParamWhich(_.hasDefault) && !nme.isProtectedAccessorName(sym.name))
+ def hasDefaultParam(tpe: Type): Boolean = tpe match {
+ case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe)
+ case _ => false
+ }
+ val haveDefaults = methods filter (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name))
if (haveDefaults.lengthCompare(1) > 0) {
val owners = haveDefaults map (_.owner)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7df2f323e1..46fbaee20a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -352,7 +352,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (formals exists (isRepeatedParamType(_)))
error(pos, "methods with `*`-parameters cannot be converted to function values");
*/
- if (restpe.isDependent)
+ if (tpe.isDependentMethodType)
DependentMethodTpeConversionToFunctionError(tree, tpe)
checkParamsConvertible(tree, restpe)
case _ =>
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 5da4942a89..17f4669c29 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1378,8 +1378,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The value parameter sections of this symbol.
*/
def paramss: List[List[Symbol]] = info.paramss
- def hasParamWhich(cond: Symbol => Boolean) = mexists(paramss)(cond)
-
+
/** The least proper supertype of a class; includes all parent types
* and refinement where needed. You need to compute that in a situation like this:
* {
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 9514898ce5..dd47ee2181 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -293,7 +293,7 @@ trait Types extends api.Types { self: SymbolTable =>
case SuperType(_, _) => false
case SingleType(pre, sym) => notConcreteSym(sym)
case ConstantType(_) => false
- case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists (arg => notConcreteTpe(arg)))
+ case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists notConcreteTpe)
case RefinedType(_, _) => false
case ExistentialType(_, _) => false
case AnnotatedType(_, tp, _) => notConcreteTpe(tp)
@@ -343,9 +343,9 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def isImmediatelyDependent: Boolean = false
- /** Does this depend on an enclosing method parameter? */
- def isDependent: Boolean = IsDependentCollector.collect(this)
-
+ /** Is this type a dependent method type? */
+ def isDependentMethodType: Boolean = false
+
/** True for WildcardType or BoundedWildcardType. */
def isWildcard = false
@@ -1579,10 +1579,10 @@ trait Types extends api.Types { self: SymbolTable =>
}
override def narrow: Type = typeSymbol.thisType
- override def isNotNull: Boolean = parents exists (_.isNotNull)
+ override def isNotNull: Boolean = parents exists typeIsNotNull
override def isStructuralRefinement: Boolean =
- typeSymbol.isAnonOrRefinementClass && decls.exists(_.isPossibleInRefinement)
+ typeSymbol.isAnonOrRefinementClass && (decls exists symbolIsPossibleInRefinement)
// override def isNullable: Boolean =
// parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
@@ -1598,7 +1598,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (period != currentPeriod) {
tpe.baseTypeSeqPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- if (tpe.parents.exists(_.exists(_.isInstanceOf[TypeVar]))) {
+ if (tpe.parents exists typeContainsTypeVar) {
// rename type vars to fresh type params, take base type sequence of
// resulting type, and rename back all the entries in that sequence
var tvs = Set[TypeVar]()
@@ -2399,7 +2399,7 @@ trait Types extends api.Types { self: SymbolTable =>
private def needsPreString = (
settings.debug.value
|| !shorthands(sym.fullName)
- || sym.ownerChain.exists(s => !s.isClass)
+ || (sym.ownersIterator exists (s => !s.isClass))
)
private def preString = if (needsPreString) pre.prefixString else ""
private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]")
@@ -2530,7 +2530,7 @@ trait Types extends api.Types { self: SymbolTable =>
resultType.isTrivial && (resultType eq resultType.withoutAnnotations)
private def isTrivialParam(p: Symbol) =
- p.tpe.isTrivial && !(params.exists(_.tpe contains p) || (resultType contains p))
+ p.tpe.isTrivial && !typesContain(paramTypes, p) && !(resultType contains p)
def isImplicit = params.nonEmpty && params.head.isImplicit
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 =>
override def resultType(actuals: List[Type]) =
if (isTrivial || phase.erasedTypes) resultType
- else if (sameLength(actuals, params)) {
+ else if (/*isDependentMethodType && */sameLength(actuals, params)) {
val idm = new InstantiateDependentMap(params, actuals)
val res = idm(resultType)
existentialAbstraction(idm.existentialsNeeded, res)
}
else existentialAbstraction(params, resultType)
+ override lazy val isDependentMethodType: Boolean = IsDependentCollector.collect(resultType)
+
// implicit args can only be depended on in result type:
//TODO this may be generalised so that the only constraint is dependencies are acyclic
def approximate: MethodType = MethodType(params, resultApprox)
@@ -2567,7 +2569,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
override def atOwner(owner: Symbol) =
- if ((params exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
+ if (!allSymbolsHaveOwner(params, owner) || (resultType.atOwner(owner) ne resultType))
cloneInfo(owner)
else
this
@@ -2655,7 +2657,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
override def atOwner(owner: Symbol) =
- if ((typeParams exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
+ if (!allSymbolsHaveOwner(typeParams, owner) || (resultType.atOwner(owner) ne resultType))
cloneInfo(owner)
else
this
@@ -2759,7 +2761,7 @@ trait Types extends api.Types { self: SymbolTable =>
createFromClonedSymbolsAtOwner(quantified, owner, underlying)(newExistentialType)
override def atOwner(owner: Symbol) =
- if (quantified exists (_.owner != owner)) cloneInfo(owner) else this
+ if (!allSymbolsHaveOwner(quantified, owner)) cloneInfo(owner) else this
override def kind = "ExistentialType"
@@ -2870,7 +2872,7 @@ trait Types extends api.Types { self: SymbolTable =>
* any results.
*/
if (propagateParameterBoundsToTypeVars) {
- val exclude = bounds.isEmptyBounds || bounds.exists(_.typeSymbolDirect.isNonClassType)
+ val exclude = bounds.isEmptyBounds || (bounds exists typeIsNonClassType)
if (exclude) new TypeConstraint
else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(new TypeConstraint(bounds))
@@ -2916,13 +2918,12 @@ trait Types extends api.Types { self: SymbolTable =>
if (tp == NoType) tp
else existentialAbstraction(existentialsInType(tp), tp)
)
+
def containsExistential(tpe: Type) =
- tpe exists (_.typeSymbol.isExistentiallyBound)
+ tpe exists typeIsExistentiallyBound
- def existentialsInType(tpe: Type) = (
- for (tp <- tpe ; if tp.typeSymbol.isExistentiallyBound) yield
- tp.typeSymbol
- )
+ def existentialsInType(tpe: Type) =
+ tpe withFilter typeIsExistentiallyBound map typeSymbolOfType
/** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.)
*/
@@ -4479,7 +4480,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (sameLength(basesym.typeParams, baseargs))
instParam(basesym.typeParams, baseargs)
else
- if (symclazz.tpe.parents.exists(_.isErroneous))
+ if (symclazz.tpe.parents exists typeIsErroneous)
ErrorType // don't be to overzealous with throwing exceptions, see #2641
else
throw new Error(
@@ -4530,7 +4531,7 @@ trait Types extends api.Types { self: SymbolTable =>
else subst(tp, sym, from.tail, to.tail)
val boundSyms = tp0.boundSyms
- val tp1 = if (boundSyms exists from.contains) renameBoundSyms(tp0) else tp0
+ val tp1 = if (boundSyms.nonEmpty && (boundSyms exists from.contains)) renameBoundSyms(tp0) else tp0
val tp = mapOver(tp1)
tp match {
@@ -4671,6 +4672,8 @@ trait Types extends api.Types { self: SymbolTable =>
else mapOver(tp)
}
+ /** Note: This map is needed even for non-dependent method types, despite what the name might imply.
+ */
class InstantiateDependentMap(params: List[Symbol], actuals0: List[Type]) extends TypeMap with KeepOnlyTypeConstraints {
private val actuals = actuals0.toIndexedSeq
private val existentials = new Array[Symbol](actuals.size)
@@ -5897,9 +5900,17 @@ trait Types extends api.Types { self: SymbolTable =>
def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean =
tp.typeSymbol == NothingClass ||
- tp.typeSymbol == NullClass && containsNull(sym.owner) ||
- (tp.nonPrivateMember(sym.name).alternatives exists
- (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth)))
+ tp.typeSymbol == NullClass && containsNull(sym.owner) || {
+ def specializedBy(membr: Symbol): Boolean =
+ membr == sym || specializesSym(tp.narrow, membr, sym.owner.thisType, sym, depth)
+ val member = tp.nonPrivateMember(sym.name)
+ if (member eq NoSymbol) false
+ else if (member.isOverloaded) member.alternatives exists specializedBy
+ else specializedBy(member)
+ // was
+ // (tp.nonPrivateMember(sym.name).alternatives exists
+ // (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth)))
+ }
/** Does member `sym1` of `tp1` have a stronger type
* than member `sym2` of `tp2`?
@@ -6145,9 +6156,9 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = {
var bounds = instantiatedBounds(pre, owner, tparams, targs)
- if (targs.exists(_.annotations.nonEmpty))
+ if (targs exists typeHasAnnotations)
bounds = adaptBoundsToAnnotations(bounds, tparams, targs)
- (bounds corresponds targs)(_ containsType _)
+ (bounds corresponds targs)(boundsContainType)
}
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 =>
def loop(tsBts: List[List[Type]]): List[Type] = {
lubListDepth += 1
- if (tsBts.isEmpty || tsBts.exists(_.isEmpty)) Nil
+ if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) Nil
else if (tsBts.tail.isEmpty) tsBts.head
else {
// ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts.
@@ -6307,10 +6318,12 @@ trait Types extends api.Types { self: SymbolTable =>
* of some other element of the list. */
private def elimSuper(ts: List[Type]): List[Type] = ts match {
case List() => List()
+ case List(t) => List(t)
case t :: ts1 =>
val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
if (rest exists (t1 => t1 <:< t)) rest else t :: rest
}
+
def elimAnonymousClass(t: Type) = t match {
case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass =>
clazz.classBound.asSeenFrom(pre, clazz.owner)
@@ -6327,6 +6340,7 @@ trait Types extends api.Types { self: SymbolTable =>
private def elimSub(ts: List[Type], depth: Int): List[Type] = {
def elimSub0(ts: List[Type]): List[Type] = ts match {
case List() => List()
+ case List(t) => List(t)
case t :: ts1 =>
val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, decr(depth))))
if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest
@@ -6360,7 +6374,7 @@ trait Types extends api.Types { self: SymbolTable =>
def weakLub(ts: List[Type]) =
if (ts.nonEmpty && (ts forall isNumericValueType)) (numericLub(ts), true)
- else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty)))
+ else if (ts exists typeHasAnnotations)
(annotationsLub(lub(ts map (_.withoutAnnotations)), ts), true)
else (lub(ts), false)
@@ -6369,7 +6383,7 @@ trait Types extends api.Types { self: SymbolTable =>
val nglb = numericGlb(ts)
if (nglb != NoType) (nglb, true)
else (glb(ts), false)
- } else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) {
+ } else if (ts exists typeHasAnnotations) {
(annotationsGlb(glb(ts map (_.withoutAnnotations)), ts), true)
} else (glb(ts), false)
}
@@ -6554,7 +6568,7 @@ trait Types extends api.Types { self: SymbolTable =>
indent = indent stripSuffix " "
println(indent + "lub of " + ts + " is " + res)//debug
}
- if (ts forall (_.isNotNull)) res.notNull else res
+ if (ts forall typeIsNotNull) res.notNull else res
}
val GlbFailure = new Throwable
@@ -6700,7 +6714,7 @@ trait Types extends api.Types { self: SymbolTable =>
// if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
- if (ts exists (_.isNotNull)) res.notNull else res
+ if (ts exists typeIsNotNull) res.notNull else res
}
/** A list of the typevars in a type. */
@@ -6742,7 +6756,7 @@ trait Types extends api.Types { self: SymbolTable =>
// special treatment for lubs of array types after erasure:
// if argss contain one value type and some other type, the lub is Object
// if argss contain several reference types, the lub is an array over lub of argtypes
- if (argss exists (_.isEmpty)) {
+ if (argss exists typeListIsEmpty) {
None // something is wrong: an array without a type arg.
} else {
val args = argss map (_.head)
@@ -6935,7 +6949,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
// Add serializable to a list of parents, unless one of them already is
def addSerializable(ps: Type*): List[Type] = (
- if (ps exists (_ <:< SerializableClass.tpe)) ps.toList
+ if (ps exists typeIsSubTypeOfSerializable) ps.toList
else (ps :+ SerializableClass.tpe).toList
)
@@ -6976,6 +6990,33 @@ trait Types extends api.Types { self: SymbolTable =>
tostringRecursions -= 1
}
+// ----- Hoisted closures and convenience methods, for compile time reductions -------
+
+ private val typeIsNotNull = (tp: Type) => tp.isNotNull
+ private val symbolIsPossibleInRefinement = (sym: Symbol) => sym.isPossibleInRefinement
+ private val isTypeVar = (tp: Type) => tp.isInstanceOf[TypeVar]
+ private val typeContainsTypeVar = (tp: Type) => tp exists isTypeVar
+ private val typeIsNonClassType = (tp: Type) => tp.typeSymbolDirect.isNonClassType
+ private val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound
+ private val typeSymbolOfType = (tp: Type) => tp.typeSymbol
+ private val typeIsErroneous = (tp: Type) => tp.isErroneous
+ private val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty
+ private val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp
+ private val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty
+ private val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableClass.tpe
+
+ @tailrec private def typesContain(tps: List[Type], sym: Symbol): Boolean = tps match {
+ case tp :: rest => (tp contains sym) || typesContain(rest, sym)
+ case _ => false
+ }
+
+ @tailrec private def allSymbolsHaveOwner(syms: List[Symbol], owner: Symbol): Boolean = syms match {
+ case sym :: rest => sym.owner == owner && allSymbolsHaveOwner(rest, owner)
+ case _ => true
+ }
+
+// -------------- Classtags --------------------------------------------------------
+
implicit val AnnotatedTypeTag = ClassTag[AnnotatedType](classOf[AnnotatedType])
implicit val BoundedWildcardTypeTag = ClassTag[BoundedWildcardType](classOf[BoundedWildcardType])
implicit val ClassInfoTypeTag = ClassTag[ClassInfoType](classOf[ClassInfoType])
@@ -6994,7 +7035,10 @@ trait Types extends api.Types { self: SymbolTable =>
implicit val TypeRefTag = ClassTag[TypeRef](classOf[TypeRef])
implicit val TypeTagg = ClassTag[Type](classOf[Type])
+// -------------- Statistics --------------------------------------------------------
+
Statistics.newView("#unique types") { if (uniques == null) 0 else uniques.size }
+
}
object TypesStats {
diff --git a/test/files/pos/specializes-sym-crash.scala b/test/files/pos/specializes-sym-crash.scala
new file mode 100644
index 0000000000..c46f435ac4
--- /dev/null
+++ b/test/files/pos/specializes-sym-crash.scala
@@ -0,0 +1,26 @@
+import scala.collection._
+
+trait Foo[+A,
+ +Coll,
+ +This <: GenSeqView[A, Coll] with GenSeqViewLike[A, Coll, This]]
+extends GenSeq[A] with GenSeqLike[A, This] with GenIterableView[A, Coll] with GenIterableViewLike[A, Coll, This] {
+self =>
+
+ trait Transformed[+B] extends GenSeqView[B, Coll] with super.Transformed[B] {
+ def length: Int
+ def apply(idx: Int): B
+ override def toString = viewToString
+ }
+ trait Reversed extends Transformed[A] {
+ override def iterator: Iterator[A] = createReversedIterator
+ def length: Int = self.length
+ def apply(idx: Int): A = self.apply(length - 1 - idx)
+ final override protected[this] def viewIdentifier = "R"
+
+ private def createReversedIterator = {
+ var lst = List[A]()
+ for (elem <- self) lst ::= elem
+ lst.iterator
+ }
+ }
+}