summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala156
1 files changed, 87 insertions, 69 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index c43d9c8788..f29f6fa7a3 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()
@@ -545,6 +538,24 @@ trait Typers { self: Analyzer =>
final val xtypes = false
+ /** Is symbol defined and not stale?
+ */
+ def reallyExists(sym: Symbol) = {
+ if (isStale(sym)) sym.setInfo(NoType)
+ sym.exists
+ }
+
+ /** A symbol is stale if it is toplevel, to be loaded from a classfile, and
+ * the classfile is produced from a sourcefile which is compiled in the current run.
+ */
+ def isStale(sym: Symbol): Boolean = {
+ sym.rawInfo.isInstanceOf[loaders.ClassfileLoader] && {
+ sym.rawInfo.load(sym)
+ (sym.sourceFile ne null) &&
+ (currentRun.compiledFiles contains sym.sourceFile)
+ }
+ }
+
/** Does the context of tree <code>tree</code> require a stable type?
*/
private def isStableContext(tree: Tree, mode: Int, pt: Type) =
@@ -674,7 +685,7 @@ trait Typers { self: Analyzer =>
case Select(qual, _) => qual.tpe
case _ => NoPrefix
}
- if (tree.tpe.isInstanceOf[MethodType] && pre.isStable && sym.tpe.paramTypes.isEmpty &&
+ if (tree.tpe.isInstanceOf[MethodType] && pre.isStable && sym.tpe.params.isEmpty &&
(isStableContext(tree, mode, pt) || sym.isModule))
tree.setType(MethodType(List(), singleType(pre, sym)))
else tree
@@ -690,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.
*/
@@ -802,7 +820,7 @@ trait Typers { self: Analyzer =>
if (!context.undetparams.isEmpty/* && (mode & POLYmode) == 0 disabled to make implicits in new collection work; we should revisit this. */) { // (9)
// println("adapt IMT: "+(context.undetparams, pt)) //@MDEBUG
context.undetparams = inferExprInstance(
- tree, context.extractUndetparams(), pt, mt.paramTypes exists isManifest)
+ tree, context.extractUndetparams(), pt, mt.params exists (p => isManifest(p.tpe)))
// if we are looking for a manifest, instantiate type to Nothing anyway,
// as we would get amnbiguity errors otherwise. Example
// Looking for a manifest of Nil: This mas many potential types,
@@ -895,7 +913,7 @@ trait Typers { self: Analyzer =>
case _ => TypeTree(tree.tpe) setOriginal(tree)
}
} else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) { // (5)
- val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists)
+ val extractor = tree.symbol.filter(sym => reallyExists(unapplyMember(sym.tpe)))
if (extractor != NoSymbol) {
tree setSymbol extractor
val unapply = unapplyMember(extractor.tpe)
@@ -1215,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
@@ -1558,11 +1577,11 @@ trait Typers { self: Analyzer =>
def decompose(call: Tree): (Tree, List[Tree]) = call match {
case Apply(fn, args) =>
val (superConstr, args1) = decompose(fn)
- val formals = fn.tpe.paramTypes
- val args2 = if (formals.isEmpty || !isRepeatedParamType(formals.last)) args
- else args.take(formals.length - 1) ::: List(EmptyTree)
- if (args2.length != formals.length)
- assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug
+ val params = fn.tpe.params
+ val args2 = if (params.isEmpty || !isRepeatedParamType(params.last.tpe)) args
+ else args.take(params.length - 1) ::: List(EmptyTree)
+ if (args2.length != params.length)
+ assert(false, "mismatch " + clazz + " " + (params map (_.tpe)) + " " + args2);//debug
(superConstr, args1 ::: args2)
case Block(stats, expr) if !stats.isEmpty =>
decompose(stats.last)
@@ -1655,11 +1674,11 @@ trait Typers { self: Analyzer =>
while (cx != NoContext) {
val pre = cx.enclClass.prefix
val defEntry = cx.scope.lookupEntry(name)
- if ((defEntry ne null) && defEntry.sym.exists)
+ if ((defEntry ne null) && reallyExists(defEntry.sym))
return Some(defEntry.sym)
cx = cx.enclClass
- (pre member name filter (sym => sym.exists && context.isAccessible(sym, pre, false))) match {
+ (pre member name filter (sym => reallyExists(sym) && context.isAccessible(sym, pre, false))) match {
case NoSymbol => cx = cx.outer
case other => return Some(other)
}
@@ -1807,8 +1826,6 @@ trait Typers { self: Analyzer =>
transformedOrTyped(ddef.rhs, tpt1.tpe)
}
- checkMethodStructuralCompatible(meth)
-
if (meth.isPrimaryConstructor && meth.isClassConstructor &&
phase.id <= currentRun.typerPhase.id && !reporter.hasErrors)
computeParamAliases(meth.owner, vparamss1, rhs1)
@@ -2158,7 +2175,7 @@ trait Typers { self: Analyzer =>
def typedArgs(args: List[Tree], mode: Int, originalFormals: List[Type], adaptedFormals: List[Type]) = {
def newmode(i: Int) =
- if (isVarArgs(originalFormals) && i >= originalFormals.length - 1) STARmode else 0
+ if (isVarArgTpes(originalFormals) && i >= originalFormals.length - 1) STARmode else 0
for (((arg, formal), i) <- (args zip adaptedFormals).zipWithIndex) yield
typedArg(arg, mode, newmode(i), formal)
@@ -2194,14 +2211,6 @@ trait Typers { self: Analyzer =>
def isNamedApplyBlock(tree: Tree) =
context.namedApplyBlockInfo exists (_._1 == tree)
- /**
- * @param tree ...
- * @param fun0 ...
- * @param args ...
- * @param mode ...
- * @param pt ...
- * @return ...
- */
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
var fun = fun0
if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) {
@@ -2262,8 +2271,9 @@ trait Typers { self: Analyzer =>
doTypedApply(tree, adapt(fun, funMode(mode), WildcardType), args1, mode, pt)
case mt @ MethodType(params, _) =>
+ val paramTypes = mt.paramTypes
// repeat vararg as often as needed, remove by-name
- val formals = formalTypes(mt.paramTypes, args.length)
+ val formals = formalTypes(paramTypes, args.length)
/** Try packing all arguments into a Tuple and apply `fun'
* to that. This is the last thing which is tried (after
@@ -2364,7 +2374,7 @@ trait Typers { self: Analyzer =>
} else {
val tparams = context.extractUndetparams()
if (tparams.isEmpty) { // all type params are defined
- val args1 = typedArgs(args, argMode(fun, mode), mt.paramTypes, formals)
+ val args1 = typedArgs(args, argMode(fun, mode), paramTypes, formals)
val restpe = mt.resultType(args1 map (_.tpe)) // instantiate dependent method types
def ifPatternSkipFormals(tp: Type) = tp match {
case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp
@@ -3243,12 +3253,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)
@@ -3287,11 +3297,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] &&
@@ -3320,14 +3331,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
@@ -3335,6 +3347,7 @@ trait Typers { self: Analyzer =>
setError(tree)
}
case _ =>
+ stopTimer(failedApplyNanos, appStart)
reportTypeError(fun.pos, ex)
setError(tree)
}
@@ -3467,7 +3480,7 @@ trait Typers { self: Analyzer =>
val qual1 = adaptToName(qual, name)
if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt)
}
- if (!sym.exists) {
+ if (!reallyExists(sym)) {
if (settings.debug.value) Console.err.println("qual = "+qual+":"+qual.tpe+"\nSymbol="+qual.tpe.termSymbol+"\nsymbol-info = "+qual.tpe.termSymbol.info+"\nscope-id = "+qual.tpe.termSymbol.info.decls.hashCode()+"\nmembers = "+qual.tpe.members+"\nname = "+name+"\nfound = "+sym+"\nowner = "+context.enclClass.owner)
if (!qual.tpe.widen.isErroneous) {
error(tree.pos,
@@ -3534,12 +3547,15 @@ trait Typers { self: Analyzer =>
var pre: Type = NoPrefix // the prefix type of defSym, if a class member
var qual: Tree = EmptyTree // the qualififier tree if transformed tree is a select
- // if we are in a constructor of a pattern, ignore all definitions
+ // A symbol qualifies if it exists and is not stale. Stale symbols
+ // are made to disappear here. In addition,
+ // if we are in a constructor of a pattern, we ignore all definitions
// which are methods (note: if we don't do that
// case x :: xs in class List would return the :: method).
- def qualifies(sym: Symbol): Boolean =
- sym.exists &&
+ def qualifies(sym: Symbol): Boolean = {
+ reallyExists(sym) &&
((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod)
+ }
if (defSym == NoSymbol) {
var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope
@@ -3569,7 +3585,7 @@ trait Typers { self: Analyzer =>
else cx.depth - (cx.scope.nestingLevel - defEntry.owner.nestingLevel)
var impSym: Symbol = NoSymbol; // the imported symbol
var imports = context.imports; // impSym != NoSymbol => it is imported from imports.head
- while (!impSym.exists && !imports.isEmpty && imports.head.depth > symDepth) {
+ while (!reallyExists(impSym) && !imports.isEmpty && imports.head.depth > symDepth) {
impSym = imports.head.importedSymbol(name)
if (!impSym.exists) imports = imports.tail
}
@@ -3611,7 +3627,7 @@ trait Typers { self: Analyzer =>
(!imports.head.isExplicitImport(name) ||
imports1.head.depth == imports.head.depth)) {
var impSym1 = imports1.head.importedSymbol(name)
- if (impSym1.exists) {
+ if (reallyExists(impSym1)) {
if (imports1.head.isExplicitImport(name)) {
if (imports.head.isExplicitImport(name) ||
imports1.head.depth != imports.head.depth) ambiguousImport()
@@ -3623,7 +3639,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) {
@@ -3949,7 +3967,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)
@@ -3977,7 +3995,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)