summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2010-01-04 20:46:26 +0000
committerMartin Odersky <odersky@gmail.com>2010-01-04 20:46:26 +0000
commit6af8cbb3612071cdb04dcbb8d29a0c62b0690ca9 (patch)
tree32fd7d679e4f9e73f808709dd85f1fe7af31b27b /src
parente5d37b199df4d04eda46ddc0cf4b33f9503bfbc0 (diff)
downloadscala-6af8cbb3612071cdb04dcbb8d29a0c62b0690ca9.tar.gz
scala-6af8cbb3612071cdb04dcbb8d29a0c62b0690ca9.tar.bz2
scala-6af8cbb3612071cdb04dcbb8d29a0c62b0690ca9.zip
Added extensive statistics, reduced time of imp...
Added extensive statistics, reduced time of implicit resolution by 2/3rds, of whole typer by 1/4 to 1/3rd.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala16
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala94
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala299
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala102
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala86
-rw-r--r--src/compiler/scala/tools/nsc/util/Statistics.scala243
10 files changed, 594 insertions, 268 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 9adad689f1..c4c9af5294 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -102,9 +102,8 @@ trait Trees {
//def kindingIrrelevant(tp: Type) = (tp eq null) || phase.name == "erasure" || phase.erasedTypes
abstract class Tree extends Product {
- {
- import util.Statistics
- if (Statistics.enabled) nodeCount += 1
+ if (util.Statistics.enabled) {
+ util.Statistics.nodeByType(getClass) += 1
}
val id = nodeCount
diff --git a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
index 8fc01a91fb..c83138e9bc 100644
--- a/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
+++ b/src/compiler/scala/tools/nsc/symtab/BaseTypeSeqs.scala
@@ -9,6 +9,7 @@ package symtab
import scala.collection.mutable.ListBuffer
import scala.collection.immutable.Map
import math.max
+import util.Statistics._
/** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types
* of a type. It characterized by the following two laws:
@@ -32,6 +33,9 @@ trait BaseTypeSeqs {
class BaseTypeSeq(parents: List[Type], elems: Array[Type]) {
self =>
+ incCounter(baseTypeSeqCount)
+ incCounter(baseTypeSeqLenTotal, elems.length)
+
/** The number of types in the sequence */
def length: Int = elems.length
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 57245a4023..5d779e90a2 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -18,6 +18,8 @@ import scala.tools.nsc.util.{Position, NoPosition, ClassPath, ClassRep, JavaClas
import classfile.ClassfileParser
import Flags._
+import util.Statistics._
+
/** This class ...
*
* @author Martin Odersky
@@ -243,7 +245,9 @@ abstract class SymbolLoaders {
protected def description = "class file "+ classfile.toString
protected def doComplete(root: Symbol) {
+ val start = startTimer(classReadNanos)
classfileParser.parse(classfile, root)
+ stopTimer(classReadNanos, start)
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 91f26b1810..9f22bc54f7 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -10,8 +10,9 @@ package symtab
import scala.collection.mutable.ListBuffer
import scala.collection.immutable.Map
-import scala.tools.nsc.io.AbstractFile
-import scala.tools.nsc.util.{Position, NoPosition, BatchSourceFile}
+import io.AbstractFile
+import util.{Position, NoPosition, BatchSourceFile}
+import util.Statistics._
import Flags._
//todo: get rid of MONOMORPHIC flag
@@ -21,11 +22,7 @@ trait Symbols {
import definitions._
private var ids = 0
-
- //for statistics:
- def symbolCount = ids
- var typeSymbolCount = 0
- var classSymbolCount = 0
+ def symbolCount = ids // statistics
val emptySymbolArray = new Array[Symbol](0)
val emptySymbolSet = Set.empty[Symbol]
@@ -1872,7 +1869,7 @@ trait Symbols {
def cloneSymbolImpl(owner: Symbol): Symbol =
new TypeSymbol(owner, pos, name)
- if (util.Statistics.enabled) typeSymbolCount = typeSymbolCount + 1
+ incCounter(typeSymbolCount)
}
/** A class for type parameters viewed from inside their scopes
@@ -2009,7 +2006,7 @@ trait Symbols {
override def children: Set[Symbol] = childSet
override def addChild(sym: Symbol) { childSet = childSet + sym }
- if (util.Statistics.enabled) classSymbolCount = classSymbolCount + 1
+ incCounter(classSymbolCount)
}
/** A class for module class symbols
@@ -2025,6 +2022,7 @@ trait Symbols {
setSourceModule(module)
}
override def sourceModule = module
+ lazy val implicitMembers = info.implicitMembers
def setSourceModule(module: Symbol) { this.module = module }
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index d87a30f847..8a84e75be0 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -9,10 +9,12 @@ package symtab
import scala.collection.immutable
import scala.collection.mutable.{ListBuffer, HashMap, WeakHashMap}
-import scala.tools.nsc.ast.TreeGen
-import scala.tools.nsc.util.{HashSet, Position, NoPosition}
+import ast.TreeGen
+import util.{HashSet, Position, NoPosition}
+import util.Statistics._
import Flags._
+
/* A standard type pattern match:
case ErrorType =>
// internal: error
@@ -64,16 +66,7 @@ trait Types {
//statistics
- var singletonBaseTypeSeqCount = 0
- var compoundBaseTypeSeqCount = 0
- var typerefBaseTypeSeqCount = 0
- var findMemberCount = 0
- var noMemberCount = 0
- var multMemberCount = 0
- var findMemberNanos = 0l
- var subtypeCount = 0
- var sametypeCount = 0
- var subtypeNanos = 0l
+ def uniqueTypeCount = if (uniques == null) 0 else uniques.size
private var explainSwitch = false
@@ -499,9 +492,13 @@ trait Types {
*/
def asSeenFrom(pre: Type, clazz: Symbol): Type =
if (!isTrivial && (!phase.erasedTypes || pre.typeSymbol == ArrayClass)) {
+ incCounter(asSeenFromCount)
+ val start = startTimer(asSeenFromNanos)
val m = new AsSeenFromMap(pre.normalize, clazz)
val tp = m apply this
- existentialAbstraction(m.capturedParams, tp)
+ val result = existentialAbstraction(m.capturedParams, tp)
+ stopTimer(asSeenFromNanos, start)
+ result
} else this
/** The info of `sym', seen as a member of this type.
@@ -597,31 +594,36 @@ trait Types {
/** Is this type a subtype of that type? */
def <:<(that: Type): Boolean = {
-// val startTime = if (util.Statistics.enabled) System.nanoTime() else 0l
-// val result =
- ((this eq that) ||
- (if (explainSwitch) explain("<:", isSubType, this, that)
- else isSubType(this, that, AnyDepth)))
-// if (util.Statistics.enabled) {
-// subtypeNanos += System.nanoTime() - startTime
-// subtypeCount += 1
-// }
-// result
+ if (util.Statistics.enabled) stat_<:<(that)
+ else
+ (this eq that) ||
+ (if (explainSwitch) explain("<:", isSubType, this, that)
+ else isSubType(this, that, AnyDepth))
+ }
+
+ def stat_<:<(that: Type): Boolean = {
+ incCounter(subtypeCount)
+ val start = startTimer(subtypeNanos)
+ val result =
+ (this eq that) ||
+ (if (explainSwitch) explain("<:", isSubType, this, that)
+ else isSubType(this, that, AnyDepth))
+ stopTimer(subtypeNanos, start)
+ result
}
/** Is this type a weak subtype of that type? True also for numeric types, i.e. Int weak_<:< Long.
*/
- def weak_<:<(that: Type): Boolean =
-// val startTime = if (util.Statistics.enabled) System.nanoTime() else 0l
-// val result =
+ def weak_<:<(that: Type): Boolean = {
+ incCounter(subtypeCount)
+ val start = startTimer(subtypeNanos)
+ val result =
((this eq that) ||
(if (explainSwitch) explain("weak_<:", isWeakSubType, this, that)
else isWeakSubType(this, that)))
-// if (util.Statistics.enabled) {
-// subtypeNanos += System.nanoTime() - startTime
-// subtypeCount += 1
-// }
-// result
+ stopTimer(subtypeNanos, start)
+ result
+ }
/** Is this type equivalent to that type? */
def =:=(that: Type): Boolean = (
@@ -785,8 +787,9 @@ trait Types {
// See (t0851) for a situation where this happens.
if (!this.isGround)
return typeVarToOriginMap(this).findMember(name, excludedFlags, requiredFlags, stableOnly)
- if (util.Statistics.enabled) findMemberCount += 1
-// val startTime = if (util.Statistics.enabled) System.nanoTime() else 0l
+
+ incCounter(findMemberCount)
+ val start = startTimer(findMemberNanos)
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var members: Scope = null
@@ -812,7 +815,7 @@ trait Types {
sym.getFlag(PRIVATE | LOCAL) != (PRIVATE | LOCAL).toLong ||
(bcs0.head.hasTransOwner(bcs.head)))) {
if (name.isTypeName || stableOnly && sym.isStable) {
-// if (util.Statistics.enabled) findMemberNanos += System.nanoTime() - startTime
+ stopTimer(findMemberNanos, start)
return sym
} else if (member == NoSymbol) {
member = sym
@@ -852,14 +855,13 @@ trait Types {
} // while (!bcs.isEmpty)
excluded = excludedFlags
} // while (continue)
-// if (util.Statistics.enabled) findMemberNanos += System.nanoTime() - startTime
+ stopTimer(findMemberNanos, start)
if (members eq null) {
- if (util.Statistics.enabled) if (member == NoSymbol) noMemberCount += 1;
+ if (member == NoSymbol) incCounter(noMemberCount)
member
} else {
- if (util.Statistics.enabled) multMemberCount += 1;
- //val pre = if (this.typeSymbol.isClass) this.typeSymbol.thisType else this;
- (baseClasses.head.newOverloaded(this, members.toList))
+ incCounter(multMemberCount)
+ baseClasses.head.newOverloaded(this, members.toList)
}
}
@@ -970,7 +972,7 @@ trait Types {
override def isVolatile = underlying.isVolatile
override def widen: Type = underlying.widen
override def baseTypeSeq: BaseTypeSeq = {
- if (util.Statistics.enabled) singletonBaseTypeSeqCount += 1
+ incCounter(singletonBaseTypeSeqCount)
underlying.baseTypeSeq prepend this
}
override def safeToString: String = prefixString + "type"
@@ -1179,8 +1181,7 @@ trait Types {
val bts = copyRefinedType(this.asInstanceOf[RefinedType], parents map varToParam, varToParam mapOver decls).baseTypeSeq
baseTypeSeqCache = bts lateMap paramToVar
} else {
- if (util.Statistics.enabled)
- compoundBaseTypeSeqCount += 1
+ incCounter(compoundBaseTypeSeqCount)
baseTypeSeqCache = undetBaseTypeSeq
baseTypeSeqCache = memo(compoundBaseTypeSeq(this))(_.baseTypeSeq updateHead typeSymbol.tpe)
}
@@ -1711,13 +1712,11 @@ A type's typeSymbol should never be inspected directly.
if (period != currentPeriod) {
baseTypeSeqPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- if (util.Statistics.enabled)
- typerefBaseTypeSeqCount += 1
+ incCounter(typerefBaseTypeSeqCount)
baseTypeSeqCache = undetBaseTypeSeq
baseTypeSeqCache =
if (sym.isAbstractType) transform(bounds.hi).baseTypeSeq prepend this
else sym.info.baseTypeSeq map transform
-
}
}
if (baseTypeSeqCache == undetBaseTypeSeq)
@@ -2642,9 +2641,8 @@ A type's typeSymbol should never be inspected directly.
private var uniques: HashSet[AnyRef] = _
private var uniqueRunId = NoRunId
- def uniqueTypeCount = if (uniques == null) 0 else uniques.size // for statistics
-
private def unique[T <: AnyRef](tp: T): T = {
+ incCounter(rawTypeCount)
if (uniqueRunId != currentRunId) {
uniques = new HashSet("uniques", initialUniquesCapacity)
uniqueRunId = currentRunId
@@ -3757,7 +3755,7 @@ A type's typeSymbol should never be inspected directly.
/** Do `tp1' and `tp2' denote equivalent types?
*/
def isSameType(tp1: Type, tp2: Type): Boolean = try {
- sametypeCount += 1
+ incCounter(sametypeCount)
subsametypeRecursions += 1
undoLog undoUnless {
isSameType0(tp1, tp2)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index ead20f1cb8..519ad1b0bf 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -7,6 +7,8 @@
package scala.tools.nsc
package typechecker
+import util.Statistics._
+
/** The main attribution phase.
*/
trait Analyzer extends AnyRef
@@ -63,8 +65,6 @@ trait Analyzer extends AnyRef
}
}
- var typerTime = 0L
-
object typerFactory extends SubComponent {
val global: Analyzer.this.global.type = Analyzer.this.global
val phaseName = "typer"
@@ -73,10 +73,9 @@ trait Analyzer extends AnyRef
def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) {
resetTyper()
override def run {
- val start = if (util.Statistics.enabled) System.nanoTime() else 0L
+ val start = startTimer(typerNanos)
currentRun.units foreach applyPhase
- if (util.Statistics.enabled)
- typerTime += System.nanoTime() - start
+ stopTimer(typerNanos, start)
}
def apply(unit: CompilationUnit) {
try {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index eea5be32b7..b8d2db3221 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -14,6 +14,7 @@ package typechecker
import scala.collection.mutable.{LinkedHashMap, ListBuffer}
import scala.tools.nsc.util.{ HashSet, Position, Set, NoPosition, SourceFile }
import symtab.Flags._
+import util.Statistics._
/** This trait provides methods to find various kinds of implicits.
*
@@ -28,16 +29,6 @@ self: Analyzer =>
def traceImplicits = printTypings
- var implicitTime = 0L
- var inscopeSucceed = 0L
- var inscopeFail = 0L
- var oftypeSucceed = 0L
- var oftypeFail = 0L
- var manifSucceed = 0L
- var manifFail = 0L
- var hits = 0
- var misses = 0
-
/** Search for an implicit value. See the comment on `result` at the end of class `ImplicitSearch`
* for more info how the search is conducted.
* @param tree The tree for which the implicit needs to be inserted.
@@ -52,10 +43,18 @@ self: Analyzer =>
* @return A search result
*/
def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = {
+ val rawTypeStart = startCounter(rawTypeImpl)
+ val findMemberStart = startCounter(findMemberImpl)
+ val subtypeStart = startCounter(subtypeImpl)
+ val start = startTimer(implicitNanos)
if (traceImplicits && !tree.isEmpty && !context.undetparams.isEmpty)
println("typing implicit with undetermined type params: "+context.undetparams+"\n"+tree)
val result = new ImplicitSearch(tree, pt, isView, context.makeImplicit(reportAmbiguous)).bestImplicit
context.undetparams = context.undetparams filterNot (result.subst.from contains _)
+ stopTimer(implicitNanos, start)
+ stopCounter(rawTypeImpl, rawTypeStart)
+ stopCounter(findMemberImpl, findMemberStart)
+ stopCounter(subtypeImpl, subtypeStart)
result
}
@@ -103,9 +102,14 @@ self: Analyzer =>
/** Does type `tp` contain an Error type as parameter or result?
*/
private def containsError(tp: Type): Boolean = tp match {
- case PolyType(tparams, restpe) => containsError(restpe)
- case MethodType(params, restpe) => (params map (_.tpe) exists (_.isError)) || containsError(restpe)
- case _ => tp.isError
+ case PolyType(tparams, restpe) =>
+ containsError(restpe)
+ case MethodType(params, restpe) =>
+ for (p <- params)
+ if (p.tpe.isError) return true
+ containsError(restpe)
+ case _ =>
+ tp.isError
}
def isCyclicOrErroneous = try {
@@ -214,10 +218,12 @@ self: Analyzer =>
/** Is implicit info `info1` better than implicit info `info2`?
*/
- def improves(info1: ImplicitInfo, info2: ImplicitInfo) =
+ def improves(info1: ImplicitInfo, info2: ImplicitInfo) = {
+ incCounter(improvesCount)
(info2 == NoImplicitInfo) ||
(info1 != NoImplicitInfo) &&
isStrictlyMoreSpecific(info1.tpe, info2.tpe, info1.sym, info2.sym)
+ }
/** Map all type params in given list to WildcardType
* @param tp The type in which to do the mapping
@@ -282,7 +288,7 @@ self: Analyzer =>
overlaps(dtor1, dted1) && (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1))
}
- if (util.Statistics.enabled) implcnt += 1
+ incCounter(implicitSearchCount)
/** Issues an error signalling ambiguous implicits */
private def ambiguousImplicitError(info1: ImplicitInfo, info2: ImplicitInfo,
@@ -307,6 +313,12 @@ self: Analyzer =>
/** The type parameters to instantiate */
val undetParams = if (isView) List() else context.outer.undetparams
+ /** Replace undetParams in type `tp` by Any/Nothing, according to variance */
+ def approximate(tp: Type) =
+ tp.instantiateTypeParams(undetParams, undetParams map (_ => WildcardType))
+
+ val wildPt = approximate(pt)
+
/** Try to construct a typed tree from given implicit info with given
* expected type.
* Detect infinite search trees for implicits.
@@ -353,48 +365,56 @@ self: Analyzer =>
case _ => tp.isStable
}
- /** Replace undetParams in type `tp` by Any/Nothing, according to variance */
- def approximate(tp: Type) =
- tp.instantiateTypeParams(undetParams, undetParams map (_ => WildcardType))
-
- /** Instantiated `pt' so that undetermined type parameters are replaced by wildcards
- */
- val wildPt = approximate(pt)
-
/** Does type `tp' match expected type `pt'
* This is the case if either `pt' is a unary function type with a
* HasMethodMatching type as result, and `tp' is a unary function
* or method type whose result type has a method whose name and type
* correspond to the HasMethodMatching type,
* or otherwise if `tp' is compatible with `pt'.
+ * This methid is performance critical: 5-8% of typechecking time.
*/
def matchesPt(tp: Type, pt: Type, undet: List[Symbol]) = {
- isCompatible(tp, pt) ||
- isView && {
+ val start = startTimer(matchesPtNanos)
+ val result = normSubType(tp, pt) || isView && {
pt match {
case Function1(arg, res) =>
- normalize(tp) match {
- case Function1(arg1, res1) =>
- (arg.deconst weak_<:< arg1) && {
- res match {
- case HasMethodMatching(name, argtpes, restpe) =>
- (res1.member(name) filter (m =>
- isApplicableSafe(undet, m.tpe, argtpes, restpe))) != NoSymbol
- case _ =>
- res1 <:< res
- }
- }
- case _ => false
- }
- case _ => false
+ matchesPtView(tp, arg, res, undet)
+ case _ =>
+ false
}
}
+ stopTimer(matchesPtNanos, start)
+ result
}
- //if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+depoly(info.tpe)+"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesPt(depoly(info.tpe), wildPt, List()))
- if (isPlausiblyCompatible(info.tpe, wildPt) &&
- matchesPt(depoly(info.tpe), wildPt, List()) &&
- isStable(info.pre)) {
+ def matchesPtView(tp: Type, ptarg: Type, ptres: Type, undet: List[Symbol]): Boolean = tp match {
+ case MethodType(params, restpe) =>
+ if (tp.isInstanceOf[ImplicitMethodType]) matchesPtView(restpe, ptarg, ptres, undet)
+ else params.length == 1 && matchesArgRes(params.head.tpe, restpe, ptarg, ptres, undet)
+ case ExistentialType(tparams, qtpe) =>
+ matchesPtView(normalize(tp), ptarg, ptres, undet)
+ case Function1(arg1, res1) =>
+ matchesArgRes(arg1, res1, ptarg, ptres, undet)
+ case _ => false
+ }
+
+ def matchesArgRes(tparg: Type, tpres: Type, ptarg: Type, ptres: Type, undet: List[Symbol]): Boolean =
+ (ptarg weak_<:< tparg) && {
+ ptres match {
+ case HasMethodMatching(name, argtpes, restpe) =>
+ (tpres.member(name) filter (m =>
+ isApplicableSafe(undet, m.tpe, argtpes, restpe))) != NoSymbol
+ case _ =>
+ tpres <:< ptres
+ }
+ }
+
+ incCounter(plausiblyCompatibleImplicits)
+
+ //if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+depoly(info.tpe)+"/"+undetParams+"/"+isPlausiblyCompatible(info.tpe, wildPt)+"/"+matchesPt(depoly(info.tpe), wildPt, List())+"/"+info.pre+"/"+isStable(info.pre))
+ if (matchesPt(depoly(info.tpe), wildPt, List()) && isStable(info.pre)) {
+
+ incCounter(matchingImplicits)
val itree = atPos(tree.pos.focus) {
if (info.pre == NoPrefix) Ident(info.name)
@@ -417,6 +437,8 @@ self: Analyzer =>
else
typed1(itree, EXPRmode, wildPt)
+ incCounter(typedImplicits)
+
if (traceImplicits) println("typed implicit "+itree1+":"+itree1.tpe+", pt = "+wildPt)
val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun }
else adapt(itree1, EXPRmode, wildPt)
@@ -451,6 +473,7 @@ self: Analyzer =>
subst traverse itree2
val result = new SearchResult(itree2, subst)
+ incCounter(foundImplicits)
if (traceImplicits) println("RESULT = "+result)
// println("RESULT = "+itree+"///"+itree1+"///"+itree2)//DEBUG
result
@@ -517,6 +540,8 @@ self: Analyzer =>
isLocal: Boolean,
invalidImplicits: ListBuffer[Symbol]): Map[ImplicitInfo, SearchResult] = {
+ val start = startCounter(subtypeAppInfos)
+
/** A set containing names that are shadowed by implicit infos */
lazy val shadowed = new HashSet[Name]("shadowed", 512)
@@ -529,17 +554,21 @@ self: Analyzer =>
* @return A search result with an attributed tree containing the implicit if succeeded,
* SearchFailure if not.
*/
- def tryImplicit(info: ImplicitInfo): SearchResult =
+ def tryImplicit(info: ImplicitInfo): SearchResult = {
+ incCounter(triedImplicits)
if (info.isCyclicOrErroneous ||
(isLocal && shadowed.contains(info.name)) ||
- (isView && (info.sym == Predef_identity || info.sym == Predef_conforms)) //@M this condition prevents no-op conversions, which are a problem (besides efficiency),
+ (isView && (info.sym == Predef_identity || info.sym == Predef_conforms)) || //@M this condition prevents no-op conversions, which are a problem (besides efficiency),
+ !isPlausiblyCompatible(info.tpe, wildPt))
// TODO: remove `info.sym == Predef_identity` once we have a new STARR that only has conforms as an implicit
// one example is removeNames in NamesDefaults, which relies on the type checker failing in case of ambiguity between an assignment/named arg
- ) SearchFailure
- else typedImplicit(info)
+ SearchFailure
+ else
+ typedImplicit(info)
+ }
- def appInfos(is: List[ImplicitInfo]): Map[ImplicitInfo, SearchResult] = {
- var applicable = Map[ImplicitInfo, SearchResult]()
+ def addAppInfos(is: List[ImplicitInfo], m: Map[ImplicitInfo, SearchResult]): Map[ImplicitInfo, SearchResult] = {
+ var applicable = m
for (i <- is)
if (!isValid(i.sym)) invalidImplicits += i.sym
else {
@@ -551,7 +580,11 @@ self: Analyzer =>
applicable
}
- (Map[ImplicitInfo, SearchResult]() /: (iss map appInfos))(_ ++ _)
+ var applicable = Map[ImplicitInfo, SearchResult]()
+ for (is <- iss) applicable = addAppInfos(is, applicable)
+
+ stopCounter(subtypeAppInfos, start)
+ applicable
}
/** Search list of implicit info lists for one matching prototype
@@ -580,6 +613,8 @@ self: Analyzer =>
"\n because it comes after the application point and it lacks an explicit result type")
}
+ val start = startCounter(subtypeImprovCount)
+
/** A candidate for best applicable info wrt `improves` */
val best = (NoImplicitInfo /: applicable.keysIterator) (
(best, alt) => if (improves(alt, best)) alt else best)
@@ -589,20 +624,7 @@ self: Analyzer =>
val competing = applicable.keySet dropWhile (alt => best == alt || improves(best, alt))
if (!competing.isEmpty) ambiguousImplicitError(best, competing.head, "both", "and", "")
- // Also check that applicable infos that did not get selected are not
- // in (a companion object of) a subclass of (a companion object of) the class
- // containing the winning info.
- // (no longer needed; rules have changed)
- /*
- for (alt <- applicable.keySet) {
- if (isProperSubClassOrObject(alt.sym.owner, best.sym.owner)) {
- ambiguousImplicitError(best, alt,
- "most specific definition is:",
- "yet alternative definition ",
- "is defined in a subclass.\n Both definitions ")
- }
- }
- */
+ stopCounter(subtypeImprovCount, start)
applicable(best)
}
} // end searchImplicit
@@ -682,37 +704,88 @@ self: Analyzer =>
for ((k, ts) <- partMap.iterator.toList; t <- compactify(ts)) yield t
}
+ /** The parts of a type is the smallest set of types that contains
+ * - the type itself
+ * - the parts of its immediate components (prefix and argument)
+ * - the parts of its base types
+ */
+ private def companionImplicits(tp: Type): List[List[ImplicitInfo]] = {
+
+ val parts = new HashSet[Symbol]
+
+ /** Enter all parts of `tp` into `parts` set.
+ * This method is performance critical: about 2-4% of all type checking is spent here
+ */
+ def getParts(tp: Type) {
+ tp match {
+ case TypeRef(pre, sym, args) =>
+ if (sym.isClass) {
+ if (!((sym.name == nme.REFINE_CLASS_NAME.toTypeName) ||
+ (sym.name startsWith nme.ANON_CLASS_NAME) ||
+ (sym.name == nme.ROOT.toTypeName) ||
+ (parts.findEntry(sym) != null))) {
+ parts.addEntry(sym)
+ val bts = tp.baseTypeSeq
+ var i = 1
+ while (i < bts.length) {
+ getParts(bts(i))
+ i += 1
+ }
+ getParts(pre)
+ args foreach getParts
+ }
+ } else if (sym.isAliasType) {
+ getParts(tp.dealias)
+ } else if (sym.isAbstractType) {
+ getParts(tp.bounds.hi)
+ }
+ case ThisType(_) =>
+ getParts(tp.widen)
+ case _: SingletonType =>
+ getParts(tp.widen)
+ case RefinedType(ps, _) =>
+ for (p <- ps) getParts(p)
+ case AnnotatedType(_, t, _) =>
+ getParts(t)
+ case ExistentialType(tparams, t) =>
+ getParts(t)
+ case _ =>
+ }
+ }
+
+ getParts(tp)
+ val buf = new ListBuffer[List[ImplicitInfo]]
+ for (clazz <- parts.iterator) {
+ if (clazz.isStatic) {
+ clazz.linkedClassOfClass match {
+ case mc: ModuleClassSymbol =>
+ buf += (mc.implicitMembers map (im => new ImplicitInfo(im.name, mc.thisType, im)))
+ case _ =>
+ }
+ }
+ }
+ //println("companion implicits of "+tp+" = "+buf.toList) // DEBUG
+ buf.toList
+ }
+
/** The implicits made available by type `pt`.
* These are all implicits found in companion objects of classes C
* such that some part of `tp` has C as one of its superclasses.
*/
private def implicitsOfExpectedType: List[List[ImplicitInfo]] = implicitsCache get pt match {
- case Some(implicitInfoss) => hits += 1; implicitInfoss
- case None => {
- misses += 1
- val implicitInfoss = parts(pt).iterator.map(implicitsOfClass).toList
+ case Some(implicitInfoss) =>
+ incCounter(implicitCacheHits)
+ implicitInfoss
+ case None =>
+ incCounter(implicitCacheMisses)
+ val start = startTimer(subtypeETNanos)
+ val implicitInfoss = if (true || settings.Xexperimental.value) companionImplicits(pt)
+ else parts(pt).iterator.map(implicitsOfClass).toList
+ stopTimer(subtypeETNanos, start)
implicitsCache(pt) = implicitInfoss
if (implicitsCache.size >= sizeLimit)
implicitsCache -= implicitsCache.keysIterator.next
implicitInfoss
- }
- }
-
-
- /** The manifest corresponding to type `pt`, provided `pt` is an instance of Manifest.
- */
- private def implicitManifest(pt: Type): Tree = pt.dealias match {
- case TypeRef(_, FullManifestClass, List(arg)) =>
- manifestOfType(arg, true)
- case TypeRef(_, PartialManifestClass, List(arg)) =>
- manifestOfType(arg, false)
- case TypeRef(_, OptManifestClass, List(arg)) =>
- val itree = manifestOfType(arg, false)
- if (itree == EmptyTree) gen.mkAttributedRef(NoManifest) else itree
- case TypeRef(_, tsym, _) if (tsym.isAbstractType) =>
- implicitManifest(pt.bounds.lo)
- case _ =>
- EmptyTree
}
/** Creates a tree that calls the relevant factory method in object
@@ -804,6 +877,26 @@ self: Analyzer =>
mot(tp)
}
+ def wrapResult(tree: Tree): SearchResult =
+ if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter)
+
+ /** The manifest corresponding to type `pt`, provided `pt` is an instance of Manifest.
+ */
+ private def implicitManifestOrOfExpectedType(pt: Type): SearchResult = pt.dealias match {
+ case TypeRef(_, FullManifestClass, List(arg)) =>
+ wrapResult(manifestOfType(arg, true))
+ case TypeRef(_, PartialManifestClass, List(arg)) =>
+ wrapResult(manifestOfType(arg, false))
+ case TypeRef(_, OptManifestClass, List(arg)) =>
+ val itree = manifestOfType(arg, false)
+ wrapResult(if (itree == EmptyTree) gen.mkAttributedRef(NoManifest)
+ else itree)
+ case TypeRef(_, tsym, _) if (tsym.isAbstractType) =>
+ implicitManifestOrOfExpectedType(pt.bounds.lo)
+ case _ =>
+ searchImplicit(implicitsOfExpectedType, false)
+ }
+
/** The result of the implicit search:
* First search implicits visible in current context.
* If that fails, search implicits in expected type `pt`.
@@ -811,24 +904,34 @@ self: Analyzer =>
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
- val start = System.nanoTime()
+ val failstart = startTimer(inscopeFailNanos)
+ val succstart = startTimer(inscopeSucceedNanos)
+
var result = searchImplicit(context.implicitss, true)
- val timer1 = System.nanoTime()
- if (result == SearchFailure) inscopeFail += timer1 - start else inscopeSucceed += timer1 - start
- if (result == SearchFailure)
- result = searchImplicit(implicitsOfExpectedType, false)
- val timer2 = System.nanoTime()
- if (result == SearchFailure) oftypeFail += timer2 - timer1 else oftypeSucceed += timer2 - timer1
if (result == SearchFailure) {
- val resultTree = implicitManifest(pt)
- if (resultTree != EmptyTree) result = new SearchResult(resultTree, EmptyTreeTypeSubstituter)
+ stopTimer(inscopeFailNanos, failstart)
+ } else {
+ stopTimer(inscopeSucceedNanos, succstart)
+ incCounter(inscopeImplicitHits)
}
- val timer3 = System.nanoTime()
- if (result == SearchFailure) manifFail += timer3 - timer2 else manifSucceed += timer3 - timer2
+ if (result == SearchFailure) {
+ val failstart = startTimer(oftypeFailNanos)
+ val succstart = startTimer(oftypeSucceedNanos)
+
+ result = implicitManifestOrOfExpectedType(pt)
+
+ if (result == SearchFailure) {
+ stopTimer(oftypeFailNanos, failstart)
+ } else {
+ stopTimer(oftypeSucceedNanos, succstart)
+ incCounter(oftypeImplicitHits)
+ }
+ }
+
if (result == SearchFailure && settings.debug.value)
log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+parts(pt)+implicitsOfExpectedType)
- implicitTime += System.nanoTime() - start
+
result
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 76ff6734d4..ad2c70c9ce 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -21,11 +21,6 @@ trait Infer {
import global._
import definitions._
- // statistics
- var normM = 0
- var normP = 0
- var normO = 0
-
private final val inferInfo = false //@MDEBUG
/* -- Type parameter inference utility functions --------------------------- */
@@ -181,18 +176,17 @@ trait Infer {
* A method type becomes the corresponding function type.
* A nullary method type becomes its result type.
* Implicit parameters are skipped.
+ * This method seems to be performance critical.
*/
- def normalize(tp: Type): Type = skipImplicit(tp) match {
+ def normalize(tp: Type): Type = tp match {
case MethodType(params, restpe) if (!restpe.isDependent) =>
- if (util.Statistics.enabled) normM += 1
- functionType(params map (_.tpe), normalize(restpe))
+ if (tp.isInstanceOf[ImplicitMethodType]) normalize(restpe)
+ else functionType(params map (_.tpe), normalize(restpe))
case PolyType(List(), restpe) => // nullary method type
- if (util.Statistics.enabled) normP += 1
normalize(restpe)
case ExistentialType(tparams, qtpe) =>
ExistentialType(tparams, normalize(qtpe))
case tp1 =>
- if (util.Statistics.enabled) normO += 1
tp1 // @MAT aliases already handled by subtyping
}
@@ -401,32 +395,51 @@ trait Infer {
isPlausiblyCompatible(mt.resultType, pt)
case ExistentialType(tparams, qtpe) =>
isPlausiblyCompatible(qtpe, pt)
- case MethodType(params, _) =>
- val formals = tp.paramTypes
- pt.normalize match {
+ case MethodType(params, restpe) =>
+ if (tp.isInstanceOf[ImplicitMethodType]) isPlausiblyCompatible(restpe, pt)
+ else pt match {
case TypeRef(pre, sym, args) =>
- !sym.isClass || {
+ if (sym.isAliasType) {
+ isPlausiblyCompatible(tp, pt.dealias)
+ } else if (sym.isAbstractType) {
+ isPlausiblyCompatible(tp, pt.bounds.lo)
+ } else {
val l = args.length - 1
- l == formals.length &&
- sym == FunctionClass(l) &&
- ((args, formals).zipped forall isPlausiblySubType) &&
- isPlausiblySubType(tp.resultApprox, args.last)
+ l == params.length &&
+ sym == FunctionClass(l) && {
+ var curargs = args
+ var curparams = params
+ while (curparams.nonEmpty) {
+ if (!isPlausiblySubType(curargs.head, curparams.head.tpe))
+ return false
+ curargs = curargs.tail
+ curparams = curparams.tail
+ }
+ isPlausiblySubType(restpe, curargs.head)
+ }
}
case _ =>
- true
+ false
}
case _ =>
- true
+ isPlausiblySubType(tp, pt)
}
- private def isPlausiblySubType(tp1: Type, tp2: Type): Boolean = tp1.normalize match {
+ private def isPlausiblySubType(tp1: Type, tp2: Type): Boolean = tp1 match {
case TypeRef(_, sym1, _) =>
- !sym1.isClass || {
- tp2.normalize match {
- case TypeRef(_, sym2, _) =>
- !sym2.isClass || (sym1 isSubClass sym2) || isNumericSubType(tp1, tp2)
- case _ => true
- }
+ if (sym1.isAliasType) isPlausiblySubType(tp1.dealias, tp2)
+ else if (!sym1.isClass) true
+ else tp2 match {
+ case TypeRef(_, sym2, _) =>
+ if (sym2.isAliasType) isPlausiblySubType(tp1, tp2.dealias)
+ else if (!sym2.isClass) true
+ else if (sym1 isSubClass sym2) true
+ else
+ isNumericValueClass(sym1) &&
+ isNumericValueClass(sym2) &&
+ (sym1 == sym2 || numericWidth(sym1) < numericWidth(sym2))
+ case _ =>
+ true
}
case _ =>
true
@@ -437,6 +450,41 @@ trait Infer {
(tp1 <:< pt) || isCoercible(tp1, pt)
}
+ final def normSubType(tp: Type, pt: Type): Boolean = tp match {
+ case MethodType(params, restpe) =>
+ if (tp.isInstanceOf[ImplicitMethodType]) normSubType(restpe, pt)
+ else pt match {
+ case TypeRef(pre, sym, args) =>
+ if (sym.isAliasType) {
+ normSubType(tp, pt.dealias)
+ } else if (sym.isAbstractType) {
+ normSubType(tp, pt.bounds.lo)
+ } else {
+ val l = args.length - 1
+ l == params.length &&
+ sym == FunctionClass(l) && {
+ var curargs = args
+ var curparams = params
+ while (curparams.nonEmpty) {
+ if (!(curargs.head <:< curparams.head.tpe))
+ return false
+ curargs = curargs.tail
+ curparams = curparams.tail
+ }
+ normSubType(restpe, curargs.head)
+ }
+ }
+ case _ =>
+ tp <:< pt
+ }
+ case PolyType(List(), restpe) => // nullary method type
+ normSubType(restpe, pt)
+ case ExistentialType(tparams, qtpe) =>
+ normalize(tp) <:< pt
+ case _ =>
+ tp <:< pt
+ }
+
def isCompatibleArg(tp: Type, pt: Type): Boolean = {
val tp1 = normalize(tp)
(tp1 weak_<:< pt) || isCoercible(tp1, pt)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 0e756308c3..3611b32ba6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -13,11 +13,12 @@ package typechecker
import scala.collection.mutable.{HashMap, ListBuffer}
import scala.util.control.ControlException
-import scala.compat.Platform.currentTime
import scala.tools.nsc.interactive.RangePositions
import scala.tools.nsc.util.{ Position, Set, NoPosition, SourceFile, BatchSourceFile }
import symtab.Flags._
+import util.Statistics._
+
// Suggestion check whether we can do without priming scopes with symbols of outer scopes,
// like the IDE does.
/** This trait provides methods to assign types to trees.
@@ -29,16 +30,6 @@ trait Typers { self: Analyzer =>
import global._
import definitions._
- var appcnt = 0
- var idcnt = 0
- var selcnt = 0
- var implcnt = 0
- var impltime = 0l
-
- var failedApplies = 0L
- var failedOpEqs = 0L
- var failedSilent = 0L
-
// namer calls typer.computeType(rhs) on DefDef / ValDef when tpt is empty. the result
// is cached here and re-used in typedDefDef / typedValDef
private val transformed = new HashMap[Tree, Tree]
@@ -46,6 +37,8 @@ trait Typers { self: Analyzer =>
// currently not used at all (March 09)
private val superDefs = new HashMap[Symbol, ListBuffer[Tree]]
+ final val shortenImports = false
+
def resetTyper() {
resetContexts
resetNamer()
@@ -708,28 +701,35 @@ trait Typers { self: Analyzer =>
}
def silent[T](op: Typer => T): Any /* in fact, TypeError or T */ = {
-// val start = System.nanoTime()
+ val rawTypeStart = startCounter(rawTypeFailed)
+ val findMemberStart = startCounter(findMemberFailed)
+ val subtypeStart = startCounter(subtypeFailed)
+ val failedSilentStart = startTimer(failedSilentNanos)
try {
- if (context.reportGeneralErrors) {
- val context1 = context.makeSilent(context.reportAmbiguousErrors)
- context1.undetparams = context.undetparams
- context1.savedTypeBounds = context.savedTypeBounds
- context1.namedApplyBlockInfo = context.namedApplyBlockInfo
- val typer1 = newTyper(context1)
- val result = op(typer1)
- context.undetparams = context1.undetparams
- context.savedTypeBounds = context1.savedTypeBounds
- context.namedApplyBlockInfo = context1.namedApplyBlockInfo
- result
- } else {
- op(this)
+ if (context.reportGeneralErrors) {
+ val context1 = context.makeSilent(context.reportAmbiguousErrors)
+ context1.undetparams = context.undetparams
+ context1.savedTypeBounds = context.savedTypeBounds
+ context1.namedApplyBlockInfo = context.namedApplyBlockInfo
+ val typer1 = newTyper(context1)
+ val result = op(typer1)
+ context.undetparams = context1.undetparams
+ context.savedTypeBounds = context1.savedTypeBounds
+ context.namedApplyBlockInfo = context1.namedApplyBlockInfo
+ result
+ } else {
+ op(this)
+ }
+ } catch {
+ case ex: CyclicReference => throw ex
+ case ex: TypeError =>
+ stopCounter(rawTypeFailed, rawTypeStart)
+ stopCounter(findMemberFailed, findMemberStart)
+ stopCounter(subtypeFailed, subtypeStart)
+ stopTimer(failedSilentNanos, failedSilentStart)
+ ex
}
- } catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError =>
-// failedSilent += System.nanoTime() - start
- ex
- }}
+ }
/** Utility method: Try op1 on tree. If that gives an error try op2 instead.
*/
@@ -1233,7 +1233,8 @@ trait Typers { self: Analyzer =>
if (!(selfType <:< parent.tpe.typeOfThis) &&
!phase.erasedTypes &&
!(context.owner hasFlag SYNTHETIC) && // don't do this check for synthetic concrete classes for virtuals (part of DEVIRTUALIZE)
- !(settings.suppressVTWarn.value))
+ !(settings.suppressVTWarn.value) &&
+ !selfType.isErroneous && !parent.tpe.isErroneous)
{
//Console.println(context.owner);//DEBUG
//Console.println(context.owner.unsafeTypeParams);//DEBUG
@@ -3261,12 +3262,12 @@ trait Typers { self: Analyzer =>
* insert an implicit conversion.
*/
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
- val start = System.nanoTime()
+ val start = startTimer(failedApplyNanos)
silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
case t: Tree =>
t
case ex: TypeError =>
- failedApplies += System.nanoTime() - start
+ stopTimer(failedApplyNanos, start)
def errorInResult(tree: Tree): Boolean = tree.pos == ex.pos || {
tree match {
case Block(_, r) => errorInResult(r)
@@ -3305,11 +3306,12 @@ trait Typers { self: Analyzer =>
typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
} else {
val funpt = if ((mode & PATTERNmode) != 0) pt else WildcardType
- val start = System.nanoTime()
+ val appStart = startTimer(failedApplyNanos)
+ val opeqStart = startTimer(failedOpEqNanos)
silent(_.typed(fun, funMode(mode), funpt)) match {
case fun1: Tree =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
- if (util.Statistics.enabled) appcnt += 1
+ incCounter(typedApplyCount)
val res =
if (phase.id <= currentRun.typerPhase.id &&
fun2.isInstanceOf[Select] &&
@@ -3338,14 +3340,15 @@ trait Typers { self: Analyzer =>
else res
*/
case ex: TypeError =>
- failedOpEqs += System.nanoTime() - start
fun match {
case Select(qual, name)
if (mode & PATTERNmode) == 0 && nme.isOpAssignmentName(name.decode) =>
val qual1 = typedQualifier(qual)
if (treeInfo.isVariableOrGetter(qual1)) {
+ stopTimer(failedOpEqNanos, opeqStart)
convertToAssignment(fun, qual1, name, args, ex)
} else {
+ stopTimer(failedApplyNanos, appStart)
if ((qual1.symbol ne null) && qual1.symbol.isValue)
error(tree.pos, "reassignment to val")
else
@@ -3353,6 +3356,7 @@ trait Typers { self: Analyzer =>
setError(tree)
}
case _ =>
+ stopTimer(failedApplyNanos, appStart)
reportTypeError(fun.pos, ex)
setError(tree)
}
@@ -3644,7 +3648,9 @@ trait Typers { self: Analyzer =>
imports1 = imports1.tail
}
defSym = impSym
- qual = atPos(tree.pos.focusStart)(resetPos(imports.head.qual.duplicate))
+ val qual0 = imports.head.qual
+ if (!(shortenImports && qual0.symbol.isPackage)) // optimization: don't write out package prefixes
+ qual = atPos(tree.pos.focusStart)(resetPos(qual0.duplicate))
pre = qual.tpe
} else {
if (settings.debug.value) {
@@ -3970,7 +3976,7 @@ trait Typers { self: Analyzer =>
typedSelect(qual1, nme.CONSTRUCTOR)
case Select(qual, name) =>
- if (util.Statistics.enabled) selcnt += 1
+ incCounter(typedSelectCount)
var qual1 = checkDead(typedQualifier(qual, mode))
if (name.isTypeName) qual1 = checkStable(qual1)
@@ -3998,7 +4004,7 @@ trait Typers { self: Analyzer =>
else tree1
case Ident(name) =>
- if (util.Statistics.enabled) idcnt += 1
+ incCounter(typedIdentCount)
if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
(name == nme.WILDCARD.toTypeName && (mode & TYPEmode) != 0))
tree setType makeFullyDefined(pt)
diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala
index e9e9f65058..316313831f 100644
--- a/src/compiler/scala/tools/nsc/util/Statistics.scala
+++ b/src/compiler/scala/tools/nsc/util/Statistics.scala
@@ -9,56 +9,223 @@ package scala.tools.nsc
package util
object Statistics {
+
var enabled = false
+ var phasesShown = List("typer", "erasure", "cleanup")
+
+ def currentTime() =
+ if (enabled) System.nanoTime() else 0L
+
+ private def showPercent(x: Double, base: Double) =
+ if (base == 0) "" else " ("+"%2.1f".format(x / base * 100)+")"
+
+ def incCounter(c: Counter) {
+ if (enabled) c.value += 1
+ }
+
+ def incCounter(c: Counter, delta: Int) {
+ if (enabled) c.value += delta
+ }
+
+ def startCounter(sc: SubCounter): IntPair =
+ if (enabled) sc.start() else null
+
+ def stopCounter(sc: SubCounter, start: IntPair) {
+ if (enabled) sc.stop(start)
+ }
+
+ def startTimer(tm: Timer): LongPair =
+ if (enabled) tm.start() else null
+
+ def stopTimer(tm: Timer, start: LongPair) {
+ if (enabled) tm.stop(start)
+ }
+
+ case class IntPair(x: Int, y: Int)
+ case class LongPair(x: Long, y: Long)
+
+ class Counter {
+ var value: Int = 0
+ override def toString = value.toString
+ }
+
+ class SubCounter(c: Counter) {
+ var value: Int = 0
+ def start(): IntPair =
+ if (enabled) IntPair(value, c.value) else null
+ def stop(prev: IntPair) {
+ if (enabled) {
+ val IntPair(value0, cvalue0) = prev
+ value = value0 + c.value - cvalue0
+ }
+ }
+ override def toString =
+ value+showPercent(value, c.value)
+ }
+
+ class Timer {
+ var nanos: Long = 0L
+ def start(): LongPair =
+ if (enabled) LongPair(nanos, System.nanoTime()) else null
+ def stop(prev: LongPair) {
+ if (enabled) {
+ val LongPair(nanos0, start) = prev
+ nanos = nanos0 + System.nanoTime() - start
+ }
+ }
+ override def toString = nanos.toString+"ns"
+ }
+
+ class ClassCounts extends scala.collection.mutable.HashMap[Class[_], Int] {
+ override def default(key: Class[_]) = 0
+ }
+
+ var nodeByType = new ClassCounts
+
+ val singletonBaseTypeSeqCount = new Counter
+ val compoundBaseTypeSeqCount = new Counter
+ val typerefBaseTypeSeqCount = new Counter
+ val findMemberCount = new Counter
+ val noMemberCount = new Counter
+ val multMemberCount = new Counter
+ val findMemberNanos = new Timer
+ val asSeenFromCount = new Counter
+ val asSeenFromNanos = new Timer
+ val subtypeCount = new Counter
+ val subtypeNanos = new Timer
+ val sametypeCount = new Counter
+ val rawTypeCount = new Counter
+ val rawTypeFailed = new SubCounter(rawTypeCount)
+ val findMemberFailed = new SubCounter(findMemberCount)
+ val subtypeFailed = new SubCounter(subtypeCount)
+ val rawTypeImpl = new SubCounter(rawTypeCount)
+ val findMemberImpl = new SubCounter(findMemberCount)
+ val subtypeImpl = new SubCounter(subtypeCount)
+ val baseTypeSeqCount = new Counter
+ val baseTypeSeqLenTotal = new Counter
+ val typeSymbolCount = new Counter
+ val classSymbolCount = new Counter
+ val typedApplyCount = new Counter
+ val typedIdentCount = new Counter
+ val typedSelectCount = new Counter
+ val typerNanos = new Timer
+ val classReadNanos = new Timer
+
+ val failedApplyNanos = new Timer
+ val failedOpEqNanos = new Timer
+ val failedSilentNanos = new Timer
+
+ val implicitSearchCount = new Counter
+ val implicitNanos = new Timer
+ val oftypeImplicitHits = new Counter
+ val inscopeImplicitHits = new Counter
+
+ val triedImplicits = new Counter
+ val plausiblyCompatibleImplicits = new Counter
+ val matchingImplicits = new Counter
+ val typedImplicits = new Counter
+ val foundImplicits = new Counter
+
+ val inscopeSucceedNanos = new Timer
+ val inscopeFailNanos = new Timer
+ val oftypeSucceedNanos = new Timer
+ val oftypeFailNanos = new Timer
+ val implicitCacheHits = new Counter
+ val implicitCacheMisses = new Counter
+ val improvesCount = new Counter
+ val subtypeAppInfos = new SubCounter(subtypeCount)
+ val subtypeImprovCount = new SubCounter(subtypeCount)
+ val subtypeETNanos = new Timer
+ val matchesPtNanos = new Timer
}
abstract class Statistics {
+ import Statistics._
+
val global: Global
import global._
- def showRelative(base: Long)(time: Long) = "%2.1f".format(time.toDouble / base * 100)+" / "+time+"ns"
- def showRelTyper(time: Long) = showRelative(analyzer.typerTime)(time)
+ def countNodes(tree: Tree, counts: ClassCounts) {
+ for (t <- tree) counts(t.getClass) += 1
+ counts
+ }
+
+ def showRelative(base: Long)(value: Long) =
+ value+showPercent(value, base)
- def print(phase: Phase) = {
- if (List("typer", "erasure", "cleanup") contains phase.name) {
+ def showRelTyper(timer: Timer) = showRelative(typerNanos.nanos)(timer.nanos)
+
+ def showCounts(counts: ClassCounts) =
+ counts.toSeq.sortWith(_._2 > _._2).map {
+ case (cls, cnt) =>
+ cls.toString.substring(cls.toString.lastIndexOf("$") + 1)+": "+cnt
+ }
+
+ def print(phase: Phase) = if (phasesShown contains phase.name) {
+ if (phase.name == "parser") {
inform("*** Cumulative statistics at phase " + phase)
- inform("#tree nodes : " + nodeCount)
- inform("#identifiers : " + analyzer.idcnt)
- inform("#selections : " + analyzer.selcnt)
- inform("#applications: " + analyzer.appcnt)
- inform("#implicits : " + analyzer.implcnt)
- inform("#uniquetypes : " + uniqueTypeCount)
- inform("#symbols : " + symbolCount)
- inform("#type symbols: " + typeSymbolCount)
- inform("#class symbols: " + classSymbolCount)
- inform("#singleton closures: " + singletonBaseTypeSeqCount)
- inform("#compound closures : " + compoundBaseTypeSeqCount)
- inform("#typeref closures : " + typerefBaseTypeSeqCount)
- inform("#findMember : " + findMemberCount)
- inform("#notfound member: " + noMemberCount)
- inform("#multiple member: " + multMemberCount)
- inform("time findMember: " + findMemberNanos)
- inform("#norm meth : " + analyzer.normM)
- inform("#norm poly : " + analyzer.normP)
- inform("#norm other : " + analyzer.normO)
- inform("#subtype : " + subtypeCount)
- inform("ns subtype : " + subtypeNanos)
- inform("#sametype : " + sametypeCount)
+ inform("#created tree nodes : " + nodeCount)
+ inform("#created tree nodes by type: "+showCounts(nodeByType))
+ } else {
+ inform("*** Cumulative statistics at phase " + phase)
+ inform("#created tree nodes : " + nodeCount)
+ inform("#created tree nodes by type: "+showCounts(nodeByType))
+ val counts = new ClassCounts
+ for (u <- currentRun.units; t <- u.body) counts(t.getClass) += 1
+ inform("#retained nodes : " + counts.valuesIterable.sum)
+ inform("#retained nodes by type : " + showCounts(counts))
+ inform("#typechecked identifiers : " + typedIdentCount)
+ inform("#typechecked selections : " + typedSelectCount)
+ inform("#typechecked applications: " + typedApplyCount)
+ inform("#raw type creations : " + rawTypeCount)
+ inform(" of which failed : " + rawTypeFailed)
+ inform(" of which implicits : " + rawTypeImpl)
+ inform("#unique types : " + uniqueTypeCount)
+ inform("#symbols : " + symbolCount)
+ inform(" of which type symbols : " + typeSymbolCount)
+ inform(" of which class symbols : " + classSymbolCount)
+ inform("#base type seqs : " + baseTypeSeqCount)
+ inform("avg base type seq length : " + baseTypeSeqLenTotal.value.toFloat / baseTypeSeqCount.value)
+ inform("#singleton base type seqs: " + singletonBaseTypeSeqCount)
+ inform("#compound base type seqs : " + compoundBaseTypeSeqCount)
+ inform("#typeref base type seqs : " + typerefBaseTypeSeqCount)
+ inform("#findMember ops : " + findMemberCount)
+ inform(" of which failed : " + findMemberFailed)
+ inform(" of which implicits : " + findMemberImpl)
+ inform("#notfound member : " + noMemberCount)
+ inform("#multiple member : " + multMemberCount)
+ inform("#asSeenFrom ops : " + asSeenFromCount)
+ inform("#subtype : " + subtypeCount)
+ inform(" of which failed : " + subtypeFailed)
+ inform(" of which implicits : " + subtypeImpl)
+ inform(" of which app impl : " + subtypeAppInfos)
+ inform(" of which improv : " + subtypeImprovCount)
+ inform("#sametype : " + sametypeCount)
inform("ms type-flow-analysis: " + analysis.timer.millis)
+
if (phase.name == "typer") {
- inform("time spent typechecking: "+showRelTyper(analyzer.typerTime))
- inform("time spent in implicits: "+showRelTyper(analyzer.implicitTime))
- inform(" successful in scope: "+showRelTyper(analyzer.inscopeSucceed))
- inform(" failed in scope: "+showRelTyper(analyzer.inscopeFail))
- inform(" successful of type: "+showRelTyper(analyzer.oftypeSucceed))
- inform(" failed of type: "+showRelTyper(analyzer.oftypeFail))
- inform(" successful manifest: "+showRelTyper(analyzer.manifSucceed))
- inform(" failed manifest: "+showRelTyper(analyzer.manifFail))
- inform("implicit cache hitratio: "+"%2.1f".format(analyzer.hits.toDouble / (analyzer.hits + analyzer.misses) * 100))
- inform("time spent in failed : "+showRelTyper(analyzer.failedSilent))
- inform(" failed op= : "+showRelTyper(analyzer.failedOpEqs))
- inform(" failed apply : "+showRelTyper(analyzer.failedApplies))
+ inform("time spent typechecking: "+showRelTyper(typerNanos))
+ inform("time classfilereading : "+showRelTyper(classReadNanos))
+ inform("time spent in implicits: "+showRelTyper(implicitNanos))
+ inform(" successful in scope: "+showRelTyper(inscopeSucceedNanos))
+ inform(" failed in scope: "+showRelTyper(inscopeFailNanos))
+ inform(" successful of type: "+showRelTyper(oftypeSucceedNanos))
+ inform(" failed of type: "+showRelTyper(oftypeFailNanos))
+ inform(" assembling parts: "+showRelTyper(subtypeETNanos))
+ inform(" matchesPT: "+showRelTyper(matchesPtNanos))
+ inform("implicit cache hits : "+showRelative(implicitCacheHits.value + implicitCacheMisses.value)(implicitCacheHits.value))
+ inform("time spent in failed : "+showRelTyper(failedSilentNanos))
+ inform(" failed apply : "+showRelTyper(failedApplyNanos))
+ inform(" failed op= : "+showRelTyper(failedOpEqNanos))
+ inform("time spent in <:< : "+showRelTyper(subtypeNanos))
+ inform("time spent in findmember: "+showRelTyper(findMemberNanos))
+ inform("time spent in asSeenFrom: "+showRelTyper(asSeenFromNanos))
+ inform("#implicit searches : " + implicitSearchCount)
+ inform("#tried, plausible, matching, typed, found implicits: "+triedImplicits+", "+plausiblyCompatibleImplicits+", "+matchingImplicits+", "+typedImplicits+", "+foundImplicits)
+ inform("#implicit improves tests : " + improvesCount)
+ inform("#implicit inscope hits : " + inscopeImplicitHits)
+ inform("#implicit oftype hits : " + oftypeImplicitHits)
}
//for (t <- uniques.iterator) println("unique: "+t)
}