summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala173
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala159
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala777
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala643
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala85
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala312
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala58
-rw-r--r--src/compiler/scala/tools/nsc/transform/TypingTransformers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala71
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala70
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala31
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala29
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala1424
-rwxr-xr-xsrc/library/scala/collection/LinearSeqOptimized.scala13
-rw-r--r--src/library/scala/collection/TraversableLike.scala18
-rw-r--r--src/library/scala/collection/immutable/List.scala10
-rw-r--r--src/library/scala/collection/mutable/Builder.scala20
-rw-r--r--src/library/scala/util/hashing/MurmurHash3.scala20
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala23
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Importers.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Names.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala9
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala31
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala161
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala591
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala15
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala4
-rw-r--r--src/reflect/scala/reflect/internal/util/Statistics.scala22
-rw-r--r--src/reflect/scala/reflect/internal/util/ThreeValues.scala14
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala11
-rw-r--r--src/reflect/scala/tools/nsc/io/ZipArchive.scala27
-rw-r--r--test/files/pos/specializes-sym-crash.scala26
41 files changed, 2835 insertions, 2096 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index b703a90ebf..085ce82025 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -50,7 +50,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
/** Array selection <qualifier> . <name> only used during erasure */
case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type)
- extends TermTree with RefTree
+ extends RefTree with TermTree
/** Derived value class injection (equivalent to: new C(arg) after easure); only used during erasure
* The class C is stored as the symbol of the tree node.
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index cbe9d96e4d..17bea7f796 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1302,23 +1302,25 @@ self =>
placeholderParams = placeholderParams ::: savedPlaceholderParams
res
}
+
- def expr0(location: Int): Tree = in.token match {
+ def expr0(location: Int): Tree = (in.token: @scala.annotation.switch) match {
case IF =>
- atPos(in.skipToken()) {
+ def parseIf = atPos(in.skipToken()) {
val cond = condExpr()
newLinesOpt()
val thenp = expr()
val elsep = if (in.token == ELSE) { in.nextToken(); expr() }
- else Literal(Constant())
+ else Literal(Constant())
If(cond, thenp, elsep)
}
+ parseIf
case TRY =>
- atPos(in.skipToken()) {
+ def parseTry = atPos(in.skipToken()) {
val body = in.token match {
- case LBRACE => inBracesOrUnit(block())
- case LPAREN => inParensOrUnit(expr())
- case _ => expr()
+ case LBRACE => inBracesOrUnit(block())
+ case LPAREN => inParensOrUnit(expr())
+ case _ => expr()
}
def catchFromExpr() = List(makeCatchFromExpr(expr()))
val catches: List[CaseDef] =
@@ -1332,32 +1334,39 @@ self =>
}
}
val finalizer = in.token match {
- case FINALLY => in.nextToken() ; expr()
- case _ => EmptyTree
+ case FINALLY => in.nextToken(); expr()
+ case _ => EmptyTree
}
Try(body, catches, finalizer)
}
+ parseTry
case WHILE =>
- val start = in.offset
- atPos(in.skipToken()) {
- val lname: Name = freshTermName(nme.WHILE_PREFIX)
- val cond = condExpr()
- newLinesOpt()
- val body = expr()
- makeWhile(lname, cond, body)
+ def parseWhile = {
+ val start = in.offset
+ atPos(in.skipToken()) {
+ val lname: Name = freshTermName(nme.WHILE_PREFIX)
+ val cond = condExpr()
+ newLinesOpt()
+ val body = expr()
+ makeWhile(lname, cond, body)
+ }
}
+ parseWhile
case DO =>
- val start = in.offset
- atPos(in.skipToken()) {
- val lname: Name = freshTermName(nme.DO_WHILE_PREFIX)
- val body = expr()
- if (isStatSep) in.nextToken()
- accept(WHILE)
- val cond = condExpr()
- makeDoWhile(lname, body, cond)
+ def parseDo = {
+ val start = in.offset
+ atPos(in.skipToken()) {
+ val lname: Name = freshTermName(nme.DO_WHILE_PREFIX)
+ val body = expr()
+ if (isStatSep) in.nextToken()
+ accept(WHILE)
+ val cond = condExpr()
+ makeDoWhile(lname, body, cond)
+ }
}
+ parseDo
case FOR =>
- atPos(in.skipToken()) {
+ def parseFor = atPos(in.skipToken()) {
val enums =
if (in.token == LBRACE) inBracesOrNil(enumerators())
else inParensOrNil(enumerators())
@@ -1369,70 +1378,78 @@ self =>
makeFor(enums, expr())
}
}
+ parseFor
case RETURN =>
- atPos(in.skipToken()) {
- Return(if (isExprIntro) expr() else Literal(Constant()))
- }
+ def parseReturn =
+ atPos(in.skipToken()) {
+ Return(if (isExprIntro) expr() else Literal(Constant()))
+ }
+ parseReturn
case THROW =>
- atPos(in.skipToken()) {
- Throw(expr())
- }
+ def parseThrow =
+ atPos(in.skipToken()) {
+ Throw(expr())
+ }
+ parseThrow
case IMPLICIT =>
implicitClosure(in.skipToken(), location)
case _ =>
- var t = postfixExpr()
- if (in.token == EQUALS) {
- t match {
- case Ident(_) | Select(_, _) | Apply(_, _) =>
- t = atPos(t.pos.startOrPoint, in.skipToken()) { makeAssign(t, expr()) }
- case _ =>
- }
- } else if (in.token == COLON) {
- t = stripParens(t)
- val colonPos = in.skipToken()
- if (in.token == USCORE) {
- //todo: need to handle case where USCORE is a wildcard in a type
- val uscorePos = in.skipToken()
- if (isIdent && in.name == nme.STAR) {
- in.nextToken()
- t = atPos(t.pos.startOrPoint, colonPos) {
- Typed(t, atPos(uscorePos) { Ident(tpnme.WILDCARD_STAR) })
- }
- } else {
- syntaxErrorOrIncomplete("`*' expected", true)
+ def parseOther = {
+ var t = postfixExpr()
+ if (in.token == EQUALS) {
+ t match {
+ case Ident(_) | Select(_, _) | Apply(_, _) =>
+ t = atPos(t.pos.startOrPoint, in.skipToken()) { makeAssign(t, expr()) }
+ case _ =>
}
- } else if (in.token == AT) {
- t = (t /: annotations(skipNewLines = false)) (makeAnnotated)
- } else {
- t = atPos(t.pos.startOrPoint, colonPos) {
- val tpt = typeOrInfixType(location)
- if (isWildcard(t))
- (placeholderParams: @unchecked) match {
- case (vd @ ValDef(mods, name, _, _)) :: rest =>
- placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest
+ } else if (in.token == COLON) {
+ t = stripParens(t)
+ val colonPos = in.skipToken()
+ if (in.token == USCORE) {
+ //todo: need to handle case where USCORE is a wildcard in a type
+ val uscorePos = in.skipToken()
+ if (isIdent && in.name == nme.STAR) {
+ in.nextToken()
+ t = atPos(t.pos.startOrPoint, colonPos) {
+ Typed(t, atPos(uscorePos) { Ident(tpnme.WILDCARD_STAR) })
}
- // this does not correspond to syntax, but is necessary to
- // accept closures. We might restrict closures to be between {...} only.
- Typed(t, tpt)
+ } else {
+ syntaxErrorOrIncomplete("`*' expected", true)
+ }
+ } else if (in.token == AT) {
+ t = (t /: annotations(skipNewLines = false))(makeAnnotated)
+ } else {
+ t = atPos(t.pos.startOrPoint, colonPos) {
+ val tpt = typeOrInfixType(location)
+ if (isWildcard(t))
+ (placeholderParams: @unchecked) match {
+ case (vd @ ValDef(mods, name, _, _)) :: rest =>
+ placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest
+ }
+ // this does not correspond to syntax, but is necessary to
+ // accept closures. We might restrict closures to be between {...} only.
+ Typed(t, tpt)
+ }
}
+ } else if (in.token == MATCH) {
+ t = atPos(t.pos.startOrPoint, in.skipToken())(Match(stripParens(t), inBracesOrNil(caseClauses())))
+ }
+ // in order to allow anonymous functions as statements (as opposed to expressions) inside
+ // templates, we have to disambiguate them from self type declarations - bug #1565
+ // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which
+ // may be impossible to distinguish from a self-type and so remains an error. (See #1564)
+ def lhsIsTypedParamList() = t match {
+ case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true
+ case _ => false
}
- } else if (in.token == MATCH) {
- t = atPos(t.pos.startOrPoint, in.skipToken())(Match(stripParens(t), inBracesOrNil(caseClauses())))
- }
- // in order to allow anonymous functions as statements (as opposed to expressions) inside
- // templates, we have to disambiguate them from self type declarations - bug #1565
- // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which
- // may be impossible to distinguish from a self-type and so remains an error. (See #1564)
- def lhsIsTypedParamList() = t match {
- case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true
- case _ => false
- }
- if (in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)) {
- t = atPos(t.pos.startOrPoint, in.skipToken()) {
- Function(convertToParams(t), if (location != InBlock) expr() else block())
+ if (in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)) {
+ t = atPos(t.pos.startOrPoint, in.skipToken()) {
+ Function(convertToParams(t), if (location != InBlock) expr() else block())
+ }
}
+ stripParens(t)
}
- stripParens(t)
+ parseOther
}
/** {{{
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index f99b9a66c9..e6bf43fe93 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -360,16 +360,19 @@ trait Scanners extends ScannersCommon {
if (ch == '"' && token == IDENTIFIER)
token = INTERPOLATIONID
case '<' => // is XMLSTART?
- val last = if (charOffset >= 2) buf(charOffset - 2) else ' '
- nextChar()
- last match {
- case ' '|'\t'|'\n'|'{'|'('|'>' if isNameStart(ch) || ch == '!' || ch == '?' =>
- token = XMLSTART
- case _ =>
- // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG
- putChar('<')
- getOperatorRest()
+ def fetchLT = {
+ val last = if (charOffset >= 2) buf(charOffset - 2) else ' '
+ nextChar()
+ last match {
+ case ' ' | '\t' | '\n' | '{' | '(' | '>' if isNameStart(ch) || ch == '!' || ch == '?' =>
+ token = XMLSTART
+ case _ =>
+ // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG
+ putChar('<')
+ getOperatorRest()
+ }
}
+ fetchLT
case '~' | '!' | '@' | '#' | '%' |
'^' | '*' | '+' | '-' | /*'<' | */
'>' | '?' | ':' | '=' | '&' |
@@ -386,78 +389,87 @@ trait Scanners extends ScannersCommon {
getOperatorRest()
}
case '0' =>
- putChar(ch)
- nextChar()
- if (ch == 'x' || ch == 'X') {
+ def fetchZero = {
+ putChar(ch)
nextChar()
- base = 16
- }
- else {
- /** What should leading 0 be in the future? It is potentially dangerous
- * to let it be base-10 because of history. Should it be an error? Is
- * there a realistic situation where one would need it?
- */
- if (isDigit(ch)) {
- if (opt.future) syntaxError("Non-zero numbers may not have a leading zero.")
- else deprecationWarning("Treating numbers with a leading zero as octal is deprecated.")
+ if (ch == 'x' || ch == 'X') {
+ nextChar()
+ base = 16
+ } else {
+ /**
+ * What should leading 0 be in the future? It is potentially dangerous
+ * to let it be base-10 because of history. Should it be an error? Is
+ * there a realistic situation where one would need it?
+ */
+ if (isDigit(ch)) {
+ if (opt.future) syntaxError("Non-zero numbers may not have a leading zero.")
+ else deprecationWarning("Treating numbers with a leading zero as octal is deprecated.")
+ }
+ base = 8
}
- base = 8
+ getNumber()
}
- getNumber()
+ fetchZero
case '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' =>
base = 10
getNumber()
case '`' =>
getBackquotedIdent()
case '\"' =>
- if (token == INTERPOLATIONID) {
- nextRawChar()
- if (ch == '\"') {
+ def fetchDoubleQuote = {
+ if (token == INTERPOLATIONID) {
nextRawChar()
if (ch == '\"') {
nextRawChar()
- getStringPart(multiLine = true)
- sepRegions = STRINGPART :: sepRegions // indicate string part
- sepRegions = STRINGLIT :: sepRegions // once more to indicate multi line string part
+ if (ch == '\"') {
+ nextRawChar()
+ getStringPart(multiLine = true)
+ sepRegions = STRINGPART :: sepRegions // indicate string part
+ sepRegions = STRINGLIT :: sepRegions // once more to indicate multi line string part
+ } else {
+ token = STRINGLIT
+ strVal = ""
+ }
} else {
- token = STRINGLIT
- strVal = ""
+ getStringPart(multiLine = false)
+ sepRegions = STRINGLIT :: sepRegions // indicate single line string part
}
} else {
- getStringPart(multiLine = false)
- sepRegions = STRINGLIT :: sepRegions // indicate single line string part
- }
- } else {
- nextChar()
- if (ch == '\"') {
nextChar()
if (ch == '\"') {
- nextRawChar()
- getRawStringLit()
+ nextChar()
+ if (ch == '\"') {
+ nextRawChar()
+ getRawStringLit()
+ } else {
+ token = STRINGLIT
+ strVal = ""
+ }
} else {
- token = STRINGLIT
- strVal = ""
+ getStringLit()
}
- } else {
- getStringLit()
}
}
+ fetchDoubleQuote
case '\'' =>
- nextChar()
- if (isIdentifierStart(ch))
- charLitOr(getIdentRest)
- else if (isOperatorPart(ch) && (ch != '\\'))
- charLitOr(getOperatorRest)
- else {
- getLitChar()
- if (ch == '\'') {
- nextChar()
- token = CHARLIT
- setStrVal()
- } else {
- syntaxError("unclosed character literal")
+ def fetchSingleQuote = {
+ nextChar()
+ if (isIdentifierStart(ch))
+ charLitOr(getIdentRest)
+ else if (isOperatorPart(ch) && (ch != '\\'))
+ charLitOr(getOperatorRest)
+ else {
+ getLitChar()
+ if (ch == '\'') {
+ nextChar()
+ token = CHARLIT
+ setStrVal()
+ } else {
+ syntaxError("unclosed character literal")
+ }
}
}
+ fetchSingleQuote
case '.' =>
nextChar()
if ('0' <= ch && ch <= '9') {
@@ -488,22 +500,25 @@ trait Scanners extends ScannersCommon {
nextChar()
}
case _ =>
- if (ch == '\u21D2') {
- nextChar(); token = ARROW
- } else if (ch == '\u2190') {
- nextChar(); token = LARROW
- } else if (Character.isUnicodeIdentifierStart(ch)) {
- putChar(ch)
- nextChar()
- getIdentRest()
- } else if (isSpecial(ch)) {
- putChar(ch)
- nextChar()
- getOperatorRest()
- } else {
- syntaxError("illegal character '" + ("" + '\\' + 'u' + "%04x".format(ch: Int)) + "'")
- nextChar()
+ def fetchOther = {
+ if (ch == '\u21D2') {
+ nextChar(); token = ARROW
+ } else if (ch == '\u2190') {
+ nextChar(); token = LARROW
+ } else if (Character.isUnicodeIdentifierStart(ch)) {
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+ } else if (isSpecial(ch)) {
+ putChar(ch)
+ nextChar()
+ getOperatorRest()
+ } else {
+ syntaxError("illegal character '" + ("" + '\\' + 'u' + "%04x".format(ch: Int)) + "'")
+ nextChar()
+ }
}
+ fetchOther
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 3f0cef6703..8bbf11650c 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -20,6 +20,12 @@ trait BasicBlocks {
import global.{ ifDebug, settings, log, nme }
import nme.isExceptionResultName
+ /** Override Array creation for efficiency (to not go through reflection). */
+ private implicit val instructionTag: scala.reflect.ClassTag[Instruction] = new scala.reflect.ClassTag[Instruction] {
+ def runtimeClass: java.lang.Class[Instruction] = classOf[Instruction]
+ final override def newArray(len: Int): Array[Instruction] = new Array[Instruction](len)
+ }
+
object NoBasicBlock extends BasicBlock(-1, null)
/** This class represents a basic block. Each
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index a40d8c1a06..431802d185 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -628,48 +628,54 @@ abstract class GenICode extends SubComponent {
val resCtx: Context = tree match {
case LabelDef(name, params, rhs) =>
- val ctx1 = ctx.newBlock
- if (nme.isLoopHeaderLabel(name))
- ctx1.bb.loopHeader = true
-
- ctx1.labels.get(tree.symbol) match {
- case Some(label) =>
- debuglog("Found existing label for " + tree.symbol.fullLocationString)
- label.anchor(ctx1.bb)
- label.patch(ctx.method.code)
-
- case None =>
- val pair = (tree.symbol -> (new Label(tree.symbol) anchor ctx1.bb setParams (params map (_.symbol))))
- debuglog("Adding label " + tree.symbol.fullLocationString + " in genLoad.")
- ctx1.labels += pair
- ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false)));
- }
-
- ctx.bb.closeWith(JUMP(ctx1.bb), tree.pos)
- genLoad(rhs, ctx1, expectedType /*toTypeKind(tree.symbol.info.resultType)*/)
-
- case ValDef(_, nme.THIS, _, _) =>
- debuglog("skipping trivial assign to _$this: " + tree)
- ctx
-
- case ValDef(_, _, _, rhs) =>
- val sym = tree.symbol
- val local = ctx.method.addLocal(new Local(sym, toTypeKind(sym.info), false))
+ def genLoadLabelDef = {
+ val ctx1 = ctx.newBlock
+ if (nme.isLoopHeaderLabel(name))
+ ctx1.bb.loopHeader = true
+
+ ctx1.labels.get(tree.symbol) match {
+ case Some(label) =>
+ debuglog("Found existing label for " + tree.symbol.fullLocationString)
+ label.anchor(ctx1.bb)
+ label.patch(ctx.method.code)
+
+ case None =>
+ val pair = (tree.symbol -> (new Label(tree.symbol) anchor ctx1.bb setParams (params map (_.symbol))))
+ debuglog("Adding label " + tree.symbol.fullLocationString + " in genLoad.")
+ ctx1.labels += pair
+ ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false)));
+ }
- if (rhs == EmptyTree) {
- debuglog("Uninitialized variable " + tree + " at: " + (tree.pos));
- ctx.bb.emit(getZeroOf(local.kind))
+ ctx.bb.closeWith(JUMP(ctx1.bb), tree.pos)
+ genLoad(rhs, ctx1, expectedType /*toTypeKind(tree.symbol.info.resultType)*/)
}
-
- var ctx1 = ctx
- if (rhs != EmptyTree)
- ctx1 = genLoad(rhs, ctx, local.kind);
-
- ctx1.bb.emit(STORE_LOCAL(local), tree.pos)
- ctx1.scope.add(local)
- ctx1.bb.emit(SCOPE_ENTER(local))
- generatedType = UNIT
- ctx1
+ genLoadLabelDef
+
+ case ValDef(_, name, _, rhs) =>
+ def genLoadValDef =
+ if (name == nme.THIS) {
+ debuglog("skipping trivial assign to _$this: " + tree)
+ ctx
+ } else {
+ val sym = tree.symbol
+ val local = ctx.method.addLocal(new Local(sym, toTypeKind(sym.info), false))
+
+ if (rhs == EmptyTree) {
+ debuglog("Uninitialized variable " + tree + " at: " + (tree.pos));
+ ctx.bb.emit(getZeroOf(local.kind))
+ }
+
+ var ctx1 = ctx
+ if (rhs != EmptyTree)
+ ctx1 = genLoad(rhs, ctx, local.kind);
+
+ ctx1.bb.emit(STORE_LOCAL(local), tree.pos)
+ ctx1.scope.add(local)
+ ctx1.bb.emit(SCOPE_ENTER(local))
+ generatedType = UNIT
+ ctx1
+ }
+ genLoadValDef
case t @ If(cond, thenp, elsep) =>
val (newCtx, resKind) = genLoadIf(t, ctx, expectedType)
@@ -677,51 +683,55 @@ abstract class GenICode extends SubComponent {
newCtx
case Return(expr) =>
- val returnedKind = toTypeKind(expr.tpe)
- debuglog("Return(" + expr + ") with returnedKind = " + returnedKind)
-
- var ctx1 = genLoad(expr, ctx, returnedKind)
- lazy val tmp = ctx1.makeLocal(tree.pos, expr.tpe, "tmp")
- val saved = savingCleanups(ctx1) {
- var savedFinalizer = false
- ctx1.cleanups foreach {
- case MonitorRelease(m) =>
- debuglog("removing " + m + " from cleanups: " + ctx1.cleanups)
- ctx1.bb.emit(Seq(LOAD_LOCAL(m), MONITOR_EXIT()))
- ctx1.exitSynchronized(m)
-
- case Finalizer(f, finalizerCtx) =>
- debuglog("removing " + f + " from cleanups: " + ctx1.cleanups)
- if (returnedKind != UNIT && mayCleanStack(f)) {
- log("Emitting STORE_LOCAL for " + tmp + " to save finalizer.")
- ctx1.bb.emit(STORE_LOCAL(tmp))
- savedFinalizer = true
- }
+ def genLoadReturn = {
+ val returnedKind = toTypeKind(expr.tpe)
+ debuglog("Return(" + expr + ") with returnedKind = " + returnedKind)
+
+ var ctx1 = genLoad(expr, ctx, returnedKind)
+ lazy val tmp = ctx1.makeLocal(tree.pos, expr.tpe, "tmp")
+ val saved = savingCleanups(ctx1) {
+ var savedFinalizer = false
+ ctx1.cleanups foreach {
+ case MonitorRelease(m) =>
+ debuglog("removing " + m + " from cleanups: " + ctx1.cleanups)
+ ctx1.bb.emit(Seq(LOAD_LOCAL(m), MONITOR_EXIT()))
+ ctx1.exitSynchronized(m)
+
+ case Finalizer(f, finalizerCtx) =>
+ debuglog("removing " + f + " from cleanups: " + ctx1.cleanups)
+ if (returnedKind != UNIT && mayCleanStack(f)) {
+ log("Emitting STORE_LOCAL for " + tmp + " to save finalizer.")
+ ctx1.bb.emit(STORE_LOCAL(tmp))
+ savedFinalizer = true
+ }
- // duplicate finalizer (takes care of anchored labels)
- val f1 = duplicateFinalizer(Set.empty ++ ctx1.labels.keySet, ctx1, f)
+ // duplicate finalizer (takes care of anchored labels)
+ val f1 = duplicateFinalizer(Set.empty ++ ctx1.labels.keySet, ctx1, f)
- // we have to run this without the same finalizer in
- // the list, otherwise infinite recursion happens for
- // finalizers that contain 'return'
- val fctx = finalizerCtx.newBlock
- ctx1.bb.closeWith(JUMP(fctx.bb))
- ctx1 = genLoad(f1, fctx, UNIT)
+ // we have to run this without the same finalizer in
+ // the list, otherwise infinite recursion happens for
+ // finalizers that contain 'return'
+ val fctx = finalizerCtx.newBlock
+ ctx1.bb.closeWith(JUMP(fctx.bb))
+ ctx1 = genLoad(f1, fctx, UNIT)
+ }
+ savedFinalizer
}
- savedFinalizer
- }
- if (saved) {
- log("Emitting LOAD_LOCAL for " + tmp + " after saving finalizer.")
- ctx1.bb.emit(LOAD_LOCAL(tmp))
- }
- adapt(returnedKind, ctx1.method.returnType, ctx1, tree.pos)
- ctx1.bb.emit(RETURN(ctx.method.returnType), tree.pos)
- ctx1.bb.enterIgnoreMode
- generatedType = expectedType
- ctx1
+ if (saved) {
+ log("Emitting LOAD_LOCAL for " + tmp + " after saving finalizer.")
+ ctx1.bb.emit(LOAD_LOCAL(tmp))
+ }
+ adapt(returnedKind, ctx1.method.returnType, ctx1, tree.pos)
+ ctx1.bb.emit(RETURN(ctx.method.returnType), tree.pos)
+ ctx1.bb.enterIgnoreMode
+ generatedType = expectedType
+ ctx1
+ }
+ genLoadReturn
- case t @ Try(_, _, _) => genLoadTry(t, ctx, generatedType = _)
+ case t @ Try(_, _, _) =>
+ genLoadTry(t, ctx, generatedType = _)
case Throw(expr) =>
val (ctx1, expectedType) = genThrow(expr, ctx)
@@ -733,41 +743,42 @@ abstract class GenICode extends SubComponent {
" Call was genLoad" + ((tree, ctx, expectedType)))
case Apply(TypeApply(fun, targs), _) =>
- val sym = fun.symbol
- val cast = sym match {
- case Object_isInstanceOf => false
- case Object_asInstanceOf => true
- case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullName + "]" + " in: " + tree)
- }
-
- val Select(obj, _) = fun
- val l = toTypeKind(obj.tpe)
- val r = toTypeKind(targs.head.tpe)
- val ctx1 = genLoadQualifier(fun, ctx)
-
- if (l.isValueType && r.isValueType)
- genConversion(l, r, ctx1, cast)
- else if (l.isValueType) {
- ctx1.bb.emit(DROP(l), fun.pos)
- if (cast) {
- ctx1.bb.emit(Seq(
- NEW(REFERENCE(definitions.ClassCastExceptionClass)),
- DUP(ObjectReference),
- THROW(definitions.ClassCastExceptionClass)
- ))
- } else
- ctx1.bb.emit(CONSTANT(Constant(false)))
- }
- else if (r.isValueType && cast) {
- assert(false, tree) /* Erasure should have added an unboxing operation to prevent that. */
+ def genLoadApply1 = {
+ val sym = fun.symbol
+ val cast = sym match {
+ case Object_isInstanceOf => false
+ case Object_asInstanceOf => true
+ case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullName + "]" + " in: " + tree)
+ }
+
+ val Select(obj, _) = fun
+ val l = toTypeKind(obj.tpe)
+ val r = toTypeKind(targs.head.tpe)
+ val ctx1 = genLoadQualifier(fun, ctx)
+
+ if (l.isValueType && r.isValueType)
+ genConversion(l, r, ctx1, cast)
+ else if (l.isValueType) {
+ ctx1.bb.emit(DROP(l), fun.pos)
+ if (cast) {
+ ctx1.bb.emit(Seq(
+ NEW(REFERENCE(definitions.ClassCastExceptionClass)),
+ DUP(ObjectReference),
+ THROW(definitions.ClassCastExceptionClass)
+ ))
+ } else
+ ctx1.bb.emit(CONSTANT(Constant(false)))
+ } else if (r.isValueType && cast) {
+ assert(false, tree) /* Erasure should have added an unboxing operation to prevent that. */
+ } else if (r.isValueType) {
+ ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.typeSymbol))))
+ } else {
+ genCast(l, r, ctx1, cast)
+ }
+ generatedType = if (cast) r else BOOL;
+ ctx1
}
- else if (r.isValueType)
- ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.typeSymbol))))
- else
- genCast(l, r, ctx1, cast);
-
- generatedType = if (cast) r else BOOL;
- ctx1
+ genLoadApply1
// 'super' call: Note: since constructors are supposed to
// return an instance of what they construct, we have to take
@@ -776,93 +787,102 @@ abstract class GenICode extends SubComponent {
// therefore, we can ignore this fact, and generate code that leaves nothing
// on the stack (contrary to what the type in the AST says).
case Apply(fun @ Select(Super(_, mix), _), args) =>
- debuglog("Call to super: " + tree);
- val invokeStyle = SuperCall(mix)
-// if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
+ def genLoadApply2 = {
+ debuglog("Call to super: " + tree);
+ val invokeStyle = SuperCall(mix)
+ // if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
- ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
- val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx)
-
- ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos)
- generatedType =
- if (fun.symbol.isConstructor) UNIT
- else toTypeKind(fun.symbol.info.resultType)
- ctx1
+ ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
+ val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx)
+
+ ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos)
+ generatedType =
+ if (fun.symbol.isConstructor) UNIT
+ else toTypeKind(fun.symbol.info.resultType)
+ ctx1
+ }
+ genLoadApply2
// 'new' constructor call: Note: since constructors are
// thought to return an instance of what they construct,
// we have to 'simulate' it by DUPlicating the freshly created
// instance (on JVM, <init> methods return VOID).
case Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) =>
- val ctor = fun.symbol
- debugassert(ctor.isClassConstructor,
- "'new' call to non-constructor: " + ctor.name)
-
- generatedType = toTypeKind(tpt.tpe)
- debugassert(generatedType.isReferenceType || generatedType.isArrayType,
- "Non reference type cannot be instantiated: " + generatedType)
-
- generatedType match {
- case arr @ ARRAY(elem) =>
- val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
- val dims = arr.dimensions
- var elemKind = arr.elementKind
- if (args.length > dims)
- unit.error(tree.pos, "too many arguments for array constructor: found " + args.length +
- " but array has only " + dims + " dimension(s)")
- if (args.length != dims)
- for (i <- args.length until dims) elemKind = ARRAY(elemKind)
- ctx1.bb.emit(CREATE_ARRAY(elemKind, args.length), tree.pos)
- ctx1
+ def genLoadApply3 = {
+ val ctor = fun.symbol
+ debugassert(ctor.isClassConstructor,
+ "'new' call to non-constructor: " + ctor.name)
+
+ generatedType = toTypeKind(tpt.tpe)
+ debugassert(generatedType.isReferenceType || generatedType.isArrayType,
+ "Non reference type cannot be instantiated: " + generatedType)
- case rt @ REFERENCE(cls) =>
- debugassert(ctor.owner == cls,
- "Symbol " + ctor.owner.fullName + " is different than " + tpt)
-
- val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) {
- /* parameterful constructors are the only possible custom constructors,
- a default constructor can't be defined for valuetypes, CLR dixit */
- val isDefaultConstructor = args.isEmpty
- if (isDefaultConstructor) {
- msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false)
- ctx
+ generatedType match {
+ case arr @ ARRAY(elem) =>
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ val dims = arr.dimensions
+ var elemKind = arr.elementKind
+ if (args.length > dims)
+ unit.error(tree.pos, "too many arguments for array constructor: found " + args.length +
+ " but array has only " + dims + " dimension(s)")
+ if (args.length != dims)
+ for (i <- args.length until dims) elemKind = ARRAY(elemKind)
+ ctx1.bb.emit(CREATE_ARRAY(elemKind, args.length), tree.pos)
+ ctx1
+
+ case rt @ REFERENCE(cls) =>
+ debugassert(ctor.owner == cls,
+ "Symbol " + ctor.owner.fullName + " is different than " + tpt)
+
+ val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) {
+ /* parameterful constructors are the only possible custom constructors,
+ a default constructor can't be defined for valuetypes, CLR dixit */
+ val isDefaultConstructor = args.isEmpty
+ if (isDefaultConstructor) {
+ msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false)
+ ctx
+ } else {
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos)
+ ctx1
+ }
} else {
+ val nw = NEW(rt)
+ ctx.bb.emit(nw, tree.pos)
+ ctx.bb.emit(DUP(generatedType))
val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
- ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos)
+
+ val init = CALL_METHOD(ctor, Static(true))
+ nw.init = init
+ ctx1.bb.emit(init, tree.pos)
ctx1
}
- } else {
- val nw = NEW(rt)
- ctx.bb.emit(nw, tree.pos)
- ctx.bb.emit(DUP(generatedType))
- val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
-
- val init = CALL_METHOD(ctor, Static(true))
- nw.init = init
- ctx1.bb.emit(init, tree.pos)
- ctx1
- }
- ctx2
-
- case _ =>
- abort("Cannot instantiate " + tpt + " of kind: " + generatedType)
+ ctx2
+
+ case _ =>
+ abort("Cannot instantiate " + tpt + " of kind: " + generatedType)
+ }
}
+ genLoadApply3
case Apply(fun @ _, List(expr)) if (definitions.isBox(fun.symbol)) =>
- debuglog("BOX : " + fun.symbol.fullName);
- val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe))
- val nativeKind = toTypeKind(expr.tpe)
- if (settings.Xdce.value) {
- // we store this boxed value to a local, even if not really needed.
- // boxing optimization might use it, and dead code elimination will
- // take care of unnecessary stores
- var loc1 = ctx.makeLocal(tree.pos, expr.tpe, "boxed")
- ctx1.bb.emit(STORE_LOCAL(loc1))
- ctx1.bb.emit(LOAD_LOCAL(loc1))
+ def genLoadApply4 = {
+ debuglog("BOX : " + fun.symbol.fullName);
+ val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe))
+ val nativeKind = toTypeKind(expr.tpe)
+ if (settings.Xdce.value) {
+ // we store this boxed value to a local, even if not really needed.
+ // boxing optimization might use it, and dead code elimination will
+ // take care of unnecessary stores
+ var loc1 = ctx.makeLocal(tree.pos, expr.tpe, "boxed")
+ ctx1.bb.emit(STORE_LOCAL(loc1))
+ ctx1.bb.emit(LOAD_LOCAL(loc1))
+ }
+ ctx1.bb.emit(BOX(nativeKind), expr.pos)
+ generatedType = toTypeKind(fun.symbol.tpe.resultType)
+ ctx1
}
- ctx1.bb.emit(BOX(nativeKind), expr.pos)
- generatedType = toTypeKind(fun.symbol.tpe.resultType)
- ctx1
+ genLoadApply4
case Apply(fun @ _, List(expr)) if (definitions.isUnbox(fun.symbol)) =>
debuglog("UNBOX : " + fun.symbol.fullName)
@@ -886,6 +906,7 @@ abstract class GenICode extends SubComponent {
// this bypass is not done:
// - if the static intializer for the static field itself
// - if there is no companion class of the object owner - this happens in the REPL
+ def genLoadApply5 = {
val sym = fun.symbol
generatedType = toTypeKind(sym.accessed.info)
val hostOwner = qual.tpe.typeSymbol.orElse(sym.owner)
@@ -915,84 +936,89 @@ abstract class GenICode extends SubComponent {
assert(false, "supposedly unreachable")
ctx
}
+ }
+ genLoadApply5
case app @ Apply(fun, args) =>
- val sym = fun.symbol
+ def genLoadApply6 = {
+ val sym = fun.symbol
- if (sym.isLabel) { // jump to a label
- val label = ctx.labels.getOrElse(sym, {
- // it is a forward jump, scan for labels
- resolveForwardLabel(ctx.defdef, ctx, sym)
- ctx.labels.get(sym) match {
- case Some(l) =>
- log("Forward jump for " + sym.fullLocationString + ": scan found label " + l)
- l
- case _ =>
- abort("Unknown label target: " + sym + " at: " + (fun.pos) + ": ctx: " + ctx)
- }
- })
- // note: when one of the args to genLoadLabelArguments is a jump to a label,
- // it will call back into genLoad and arrive at this case, which will then set ctx1.bb.ignore to true,
- // this is okay, since we're jumping unconditionally, so the loads and jumps emitted by the outer
- // call to genLoad (by calling genLoadLabelArguments and emitOnly) can safely be ignored,
- // however, as emitOnly will close the block, which reverses its instructions (when it's still open),
- // we better not reverse when the block has already been closed but is in ignore mode
- // (if it's not in ignore mode, double-closing is an error)
- val ctx1 = genLoadLabelArguments(args, label, ctx)
- ctx1.bb.emitOnly(if (label.anchored) JUMP(label.block) else PJUMP(label))
- ctx1.bb.enterIgnoreMode
- ctx1
- } else if (isPrimitive(sym)) { // primitive method call
- val (newCtx, resKind) = genPrimitiveOp(app, ctx, expectedType)
- generatedType = resKind
- newCtx
- } else { // normal method call
- debuglog("Gen CALL_METHOD with sym: " + sym + " isStaticSymbol: " + sym.isStaticMember);
- val invokeStyle =
- if (sym.isStaticMember)
- Static(false)
- else if (sym.isPrivate || sym.isClassConstructor)
- Static(true)
- else
- Dynamic
-
- var ctx1 =
- if (invokeStyle.hasInstance) {
- if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym))
- msil_genLoadQualifierAddress(fun, ctx)
+ if (sym.isLabel) { // jump to a label
+ val label = ctx.labels.getOrElse(sym, {
+ // it is a forward jump, scan for labels
+ resolveForwardLabel(ctx.defdef, ctx, sym)
+ ctx.labels.get(sym) match {
+ case Some(l) =>
+ log("Forward jump for " + sym.fullLocationString + ": scan found label " + l)
+ l
+ case _ =>
+ abort("Unknown label target: " + sym + " at: " + (fun.pos) + ": ctx: " + ctx)
+ }
+ })
+ // note: when one of the args to genLoadLabelArguments is a jump to a label,
+ // it will call back into genLoad and arrive at this case, which will then set ctx1.bb.ignore to true,
+ // this is okay, since we're jumping unconditionally, so the loads and jumps emitted by the outer
+ // call to genLoad (by calling genLoadLabelArguments and emitOnly) can safely be ignored,
+ // however, as emitOnly will close the block, which reverses its instructions (when it's still open),
+ // we better not reverse when the block has already been closed but is in ignore mode
+ // (if it's not in ignore mode, double-closing is an error)
+ val ctx1 = genLoadLabelArguments(args, label, ctx)
+ ctx1.bb.emitOnly(if (label.anchored) JUMP(label.block) else PJUMP(label))
+ ctx1.bb.enterIgnoreMode
+ ctx1
+ } else if (isPrimitive(sym)) { // primitive method call
+ val (newCtx, resKind) = genPrimitiveOp(app, ctx, expectedType)
+ generatedType = resKind
+ newCtx
+ } else { // normal method call
+ debuglog("Gen CALL_METHOD with sym: " + sym + " isStaticSymbol: " + sym.isStaticMember);
+ val invokeStyle =
+ if (sym.isStaticMember)
+ Static(false)
+ else if (sym.isPrivate || sym.isClassConstructor)
+ Static(true)
else
- genLoadQualifier(fun, ctx)
- } else ctx
-
- ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1)
- val cm = CALL_METHOD(sym, invokeStyle)
-
- /** In a couple cases, squirrel away a little extra information in the
- * CALL_METHOD for use by GenJVM.
- */
- fun match {
- case Select(qual, _) =>
- val qualSym = findHostClass(qual.tpe, sym)
-
- if (qualSym == ArrayClass) cm setTargetTypeKind toTypeKind(qual.tpe)
- else cm setHostClass qualSym
-
- log(
- if (qualSym == ArrayClass) "Stored target type kind " + toTypeKind(qual.tpe) + " for " + sym.fullName
- else s"Set more precise host class for ${sym.fullName} hostClass: $qualSym"
- )
- case _ =>
- }
- ctx1.bb.emit(cm, tree.pos)
+ Dynamic
+
+ var ctx1 =
+ if (invokeStyle.hasInstance) {
+ if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym))
+ msil_genLoadQualifierAddress(fun, ctx)
+ else
+ genLoadQualifier(fun, ctx)
+ } else ctx
+
+ ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1)
+ val cm = CALL_METHOD(sym, invokeStyle)
+
+ /** In a couple cases, squirrel away a little extra information in the
+ * CALL_METHOD for use by GenJVM.
+ */
+ fun match {
+ case Select(qual, _) =>
+ val qualSym = findHostClass(qual.tpe, sym)
+
+ if (qualSym == ArrayClass) cm setTargetTypeKind toTypeKind(qual.tpe)
+ else cm setHostClass qualSym
+
+ log(
+ if (qualSym == ArrayClass) "Stored target type kind " + toTypeKind(qual.tpe) + " for " + sym.fullName
+ else s"Set more precise host class for ${sym.fullName} hostClass: $qualSym"
+ )
+ case _ =>
+ }
+ ctx1.bb.emit(cm, tree.pos)
- if (sym == ctx1.method.symbol) {
- ctx1.method.recursive = true
+ if (sym == ctx1.method.symbol) {
+ ctx1.method.recursive = true
+ }
+ generatedType =
+ if (sym.isClassConstructor) UNIT
+ else toTypeKind(sym.info.resultType);
+ ctx1
}
- generatedType =
- if (sym.isClassConstructor) UNIT
- else toTypeKind(sym.info.resultType);
- ctx1
}
+ genLoadApply6
case ApplyDynamic(qual, args) =>
assert(!forMSIL, tree)
@@ -1004,20 +1030,22 @@ abstract class GenICode extends SubComponent {
// ctx1
case This(qual) =>
- assert(tree.symbol == ctx.clazz.symbol || tree.symbol.isModuleClass,
- "Trying to access the this of another class: " +
- "tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol + " compilation unit:"+unit)
- if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) {
- genLoadModule(ctx, tree)
- generatedType = REFERENCE(tree.symbol)
- }
- else {
- ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
- generatedType = REFERENCE(
- if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol
- )
+ def genLoadThis = {
+ assert(tree.symbol == ctx.clazz.symbol || tree.symbol.isModuleClass,
+ "Trying to access the this of another class: " +
+ "tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol + " compilation unit:"+unit)
+ if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) {
+ genLoadModule(ctx, tree)
+ generatedType = REFERENCE(tree.symbol)
+ } else {
+ ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
+ generatedType = REFERENCE(
+ if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol
+ )
+ }
+ ctx
}
- ctx
+ genLoadThis
case Select(Ident(nme.EMPTY_PACKAGE_NAME), module) =>
debugassert(tree.symbol.isModule,
@@ -1027,60 +1055,67 @@ abstract class GenICode extends SubComponent {
genLoadModule(ctx, tree)
case Select(qualifier, selector) =>
- val sym = tree.symbol
- generatedType = toTypeKind(sym.info)
- val hostClass = findHostClass(qualifier.tpe, sym)
- log(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass")
-
- if (sym.isModule) {
- genLoadModule(ctx, tree)
- }
- else if (sym.isStaticMember) {
- ctx.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos)
- ctx
- }
- else {
- val ctx1 = genLoadQualifier(tree, ctx)
- ctx1.bb.emit(LOAD_FIELD(sym, false) setHostClass hostClass, tree.pos)
- ctx1
- }
+ def genLoadSelect = {
+ val sym = tree.symbol
+ generatedType = toTypeKind(sym.info)
+ val hostClass = findHostClass(qualifier.tpe, sym)
+ log(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass")
- case Ident(name) =>
- val sym = tree.symbol
- if (!sym.isPackage) {
if (sym.isModule) {
genLoadModule(ctx, tree)
- generatedType = toTypeKind(sym.info)
}
- else {
- try {
- val Some(l) = ctx.method.lookupLocal(sym)
- ctx.bb.emit(LOAD_LOCAL(l), tree.pos)
- generatedType = l.kind
- } catch {
- case ex: MatchError =>
- abort("symbol " + sym + " does not exist in " + ctx.method)
+ else if (sym.isStaticMember) {
+ ctx.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos)
+ ctx
+ } else {
+ val ctx1 = genLoadQualifier(tree, ctx)
+ ctx1.bb.emit(LOAD_FIELD(sym, false) setHostClass hostClass, tree.pos)
+ ctx1
+ }
+ }
+ genLoadSelect
+
+ case Ident(name) =>
+ def genLoadIdent = {
+ val sym = tree.symbol
+ if (!sym.isPackage) {
+ if (sym.isModule) {
+ genLoadModule(ctx, tree)
+ generatedType = toTypeKind(sym.info)
+ } else {
+ try {
+ val Some(l) = ctx.method.lookupLocal(sym)
+ ctx.bb.emit(LOAD_LOCAL(l), tree.pos)
+ generatedType = l.kind
+ } catch {
+ case ex: MatchError =>
+ abort("symbol " + sym + " does not exist in " + ctx.method)
+ }
}
}
+ ctx
}
- ctx
+ genLoadIdent
case Literal(value) =>
- if (value.tag != UnitTag) (value.tag, expectedType) match {
- case (IntTag, LONG) =>
- ctx.bb.emit(CONSTANT(Constant(value.longValue)), tree.pos);
- generatedType = LONG
- case (FloatTag, DOUBLE) =>
- ctx.bb.emit(CONSTANT(Constant(value.doubleValue)), tree.pos);
- generatedType = DOUBLE
- case (NullTag, _) =>
- ctx.bb.emit(CONSTANT(value), tree.pos);
- generatedType = NullReference
- case _ =>
- ctx.bb.emit(CONSTANT(value), tree.pos);
- generatedType = toTypeKind(tree.tpe)
+ def genLoadLiteral = {
+ if (value.tag != UnitTag) (value.tag, expectedType) match {
+ case (IntTag, LONG) =>
+ ctx.bb.emit(CONSTANT(Constant(value.longValue)), tree.pos);
+ generatedType = LONG
+ case (FloatTag, DOUBLE) =>
+ ctx.bb.emit(CONSTANT(Constant(value.doubleValue)), tree.pos);
+ generatedType = DOUBLE
+ case (NullTag, _) =>
+ ctx.bb.emit(CONSTANT(value), tree.pos);
+ generatedType = NullReference
+ case _ =>
+ ctx.bb.emit(CONSTANT(value), tree.pos);
+ generatedType = toTypeKind(tree.tpe)
+ }
+ ctx
}
- ctx
+ genLoadLiteral
case Block(stats, expr) =>
ctx.enterScope
@@ -1100,66 +1135,72 @@ abstract class GenICode extends SubComponent {
genStat(tree, ctx)
case ArrayValue(tpt @ TypeTree(), _elems) =>
- var ctx1 = ctx
- val elmKind = toTypeKind(tpt.tpe)
- generatedType = ARRAY(elmKind)
- val elems = _elems.toIndexedSeq
-
- ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos)
- ctx1.bb.emit(CREATE_ARRAY(elmKind, 1))
- // inline array literals
- var i = 0
- while (i < elems.length) {
- ctx1.bb.emit(DUP(generatedType), tree.pos)
- ctx1.bb.emit(CONSTANT(new Constant(i)))
- ctx1 = genLoad(elems(i), ctx1, elmKind)
- ctx1.bb.emit(STORE_ARRAY_ITEM(elmKind))
- i = i + 1
+ def genLoadArrayValue = {
+ var ctx1 = ctx
+ val elmKind = toTypeKind(tpt.tpe)
+ generatedType = ARRAY(elmKind)
+ val elems = _elems.toIndexedSeq
+
+ ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos)
+ ctx1.bb.emit(CREATE_ARRAY(elmKind, 1))
+ // inline array literals
+ var i = 0
+ while (i < elems.length) {
+ ctx1.bb.emit(DUP(generatedType), tree.pos)
+ ctx1.bb.emit(CONSTANT(new Constant(i)))
+ ctx1 = genLoad(elems(i), ctx1, elmKind)
+ ctx1.bb.emit(STORE_ARRAY_ITEM(elmKind))
+ i = i + 1
+ }
+ ctx1
}
- ctx1
+ genLoadArrayValue
case Match(selector, cases) =>
- debuglog("Generating SWITCH statement.");
- var ctx1 = genLoad(selector, ctx, INT) // TODO: Java 7 allows strings in switches (so, don't assume INT and don't convert the literals using intValue)
- val afterCtx = ctx1.newBlock
- var caseCtx: Context = null
- generatedType = toTypeKind(tree.tpe)
-
- var targets: List[BasicBlock] = Nil
- var tags: List[Int] = Nil
- var default: BasicBlock = afterCtx.bb
-
- for (caze @ CaseDef(pat, guard, body) <- cases) {
- assert(guard == EmptyTree, guard)
- val tmpCtx = ctx1.newBlock
- pat match {
- case Literal(value) =>
- tags = value.intValue :: tags
- targets = tmpCtx.bb :: targets
- case Ident(nme.WILDCARD) =>
- default = tmpCtx.bb
- case Alternative(alts) =>
- alts foreach {
- case Literal(value) =>
- tags = value.intValue :: tags
- targets = tmpCtx.bb :: targets
- case _ =>
- abort("Invalid case in alternative in switch-like pattern match: " +
- tree + " at: " + tree.pos)
- }
- case _ =>
- abort("Invalid case statement in switch-like pattern match: " +
- tree + " at: " + (tree.pos))
+ def genLoadMatch = {
+ debuglog("Generating SWITCH statement.");
+ var ctx1 = genLoad(selector, ctx, INT) // TODO: Java 7 allows strings in switches (so, don't assume INT and don't convert the literals using intValue)
+ val afterCtx = ctx1.newBlock
+ var caseCtx: Context = null
+ generatedType = toTypeKind(tree.tpe)
+
+ var targets: List[BasicBlock] = Nil
+ var tags: List[Int] = Nil
+ var default: BasicBlock = afterCtx.bb
+
+ for (caze @ CaseDef(pat, guard, body) <- cases) {
+ assert(guard == EmptyTree, guard)
+ val tmpCtx = ctx1.newBlock
+ pat match {
+ case Literal(value) =>
+ tags = value.intValue :: tags
+ targets = tmpCtx.bb :: targets
+ case Ident(nme.WILDCARD) =>
+ default = tmpCtx.bb
+ case Alternative(alts) =>
+ alts foreach {
+ case Literal(value) =>
+ tags = value.intValue :: tags
+ targets = tmpCtx.bb :: targets
+ case _ =>
+ abort("Invalid case in alternative in switch-like pattern match: " +
+ tree + " at: " + tree.pos)
+ }
+ case _ =>
+ abort("Invalid case statement in switch-like pattern match: " +
+ tree + " at: " + (tree.pos))
+ }
+
+ caseCtx = genLoad(body, tmpCtx, generatedType)
+ // close the block unless it's already been closed by the body, which closes the block if it ends in a jump (which is emitted to have alternatives share their body)
+ caseCtx.bb.closeWith(JUMP(afterCtx.bb) setPos caze.pos)
}
-
- caseCtx = genLoad(body, tmpCtx, generatedType)
- // close the block unless it's already been closed by the body, which closes the block if it ends in a jump (which is emitted to have alternatives share their body)
- caseCtx.bb.closeWith(JUMP(afterCtx.bb) setPos caze.pos)
+ ctx1.bb.emitOnly(
+ SWITCH(tags.reverse map (x => List(x)), (default :: targets).reverse) setPos tree.pos
+ )
+ afterCtx
}
- ctx1.bb.emitOnly(
- SWITCH(tags.reverse map (x => List(x)), (default :: targets).reverse) setPos tree.pos
- )
- afterCtx
+ genLoadMatch
case EmptyTree =>
if (expectedType != UNIT)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 6541a1325c..b57f5e86a3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -448,6 +448,17 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
val JAVA_LANG_OBJECT = asm.Type.getObjectType("java/lang/Object")
val JAVA_LANG_STRING = asm.Type.getObjectType("java/lang/String")
+ /**
+ * We call many Java varargs methods from ASM library that expect Arra[asm.Type] as argument so
+ * we override default (compiler-generated) ClassTag so we can provide specialized newArray implementation.
+ *
+ * Examples of methods that should pick our definition are: JBuilder.javaType and JPlainBuilder.genMethod.
+ */
+ private implicit val asmTypeTag: scala.reflect.ClassTag[asm.Type] = new scala.reflect.ClassTag[asm.Type] {
+ def runtimeClass: java.lang.Class[asm.Type] = classOf[asm.Type]
+ final override def newArray(len: Int): Array[asm.Type] = new Array[asm.Type](len)
+ }
+
/** basic functionality for class file building */
abstract class JBuilder(bytecodeWriter: BytecodeWriter) {
@@ -641,7 +652,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
def javaType(s: Symbol): asm.Type = {
if (s.isMethod) {
val resT: asm.Type = if (s.isClassConstructor) asm.Type.VOID_TYPE else javaType(s.tpe.resultType);
- asm.Type.getMethodType( resT, (s.tpe.paramTypes map javaType): _* )
+ asm.Type.getMethodType( resT, (s.tpe.paramTypes map javaType): _*)
} else { javaType(s.tpe) }
}
@@ -2371,8 +2382,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
def genBlock(b: BasicBlock) {
jmethod.visitLabel(labels(b))
- import asm.Opcodes;
-
debuglog("Generating code for block: " + b)
// val lastInstr = b.lastInstruction
@@ -2391,287 +2400,308 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
}
}
- (instr.category: @scala.annotation.switch) match {
-
- case icodes.localsCat => (instr: @unchecked) match {
- case THIS(_) => jmethod.visitVarInsn(Opcodes.ALOAD, 0)
- case LOAD_LOCAL(local) => jcode.load(indexOf(local), local.kind)
- case STORE_LOCAL(local) => jcode.store(indexOf(local), local.kind)
- case STORE_THIS(_) =>
- // this only works for impl classes because the self parameter comes first
- // in the method signature. If that changes, this code has to be revisited.
- jmethod.visitVarInsn(Opcodes.ASTORE, 0)
-
- case SCOPE_ENTER(lv) =>
- // locals removed by closelim (via CopyPropagation) may have left behind SCOPE_ENTER, SCOPE_EXIT that are to be ignored
- val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
- if(relevant) { // TODO check: does GenICode emit SCOPE_ENTER, SCOPE_EXIT for synthetic vars?
- // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
- // similarly, these labels aren't tracked in the `labels` map.
- val start = new asm.Label
- jmethod.visitLabel(start)
- scoping.pushScope(lv, start)
- }
+ genInstr(instr, b)
- case SCOPE_EXIT(lv) =>
- val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
- if(relevant) {
- // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
- // similarly, these labels aren't tracked in the `labels` map.
- val end = new asm.Label
- jmethod.visitLabel(end)
- scoping.popScope(lv, end, instr.pos)
- }
- }
+ }
- case icodes.stackCat => (instr: @unchecked) match {
+ }
- case LOAD_MODULE(module) =>
- // assert(module.isModule, "Expected module: " + module)
- debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags));
- if (clasz.symbol == module.moduleClass && jMethodName != nme.readResolve.toString) {
- jmethod.visitVarInsn(Opcodes.ALOAD, 0)
- } else {
- jmethod.visitFieldInsn(
- Opcodes.GETSTATIC,
- javaName(module) /* + "$" */ ,
- strMODULE_INSTANCE_FIELD,
- descriptor(module)
- )
- }
+ def genInstr(instr: Instruction, b: BasicBlock) {
+ import asm.Opcodes
+ (instr.category: @scala.annotation.switch) match {
+
+ case icodes.localsCat =>
+ def genLocalInstr = (instr: @unchecked) match {
+ case THIS(_) => jmethod.visitVarInsn(Opcodes.ALOAD, 0)
+ case LOAD_LOCAL(local) => jcode.load(indexOf(local), local.kind)
+ case STORE_LOCAL(local) => jcode.store(indexOf(local), local.kind)
+ case STORE_THIS(_) =>
+ // this only works for impl classes because the self parameter comes first
+ // in the method signature. If that changes, this code has to be revisited.
+ jmethod.visitVarInsn(Opcodes.ASTORE, 0)
+
+ case SCOPE_ENTER(lv) =>
+ // locals removed by closelim (via CopyPropagation) may have left behind SCOPE_ENTER, SCOPE_EXIT that are to be ignored
+ val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
+ if (relevant) { // TODO check: does GenICode emit SCOPE_ENTER, SCOPE_EXIT for synthetic vars?
+ // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
+ // similarly, these labels aren't tracked in the `labels` map.
+ val start = new asm.Label
+ jmethod.visitLabel(start)
+ scoping.pushScope(lv, start)
+ }
- case DROP(kind) => emit(if(kind.isWideType) Opcodes.POP2 else Opcodes.POP)
+ case SCOPE_EXIT(lv) =>
+ val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
+ if (relevant) {
+ // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
+ // similarly, these labels aren't tracked in the `labels` map.
+ val end = new asm.Label
+ jmethod.visitLabel(end)
+ scoping.popScope(lv, end, instr.pos)
+ }
+ }
+ genLocalInstr
+
+ case icodes.stackCat =>
+ def genStackInstr = (instr: @unchecked) match {
+
+ case LOAD_MODULE(module) =>
+ // assert(module.isModule, "Expected module: " + module)
+ debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags));
+ if (clasz.symbol == module.moduleClass && jMethodName != nme.readResolve.toString) {
+ jmethod.visitVarInsn(Opcodes.ALOAD, 0)
+ } else {
+ jmethod.visitFieldInsn(
+ Opcodes.GETSTATIC,
+ javaName(module) /* + "$" */ ,
+ strMODULE_INSTANCE_FIELD,
+ descriptor(module))
+ }
- case DUP(kind) => emit(if(kind.isWideType) Opcodes.DUP2 else Opcodes.DUP)
+ case DROP(kind) => emit(if (kind.isWideType) Opcodes.POP2 else Opcodes.POP)
- case LOAD_EXCEPTION(_) => ()
- }
+ case DUP(kind) => emit(if (kind.isWideType) Opcodes.DUP2 else Opcodes.DUP)
- case icodes.constCat => genConstant(jmethod, instr.asInstanceOf[CONSTANT].constant)
+ case LOAD_EXCEPTION(_) => ()
+ }
+ genStackInstr
- case icodes.arilogCat => genPrimitive(instr.asInstanceOf[CALL_PRIMITIVE].primitive, instr.pos)
+ case icodes.constCat => genConstant(jmethod, instr.asInstanceOf[CONSTANT].constant)
- case icodes.castsCat => (instr: @unchecked) match {
+ case icodes.arilogCat => genPrimitive(instr.asInstanceOf[CALL_PRIMITIVE].primitive, instr.pos)
- case IS_INSTANCE(tpe) =>
- val jtyp: asm.Type =
- tpe match {
- case REFERENCE(cls) => asm.Type.getObjectType(javaName(cls))
- case ARRAY(elem) => javaArrayType(javaType(elem))
- case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
- }
- jmethod.visitTypeInsn(Opcodes.INSTANCEOF, jtyp.getInternalName)
+ case icodes.castsCat =>
+ def genCastInstr = (instr: @unchecked) match {
- case CHECK_CAST(tpe) =>
+ case IS_INSTANCE(tpe) =>
+ val jtyp: asm.Type =
tpe match {
-
- case REFERENCE(cls) =>
- if (cls != ObjectClass) { // No need to checkcast for Objects
- jmethod.visitTypeInsn(Opcodes.CHECKCAST, javaName(cls))
- }
-
- case ARRAY(elem) =>
- val iname = javaArrayType(javaType(elem)).getInternalName
- jmethod.visitTypeInsn(Opcodes.CHECKCAST, iname)
-
- case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
+ case REFERENCE(cls) => asm.Type.getObjectType(javaName(cls))
+ case ARRAY(elem) => javaArrayType(javaType(elem))
+ case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
}
+ jmethod.visitTypeInsn(Opcodes.INSTANCEOF, jtyp.getInternalName)
- }
-
- case icodes.objsCat => (instr: @unchecked) match {
+ case CHECK_CAST(tpe) =>
+ tpe match {
- case BOX(kind) =>
- val MethodNameAndType(mname, mdesc) = jBoxTo(kind)
- jcode.invokestatic(BoxesRunTime, mname, mdesc)
+ case REFERENCE(cls) =>
+ if (cls != ObjectClass) { // No need to checkcast for Objects
+ jmethod.visitTypeInsn(Opcodes.CHECKCAST, javaName(cls))
+ }
- case UNBOX(kind) =>
- val MethodNameAndType(mname, mdesc) = jUnboxTo(kind)
- jcode.invokestatic(BoxesRunTime, mname, mdesc)
+ case ARRAY(elem) =>
+ val iname = javaArrayType(javaType(elem)).getInternalName
+ jmethod.visitTypeInsn(Opcodes.CHECKCAST, iname)
- case NEW(REFERENCE(cls)) =>
- val className = javaName(cls)
- jmethod.visitTypeInsn(Opcodes.NEW, className)
+ case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
+ }
- case MONITOR_ENTER() => emit(Opcodes.MONITORENTER)
- case MONITOR_EXIT() => emit(Opcodes.MONITOREXIT)
- }
+ }
+ genCastInstr
- case icodes.fldsCat => (instr: @unchecked) match {
+ case icodes.objsCat =>
+ def genObjsInstr = (instr: @unchecked) match {
- case lf @ LOAD_FIELD(field, isStatic) =>
- var owner = javaName(lf.hostClass)
- debuglog("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags))
- val fieldJName = javaName(field)
- val fieldDescr = descriptor(field)
- val opc = if (isStatic) Opcodes.GETSTATIC else Opcodes.GETFIELD
- jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
+ case BOX(kind) =>
+ val MethodNameAndType(mname, mdesc) = jBoxTo(kind)
+ jcode.invokestatic(BoxesRunTime, mname, mdesc)
- case STORE_FIELD(field, isStatic) =>
- val owner = javaName(field.owner)
- val fieldJName = javaName(field)
- val fieldDescr = descriptor(field)
- val opc = if (isStatic) Opcodes.PUTSTATIC else Opcodes.PUTFIELD
- jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
+ case UNBOX(kind) =>
+ val MethodNameAndType(mname, mdesc) = jUnboxTo(kind)
+ jcode.invokestatic(BoxesRunTime, mname, mdesc)
- }
+ case NEW(REFERENCE(cls)) =>
+ val className = javaName(cls)
+ jmethod.visitTypeInsn(Opcodes.NEW, className)
- case icodes.mthdsCat => (instr: @unchecked) match {
+ case MONITOR_ENTER() => emit(Opcodes.MONITORENTER)
+ case MONITOR_EXIT() => emit(Opcodes.MONITOREXIT)
+ }
+ genObjsInstr
+
+ case icodes.fldsCat =>
+ def genFldsInstr = (instr: @unchecked) match {
+
+ case lf @ LOAD_FIELD(field, isStatic) =>
+ var owner = javaName(lf.hostClass)
+ debuglog("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags))
+ val fieldJName = javaName(field)
+ val fieldDescr = descriptor(field)
+ val opc = if (isStatic) Opcodes.GETSTATIC else Opcodes.GETFIELD
+ jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
+
+ case STORE_FIELD(field, isStatic) =>
+ val owner = javaName(field.owner)
+ val fieldJName = javaName(field)
+ val fieldDescr = descriptor(field)
+ val opc = if (isStatic) Opcodes.PUTSTATIC else Opcodes.PUTFIELD
+ jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
- /** Special handling to access native Array.clone() */
- case call @ CALL_METHOD(definitions.Array_clone, Dynamic) =>
- val target: String = javaType(call.targetTypeKind).getInternalName
- jcode.invokevirtual(target, "clone", mdesc_arrayClone)
+ }
+ genFldsInstr
- case call @ CALL_METHOD(method, style) => genCallMethod(call)
+ case icodes.mthdsCat =>
+ def genMethodsInstr = (instr: @unchecked) match {
- }
+ /** Special handling to access native Array.clone() */
+ case call @ CALL_METHOD(definitions.Array_clone, Dynamic) =>
+ val target: String = javaType(call.targetTypeKind).getInternalName
+ jcode.invokevirtual(target, "clone", mdesc_arrayClone)
- case icodes.arraysCat => (instr: @unchecked) match {
- case LOAD_ARRAY_ITEM(kind) => jcode.aload(kind)
- case STORE_ARRAY_ITEM(kind) => jcode.astore(kind)
- case CREATE_ARRAY(elem, 1) => jcode newarray elem
- case CREATE_ARRAY(elem, dims) => jmethod.visitMultiANewArrayInsn(descriptor(ArrayN(elem, dims)), dims)
- }
+ case call @ CALL_METHOD(method, style) => genCallMethod(call)
- case icodes.jumpsCat => (instr: @unchecked) match {
-
- case sw @ SWITCH(tagss, branches) =>
- assert(branches.length == tagss.length + 1, sw)
- val flatSize = sw.flatTagsCount
- val flatKeys = new Array[Int](flatSize)
- val flatBranches = new Array[asm.Label](flatSize)
-
- var restTagss = tagss
- var restBranches = branches
- var k = 0 // ranges over flatKeys and flatBranches
- while(restTagss.nonEmpty) {
- val currLabel = labels(restBranches.head)
- for(cTag <- restTagss.head) {
- flatKeys(k) = cTag;
- flatBranches(k) = currLabel
- k += 1
- }
- restTagss = restTagss.tail
- restBranches = restBranches.tail
+ }
+ genMethodsInstr
+
+ case icodes.arraysCat =>
+ def genArraysInstr = (instr: @unchecked) match {
+ case LOAD_ARRAY_ITEM(kind) => jcode.aload(kind)
+ case STORE_ARRAY_ITEM(kind) => jcode.astore(kind)
+ case CREATE_ARRAY(elem, 1) => jcode newarray elem
+ case CREATE_ARRAY(elem, dims) => jmethod.visitMultiANewArrayInsn(descriptor(ArrayN(elem, dims)), dims)
+ }
+ genArraysInstr
+
+ case icodes.jumpsCat =>
+ def genJumpInstr = (instr: @unchecked) match {
+
+ case sw @ SWITCH(tagss, branches) =>
+ assert(branches.length == tagss.length + 1, sw)
+ val flatSize = sw.flatTagsCount
+ val flatKeys = new Array[Int](flatSize)
+ val flatBranches = new Array[asm.Label](flatSize)
+
+ var restTagss = tagss
+ var restBranches = branches
+ var k = 0 // ranges over flatKeys and flatBranches
+ while (restTagss.nonEmpty) {
+ val currLabel = labels(restBranches.head)
+ for (cTag <- restTagss.head) {
+ flatKeys(k) = cTag;
+ flatBranches(k) = currLabel
+ k += 1
}
- val defaultLabel = labels(restBranches.head)
- assert(restBranches.tail.isEmpty)
- debuglog("Emitting SWITCH:\ntags: " + tagss + "\nbranches: " + branches)
- jcode.emitSWITCH(flatKeys, flatBranches, defaultLabel, MIN_SWITCH_DENSITY)
-
- case JUMP(whereto) =>
- if (nextBlock != whereto) {
- jcode goTo labels(whereto)
- } else if(m.exh.exists(eh => eh.covers(b))) {
- // SI-6102: Determine whether eliding this JUMP results in an empty range being covered by some EH.
- // If so, emit a NOP in place of the elided JUMP, to avoid "java.lang.ClassFormatError: Illegal exception table range"
- val isSthgLeft = b.toList.exists {
- case _: LOAD_EXCEPTION => false
- case _: SCOPE_ENTER => false
- case _: SCOPE_EXIT => false
- case _: JUMP => false
- case _ => true
- }
- if(!isSthgLeft) {
- emit(asm.Opcodes.NOP)
- }
+ restTagss = restTagss.tail
+ restBranches = restBranches.tail
+ }
+ val defaultLabel = labels(restBranches.head)
+ assert(restBranches.tail.isEmpty)
+ debuglog("Emitting SWITCH:\ntags: " + tagss + "\nbranches: " + branches)
+ jcode.emitSWITCH(flatKeys, flatBranches, defaultLabel, MIN_SWITCH_DENSITY)
+
+ case JUMP(whereto) =>
+ if (nextBlock != whereto) {
+ jcode goTo labels(whereto)
+ } else if (m.exh.exists(eh => eh.covers(b))) {
+ // SI-6102: Determine whether eliding this JUMP results in an empty range being covered by some EH.
+ // If so, emit a NOP in place of the elided JUMP, to avoid "java.lang.ClassFormatError: Illegal exception table range"
+ val isSthgLeft = b.toList.exists {
+ case _: LOAD_EXCEPTION => false
+ case _: SCOPE_ENTER => false
+ case _: SCOPE_EXIT => false
+ case _: JUMP => false
+ case _ => true
}
+ if (!isSthgLeft) {
+ emit(asm.Opcodes.NOP)
+ }
+ }
- case CJUMP(success, failure, cond, kind) =>
- if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
- if (nextBlock == success) {
- jcode.emitIF_ICMP(cond.negate, labels(failure))
- // .. and fall through to success label
- } else {
- jcode.emitIF_ICMP(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
- } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
- if (nextBlock == success) {
- jcode.emitIF_ACMP(cond.negate, labels(failure))
- // .. and fall through to success label
- } else {
- jcode.emitIF_ACMP(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
+ case CJUMP(success, failure, cond, kind) =>
+ if (kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
+ if (nextBlock == success) {
+ jcode.emitIF_ICMP(cond.negate, labels(failure))
+ // .. and fall through to success label
} else {
- (kind: @unchecked) match {
- case LONG => emit(Opcodes.LCMP)
- case FLOAT =>
- if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
- else emit(Opcodes.FCMPL)
- case DOUBLE =>
- if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
- else emit(Opcodes.DCMPL)
- }
- if (nextBlock == success) {
- jcode.emitIF(cond.negate, labels(failure))
- // .. and fall through to success label
- } else {
- jcode.emitIF(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
+ jcode.emitIF_ICMP(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
}
-
- case CZJUMP(success, failure, cond, kind) =>
- if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
- if (nextBlock == success) {
- jcode.emitIF(cond.negate, labels(failure))
- } else {
- jcode.emitIF(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
- } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
- val Success = success
- val Failure = failure
- // @unchecked because references aren't compared with GT, GE, LT, LE.
- ((cond, nextBlock) : @unchecked) match {
- case (EQ, Success) => jcode emitIFNONNULL labels(failure)
- case (NE, Failure) => jcode emitIFNONNULL labels(success)
- case (EQ, Failure) => jcode emitIFNULL labels(success)
- case (NE, Success) => jcode emitIFNULL labels(failure)
- case (EQ, _) =>
- jcode emitIFNULL labels(success)
- jcode goTo labels(failure)
- case (NE, _) =>
- jcode emitIFNONNULL labels(success)
- jcode goTo labels(failure)
- }
+ } else if (kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ if (nextBlock == success) {
+ jcode.emitIF_ACMP(cond.negate, labels(failure))
+ // .. and fall through to success label
} else {
- (kind: @unchecked) match {
- case LONG =>
- emit(Opcodes.LCONST_0)
- emit(Opcodes.LCMP)
- case FLOAT =>
- emit(Opcodes.FCONST_0)
- if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
- else emit(Opcodes.FCMPL)
- case DOUBLE =>
- emit(Opcodes.DCONST_0)
- if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
- else emit(Opcodes.DCMPL)
- }
- if (nextBlock == success) {
- jcode.emitIF(cond.negate, labels(failure))
- } else {
- jcode.emitIF(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
+ jcode.emitIF_ACMP(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
}
+ } else {
+ (kind: @unchecked) match {
+ case LONG => emit(Opcodes.LCMP)
+ case FLOAT =>
+ if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
+ else emit(Opcodes.FCMPL)
+ case DOUBLE =>
+ if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
+ else emit(Opcodes.DCMPL)
+ }
+ if (nextBlock == success) {
+ jcode.emitIF(cond.negate, labels(failure))
+ // .. and fall through to success label
+ } else {
+ jcode.emitIF(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
+ }
+ }
- }
-
- case icodes.retCat => (instr: @unchecked) match {
- case RETURN(kind) => jcode emitRETURN kind
- case THROW(_) => emit(Opcodes.ATHROW)
- }
+ case CZJUMP(success, failure, cond, kind) =>
+ if (kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
+ if (nextBlock == success) {
+ jcode.emitIF(cond.negate, labels(failure))
+ } else {
+ jcode.emitIF(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
+ }
+ } else if (kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ val Success = success
+ val Failure = failure
+ // @unchecked because references aren't compared with GT, GE, LT, LE.
+ ((cond, nextBlock): @unchecked) match {
+ case (EQ, Success) => jcode emitIFNONNULL labels(failure)
+ case (NE, Failure) => jcode emitIFNONNULL labels(success)
+ case (EQ, Failure) => jcode emitIFNULL labels(success)
+ case (NE, Success) => jcode emitIFNULL labels(failure)
+ case (EQ, _) =>
+ jcode emitIFNULL labels(success)
+ jcode goTo labels(failure)
+ case (NE, _) =>
+ jcode emitIFNONNULL labels(success)
+ jcode goTo labels(failure)
+ }
+ } else {
+ (kind: @unchecked) match {
+ case LONG =>
+ emit(Opcodes.LCONST_0)
+ emit(Opcodes.LCMP)
+ case FLOAT =>
+ emit(Opcodes.FCONST_0)
+ if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
+ else emit(Opcodes.FCMPL)
+ case DOUBLE =>
+ emit(Opcodes.DCONST_0)
+ if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
+ else emit(Opcodes.DCMPL)
+ }
+ if (nextBlock == success) {
+ jcode.emitIF(cond.negate, labels(failure))
+ } else {
+ jcode.emitIF(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
+ }
+ }
}
+ genJumpInstr
+ case icodes.retCat =>
+ def genRetInstr = (instr: @unchecked) match {
+ case RETURN(kind) => jcode emitRETURN kind
+ case THROW(_) => emit(Opcodes.ATHROW)
+ }
+ genRetInstr
}
-
- } // end of genCode()'s genBlock()
+ }
/**
* Emits one or more conversion instructions based on the types given as arguments.
@@ -2755,6 +2785,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
case Negation(kind) => jcode.neg(kind)
case Arithmetic(op, kind) =>
+ def genArith = {
op match {
case ADD => jcode.add(kind)
@@ -2777,57 +2808,89 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
case _ =>
abort("Unknown arithmetic primitive " + primitive)
}
+ }
+ genArith
// TODO Logical's 2nd elem should be declared ValueTypeKind, to better approximate its allowed values (isIntSized, its comments appears to convey)
// TODO GenICode uses `toTypeKind` to define that elem, `toValueTypeKind` would be needed instead.
// TODO How about adding some asserts to Logical and similar ones to capture the remaining constraint (UNIT not allowed).
- case Logical(op, kind) => ((op, kind): @unchecked) match {
- case (AND, LONG) => emit(Opcodes.LAND)
- case (AND, INT) => emit(Opcodes.IAND)
- case (AND, _) =>
- emit(Opcodes.IAND)
- if (kind != BOOL) { emitT2T(INT, kind) }
-
- case (OR, LONG) => emit(Opcodes.LOR)
- case (OR, INT) => emit(Opcodes.IOR)
- case (OR, _) =>
- emit(Opcodes.IOR)
- if (kind != BOOL) { emitT2T(INT, kind) }
-
- case (XOR, LONG) => emit(Opcodes.LXOR)
- case (XOR, INT) => emit(Opcodes.IXOR)
- case (XOR, _) =>
- emit(Opcodes.IXOR)
- if (kind != BOOL) { emitT2T(INT, kind) }
- }
-
- case Shift(op, kind) => ((op, kind): @unchecked) match {
- case (LSL, LONG) => emit(Opcodes.LSHL)
- case (LSL, INT) => emit(Opcodes.ISHL)
- case (LSL, _) =>
- emit(Opcodes.ISHL)
- emitT2T(INT, kind)
-
- case (ASR, LONG) => emit(Opcodes.LSHR)
- case (ASR, INT) => emit(Opcodes.ISHR)
- case (ASR, _) =>
- emit(Opcodes.ISHR)
- emitT2T(INT, kind)
-
- case (LSR, LONG) => emit(Opcodes.LUSHR)
- case (LSR, INT) => emit(Opcodes.IUSHR)
- case (LSR, _) =>
- emit(Opcodes.IUSHR)
- emitT2T(INT, kind)
- }
+ case Logical(op, kind) =>
+ def genLogical = op match {
+ case AND =>
+ kind match {
+ case LONG => emit(Opcodes.LAND)
+ case INT => emit(Opcodes.IAND)
+ case _ =>
+ emit(Opcodes.IAND)
+ if (kind != BOOL) { emitT2T(INT, kind) }
+ }
+ case OR =>
+ kind match {
+ case LONG => emit(Opcodes.LOR)
+ case INT => emit(Opcodes.IOR)
+ case _ =>
+ emit(Opcodes.IOR)
+ if (kind != BOOL) { emitT2T(INT, kind) }
+ }
+ case XOR =>
+ kind match {
+ case LONG => emit(Opcodes.LXOR)
+ case INT => emit(Opcodes.IXOR)
+ case _ =>
+ emit(Opcodes.IXOR)
+ if (kind != BOOL) { emitT2T(INT, kind) }
+ }
+ }
+ genLogical
+
+ case Shift(op, kind) =>
+ def genShift = op match {
+ case LSL =>
+ kind match {
+ case LONG => emit(Opcodes.LSHL)
+ case INT => emit(Opcodes.ISHL)
+ case _ =>
+ emit(Opcodes.ISHL)
+ emitT2T(INT, kind)
+ }
+ case ASR =>
+ kind match {
+ case LONG => emit(Opcodes.LSHR)
+ case INT => emit(Opcodes.ISHR)
+ case _ =>
+ emit(Opcodes.ISHR)
+ emitT2T(INT, kind)
+ }
+ case LSR =>
+ kind match {
+ case LONG => emit(Opcodes.LUSHR)
+ case INT => emit(Opcodes.IUSHR)
+ case _ =>
+ emit(Opcodes.IUSHR)
+ emitT2T(INT, kind)
+ }
+ }
+ genShift
- case Comparison(op, kind) => ((op, kind): @unchecked) match {
- case (CMP, LONG) => emit(Opcodes.LCMP)
- case (CMPL, FLOAT) => emit(Opcodes.FCMPL)
- case (CMPG, FLOAT) => emit(Opcodes.FCMPG)
- case (CMPL, DOUBLE) => emit(Opcodes.DCMPL)
- case (CMPG, DOUBLE) => emit(Opcodes.DCMPL) // TODO bug? why not DCMPG? http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc3.html
- }
+ case Comparison(op, kind) =>
+ def genCompare = op match {
+ case CMP =>
+ (kind: @unchecked) match {
+ case LONG => emit(Opcodes.LCMP)
+ }
+ case CMPL =>
+ (kind: @unchecked) match {
+ case FLOAT => emit(Opcodes.FCMPL)
+ case DOUBLE => emit(Opcodes.DCMPL)
+ }
+ case CMPG =>
+ (kind: @unchecked) match {
+ case FLOAT => emit(Opcodes.FCMPG)
+ case DOUBLE => emit(Opcodes.DCMPL) // TODO bug? why not DCMPG? http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc3.html
+
+ }
+ }
+ genCompare
case Conversion(src, dst) =>
debuglog("Converting from: " + src + " to: " + dst)
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 213a995e96..8e77f8b6f4 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -250,7 +250,7 @@ abstract class SymbolLoaders {
protected def description = "class file "+ classfile.toString
protected def doComplete(root: Symbol) {
- val start = Statistics.startTimer(classReadNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(classReadNanos) else null
classfileParser.parse(classfile, root)
if (root.associatedFile eq null) {
root match {
@@ -262,7 +262,7 @@ abstract class SymbolLoaders {
debuglog("Not setting associatedFile to %s because %s is a %s".format(classfile, root.name, root.shortSymbolClass))
}
}
- Statistics.stopTimer(classReadNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(classReadNanos, start)
}
override def sourcefile: Option[AbstractFile] = classfileParser.srcfile
}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 300bf833a8..570704f049 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -91,40 +91,9 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
*/
def toBoxedType(tp: Type) = if (isJavaValueType(tp)) boxedClass(tp.typeSymbol).tpe else tp
- override def transform(tree: Tree): Tree = tree match {
-
- /* Transforms dynamic calls (i.e. calls to methods that are undefined
- * in the erased type space) to -- dynamically -- unsafe calls using
- * reflection. This is used for structural sub-typing of refinement
- * types, but may be used for other dynamic calls in the future.
- * For 'a.f(b)' it will generate something like:
- * 'a.getClass().
- * ' getMethod("f", Array(classOf[b.type])).
- * ' invoke(a, Array(b))
- * plus all the necessary casting/boxing/etc. machinery required
- * for type-compatibility (see fixResult).
- *
- * USAGE CONTRACT:
- * There are a number of assumptions made on the way a dynamic apply
- * is used. Assumptions relative to type are handled by the erasure
- * phase.
- * - The applied arguments are compatible with AnyRef, which means
- * that an argument tree typed as AnyVal has already been extended
- * with the necessary boxing calls. This implies that passed
- * arguments might not be strictly compatible with the method's
- * parameter types (a boxed integer while int is expected).
- * - The expected return type is an AnyRef, even when the method's
- * return type is an AnyVal. This means that the tree containing the
- * call has already been extended with the necessary unboxing calls
- * (or is happy with the boxed type).
- * - The type-checker has prevented dynamic applies on methods which
- * parameter's erased types are not statically known at the call site.
- * This is necessary to allow dispatching the call to the correct
- * method (dispatching on parameters is static in Scala). In practice,
- * this limitation only arises when the called method is defined as a
- * refinement, where the refinement defines a parameter based on a
- * type variable. */
- case ad@ApplyDynamic(qual0, params) =>
+ def transformApplyDynamic(ad: ApplyDynamic) = {
+ val qual0 = ad.qual
+ val params = ad.args
if (settings.logReflectiveCalls.value)
unit.echo(ad.pos, "method invocation uses reflection")
@@ -516,6 +485,44 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
transform(t)
}
/* ### END OF DYNAMIC APPLY TRANSFORM ### */
+ }
+
+ override def transform(tree: Tree): Tree = tree match {
+
+ /* Transforms dynamic calls (i.e. calls to methods that are undefined
+ * in the erased type space) to -- dynamically -- unsafe calls using
+ * reflection. This is used for structural sub-typing of refinement
+ * types, but may be used for other dynamic calls in the future.
+ * For 'a.f(b)' it will generate something like:
+ * 'a.getClass().
+ * ' getMethod("f", Array(classOf[b.type])).
+ * ' invoke(a, Array(b))
+ * plus all the necessary casting/boxing/etc. machinery required
+ * for type-compatibility (see fixResult).
+ *
+ * USAGE CONTRACT:
+ * There are a number of assumptions made on the way a dynamic apply
+ * is used. Assumptions relative to type are handled by the erasure
+ * phase.
+ * - The applied arguments are compatible with AnyRef, which means
+ * that an argument tree typed as AnyVal has already been extended
+ * with the necessary boxing calls. This implies that passed
+ * arguments might not be strictly compatible with the method's
+ * parameter types (a boxed integer while int is expected).
+ * - The expected return type is an AnyRef, even when the method's
+ * return type is an AnyVal. This means that the tree containing the
+ * call has already been extended with the necessary unboxing calls
+ * (or is happy with the boxed type).
+ * - The type-checker has prevented dynamic applies on methods which
+ * parameter's erased types are not statically known at the call site.
+ * This is necessary to allow dispatching the call to the correct
+ * method (dispatching on parameters is static in Scala). In practice,
+ * this limitation only arises when the called method is defined as a
+ * refinement, where the refinement defines a parameter based on a
+ * type variable. */
+
+ case tree: ApplyDynamic =>
+ transformApplyDynamic(tree)
/* Some cleanup transformations add members to templates (classes, traits, etc).
* When inside a template (i.e. the body of one of its members), two maps
@@ -544,6 +551,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
}
case ValDef(mods, name, tpt, rhs) if tree.symbol.hasStaticAnnotation =>
+ def transformStaticValDef = {
log("moving @static valdef field: " + name + ", in: " + tree.symbol.owner)
val sym = tree.symbol
val owner = sym.owner
@@ -608,12 +616,15 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
}
}
super.transform(tree)
+ }
+ transformStaticValDef
/* MSIL requires that the stack is empty at the end of a try-block.
* Hence, we here rewrite all try blocks with a result != {Unit, All} such that they
* store their result in a local variable. The catch blocks are adjusted as well.
* The try tree is subsituted by a block whose result expression is read of that variable. */
case theTry @ Try(block, catches, finalizer) if shouldRewriteTry(theTry) =>
+ def transformTry = {
val tpe = theTry.tpe.widen
val tempVar = currentOwner.newVariable(mkTerm(nme.EXCEPTION_RESULT_PREFIX), theTry.pos).setInfo(tpe)
def assignBlock(rhs: Tree) = super.transform(BLOCK(Ident(tempVar) === transform(rhs)))
@@ -624,7 +635,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val newTry = Try(newBlock, newCatches, super.transform(finalizer))
typedWithPos(theTry.pos)(BLOCK(VAL(tempVar) === EmptyTree, newTry, Ident(tempVar)))
-
+ }
+ transformTry
/*
* This transformation should identify Scala symbol invocations in the tree and replace them
* with references to a static member. Also, whenever a class has at least a single symbol invocation
@@ -657,12 +669,15 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
* have little in common.
*/
case Apply(fn, (arg @ Literal(Constant(symname: String))) :: Nil) if fn.symbol == Symbol_apply =>
+ def transformApply = {
// add the symbol name to a map if it's not there already
val rhs = gen.mkMethodCall(Symbol_apply, arg :: Nil)
val staticFieldSym = getSymbolStaticField(tree.pos, symname, rhs, tree)
// create a reference to a static field
val ntree = typedWithPos(tree.pos)(REF(staticFieldSym))
super.transform(ntree)
+ }
+ transformApply
// This transform replaces Array(Predef.wrapArray(Array(...)), <tag>)
// with just Array(...)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index eb3c965d7f..d97fbf5daa 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -271,8 +271,11 @@ abstract class Erasure extends AddInterfaces
poly + jsig(restpe)
case MethodType(params, restpe) =>
- "("+(params map (_.tpe) map (jsig(_))).mkString+")"+
- (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe))
+ val buf = new StringBuffer("(")
+ params foreach (p => buf append jsig(p.tpe))
+ buf append ")"
+ buf append (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe))
+ buf.toString
case RefinedType(parent :: _, decls) =>
boxedSig(parent)
@@ -485,7 +488,7 @@ abstract class Erasure extends AddInterfaces
private def isPrimitiveValueMember(sym: Symbol) =
sym != NoSymbol && isPrimitiveValueClass(sym.owner)
- private def box(tree: Tree, target: => String): Tree = {
+ @inline private def box(tree: Tree, target: => String): Tree = {
val result = box1(tree)
log("boxing "+tree+":"+tree.tpe+" to "+target+" = "+result+":"+result.tpe)
result
@@ -928,152 +931,175 @@ abstract class Erasure extends AddInterfaces
* - Reset all other type attributes to null, thus enforcing a retyping.
*/
private val preTransformer = new TypingTransformer(unit) {
- def preErase(tree: Tree): Tree = tree match {
- case ClassDef(_,_,_,_) =>
- debuglog("defs of " + tree.symbol + " = " + tree.symbol.info.decls)
- copyClassDef(tree)(tparams = Nil)
- case DefDef(_,_,_,_,_,_) =>
- copyDefDef(tree)(tparams = Nil)
- case TypeDef(_, _, _, _) =>
- EmptyTree
- case Apply(instanceOf @ TypeApply(fun @ Select(qual, name), args @ List(arg)), List()) // !!! todo: simplify by having GenericArray also extract trees
- if ((fun.symbol == Any_isInstanceOf || fun.symbol == Object_isInstanceOf) &&
- unboundedGenericArrayLevel(arg.tpe) > 0) =>
- val level = unboundedGenericArrayLevel(arg.tpe)
- def isArrayTest(arg: Tree) =
- gen.mkRuntimeCall(nme.isArray, List(arg, Literal(Constant(level))))
-
- global.typer.typedPos(tree.pos) {
- if (level == 1) isArrayTest(qual)
- else gen.evalOnce(qual, currentOwner, unit) { qual1 =>
- gen.mkAnd(
- gen.mkMethodCall(
- qual1(),
- fun.symbol,
- List(specialErasure(fun.symbol)(arg.tpe)),
- Nil
- ),
- isArrayTest(qual1())
- )
- }
+
+ private def preEraseNormalApply(tree: Apply) = {
+ val fn = tree.fun
+ val args = tree.args
+
+ def qualifier = fn match {
+ case Select(qual, _) => qual
+ case TypeApply(Select(qual, _), _) => qual
+ }
+
+ def preEraseAsInstanceOf = {
+ (fn: @unchecked) match {
+ case TypeApply(Select(qual, _), List(targ)) =>
+ if (qual.tpe <:< targ.tpe)
+ atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
+ else if (isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(targ.tpe.typeSymbol))
+ atPos(tree.pos)(numericConversion(qual, targ.tpe.typeSymbol))
+ else
+ tree
}
- case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
- fun.symbol != Object_asInstanceOf &&
- fun.symbol != Object_isInstanceOf) =>
- // leave all other type tests/type casts, remove all other type applications
- preErase(fun)
- case Apply(fn @ Select(qual, name), args) if fn.symbol.owner == ArrayClass =>
- // Have to also catch calls to abstract types which are bounded by Array.
- if (unboundedGenericArrayLevel(qual.tpe.widen) == 1 || qual.tpe.typeSymbol.isAbstractType) {
- // convert calls to apply/update/length on generic arrays to
- // calls of ScalaRunTime.array_xxx method calls
- global.typer.typedPos(tree.pos)({
- val arrayMethodName = name match {
- case nme.apply => nme.array_apply
- case nme.length => nme.array_length
- case nme.update => nme.array_update
- case nme.clone_ => nme.array_clone
- case _ => unit.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME
+ // todo: also handle the case where the singleton type is buried in a compound
+ }
+
+ def preEraseIsInstanceOf = {
+ fn match {
+ case TypeApply(sel @ Select(qual, name), List(targ)) =>
+ if (qual.tpe != null && isPrimitiveValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefClass.tpe)
+ unit.error(sel.pos, "isInstanceOf cannot test if value types are references.")
+
+ def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
+ Apply(
+ TypeApply(
+ Select(q(), Object_isInstanceOf) setPos sel.pos,
+ List(TypeTree(tp) setPos targ.pos)) setPos fn.pos,
+ List()) setPos tree.pos
+ targ.tpe match {
+ case SingleType(_, _) | ThisType(_) | SuperType(_, _) =>
+ val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq
+ atPos(tree.pos) {
+ Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe)))
+ }
+ case RefinedType(parents, decls) if (parents.length >= 2) =>
+ // Optimization: don't generate isInstanceOf tests if the static type
+ // conforms, because it always succeeds. (Or at least it had better.)
+ // At this writing the pattern matcher generates some instance tests
+ // involving intersections where at least one parent is statically known true.
+ // That needs fixing, but filtering the parents here adds an additional
+ // level of robustness (in addition to the short term fix.)
+ val parentTests = parents filterNot (qual.tpe <:< _)
+
+ if (parentTests.isEmpty) Literal(Constant(true))
+ else gen.evalOnce(qual, currentOwner, unit) { q =>
+ atPos(tree.pos) {
+ parentTests map mkIsInstanceOf(q) reduceRight gen.mkAnd
+ }
+ }
+ case _ =>
+ tree
}
- gen.mkRuntimeCall(arrayMethodName, qual :: args)
- })
+ case _ => tree
}
- else {
- // store exact array erasure in map to be retrieved later when we might
- // need to do the cast in adaptMember
- treeCopy.Apply(
- tree,
- SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn),
- args)
- }
- case Apply(fn @ Select(qual, _), Nil) if interceptedMethods(fn.symbol) =>
- if (fn.symbol == Any_## || fn.symbol == Object_##) {
- // This is unattractive, but without it we crash here on ().## because after
- // erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int.
- // This must be because some earlier transformation is being skipped on ##, but so
- // far I don't know what. For null we now define null.## == 0.
- qual.tpe.typeSymbol match {
- case UnitClass | NullClass => LIT(0)
- case IntClass => qual
- case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual, s)
- case BooleanClass => If(qual, LIT(true.##), LIT(false.##))
- case _ =>
- global.typer.typed(gen.mkRuntimeCall(nme.hash_, List(qual)))
- }
- }
- // Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
- else if (isPrimitiveValueClass(qual.tpe.typeSymbol))
- global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen))))
- else
- tree
+ }
+ if (fn.symbol == Any_asInstanceOf) {
+ preEraseAsInstanceOf
+ } else if (fn.symbol == Any_isInstanceOf) {
+ preEraseIsInstanceOf
+ } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) {
+ ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos
+ } else if (fn.symbol.isMethodWithExtension) {
+ Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args)
+ } else {
+ tree
+ }
+ }
- case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isDerivedValueClass) =>
-// println("inject derived: "+arg+" "+tpt.tpe)
- InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol
- new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef])
- case Apply(fn, args) =>
- def qualifier = fn match {
- case Select(qual, _) => qual
- case TypeApply(Select(qual, _), _) => qual
- }
- if (fn.symbol == Any_asInstanceOf)
- (fn: @unchecked) match {
- case TypeApply(Select(qual, _), List(targ)) =>
- if (qual.tpe <:< targ.tpe)
- atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
- else if (isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(targ.tpe.typeSymbol))
- atPos(tree.pos)(numericConversion(qual, targ.tpe.typeSymbol))
- else
- tree
+ private def preEraseApply(tree: Apply) = {
+ tree.fun match {
+ case TypeApply(fun @ Select(qual, name), args @ List(arg))
+ if ((fun.symbol == Any_isInstanceOf || fun.symbol == Object_isInstanceOf) &&
+ unboundedGenericArrayLevel(arg.tpe) > 0) => // !!! todo: simplify by having GenericArray also extract trees
+ val level = unboundedGenericArrayLevel(arg.tpe)
+ def isArrayTest(arg: Tree) =
+ gen.mkRuntimeCall(nme.isArray, List(arg, Literal(Constant(level))))
+
+ global.typer.typedPos(tree.pos) {
+ if (level == 1) isArrayTest(qual)
+ else gen.evalOnce(qual, currentOwner, unit) { qual1 =>
+ gen.mkAnd(
+ gen.mkMethodCall(
+ qual1(),
+ fun.symbol,
+ List(specialErasure(fun.symbol)(arg.tpe)),
+ Nil
+ ),
+ isArrayTest(qual1())
+ )
+ }
}
- // todo: also handle the case where the singleton type is buried in a compound
- else if (fn.symbol == Any_isInstanceOf) {
- fn match {
- case TypeApply(sel @ Select(qual, name), List(targ)) =>
- if (qual.tpe != null && isPrimitiveValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefClass.tpe)
- unit.error(sel.pos, "isInstanceOf cannot test if value types are references.")
-
- def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
- Apply(
- TypeApply(
- Select(q(), Object_isInstanceOf) setPos sel.pos,
- List(TypeTree(tp) setPos targ.pos)) setPos fn.pos,
- List()) setPos tree.pos
- targ.tpe match {
- case SingleType(_, _) | ThisType(_) | SuperType(_, _) =>
- val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq
- atPos(tree.pos) {
- Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe)))
- }
- case RefinedType(parents, decls) if (parents.length >= 2) =>
- // Optimization: don't generate isInstanceOf tests if the static type
- // conforms, because it always succeeds. (Or at least it had better.)
- // At this writing the pattern matcher generates some instance tests
- // involving intersections where at least one parent is statically known true.
- // That needs fixing, but filtering the parents here adds an additional
- // level of robustness (in addition to the short term fix.)
- val parentTests = parents filterNot (qual.tpe <:< _)
-
- if (parentTests.isEmpty) Literal(Constant(true))
- else gen.evalOnce(qual, currentOwner, unit) { q =>
- atPos(tree.pos) {
- parentTests map mkIsInstanceOf(q) reduceRight gen.mkAnd
- }
- }
- case _ =>
- tree
+ case fn @ Select(qual, name) =>
+ val args = tree.args
+ if (fn.symbol.owner == ArrayClass) {
+ // Have to also catch calls to abstract types which are bounded by Array.
+ if (unboundedGenericArrayLevel(qual.tpe.widen) == 1 || qual.tpe.typeSymbol.isAbstractType) {
+ // convert calls to apply/update/length on generic arrays to
+ // calls of ScalaRunTime.array_xxx method calls
+ global.typer.typedPos(tree.pos) {
+ val arrayMethodName = name match {
+ case nme.apply => nme.array_apply
+ case nme.length => nme.array_length
+ case nme.update => nme.array_update
+ case nme.clone_ => nme.array_clone
+ case _ => unit.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME
+ }
+ gen.mkRuntimeCall(arrayMethodName, qual :: args)
}
- case _ => tree
- }
- } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) {
- ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos
- } else if (fn.symbol.isMethodWithExtension) {
- Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args)
- } else {
+ } else {
+ // store exact array erasure in map to be retrieved later when we might
+ // need to do the cast in adaptMember
+ treeCopy.Apply(
+ tree,
+ SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn),
+ args)
+ }
+ } else if (args.isEmpty && interceptedMethods(fn.symbol)) {
+ if (fn.symbol == Any_## || fn.symbol == Object_##) {
+ // This is unattractive, but without it we crash here on ().## because after
+ // erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int.
+ // This must be because some earlier transformation is being skipped on ##, but so
+ // far I don't know what. For null we now define null.## == 0.
+ qual.tpe.typeSymbol match {
+ case UnitClass | NullClass => LIT(0)
+ case IntClass => qual
+ case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual, s)
+ case BooleanClass => If(qual, LIT(true.##), LIT(false.##))
+ case _ =>
+ global.typer.typed(gen.mkRuntimeCall(nme.hash_, List(qual)))
+ }
+ } else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
+ // Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
+ global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen))))
+ } else {
tree
+ }
+ } else qual match {
+ case New(tpt) if name == nme.CONSTRUCTOR && tpt.tpe.typeSymbol.isDerivedValueClass =>
+ // println("inject derived: "+arg+" "+tpt.tpe)
+ val List(arg) = args
+ InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol
+ new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef])
+ case _ =>
+ preEraseNormalApply(tree)
}
+ case _ =>
+ preEraseNormalApply(tree)
+ }
+ }
+
+ def preErase(tree: Tree): Tree = tree match {
+ case tree: Apply =>
+ preEraseApply(tree)
+
+ case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
+ fun.symbol != Object_asInstanceOf &&
+ fun.symbol != Object_isInstanceOf) =>
+ // leave all other type tests/type casts, remove all other type applications
+ preErase(fun)
+
case Select(qual, name) =>
val owner = tree.symbol.owner
// println("preXform: "+ (tree, tree.symbol, tree.symbol.owner, tree.symbol.owner.isRefinementClass))
@@ -1120,6 +1146,14 @@ abstract class Erasure extends AddInterfaces
}
treeCopy.Literal(tree, Constant(erased))
+ case ClassDef(_,_,_,_) =>
+ debuglog("defs of " + tree.symbol + " = " + tree.symbol.info.decls)
+ copyClassDef(tree)(tparams = Nil)
+ case DefDef(_,_,_,_,_,_) =>
+ copyDefDef(tree)(tparams = Nil)
+ case TypeDef(_, _, _, _) =>
+ EmptyTree
+
case _ =>
tree
}
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 30cab66677..fc9e611d20 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -1399,6 +1399,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
curTree = tree
tree match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
+ def transformNew = {
debuglog("Attempting to specialize new %s(%s)".format(tpt, args.mkString(", ")))
val found = findSpec(tpt.tpe)
if (found.typeSymbol ne tpt.tpe.typeSymbol) {
@@ -1410,9 +1411,26 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
_ => super.transform(tree)
}
} else super.transform(tree)
+ }
+ transformNew
+
+ case Apply(sel @ Select(sup @ Super(qual, name), name1), args)
+ if (sup.symbol.info.parents != beforePrevPhase(sup.symbol.info.parents)) =>
+ def transformSuperApply = {
+
+ def parents = sup.symbol.info.parents
+ debuglog(tree + " parents changed from: " + beforePrevPhase(parents) + " to: " + parents)
+
+ val res = localTyper.typed(
+ Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos)
+ debuglog("retyping call to super, from: " + symbol + " to " + res.symbol)
+ res
+ }
+ transformSuperApply
case TypeApply(sel @ Select(qual, name), targs)
if (!specializedTypeVars(symbol.info).isEmpty && name != nme.CONSTRUCTOR) =>
+ def transformTypeApply = {
debuglog("checking typeapp for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe)
val qual1 = transform(qual)
// log(">>> TypeApply: " + tree + ", qual1: " + qual1)
@@ -1445,14 +1463,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// See pos/exponential-spec.scala - can't call transform on the whole tree again.
// super.transform(tree)
}
-
- case Select(Super(_, _), name) if illegalSpecializedInheritance(currentClass) =>
- val pos = tree.pos
- debuglog(pos.source.file.name+":"+pos.line+": not specializing call to super inside illegal specialized inheritance class.")
- debuglog(pos.lineContent)
- tree
+ }
+ transformTypeApply
case Select(qual, name) =>
+ def transformSelect = {
+ qual match {
+ case _: Super if illegalSpecializedInheritance(currentClass) =>
+ val pos = tree.pos
+ debuglog(pos.source.file.name+":"+pos.line+": not specializing call to super inside illegal specialized inheritance class.")
+ debuglog(pos.lineContent)
+ tree
+ case _ =>
+
debuglog("specializing Select %s [tree.tpe: %s]".format(symbol.defString, tree.tpe))
//log("!!! select " + tree + " -> " + symbol.info + " specTypeVars: " + specializedTypeVars(symbol.info))
@@ -1488,6 +1511,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case None =>
super.transform(tree)
}
+ }
+ }
+ transformSelect
case PackageDef(pid, stats) =>
tree.symbol.info // make sure specializations have been performed
@@ -1497,6 +1523,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
case Template(parents, self, body) =>
+ def transformTemplate = {
val specMembers = makeSpecializedMembers(tree.symbol.enclClass) ::: (implSpecClasses(body) map localTyper.typed)
if (!symbol.isPackageClass)
(new CollectMethodBodies)(tree)
@@ -1507,8 +1534,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ ,
self,
atOwner(currentOwner)(transformTrees(body ::: specMembers)))
+ }
+ transformTemplate
case ddef @ DefDef(_, _, _, vparamss, _, _) if info.isDefinedAt(symbol) =>
+ def transformDefDef = {
// log("--> method: " + ddef + " in " + ddef.symbol.owner + ", " + info(symbol))
def reportTypeError(body: =>Tree) = reportError(body)(_ => ddef)
@@ -1597,8 +1627,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
debuglog("abstract: " + targ)
localTyper.typed(deriveDefDef(tree)(rhs => rhs))
}
+ }
+ transformDefDef
case ValDef(_, _, _, _) if symbol.hasFlag(SPECIALIZED) && !symbol.isParamAccessor =>
+ def transformValDef = {
assert(body.isDefinedAt(symbol.alias), body)
val tree1 = deriveValDef(tree)(_ => body(symbol.alias).duplicate)
debuglog("now typing: " + tree1 + " in " + tree.symbol.owner.fullName)
@@ -1612,17 +1645,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
typeEnv(symbol.alias) ++ typeEnv(tree.symbol)
)
deriveValDef(newValDef)(transform)
-
- case Apply(sel @ Select(sup @ Super(qual, name), name1), args)
- if (sup.symbol.info.parents != beforePrevPhase(sup.symbol.info.parents)) =>
-
- def parents = sup.symbol.info.parents
- debuglog(tree + " parents changed from: " + beforePrevPhase(parents) + " to: " + parents)
-
- val res = localTyper.typed(
- Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos)
- debuglog("retyping call to super, from: " + symbol + " to " + res.symbol)
- res
+ }
+ transformValDef
case _ =>
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
index 9e681b321c..82e95523d9 100644
--- a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
+++ b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
@@ -25,19 +25,14 @@ trait TypingTransformers {
protected var curTree: Tree = _
protected def typedPos(pos: Position)(tree: Tree) = localTyper typed { atPos(pos)(tree) }
- /** a typer for each enclosing class */
- val typers: mutable.Map[Symbol, analyzer.Typer] = new mutable.HashMap
-
- override def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans)
+ override final def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans)
def atOwner[A](tree: Tree, owner: Symbol)(trans: => A): A = {
val savedLocalTyper = localTyper
// println("transformer atOwner: " + owner + " isPackage? " + owner.isPackage)
localTyper = localTyper.atOwner(tree, if (owner.isModule) owner.moduleClass else owner)
- typers += Pair(owner, localTyper)
val result = super.atOwner(owner)(trans)
localTyper = savedLocalTyper
- typers -= owner
result
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index aae9625e2d..181463657b 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -693,6 +693,46 @@ abstract class UnCurry extends InfoTransform
else
tree
}
+
+ def isThrowable(pat: Tree): Boolean = pat match {
+ case Typed(Ident(nme.WILDCARD), tpt) =>
+ tpt.tpe =:= ThrowableClass.tpe
+ case Bind(_, pat) =>
+ isThrowable(pat)
+ case _ =>
+ false
+ }
+
+ def isDefaultCatch(cdef: CaseDef) = isThrowable(cdef.pat) && cdef.guard.isEmpty
+
+ def postTransformTry(tree: Try) = {
+ val body = tree.block
+ val catches = tree.catches
+ val finalizer = tree.finalizer
+ if (opt.virtPatmat) {
+ if (catches exists (cd => !treeInfo.isCatchCase(cd)))
+ debugwarn("VPM BUG! illegal try/catch " + catches)
+ tree
+ } else if (catches forall treeInfo.isCatchCase) {
+ tree
+ } else {
+ val exname = unit.freshTermName("ex$")
+ val cases =
+ if ((catches exists treeInfo.isDefaultCase) || isDefaultCatch(catches.last)) catches
+ else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
+ val catchall =
+ atPos(tree.pos) {
+ CaseDef(
+ Bind(exname, Ident(nme.WILDCARD)),
+ EmptyTree,
+ Match(Ident(exname), cases))
+ }
+ debuglog("rewrote try: " + catches + " ==> " + catchall);
+ val catches1 = localTyper.typedCases(
+ List(catchall), ThrowableClass.tpe, WildcardType)
+ treeCopy.Try(tree, body, catches1, finalizer)
+ }
+ }
tree match {
/* Some uncurry post transformations add members to templates.
@@ -724,35 +764,12 @@ abstract class UnCurry extends InfoTransform
)
addJavaVarargsForwarders(dd, flatdd)
- case Try(body, catches, finalizer) =>
- if (opt.virtPatmat) { if(catches exists (cd => !treeInfo.isCatchCase(cd))) debugwarn("VPM BUG! illegal try/catch "+ catches); tree }
- else if (catches forall treeInfo.isCatchCase) tree
- else {
- val exname = unit.freshTermName("ex$")
- val cases =
- if ((catches exists treeInfo.isDefaultCase) || (catches.last match { // bq: handle try { } catch { ... case ex:Throwable => ...}
- case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>
- true
- case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>
- true
- case _ =>
- false
- })) catches
- else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
- val catchall =
- atPos(tree.pos) {
- CaseDef(
- Bind(exname, Ident(nme.WILDCARD)),
- EmptyTree,
- Match(Ident(exname), cases))
- }
- debuglog("rewrote try: " + catches + " ==> " + catchall);
- val catches1 = localTyper.typedCases(
- List(catchall), ThrowableClass.tpe, WildcardType)
- treeCopy.Try(tree, body, catches1, finalizer)
- }
+ case tree: Try =>
+ postTransformTry(tree)
+
case Apply(Apply(fn, args), args1) =>
treeCopy.Apply(tree, fn, args ::: args1)
+
case Ident(name) =>
assert(name != tpnme.WILDCARD_STAR, tree)
applyUnary()
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 7f4f61bf80..ab8836f339 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -85,13 +85,13 @@ trait Analyzer extends AnyRef
// compiler run). This is good enough for the resident compiler, which was the most affected.
undoLog.clear()
override def run() {
- val start = Statistics.startTimer(typerNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(typerNanos) else null
global.echoPhaseSummary(this)
currentRun.units foreach applyPhase
undoLog.clear()
// need to clear it after as well or 10K+ accumulated entries are
// uncollectable the rest of the way.
- Statistics.stopTimer(typerNanos, start)
+ if (Statistics.canEnable) Statistics.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 a34fc71b8f..226e17f605 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -72,10 +72,10 @@ trait Implicits {
)
indentTyping()
- val rawTypeStart = Statistics.startCounter(rawTypeImpl)
- val findMemberStart = Statistics.startCounter(findMemberImpl)
- val subtypeStart = Statistics.startCounter(subtypeImpl)
- val start = Statistics.startTimer(implicitNanos)
+ val rawTypeStart = if (Statistics.canEnable) Statistics.startCounter(rawTypeImpl) else null
+ val findMemberStart = if (Statistics.canEnable) Statistics.startCounter(findMemberImpl) else null
+ val subtypeStart = if (Statistics.canEnable) Statistics.startCounter(subtypeImpl) else null
+ val start = if (Statistics.canEnable) Statistics.startTimer(implicitNanos) else null
if (printInfers && !tree.isEmpty && !context.undetparams.isEmpty)
printTyping("typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
@@ -87,10 +87,10 @@ trait Implicits {
printInference("[infer implicit] inferred " + result)
context.undetparams = context.undetparams filterNot result.subst.from.contains
- Statistics.stopTimer(implicitNanos, start)
- Statistics.stopCounter(rawTypeImpl, rawTypeStart)
- Statistics.stopCounter(findMemberImpl, findMemberStart)
- Statistics.stopCounter(subtypeImpl, subtypeStart)
+ if (Statistics.canEnable) Statistics.stopTimer(implicitNanos, start)
+ if (Statistics.canEnable) Statistics.stopCounter(rawTypeImpl, rawTypeStart)
+ if (Statistics.canEnable) Statistics.stopCounter(findMemberImpl, findMemberStart)
+ if (Statistics.canEnable) Statistics.stopCounter(subtypeImpl, subtypeStart)
deindentTyping()
printTyping("Implicit search yielded: "+ result)
result
@@ -181,8 +181,8 @@ trait Implicits {
containsError(restpe)
case NullaryMethodType(restpe) =>
containsError(restpe)
- case MethodType(params, restpe) =>
- params.exists(_.tpe.isError) || containsError(restpe)
+ case mt @ MethodType(_, restpe) =>
+ (mt.paramTypes exists typeIsError) || containsError(restpe)
case _ =>
tp.isError
}
@@ -308,12 +308,12 @@ trait Implicits {
/** Is implicit info `info1` better than implicit info `info2`?
*/
def improves(info1: ImplicitInfo, info2: ImplicitInfo) = {
- Statistics.incCounter(improvesCount)
+ if (Statistics.canEnable) Statistics.incCounter(improvesCount)
(info2 == NoImplicitInfo) ||
(info1 != NoImplicitInfo) && {
if (info1.sym.isStatic && info2.sym.isStatic) {
improvesCache get (info1, info2) match {
- case Some(b) => Statistics.incCounter(improvesCachedCount); b
+ case Some(b) => if (Statistics.canEnable) Statistics.incCounter(improvesCachedCount); b
case None =>
val result = isStrictlyMoreSpecific(info1.tpe, info2.tpe, info1.sym, info2.sym)
improvesCache((info1, info2)) = result
@@ -377,7 +377,7 @@ trait Implicits {
overlaps(dtor1, dted1) && (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1))
}
- Statistics.incCounter(implicitSearchCount)
+ if (Statistics.canEnable) Statistics.incCounter(implicitSearchCount)
/** The type parameters to instantiate */
val undetParams = if (isView) List() else context.outer.undetparams
@@ -429,7 +429,7 @@ trait Implicits {
* This method is performance critical: 5-8% of typechecking time.
*/
private def matchesPt(tp: Type, pt: Type, undet: List[Symbol]): Boolean = {
- val start = Statistics.startTimer(matchesPtNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(matchesPtNanos) else null
val result = normSubType(tp, pt) || isView && {
pt match {
case TypeRef(_, Function1.Sym, args) =>
@@ -438,7 +438,7 @@ trait Implicits {
false
}
}
- Statistics.stopTimer(matchesPtNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(matchesPtNanos, start)
result
}
private def matchesPt(info: ImplicitInfo): Boolean = (
@@ -537,7 +537,7 @@ trait Implicits {
}
private def typedImplicit0(info: ImplicitInfo, ptChecked: Boolean, isLocal: Boolean): SearchResult = {
- Statistics.incCounter(plausiblyCompatibleImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(plausiblyCompatibleImplicits)
printTyping (
ptBlock("typedImplicit0",
"info.name" -> info.name,
@@ -557,7 +557,7 @@ trait Implicits {
}
private def typedImplicit1(info: ImplicitInfo, isLocal: Boolean): SearchResult = {
- Statistics.incCounter(matchingImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(matchingImplicits)
val itree = atPos(pos.focus) {
// workaround for deficient context provided by ModelFactoryImplicitSupport#makeImplicitConstraints
@@ -595,7 +595,7 @@ trait Implicits {
if (context.hasErrors)
return fail("typed implicit %s has errors".format(info.sym.fullLocationString))
- Statistics.incCounter(typedImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(typedImplicits)
printTyping("typed implicit %s:%s, pt=%s".format(itree1, itree1.tpe, wildPt))
val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun }
@@ -678,7 +678,7 @@ trait Implicits {
fail("typing TypeApply reported errors for the implicit tree")
else {
val result = new SearchResult(itree2, subst)
- Statistics.incCounter(foundImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(foundImplicits)
printInference("[success] found %s for pt %s".format(result, ptInstantiated))
result
}
@@ -905,11 +905,11 @@ trait Implicits {
* @return map from infos to search results
*/
def applicableInfos(iss: Infoss, isLocal: Boolean): Map[ImplicitInfo, SearchResult] = {
- val start = Statistics.startCounter(subtypeAppInfos)
+ val start = if (Statistics.canEnable) Statistics.startCounter(subtypeAppInfos) else null
val computation = new ImplicitComputation(iss, isLocal) { }
val applicable = computation.findAll()
- Statistics.stopCounter(subtypeAppInfos, start)
+ if (Statistics.canEnable) Statistics.stopCounter(subtypeAppInfos, start)
applicable
}
@@ -1125,13 +1125,13 @@ trait Implicits {
* such that some part of `tp` has C as one of its superclasses.
*/
private def implicitsOfExpectedType: Infoss = {
- Statistics.incCounter(implicitCacheAccs)
+ if (Statistics.canEnable) Statistics.incCounter(implicitCacheAccs)
implicitsCache get pt match {
case Some(implicitInfoss) =>
- Statistics.incCounter(implicitCacheHits)
+ if (Statistics.canEnable) Statistics.incCounter(implicitCacheHits)
implicitInfoss
case None =>
- val start = Statistics.startTimer(subtypeETNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(subtypeETNanos) else null
// val implicitInfoss = companionImplicits(pt)
val implicitInfoss1 = companionImplicitMap(pt).valuesIterator.toList
// val is1 = implicitInfoss.flatten.toSet
@@ -1140,7 +1140,7 @@ trait Implicits {
// if (!(is2 contains i)) println("!!! implicit infos of "+pt+" differ, new does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
// for (i <- is2)
// if (!(is1 contains i)) println("!!! implicit infos of "+pt+" differ, old does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
- Statistics.stopTimer(subtypeETNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(subtypeETNanos, start)
implicitsCache(pt) = implicitInfoss1
if (implicitsCache.size >= sizeLimit)
implicitsCache -= implicitsCache.keysIterator.next
@@ -1372,21 +1372,21 @@ trait Implicits {
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
- val failstart = Statistics.startTimer(inscopeFailNanos)
- val succstart = Statistics.startTimer(inscopeSucceedNanos)
+ val failstart = if (Statistics.canEnable) Statistics.startTimer(inscopeFailNanos) else null
+ val succstart = if (Statistics.canEnable) Statistics.startTimer(inscopeSucceedNanos) else null
var result = searchImplicit(context.implicitss, true)
if (result == SearchFailure) {
- Statistics.stopTimer(inscopeFailNanos, failstart)
+ if (Statistics.canEnable) Statistics.stopTimer(inscopeFailNanos, failstart)
} else {
- Statistics.stopTimer(inscopeSucceedNanos, succstart)
- Statistics.incCounter(inscopeImplicitHits)
+ if (Statistics.canEnable) Statistics.stopTimer(inscopeSucceedNanos, succstart)
+ if (Statistics.canEnable) Statistics.incCounter(inscopeImplicitHits)
}
if (result == SearchFailure) {
val previousErrs = context.flushAndReturnBuffer()
- val failstart = Statistics.startTimer(oftypeFailNanos)
- val succstart = Statistics.startTimer(oftypeSucceedNanos)
+ val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null
+ val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null
result = materializeImplicit(pt)
@@ -1396,10 +1396,10 @@ trait Implicits {
if (result == SearchFailure) {
context.updateBuffer(previousErrs)
- Statistics.stopTimer(oftypeFailNanos, failstart)
+ if (Statistics.canEnable) Statistics.stopTimer(oftypeFailNanos, failstart)
} else {
- Statistics.stopTimer(oftypeSucceedNanos, succstart)
- Statistics.incCounter(oftypeImplicitHits)
+ if (Statistics.canEnable) Statistics.stopTimer(oftypeSucceedNanos, succstart)
+ if (Statistics.canEnable) Statistics.incCounter(oftypeImplicitHits)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index b502af4a7f..aa1bc0ce9d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -240,8 +240,8 @@ 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 =>
- functionType(params map (_.tpe), normalize(restpe))
+ case mt @ MethodType(_, restpe) if !mt.isDependentMethodType =>
+ functionType(mt.paramTypes, normalize(restpe))
case NullaryMethodType(restpe) =>
normalize(restpe)
case ExistentialType(tparams, qtpe) =>
@@ -661,7 +661,13 @@ trait Infer {
val restp1 = followApply(restp)
if (restp1 eq restp) tp else restp1
case _ =>
- val appmeth = tp.nonPrivateMember(nme.apply) filter (_.isPublic)
+ val appmeth = {
+ //OPT cut down on #closures by special casing non-overloaded case
+ // was: tp.nonPrivateMember(nme.apply) filter (_.isPublic)
+ val result = tp.nonPrivateMember(nme.apply)
+ if ((result eq NoSymbol) || !result.isOverloaded && result.isPublic) result
+ else result filter (_.isPublic)
+ }
if (appmeth == NoSymbol) tp
else OverloadedType(tp, appmeth.alternatives)
}
@@ -747,8 +753,8 @@ trait Infer {
alts exists (alt => isApplicable(undetparams, pre.memberType(alt), argtpes0, pt))
case ExistentialType(tparams, qtpe) =>
isApplicable(undetparams, qtpe, argtpes0, pt)
- case MethodType(params, _) =>
- val formals = formalTypes(params map { _.tpe }, argtpes0.length, removeByName = false)
+ case mt @ MethodType(params, _) =>
+ val formals = formalTypes(mt.paramTypes, argtpes0.length, removeByName = false)
def tryTupleApply: Boolean = {
// if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0
@@ -854,8 +860,8 @@ trait Infer {
isAsSpecific(res, ftpe2)
case mt: MethodType if mt.isImplicit =>
isAsSpecific(ftpe1.resultType, ftpe2)
- case MethodType(params, _) if params.nonEmpty =>
- var argtpes = params map (_.tpe)
+ case mt @ MethodType(params, _) if params.nonEmpty =>
+ var argtpes = mt.paramTypes
if (isVarArgsList(params) && isVarArgsList(ftpe2.params))
argtpes = argtpes map (argtpe =>
if (isRepeatedParamType(argtpe)) argtpe.typeArgs.head else argtpe)
@@ -864,8 +870,8 @@ trait Infer {
isAsSpecific(PolyType(tparams, res), ftpe2)
case PolyType(tparams, mt: MethodType) if mt.isImplicit =>
isAsSpecific(PolyType(tparams, mt.resultType), ftpe2)
- case PolyType(_, MethodType(params, _)) if params.nonEmpty =>
- isApplicable(List(), ftpe2, params map (_.tpe), WildcardType)
+ case PolyType(_, (mt @ MethodType(params, _))) if params.nonEmpty =>
+ isApplicable(List(), ftpe2, mt.paramTypes, WildcardType)
// case NullaryMethodType(res) =>
// isAsSpecific(res, ftpe2)
case ErrorType =>
@@ -1111,10 +1117,10 @@ trait Infer {
*/
def inferMethodInstance(fn: Tree, undetparams: List[Symbol],
args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match {
- case MethodType(params0, _) =>
+ case mt @ MethodType(params0, _) =>
try {
val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
- val formals = formalTypes(params0 map (_.tpe), args.length)
+ val formals = formalTypes(mt.paramTypes, args.length)
val argtpes = actualTypes(args map (x => elimAnonymousClass(x.tpe.deconst)), formals.length)
val restpe = fn.tpe.resultType(argtpes)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index abfefcd31e..dbafd01ebc 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -696,8 +696,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
* the expandee with an error marker set if there has been an error
*/
def macroExpand(typer: Typer, expandee: Tree, mode: Int = EXPRmode, pt: Type = WildcardType): Tree = {
- val start = Statistics.startTimer(macroExpandNanos)
- Statistics.incCounter(macroExpandCount)
+ val start = if (Statistics.canEnable) Statistics.startTimer(macroExpandNanos) else null
+ if (Statistics.canEnable) Statistics.incCounter(macroExpandCount)
try {
macroExpand1(typer, expandee) match {
case Success(expanded) =>
@@ -725,7 +725,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
result
}
} finally {
- Statistics.stopTimer(macroExpandNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(macroExpandNanos, start)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index 6eeba2b4bf..c60118a8b4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -277,7 +277,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
if(phase.id >= currentRun.uncurryPhase.id) debugwarn("running translateMatch at "+ phase +" on "+ selector +" match "+ cases)
patmatDebug("translating "+ cases.mkString("{", "\n", "}"))
- val start = Statistics.startTimer(patmatNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatNanos) else null
val selectorTp = repeatedToSeq(elimAnonymousClass(selector.tpe.widen.withoutAnnotations))
@@ -305,7 +305,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental
val combined = combineCases(selector, selectorSym, cases map translateCase(selectorSym, pt), pt, matchOwner, matchFailGenOverride)
- Statistics.stopTimer(patmatNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatNanos, start)
combined
}
@@ -1954,7 +1954,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// TODO: for V1 representing x1 and V2 standing for x1.head, encode that
// V1 = Nil implies -(V2 = Ci) for all Ci in V2's domain (i.e., it is unassignable)
def removeVarEq(props: List[Prop], modelNull: Boolean = false): (Prop, List[Prop]) = {
- val start = Statistics.startTimer(patmatAnaVarEq)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaVarEq) else null
val vars = new collection.mutable.HashSet[Var]
@@ -2009,7 +2009,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
patmatDebug("eqAxioms:\n"+ cnfString(eqFreePropToSolvable(eqAxioms)))
patmatDebug("pure:"+ pure.map(p => cnfString(eqFreePropToSolvable(p))).mkString("\n"))
- Statistics.stopTimer(patmatAnaVarEq, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaVarEq, start)
(eqAxioms, pure)
}
@@ -2040,6 +2040,11 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
trait CNF extends Logic {
// CNF: a formula is a conjunction of clauses
type Formula = Array[Clause]
+ /** Override Array creation for efficiency (to not go through reflection). */
+ private implicit val formulaTag: scala.reflect.ClassTag[Formula] = new scala.reflect.ClassTag[Formula] {
+ def runtimeClass: java.lang.Class[Formula] = classOf[Formula]
+ final override def newArray(len: Int): Array[Formula] = new Array[Formula](len)
+ }
def formula(c: Clause*): Formula = c.toArray
def andFormula(a: Formula, b: Formula): Formula = a ++ b
@@ -2116,13 +2121,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- val start = Statistics.startTimer(patmatCNF)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatCNF) else null
val res = conjunctiveNormalForm(negationNormalForm(p))
- Statistics.stopTimer(patmatCNF, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatCNF, start)
//
- if (Statistics.enabled) patmatCNFSizes(res.size).value += 1
+ if (Statistics.canEnable) patmatCNFSizes(res.size).value += 1
// patmatDebug("cnf for\n"+ p +"\nis:\n"+cnfString(res))
res
@@ -2199,7 +2204,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
patmatDebug("DPLL\n"+ cnfString(f))
- val start = Statistics.startTimer(patmatAnaDPLL)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaDPLL) else null
val satisfiableWithModel: Model =
if (f isEmpty) EmptyModel
@@ -2237,7 +2242,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- Statistics.stopTimer(patmatAnaDPLL, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaDPLL, start)
satisfiableWithModel
}
@@ -2598,7 +2603,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// thus, the case is unreachable if there is no model for -(-P /\ C),
// or, equivalently, P \/ -C, or C => P
def unreachableCase(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Int] = {
- val start = Statistics.startTimer(patmatAnaReach)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaReach) else null
// use the same approximator so we share variables,
// but need different conditions depending on whether we're conservatively looking for failure or success
@@ -2652,7 +2657,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- Statistics.stopTimer(patmatAnaReach, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaReach, start)
if (reachable) None else Some(caseIndex)
} catch {
@@ -2745,7 +2750,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// - back off (to avoid crying exhaustive too often) when:
// - there are guards -->
// - there are extractor calls (that we can't secretly/soundly) rewrite
- val start = Statistics.startTimer(patmatAnaExhaust)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaExhaust) else null
var backoff = false
val approx = new TreeMakersToConds(prevBinder)
@@ -2797,7 +2802,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
val pruned = CounterExample.prune(counterExamples).map(_.toString).sorted
- Statistics.stopTimer(patmatAnaExhaust, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaExhaust, start)
pruned
} catch {
case ex : AnalysisBudget.Exception =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 601ceaaa53..9201981635 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)
@@ -937,9 +941,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
case TypeBounds(lo, hi) =>
validateVariance(lo, -variance)
validateVariance(hi, variance)
- case MethodType(formals, result) =>
+ case mt @ MethodType(formals, result) =>
if (inRefinement)
- validateVariances(formals map (_.tpe), -variance)
+ validateVariances(mt.paramTypes, -variance)
validateVariance(result, variance)
case NullaryMethodType(result) =>
validateVariance(result, variance)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 77c1bedc8e..63050bc032 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -170,6 +170,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
treeCopy.CaseDef(tree, pat, transform(guard), transform(body))
case ClassDef(_, _, _, _) =>
+ def transformClassDef = {
checkCompanionNameClashes(sym)
val decls = sym.info.decls
for (s <- decls) {
@@ -195,12 +196,15 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
}
super.transform(tree)
+ }
+ transformClassDef
case ModuleDef(_, _, _) =>
checkCompanionNameClashes(sym)
super.transform(tree)
case Template(_, _, body) =>
+ def transformTemplate = {
val ownAccDefs = new ListBuffer[Tree]
accDefs(currentOwner) = ownAccDefs
@@ -213,6 +217,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
accDefs -= currentOwner
ownAccDefs ++= body1
deriveTemplate(tree)(_ => ownAccDefs.toList)
+ }
+ transformTemplate
case TypeApply(sel @ Select(This(_), name), args) =>
mayNeedProtectedAccessor(sel, args, false)
@@ -227,6 +233,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
typeDef
case sel @ Select(qual, name) =>
+ def transformSelect = {
/** return closest enclosing method, unless shadowed by an enclosing class;
* no use of closures here in the interest of speed.
*/
@@ -305,6 +312,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
case _ =>
mayNeedProtectedAccessor(sel, EmptyTree.asList, true)
}
+ }
+ transformSelect
case DefDef(mods, name, tparams, vparamss, tpt, rhs) if tree.symbol.isMethodWithExtension =>
treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, withInvalidOwner(transform(rhs)))
@@ -313,6 +322,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
mayNeedProtectedAccessor(sel, args, true)
case Assign(lhs @ Select(qual, name), rhs) =>
+ def transformAssign = {
if (lhs.symbol.isVariable &&
lhs.symbol.isJavaDefined &&
needsProtectedAccessor(lhs.symbol, tree.pos)) {
@@ -322,6 +332,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
transform(localTyper.typed(Apply(setter, List(qual, rhs))))
} else
super.transform(tree)
+ }
+ transformAssign
case Apply(fn, args) =>
assert(fn.tpe != null, tree)
@@ -345,9 +357,22 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
}
- override def atOwner[A](owner: Symbol)(trans: => A): A = {
+ /** a typer for each enclosing class */
+ private var typers = immutable.Map[Symbol, analyzer.Typer]()
+
+ /** Specialized here for performance; the previous blanked
+ * introduction of typers in TypingTransformer caused a >5%
+ * performance hit for the compiler as a whole.
+ */
+ override def atOwner[A](tree: Tree, owner: Symbol)(trans: => A): A = {
if (owner.isClass) validCurrentOwner = true
- super.atOwner(owner)(trans)
+ val savedLocalTyper = localTyper
+ localTyper = localTyper.atOwner(tree, if (owner.isModule) owner.moduleClass else owner)
+ typers = typers updated (owner, localTyper)
+ val result = super.atOwner(tree, owner)(trans)
+ localTyper = savedLocalTyper
+ typers -= owner
+ result
}
private def withInvalidOwner[A](trans: => A): A = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7df2f323e1..dfe08c398e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -104,7 +104,8 @@ trait Typers extends Modes with Adaptations with Tags {
tp.isError || pt.isError ||
context0.implicitsEnabled && // this condition prevents chains of views
inferView(EmptyTree, tp, pt, false) != EmptyTree
- }}
+ }
+ }
/** Find implicit arguments and pass them to given tree.
*/
@@ -352,7 +353,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 _ =>
@@ -606,21 +607,23 @@ trait Typers extends Modes with Adaptations with Tags {
/** Is `sym` defined in package object of package `pkg`?
*/
- private def isInPackageObject(sym: Symbol, pkg: Symbol) =
- pkg.isPackageClass && {
- sym.alternatives forall { sym =>
- !sym.owner.isPackage && {
- sym.owner.isPackageObjectClass &&
+ private def isInPackageObject(sym: Symbol, pkg: Symbol) = {
+ def isInPkgObj(sym: Symbol) =
+ !sym.owner.isPackage && {
+ sym.owner.isPackageObjectClass &&
sym.owner.owner == pkg ||
pkg.isInitialized && {
// need to be careful here to not get a cyclic reference during bootstrap
val pkgobj = pkg.info.member(nme.PACKAGEkw)
pkgobj.isInitialized &&
- (pkgobj.info.member(sym.name).alternatives contains sym)
+ (pkgobj.info.member(sym.name).alternatives contains sym)
}
- }
}
+ pkg.isPackageClass && {
+ if (sym.isOverloaded) sym.alternatives forall isInPkgObj
+ else isInPkgObj(sym)
}
+ }
/** Post-process an identifier or selection node, performing the following:
* 1. Check that non-function pattern expressions are stable
@@ -703,15 +706,15 @@ trait Typers extends Modes with Adaptations with Tags {
def silent[T](op: Typer => T,
reportAmbiguousErrors: Boolean = context.ambiguousErrors,
newtree: Tree = context.tree): SilentResult[T] = {
- val rawTypeStart = Statistics.startCounter(rawTypeFailed)
- val findMemberStart = Statistics.startCounter(findMemberFailed)
- val subtypeStart = Statistics.startCounter(subtypeFailed)
- val failedSilentStart = Statistics.startTimer(failedSilentNanos)
+ val rawTypeStart = if (Statistics.canEnable) Statistics.startCounter(rawTypeFailed) else null
+ val findMemberStart = if (Statistics.canEnable) Statistics.startCounter(findMemberFailed) else null
+ val subtypeStart = if (Statistics.canEnable) Statistics.startCounter(subtypeFailed) else null
+ val failedSilentStart = if (Statistics.canEnable) Statistics.startTimer(failedSilentNanos) else null
def stopStats() = {
- Statistics.stopCounter(rawTypeFailed, rawTypeStart)
- Statistics.stopCounter(findMemberFailed, findMemberStart)
- Statistics.stopCounter(subtypeFailed, subtypeStart)
- Statistics.stopTimer(failedSilentNanos, failedSilentStart)
+ if (Statistics.canEnable) Statistics.stopCounter(rawTypeFailed, rawTypeStart)
+ if (Statistics.canEnable) Statistics.stopCounter(findMemberFailed, findMemberStart)
+ if (Statistics.canEnable) Statistics.stopCounter(subtypeFailed, subtypeStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedSilentNanos, failedSilentStart)
}
try {
if (context.reportErrors ||
@@ -1131,109 +1134,112 @@ trait Typers extends Modes with Adaptations with Tags {
} else if (tree.tpe <:< pt) {
tree
} else {
- if (inPatternMode(mode)) {
- if ((tree.symbol ne null) && tree.symbol.isModule)
- inferModulePattern(tree, pt)
- if (isPopulated(tree.tpe, approximateAbstracts(pt)))
- return tree
- }
- val tree1 = constfold(tree, pt) // (10) (11)
- if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original)
- else {
- if (inExprModeButNot(mode, FUNmode)) {
- pt.normalize match {
- case TypeRef(_, sym, _) =>
- // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially
- // infinite expansion if pt is constant type ()
- if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) { // (12)
- if (settings.warnValueDiscard.value)
- context.unit.warning(tree.pos, "discarded non-Unit value")
- return typed(atPos(tree.pos)(Block(List(tree), Literal(Constant()))), mode, pt)
- } else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt)) {
- if (settings.warnNumericWiden.value)
- context.unit.warning(tree.pos, "implicit numeric widening")
- return typed(atPos(tree.pos)(Select(tree, "to" + sym.name)), mode, pt)
- }
- case AnnotatedType(_, _, _) if canAdaptAnnotations(tree, mode, pt) => // (13)
- return typed(adaptAnnotations(tree, mode, pt), mode, pt)
- case _ =>
- }
- if (!context.undetparams.isEmpty) {
- return instantiate(tree, mode, pt)
- }
- if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) {
- // (14); the condition prevents chains of views
- debuglog("inferring view from " + tree.tpe + " to " + pt)
- val coercion = inferView(tree, tree.tpe, pt, true)
- // convert forward views of delegate types into closures wrapped around
- // the delegate's apply method (the "Invoke" method, which was translated into apply)
- if (forMSIL && coercion != null && isCorrespondingDelegate(tree.tpe, pt)) {
- val meth: Symbol = tree.tpe.member(nme.apply)
- debuglog("replacing forward delegate view with: " + meth + ":" + meth.tpe)
- return typed(Select(tree, meth), mode, pt)
+ def fallBack: Tree = {
+ if (inPatternMode(mode)) {
+ if ((tree.symbol ne null) && tree.symbol.isModule)
+ inferModulePattern(tree, pt)
+ if (isPopulated(tree.tpe, approximateAbstracts(pt)))
+ return tree
+ }
+ val tree1 = constfold(tree, pt) // (10) (11)
+ if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original)
+ else {
+ if (inExprModeButNot(mode, FUNmode)) {
+ pt.normalize match {
+ case TypeRef(_, sym, _) =>
+ // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially
+ // infinite expansion if pt is constant type ()
+ if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) { // (12)
+ if (settings.warnValueDiscard.value)
+ context.unit.warning(tree.pos, "discarded non-Unit value")
+ return typed(atPos(tree.pos)(Block(List(tree), Literal(Constant()))), mode, pt)
+ } else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt)) {
+ if (settings.warnNumericWiden.value)
+ context.unit.warning(tree.pos, "implicit numeric widening")
+ return typed(atPos(tree.pos)(Select(tree, "to" + sym.name)), mode, pt)
+ }
+ case AnnotatedType(_, _, _) if canAdaptAnnotations(tree, mode, pt) => // (13)
+ return typed(adaptAnnotations(tree, mode, pt), mode, pt)
+ case _ =>
}
- if (coercion != EmptyTree) {
- def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe
- if (settings.logImplicitConv.value)
- unit.echo(tree.pos, msg)
-
- debuglog(msg)
- val silentContext = context.makeImplicit(context.ambiguousErrors)
- val res = newTyper(silentContext).typed(
- new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
- if (silentContext.hasErrors) context.issue(silentContext.errBuffer.head) else return res
+ if (!context.undetparams.isEmpty) {
+ return instantiate(tree, mode, pt)
+ }
+ if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) {
+ // (14); the condition prevents chains of views
+ debuglog("inferring view from " + tree.tpe + " to " + pt)
+ val coercion = inferView(tree, tree.tpe, pt, true)
+ // convert forward views of delegate types into closures wrapped around
+ // the delegate's apply method (the "Invoke" method, which was translated into apply)
+ if (forMSIL && coercion != null && isCorrespondingDelegate(tree.tpe, pt)) {
+ val meth: Symbol = tree.tpe.member(nme.apply)
+ debuglog("replacing forward delegate view with: " + meth + ":" + meth.tpe)
+ return typed(Select(tree, meth), mode, pt)
+ }
+ if (coercion != EmptyTree) {
+ def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe
+ if (settings.logImplicitConv.value)
+ unit.echo(tree.pos, msg)
+
+ debuglog(msg)
+ val silentContext = context.makeImplicit(context.ambiguousErrors)
+ val res = newTyper(silentContext).typed(
+ new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
+ if (silentContext.hasErrors) context.issue(silentContext.errBuffer.head) else return res
+ }
}
}
- }
- if (settings.debug.value) {
- log("error tree = " + tree)
- if (settings.explaintypes.value) explainTypes(tree.tpe, pt)
- }
+ if (settings.debug.value) {
+ log("error tree = " + tree)
+ if (settings.explaintypes.value) explainTypes(tree.tpe, pt)
+ }
- val found = tree.tpe
- if (!found.isErroneous && !pt.isErroneous) {
- if (!context.reportErrors && isPastTyper) {
- val (bound, req) = pt match {
- case ExistentialType(qs, tpe) => (qs, tpe)
- case _ => (Nil, pt)
- }
- val boundOrSkolems = bound ++ pt.skolemsExceptMethodTypeParams
- if (boundOrSkolems.nonEmpty) {
- // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
- // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
- // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
- //
- // val x: T = expr
- //
- // where T is the type of expr, but T contains existential skolems ts.
- // In that case, this value definition does not typecheck.
- // The value definition
- //
- // val x: T forSome { ts } = expr
- //
- // would typecheck. Or one can simply leave out the type of the `val`:
- //
- // val x = expr
- //
- // SI-6029 shows another case where we also fail (in uncurry), but this time the expected
- // type is an existential type.
- //
- // The reason for both failures have to do with the way we (don't) transform
- // skolem types along with the trees that contain them. We'd need a
- // radically different approach to do it. But before investing a lot of time to
- // to do this (I have already sunk 3 full days with in the end futile attempts
- // to consistently transform skolems and fix 6029), I'd like to
- // investigate ways to avoid skolems completely.
- //
- log("recovering from existential or skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree)
- return adapt(tree, mode, deriveTypeWithWildcards(boundOrSkolems)(pt))
+ val found = tree.tpe
+ if (!found.isErroneous && !pt.isErroneous) {
+ if (!context.reportErrors && isPastTyper) {
+ val (bound, req) = pt match {
+ case ExistentialType(qs, tpe) => (qs, tpe)
+ case _ => (Nil, pt)
+ }
+ val boundOrSkolems = bound ++ pt.skolemsExceptMethodTypeParams
+ if (boundOrSkolems.nonEmpty) {
+ // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
+ // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
+ // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
+ //
+ // val x: T = expr
+ //
+ // where T is the type of expr, but T contains existential skolems ts.
+ // In that case, this value definition does not typecheck.
+ // The value definition
+ //
+ // val x: T forSome { ts } = expr
+ //
+ // would typecheck. Or one can simply leave out the type of the `val`:
+ //
+ // val x = expr
+ //
+ // SI-6029 shows another case where we also fail (in uncurry), but this time the expected
+ // type is an existential type.
+ //
+ // The reason for both failures have to do with the way we (don't) transform
+ // skolem types along with the trees that contain them. We'd need a
+ // radically different approach to do it. But before investing a lot of time to
+ // to do this (I have already sunk 3 full days with in the end futile attempts
+ // to consistently transform skolems and fix 6029), I'd like to
+ // investigate ways to avoid skolems completely.
+ //
+ log("recovering from existential or skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree)
+ return adapt(tree, mode, deriveTypeWithWildcards(boundOrSkolems)(pt))
+ }
}
+ // create an actual error
+ AdaptTypeError(tree, found, pt)
}
- // create an actual error
- AdaptTypeError(tree, found, pt)
+ setError(tree)
}
- setError(tree)
}
+ fallBack
}
}
}
@@ -2848,73 +2854,79 @@ trait Typers extends Modes with Adaptations with Tags {
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
- var fun = fun0
- if (fun.hasSymbol && fun.symbol.isOverloaded) {
- // remove alternatives with wrong number of parameters without looking at types.
- // less expensive than including them in inferMethodAlternatvie (see below).
- def shapeType(arg: Tree): Type = arg match {
- case Function(vparams, body) =>
- functionType(vparams map (vparam => AnyClass.tpe), shapeType(body))
- case AssignOrNamedArg(Ident(name), rhs) =>
- NamedType(name, shapeType(rhs))
- case _ =>
- NothingClass.tpe
- }
- val argtypes = args map shapeType
- val pre = fun.symbol.tpe.prefix
-
- var sym = fun.symbol filter { alt =>
- // must use pt as expected type, not WildcardType (a tempting quick fix to #2665)
- // now fixed by using isWeaklyCompatible in exprTypeArgs
- // TODO: understand why exactly -- some types were not inferred anymore (`ant clean quick.bin` failed)
- // (I had expected inferMethodAlternative to pick up the slack introduced by using WildcardType here)
- //
- // @PP responds: I changed it to pass WildcardType instead of pt and only one line in
- // trunk (excluding scalacheck, which had another) failed to compile. It was this line in
- // Types: "refs = Array(Map(), Map())". I determined that inference fails if there are at
- // least two invariant type parameters. See the test case I checked in to help backstop:
- // pos/isApplicableSafe.scala.
- isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
- }
- if (sym.isOverloaded) {
- val sym1 = sym filter (alt => {
- // eliminate functions that would result from tupling transforms
- // keeps alternatives with repeated params
- hasExactlyNumParams(followApply(alt.tpe), argtypes.length) ||
- // also keep alts which define at least one default
- alt.tpe.paramss.exists(_.exists(_.hasDefault))
- })
- if (sym1 != NoSymbol) sym = sym1
- }
- if (sym != NoSymbol)
- fun = adapt(fun setSymbol sym setType pre.memberType(sym), forFunMode(mode), WildcardType)
+ def preSelectOverloaded(fun: Tree): Tree = {
+ if (fun.hasSymbol && fun.symbol.isOverloaded) {
+ // remove alternatives with wrong number of parameters without looking at types.
+ // less expensive than including them in inferMethodAlternatvie (see below).
+ def shapeType(arg: Tree): Type = arg match {
+ case Function(vparams, body) =>
+ functionType(vparams map (vparam => AnyClass.tpe), shapeType(body))
+ case AssignOrNamedArg(Ident(name), rhs) =>
+ NamedType(name, shapeType(rhs))
+ case _ =>
+ NothingClass.tpe
+ }
+ val argtypes = args map shapeType
+ val pre = fun.symbol.tpe.prefix
+
+ var sym = fun.symbol filter { alt =>
+ // must use pt as expected type, not WildcardType (a tempting quick fix to #2665)
+ // now fixed by using isWeaklyCompatible in exprTypeArgs
+ // TODO: understand why exactly -- some types were not inferred anymore (`ant clean quick.bin` failed)
+ // (I had expected inferMethodAlternative to pick up the slack introduced by using WildcardType here)
+ //
+ // @PP responds: I changed it to pass WildcardType instead of pt and only one line in
+ // trunk (excluding scalacheck, which had another) failed to compile. It was this line in
+ // Types: "refs = Array(Map(), Map())". I determined that inference fails if there are at
+ // least two invariant type parameters. See the test case I checked in to help backstop:
+ // pos/isApplicableSafe.scala.
+ isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
+ }
+ if (sym.isOverloaded) {
+ val sym1 = sym filter (alt => {
+ // eliminate functions that would result from tupling transforms
+ // keeps alternatives with repeated params
+ hasExactlyNumParams(followApply(alt.tpe), argtypes.length) ||
+ // also keep alts which define at least one default
+ alt.tpe.paramss.exists(_.exists(_.hasDefault))
+ })
+ if (sym1 != NoSymbol) sym = sym1
+ }
+ if (sym == NoSymbol) fun
+ else adapt(fun setSymbol sym setType pre.memberType(sym), forFunMode(mode), WildcardType)
+ } else fun
}
+ val fun = preSelectOverloaded(fun0)
+
fun.tpe match {
case OverloadedType(pre, alts) =>
- val undetparams = context.extractUndetparams()
-
- val argtpes = new ListBuffer[Type]
- val amode = forArgMode(fun, mode)
- val args1 = args map {
- case arg @ AssignOrNamedArg(Ident(name), rhs) =>
- // named args: only type the righthand sides ("unknown identifier" errors otherwise)
- val rhs1 = typedArg(rhs, amode, BYVALmode, WildcardType)
- argtpes += NamedType(name, rhs1.tpe.deconst)
- // the assign is untyped; that's ok because we call doTypedApply
- atPos(arg.pos) { new AssignOrNamedArg(arg.lhs , rhs1) }
- case arg =>
- val arg1 = typedArg(arg, amode, BYVALmode, WildcardType)
- argtpes += arg1.tpe.deconst
- arg1
- }
- context.undetparams = undetparams
- if (context.hasErrors)
- setError(tree)
- else {
- inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
- doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ def handleOverloaded = {
+ val undetparams = context.extractUndetparams()
+
+ val argtpes = new ListBuffer[Type]
+ val amode = forArgMode(fun, mode)
+ val args1 = args map {
+ case arg @ AssignOrNamedArg(Ident(name), rhs) =>
+ // named args: only type the righthand sides ("unknown identifier" errors otherwise)
+ val rhs1 = typedArg(rhs, amode, BYVALmode, WildcardType)
+ argtpes += NamedType(name, rhs1.tpe.deconst)
+ // the assign is untyped; that's ok because we call doTypedApply
+ atPos(arg.pos) { new AssignOrNamedArg(arg.lhs, rhs1) }
+ case arg =>
+ val arg1 = typedArg(arg, amode, BYVALmode, WildcardType)
+ argtpes += arg1.tpe.deconst
+ arg1
+ }
+ context.undetparams = undetparams
+ if (context.hasErrors)
+ setError(tree)
+ else {
+ inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
+ doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ }
}
+ handleOverloaded
case mt @ MethodType(params, _) =>
val paramTypes = mt.paramTypes
@@ -3035,101 +3047,107 @@ trait Typers extends Modes with Adaptations with Tags {
} else {
val tparams = context.extractUndetparams()
if (tparams.isEmpty) { // all type params are defined
- // In order for checkDead not to be misled by the unfortunate special
- // case of AnyRef#synchronized (which is implemented with signature T => T
- // but behaves as if it were (=> T) => T) we need to know what is the actual
- // target of a call. Since this information is no longer available from
- // typedArg, it is recorded here.
- checkDead.updateExpr(fun)
-
- val args1 =
- // no expected type when jumping to a match label -- anything goes (this is ok since we're typing the translation of well-typed code)
- // ... except during erasure: we must take the expected type into account as it drives the insertion of casts!
- // I've exhausted all other semi-clean approaches I could think of in balancing GADT magic, SI-6145, CPS type-driven transforms and other existential trickiness
- // (the right thing to do -- packing existential types -- runs into limitations in subtyping existential types,
- // casting breaks SI-6145,
- // not casting breaks GADT typing as it requires sneaking ill-typed trees past typer)
- if (!phase.erasedTypes && fun.symbol.isLabel && treeInfo.isSynthCaseSymbol(fun.symbol))
- typedArgs(args, forArgMode(fun, mode))
- else
- typedArgs(args, forArgMode(fun, mode), paramTypes, formals)
-
- // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case:
- // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo)
- // precise(foo) : foo.type => foo.type
- val restpe = mt.resultType(args1 map (arg => gen.stableTypeFor(arg) getOrElse arg.tpe))
- def ifPatternSkipFormals(tp: Type) = tp match {
- case MethodType(_, rtp) if (inPatternMode(mode)) => rtp
- case _ => tp
- }
+ def handleMonomorphicCall: Tree = {
+ // In order for checkDead not to be misled by the unfortunate special
+ // case of AnyRef#synchronized (which is implemented with signature T => T
+ // but behaves as if it were (=> T) => T) we need to know what is the actual
+ // target of a call. Since this information is no longer available from
+ // typedArg, it is recorded here.
+ checkDead.updateExpr(fun)
+
+ val args1 =
+ // no expected type when jumping to a match label -- anything goes (this is ok since we're typing the translation of well-typed code)
+ // ... except during erasure: we must take the expected type into account as it drives the insertion of casts!
+ // I've exhausted all other semi-clean approaches I could think of in balancing GADT magic, SI-6145, CPS type-driven transforms and other existential trickiness
+ // (the right thing to do -- packing existential types -- runs into limitations in subtyping existential types,
+ // casting breaks SI-6145,
+ // not casting breaks GADT typing as it requires sneaking ill-typed trees past typer)
+ if (!phase.erasedTypes && fun.symbol.isLabel && treeInfo.isSynthCaseSymbol(fun.symbol))
+ typedArgs(args, forArgMode(fun, mode))
+ else
+ typedArgs(args, forArgMode(fun, mode), paramTypes, formals)
+
+ // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case:
+ // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo)
+ // precise(foo) : foo.type => foo.type
+ val restpe = mt.resultType(args1 map (arg => gen.stableTypeFor(arg) getOrElse arg.tpe))
+ def ifPatternSkipFormals(tp: Type) = tp match {
+ case MethodType(_, rtp) if (inPatternMode(mode)) => rtp
+ case _ => tp
+ }
- // Replace the Delegate-Chainer methods += and -= with corresponding
- // + and - calls, which are translated in the code generator into
- // Combine and Remove
- if (forMSIL) {
- fun match {
- case Select(qual, name) =>
- if (isSubType(qual.tpe, DelegateClass.tpe)
- && (name == encode("+=") || name == encode("-=")))
- {
- val n = if (name == encode("+=")) nme.PLUS else nme.MINUS
- val f = Select(qual, n)
- // the compiler thinks, the PLUS method takes only one argument,
- // but he thinks it's an instance method -> still two ref's on the stack
- // -> translated by backend
- val rhs = treeCopy.Apply(tree, f, args)
- return typed(Assign(qual, rhs))
- }
- case _ => ()
+ // Replace the Delegate-Chainer methods += and -= with corresponding
+ // + and - calls, which are translated in the code generator into
+ // Combine and Remove
+ if (forMSIL) {
+ fun match {
+ case Select(qual, name) =>
+ if (isSubType(qual.tpe, DelegateClass.tpe)
+ && (name == encode("+=") || name == encode("-="))) {
+ val n = if (name == encode("+=")) nme.PLUS else nme.MINUS
+ val f = Select(qual, n)
+ // the compiler thinks, the PLUS method takes only one argument,
+ // but he thinks it's an instance method -> still two ref's on the stack
+ // -> translated by backend
+ val rhs = treeCopy.Apply(tree, f, args)
+ return typed(Assign(qual, rhs))
+ }
+ case _ => ()
+ }
}
- }
- /** This is translating uses of List() into Nil. This is less
- * than ideal from a consistency standpoint, but it shouldn't be
- * altered without due caution.
- * ... this also causes bootstrapping cycles if List_apply is
- * forced during kind-arity checking, so it is guarded by additional
- * tests to ensure we're sufficiently far along.
- */
- if (args.isEmpty && !forInteractive && fun.symbol.isInitialized && ListModule.hasCompleteInfo && (fun.symbol == List_apply))
- atPos(tree.pos)(gen.mkNil setType restpe)
- else
- constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe))
+ /**
+ * This is translating uses of List() into Nil. This is less
+ * than ideal from a consistency standpoint, but it shouldn't be
+ * altered without due caution.
+ * ... this also causes bootstrapping cycles if List_apply is
+ * forced during kind-arity checking, so it is guarded by additional
+ * tests to ensure we're sufficiently far along.
+ */
+ if (args.isEmpty && !forInteractive && fun.symbol.isInitialized && ListModule.hasCompleteInfo && (fun.symbol == List_apply))
+ atPos(tree.pos)(gen.mkNil setType restpe)
+ else
+ constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe))
+ }
+ handleMonomorphicCall
} else if (needsInstantiation(tparams, formals, args)) {
//println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info)))
inferExprInstance(fun, tparams)
doTypedApply(tree, fun, args, mode, pt)
} else {
- assert(!inPatternMode(mode), modeString(mode)) // this case cannot arise for patterns
- val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
- val strictTargs = map2(lenientTargs, tparams)((targ, tparam) =>
- if (targ == WildcardType) tparam.tpeHK else targ)
- var remainingParams = paramTypes
- def typedArgToPoly(arg: Tree, formal: Type): Tree = { //TR TODO: cleanup
- val lenientPt = formal.instantiateTypeParams(tparams, lenientTargs)
- val newmode =
- if (isByNameParamType(remainingParams.head)) POLYmode
- else POLYmode | BYVALmode
- if (remainingParams.tail.nonEmpty) remainingParams = remainingParams.tail
- val arg1 = typedArg(arg, forArgMode(fun, mode), newmode, lenientPt)
- val argtparams = context.extractUndetparams()
- if (!argtparams.isEmpty) {
- val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
- inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
- arg1
- } else arg1
- }
- val args1 = map2(args, formals)(typedArgToPoly)
- if (args1 exists {_.isErrorTyped}) duplErrTree
- else {
- debuglog("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug
- // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun"
- // returns those undetparams which have not been instantiated.
- val undetparams = inferMethodInstance(fun, tparams, args1, pt)
- val result = doTypedApply(tree, fun, args1, mode, pt)
- context.undetparams = undetparams
- result
+ def handlePolymorphicCall = {
+ assert(!inPatternMode(mode), modeString(mode)) // this case cannot arise for patterns
+ val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
+ val strictTargs = map2(lenientTargs, tparams)((targ, tparam) =>
+ if (targ == WildcardType) tparam.tpeHK else targ)
+ var remainingParams = paramTypes
+ def typedArgToPoly(arg: Tree, formal: Type): Tree = { //TR TODO: cleanup
+ val lenientPt = formal.instantiateTypeParams(tparams, lenientTargs)
+ val newmode =
+ if (isByNameParamType(remainingParams.head)) POLYmode
+ else POLYmode | BYVALmode
+ if (remainingParams.tail.nonEmpty) remainingParams = remainingParams.tail
+ val arg1 = typedArg(arg, forArgMode(fun, mode), newmode, lenientPt)
+ val argtparams = context.extractUndetparams()
+ if (!argtparams.isEmpty) {
+ val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
+ inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
+ arg1
+ } else arg1
+ }
+ val args1 = map2(args, formals)(typedArgToPoly)
+ if (args1 exists { _.isErrorTyped }) duplErrTree
+ else {
+ debuglog("infer method inst " + fun + ", tparams = " + tparams + ", args = " + args1.map(_.tpe) + ", pt = " + pt + ", lobounds = " + tparams.map(_.tpe.bounds.lo) + ", parambounds = " + tparams.map(_.info)) //debug
+ // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun"
+ // returns those undetparams which have not been instantiated.
+ val undetparams = inferMethodInstance(fun, tparams, args1, pt)
+ val result = doTypedApply(tree, fun, args1, mode, pt)
+ context.undetparams = undetparams
+ result
+ }
}
+ handlePolymorphicCall
}
}
@@ -3570,9 +3588,9 @@ trait Typers extends Modes with Adaptations with Tags {
def isCapturedExistential(sym: Symbol) =
(sym hasAllFlags (EXISTENTIAL | CAPTURED)) && {
- val start = Statistics.startTimer(isReferencedNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(isReferencedNanos) else null
try !isReferencedFrom(context, sym)
- finally Statistics.stopTimer(isReferencedNanos, start)
+ finally if (Statistics.canEnable) Statistics.stopTimer(isReferencedNanos, start)
}
def packCaptured(tpe: Type): Type = {
@@ -3852,7 +3870,9 @@ trait Typers extends Modes with Adaptations with Tags {
case _ => NoType
}
- def typedAnnotated(ann: Tree, arg1: Tree): Tree = {
+ def typedAnnotated(atd: Annotated): Tree = {
+ val ann = atd.annot
+ val arg1 = typed(atd.arg, mode, pt)
/** mode for typing the annotation itself */
val annotMode = mode & ~TYPEmode | EXPRmode
@@ -3931,7 +3951,9 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedBind(name: Name, body: Tree) =
+ def typedBind(tree: Bind) = {
+ val name = tree.name
+ val body = tree.body
name match {
case name: TypeName => assert(body == EmptyTree, context.unit + " typedBind: " + name.debugString + " " + body + " " + body.getClass)
val sym =
@@ -3975,11 +3997,11 @@ trait Typers extends Modes with Adaptations with Tags {
tree setSymbol sym
treeCopy.Bind(tree, name, body1) setSymbol sym setType body1.tpe
}
+ }
-
- def typedArrayValue(elemtpt: Tree, elems: List[Tree]) = {
- val elemtpt1 = typedType(elemtpt, mode)
- val elems1 = elems mapConserve (elem => typed(elem, mode, elemtpt1.tpe))
+ def typedArrayValue(tree: ArrayValue) = {
+ val elemtpt1 = typedType(tree.elemtpt, mode)
+ val elems1 = tree.elems mapConserve (elem => typed(elem, mode, elemtpt1.tpe))
treeCopy.ArrayValue(tree, elemtpt1, elems1)
.setType(
(if (isFullyDefined(pt) && !phase.erasedTypes) pt
@@ -4022,8 +4044,10 @@ trait Typers extends Modes with Adaptations with Tags {
else fail()
}
- def typedIf(cond: Tree, thenp: Tree, elsep: Tree) = {
- val cond1 = checkDead(typed(cond, EXPRmode | BYVALmode, BooleanClass.tpe))
+ def typedIf(tree: If) = {
+ val cond1 = checkDead(typed(tree.cond, EXPRmode | BYVALmode, BooleanClass.tpe))
+ val thenp = tree.thenp
+ val elsep = tree.elsep
if (elsep.isEmpty) { // in the future, should be unnecessary
val thenp1 = typed(thenp, UnitClass.tpe)
treeCopy.If(tree, cond1, thenp1, elsep) setType thenp1.tpe
@@ -4057,7 +4081,9 @@ trait Typers extends Modes with Adaptations with Tags {
// under -Xexperimental (and not -Xoldpatmat), and when there's a suitable __match in scope, virtualize the pattern match
// otherwise, type the Match and leave it until phase `patmat` (immediately after typer)
// empty-selector matches are transformed into synthetic PartialFunction implementations when the expected type demands it
- def typedVirtualizedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree =
+ def typedVirtualizedMatch(tree: Match): Tree = {
+ val selector = tree.selector
+ val cases = tree.cases
if (selector == EmptyTree) {
if (newPatternMatching && (pt.typeSymbol == PartialFunctionClass)) (new MatchFunTyper(tree, cases, mode, pt)).translated
else {
@@ -4074,8 +4100,10 @@ trait Typers extends Modes with Adaptations with Tags {
}
} else
virtualizedMatch(typedMatch(selector, cases, mode, pt, tree), mode, pt)
+ }
- def typedReturn(expr: Tree) = {
+ def typedReturn(tree: Return) = {
+ val expr = tree.expr
val enclMethod = context.enclMethod
if (enclMethod == NoContext ||
enclMethod.owner.isConstructor ||
@@ -4102,7 +4130,8 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedNew(tpt: Tree) = {
+ def typedNew(tree: New) = {
+ val tpt = tree.tpt
val tpt1 = {
val tpt0 = typedTypeConstructor(tpt)
if (checkStablePrefixClassType(tpt0))
@@ -4210,10 +4239,10 @@ trait Typers extends Modes with Adaptations with Tags {
* insert an implicit conversion.
*/
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
- val start = Statistics.startTimer(failedApplyNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null
def onError(typeError: AbsTypeError): Tree = {
- Statistics.stopTimer(failedApplyNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, start)
// If the problem is with raw types, copnvert to existentials and try again.
// See #4712 for a case where this situation arises,
@@ -4269,15 +4298,15 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedApply(fun: Tree, args: List[Tree]) = {
+ def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = {
val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable
if (stableApplication && isPatternMode) {
// treat stable function applications f() as expressions.
typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
} else {
val funpt = if (isPatternMode) pt else WildcardType
- val appStart = Statistics.startTimer(failedApplyNanos)
- val opeqStart = Statistics.startTimer(failedOpEqNanos)
+ val appStart = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null
+ val opeqStart = if (Statistics.canEnable) Statistics.startTimer(failedOpEqNanos) else null
def onError(reportError: => Tree): Tree = {
fun match {
@@ -4285,14 +4314,14 @@ trait Typers extends Modes with Adaptations with Tags {
if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) =>
val qual1 = typedQualifier(qual)
if (treeInfo.isVariableOrGetter(qual1)) {
- Statistics.stopTimer(failedOpEqNanos, opeqStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedOpEqNanos, opeqStart)
convertToAssignment(fun, qual1, name, args)
} else {
- Statistics.stopTimer(failedApplyNanos, appStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart)
reportError
}
case _ =>
- Statistics.stopTimer(failedApplyNanos, appStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart)
reportError
}
}
@@ -4301,7 +4330,7 @@ trait Typers extends Modes with Adaptations with Tags {
if ((mode & EXPRmode) != 0) tree else context.tree) match {
case SilentResultValue(fun1) =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
- Statistics.incCounter(typedApplyCount)
+ if (Statistics.canEnable) Statistics.incCounter(typedApplyCount)
def isImplicitMethod(tpe: Type) = tpe match {
case mt: MethodType => mt.isImplicit
case _ => false
@@ -4340,6 +4369,38 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
+ def typedApply(tree: Apply) = {
+ val fun = tree.fun
+ val args = tree.args
+ fun match {
+ case Block(stats, expr) =>
+ typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt)
+ case _ =>
+ normalTypedApply(tree, fun, args) match {
+ case Apply(Select(New(tpt), name), args)
+ if (tpt.tpe != null &&
+ tpt.tpe.typeSymbol == ArrayClass &&
+ args.length == 1 &&
+ erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor
+ // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len)
+ // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len), where Array HK gets applied (N-1) times
+ // [Eugene] no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions)
+ val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
+ val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.toTypeConstructor, List(tpe))).last
+ val newArrayApp = atPos(tree.pos) {
+ val tag = resolveClassTag(tree.pos, tagType)
+ if (tag.isEmpty) MissingClassTagError(tree, tagType)
+ else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
+ }
+ typed(newArrayApp, mode, pt)
+ case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => //SI-5696
+ TooManyArgumentListsForConstructor(tree)
+ case tree1 =>
+ tree1
+ }
+ }
+ }
+
def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = {
val prefix = name.toTermName stripSuffix nme.EQL
def mkAssign(vble: Tree): Tree =
@@ -4385,8 +4446,9 @@ trait Typers extends Modes with Adaptations with Tags {
typed1(tree1, mode, pt)
}
- def typedSuper(qual: Tree, mix: TypeName) = {
- val qual1 = typed(qual)
+ def typedSuper(tree: Super) = {
+ val mix = tree.mix
+ val qual1 = typed(tree.qual)
val clazz = qual1 match {
case This(_) => qual1.symbol
@@ -4429,12 +4491,13 @@ trait Typers extends Modes with Adaptations with Tags {
treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype)
}
- def typedThis(qual: Name) = tree.symbol orElse qualifyingClass(tree, qual, packageOK = false) match {
- case NoSymbol => tree
- case clazz =>
- tree setSymbol clazz setType clazz.thisType.underlying
- if (isStableContext(tree, mode, pt)) tree setType clazz.thisType else tree
- }
+ def typedThis(tree: This) =
+ tree.symbol orElse qualifyingClass(tree, tree.qual, packageOK = false) match {
+ case NoSymbol => tree
+ case clazz =>
+ tree setSymbol clazz setType clazz.thisType.underlying
+ if (isStableContext(tree, mode, pt)) tree setType clazz.thisType else tree
+ }
/** Attribute a selection where <code>tree</code> is <code>qual.name</code>.
* <code>qual</code> is already attributed.
@@ -4443,7 +4506,7 @@ trait Typers extends Modes with Adaptations with Tags {
* @param name ...
* @return ...
*/
- def typedSelect(qual: Tree, name: Name): Tree = {
+ def typedSelect(tree: Tree, qual: Tree, name: Name): Tree = {
def asDynamicCall = dyna.mkInvoke(context.tree, tree, qual, name) map (typed1(_, mode, pt))
val sym = tree.symbol orElse member(qual, name) orElse {
@@ -4461,41 +4524,43 @@ trait Typers extends Modes with Adaptations with Tags {
qual.tpe = tree.symbol.owner.tpe
if (!reallyExists(sym)) {
- if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) {
- val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) }
- if (tree1 != EmptyTree) return typed1(tree1, mode, pt)
- }
+ def handleMissing: Tree = {
+ if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) {
+ val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) }
+ if (tree1 != EmptyTree) return typed1(tree1, mode, pt)
+ }
- // try to expand according to Dynamic rules.
- asDynamicCall foreach (x => return x)
+ // try to expand according to Dynamic rules.
+ asDynamicCall foreach (x => return x)
- debuglog(
- "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
- )
+ debuglog(
+ "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)
- def makeInteractiveErrorTree = {
- val tree1 = tree match {
- case Select(_, _) => treeCopy.Select(tree, qual, name)
- case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
+ def makeInteractiveErrorTree = {
+ val tree1 = tree match {
+ case Select(_, _) => treeCopy.Select(tree, qual, name)
+ case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
+ }
+ setError(tree1)
}
- setError(tree1)
- }
- if (name == nme.ERROR && forInteractive)
- return makeInteractiveErrorTree
+ if (name == nme.ERROR && forInteractive)
+ return makeInteractiveErrorTree
- if (!qual.tpe.widen.isErroneous) {
- if ((mode & QUALmode) != 0) {
- val lastTry = rootMirror.missingHook(qual.tpe.typeSymbol, name)
- if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
+ if (!qual.tpe.widen.isErroneous) {
+ if ((mode & QUALmode) != 0) {
+ val lastTry = rootMirror.missingHook(qual.tpe.typeSymbol, name)
+ if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
+ }
+ NotAMemberError(tree, qual, name)
}
- NotAMemberError(tree, qual, name)
- }
- if (forInteractive) makeInteractiveErrorTree else setError(tree)
+ if (forInteractive) makeInteractiveErrorTree else setError(tree)
+ }
+ handleMissing
} else {
val tree1 = tree match {
case Select(_, _) => treeCopy.Select(tree, qual, name)
@@ -4551,6 +4616,49 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
+ def typedSelectOrSuperCall(tree: Select) = {
+ val qual = tree.qualifier
+ val name = tree.name
+ qual match {
+ case _: Super if name == nme.CONSTRUCTOR =>
+ val qual1 =
+ typed(qual, EXPRmode | QUALmode | POLYmode | SUPERCONSTRmode, WildcardType)
+ // the qualifier type of a supercall constructor is its first parent class
+ typedSelect(tree, qual1, nme.CONSTRUCTOR)
+ case _ =>
+ if (Statistics.canEnable) Statistics.incCounter(typedSelectCount)
+ var qual1 = checkDead(typedQualifier(qual, mode))
+ if (name.isTypeName) qual1 = checkStable(qual1)
+
+ val tree1 = // temporarily use `filter` and an alternative for `withFilter`
+ if (name == nme.withFilter)
+ silent(_ => typedSelect(tree, qual1, name)) match {
+ case SilentResultValue(result) =>
+ result
+ case _ =>
+ silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match {
+ case SilentResultValue(result2) =>
+ unit.deprecationWarning(
+ tree.pos, "`withFilter' method does not yet exist on " + qual1.tpe.widen +
+ ", using `filter' method instead")
+ result2
+ case SilentTypeError(err) =>
+ WithFilterError(tree, err)
+ }
+ }
+ else
+ typedSelect(tree, qual1, name)
+
+ if (tree.isInstanceOf[PostfixSelect])
+ checkFeature(tree.pos, PostfixOpsFeature, name.decode)
+ if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember)
+ checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString)
+
+ if (qual1.hasSymbolWhich(_.isRootPackage)) treeCopy.Ident(tree1, name)
+ else tree1
+ }
+ }
+
/** Attribute an identifier consisting of a simple name or an outer reference.
*
* @param tree The tree representing the identifier.
@@ -4558,7 +4666,7 @@ trait Typers extends Modes with Adaptations with Tags {
* Transformations: (1) Prefix class members with this.
* (2) Change imported symbols to selections
*/
- def typedIdent(name: Name): Tree = {
+ def typedIdent(tree: Tree, name: Name): Tree = {
var errorContainer: AbsTypeError = null
@inline
def ambiguousError(msg: String) = {
@@ -4571,8 +4679,6 @@ trait Typers extends Modes with Adaptations with Tags {
errorContainer = tree
}
- val fingerPrint: Long = name.fingerPrint
-
var defSym: Symbol = tree.symbol // the directly found symbol
var pre: Type = NoPrefix // the prefix type of defSym, if a class member
var qual: Tree = EmptyTree // the qualifier tree if transformed tree is a select
@@ -4610,10 +4716,7 @@ trait Typers extends Modes with Adaptations with Tags {
var cx = startingIdentContext
while (defSym == NoSymbol && cx != NoContext && (cx.scope ne null)) { // cx.scope eq null arises during FixInvalidSyms in Duplicators
pre = cx.enclClass.prefix
- defEntry = {
- val scope = cx.scope
- if ((fingerPrint & scope.fingerPrints) != 0) scope.lookupEntry(name) else null
- }
+ defEntry = cx.scope.lookupEntry(name)
if ((defEntry ne null) && qualifies(defEntry.sym)) {
// Right here is where SI-1987, overloading in package objects, can be
// seen to go wrong. There is an overloaded symbol, but when referring
@@ -4801,7 +4904,18 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedCompoundTypeTree(templ: Template) = {
+ def typedIdentOrWildcard(tree: Ident) = {
+ val name = tree.name
+ if (Statistics.canEnable) Statistics.incCounter(typedIdentCount)
+ if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
+ (name == tpnme.WILDCARD && (mode & TYPEmode) != 0))
+ tree setType makeFullyDefined(pt)
+ else
+ typedIdent(tree, name)
+ }
+
+ def typedCompoundTypeTree(tree: CompoundTypeTree) = {
+ val templ = tree.templ
val parents1 = templ.parents mapConserve (typedType(_, mode))
if (parents1 exists (_.isErrorTyped)) tree setType ErrorType
else {
@@ -4814,7 +4928,9 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = {
+ def typedAppliedTypeTree(tree: AppliedTypeTree) = {
+ val tpt = tree.tpt
+ val args = tree.args
val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
if (tpt1.isErrorTyped) {
tpt1
@@ -4865,367 +4981,395 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- // begin typed1
val sym: Symbol = tree.symbol
if ((sym ne null) && (sym ne NoSymbol)) sym.initialize
- //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG
- tree match {
- case PackageDef(pid, stats) =>
- val pid1 = typedQualifier(pid).asInstanceOf[RefTree]
- assert(sym.moduleClass ne NoSymbol, sym)
- // complete lazy annotations
- val annots = sym.annotations
- val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
- .typedStats(stats, NoSymbol)
- treeCopy.PackageDef(tree, pid1, stats1) setType NoType
-
- case tree @ ClassDef(_, _, _, _) =>
- newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree)
- case tree @ ModuleDef(_, _, _) =>
- newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree)
+ def typedPackageDef(pdef: PackageDef) = {
+ val pid1 = typedQualifier(pdef.pid).asInstanceOf[RefTree]
+ assert(sym.moduleClass ne NoSymbol, sym)
+ // complete lazy annotations
+ val annots = sym.annotations
+ val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
+ .typedStats(pdef.stats, NoSymbol)
+ treeCopy.PackageDef(tree, pid1, stats1) setType NoType
+ }
- case vdef @ ValDef(_, _, _, _) =>
- typedValDef(vdef)
+ def typedDocDef(docdef: DocDef) = {
+ val comment = docdef.comment
+ if (forScaladoc && (sym ne null) && (sym ne NoSymbol)) {
+ docComments(sym) = comment
+ comment.defineVariables(sym)
+ val typer1 = newTyper(context.makeNewScope(tree, context.owner))
+ for (useCase <- comment.useCases) {
+ typer1.silent(_.typedUseCase(useCase)) match {
+ case SilentTypeError(err) =>
+ unit.warning(useCase.pos, err.errMsg)
+ case _ =>
+ }
+ for (useCaseSym <- useCase.defined) {
+ if (sym.name != useCaseSym.name)
+ unit.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode)
+ }
+ }
+ }
+ typed(docdef.definition, mode, pt)
+ }
- case ddef @ DefDef(_, _, _, _, _, _) =>
- // flag default getters for constructors. An actual flag would be nice. See SI-5543.
- //val flag = ddef.mods.hasDefaultFlag && ddef.mods.hasFlag(PRESUPER)
- val flag = ddef.mods.hasDefaultFlag && sym.owner.isModuleClass &&
- nme.defaultGetterToMethod(sym.name) == nme.CONSTRUCTOR
- newTyper(context.makeNewScope(tree, sym)).constrTyperIf(flag).typedDefDef(ddef)
+ def defDefTyper(ddef: DefDef) = {
+ val flag = ddef.mods.hasDefaultFlag && sym.owner.isModuleClass &&
+ nme.defaultGetterToMethod(sym.name) == nme.CONSTRUCTOR
+ newTyper(context.makeNewScope(ddef, sym)).constrTyperIf(flag)
+ }
- case tdef @ TypeDef(_, _, _, _) =>
- typedTypeDef(tdef)
+ def typedAlternative(alt: Alternative) = {
+ val alts1 = alt.trees mapConserve (alt => typed(alt, mode | ALTmode, pt))
+ treeCopy.Alternative(tree, alts1) setType pt
+ }
- case ldef @ LabelDef(_, _, _) =>
- labelTyper(ldef).typedLabelDef(ldef)
-
- case ddef @ DocDef(comment, defn) =>
- if (forScaladoc && (sym ne null) && (sym ne NoSymbol)) {
- docComments(sym) = comment
- comment.defineVariables(sym)
- val typer1 = newTyper(context.makeNewScope(tree, context.owner))
- for (useCase <- comment.useCases) {
- typer1.silent(_.typedUseCase(useCase)) match {
- case SilentTypeError(err) =>
- unit.warning(useCase.pos, err.errMsg)
- case _ =>
- }
- for (useCaseSym <- useCase.defined) {
- if (sym.name != useCaseSym.name)
- unit.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode)
+ def typedStar(tree: Star) = {
+ if ((mode & STARmode) == 0 && !isPastTyper)
+ StarPatternWithVarargParametersError(tree)
+ treeCopy.Star(tree, typed(tree.elem, mode, pt)) setType makeFullyDefined(pt)
+ }
+
+ def typedUnApply(tree: UnApply) = {
+ val fun1 = typed(tree.fun)
+ val tpes = formalTypes(unapplyTypeList(tree.fun.symbol, fun1.tpe, tree.args.length), tree.args.length)
+ val args1 = map2(tree.args, tpes)(typedPattern)
+ treeCopy.UnApply(tree, fun1, args1) setType pt
+ }
+
+ def typedTry(tree: Try) = {
+ var block1 = typed(tree.block, pt)
+ var catches1 = typedCases(tree.catches, ThrowableClass.tpe, pt)
+
+ for (cdef <- catches1 if cdef.guard.isEmpty) {
+ def warn(name: Name) = context.warning(cdef.pat.pos, s"This catches all Throwables. If this is really intended, use `case ${name.decoded} : Throwable` to clear this warning.")
+ def unbound(t: Tree) = t.symbol == null || t.symbol == NoSymbol
+ cdef.pat match {
+ case Bind(name, i @ Ident(_)) if unbound(i) => warn(name)
+ case i @ Ident(name) if unbound(i) => warn(name)
+ case _ =>
+ }
+ }
+
+ val finalizer1 =
+ if (tree.finalizer.isEmpty) tree.finalizer
+ else typed(tree.finalizer, UnitClass.tpe)
+ val (owntype, needAdapt) = ptOrLub(block1.tpe :: (catches1 map (_.tpe)), pt)
+ if (needAdapt) {
+ block1 = adapt(block1, mode, owntype)
+ catches1 = catches1 map (adaptCase(_, mode, owntype))
+ }
+
+ treeCopy.Try(tree, block1, catches1, finalizer1) setType owntype
+ }
+
+ def typedThrow(tree: Throw) = {
+ val expr1 = typed(tree.expr, EXPRmode | BYVALmode, ThrowableClass.tpe)
+ treeCopy.Throw(tree, expr1) setType NothingClass.tpe
+ }
+
+ def typedTyped(tree: Typed) = {
+ val expr = tree.expr
+ val tpt = tree.tpt
+ tpt match {
+ case Function(List(), EmptyTree) =>
+ // find out whether the programmer is trying to eta-expand a macro def
+ // to do that we need to typecheck the tree first (we need a symbol of the eta-expandee)
+ // that typecheck must not trigger macro expansions, so we explicitly prohibit them
+ // Q: "but, " - you may ask - ", `typed1` doesn't call adapt, which does macro expansion, so why explicit check?"
+ // A: solely for robustness reasons. this mechanism might change in the future, which might break unprotected code
+ val exprTyped = context.withMacrosDisabled(typed1(expr, mode, pt))
+ exprTyped match {
+ case macroDef if macroDef.symbol != null && macroDef.symbol.isTermMacro && !macroDef.symbol.isErroneous =>
+ MacroEtaError(exprTyped)
+ case _ =>
+ typedEta(checkDead(exprTyped))
+ }
+
+ case Ident(tpnme.WILDCARD_STAR) =>
+ val exprTyped = typed(expr, onlyStickyModes(mode), WildcardType)
+ def subArrayType(pt: Type) =
+ if (isPrimitiveValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
+ else {
+ val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
+ newExistentialType(List(tparam), arrayType(tparam.tpe))
}
+
+ val (exprAdapted, baseClass) = exprTyped.tpe.typeSymbol match {
+ case ArrayClass => (adapt(exprTyped, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
+ case _ => (adapt(exprTyped, onlyStickyModes(mode), seqType(pt)), SeqClass)
}
- }
- typed(defn, mode, pt)
+ exprAdapted.tpe.baseType(baseClass) match {
+ case TypeRef(_, _, List(elemtp)) =>
+ treeCopy.Typed(tree, exprAdapted, tpt setType elemtp) setType elemtp
+ case _ =>
+ setError(tree)
+ }
+
+ case _ =>
+ val tptTyped = typedType(tpt, mode)
+ val exprTyped = typed(expr, onlyStickyModes(mode), tptTyped.tpe.deconst)
+ val treeTyped = treeCopy.Typed(tree, exprTyped, tptTyped)
- case Annotated(constr, arg) =>
- typedAnnotated(constr, typed(arg, mode, pt))
+ if (isPatternMode) {
+ val uncheckedTypeExtractor = extractorForUncheckedType(tpt.pos, tptTyped.tpe)
- case tree @ Block(_, _) =>
+ // make fully defined to avoid bounded wildcard types that may be in pt from calling dropExistential (SI-2038)
+ val ptDefined = if (isFullyDefined(pt)) pt else makeFullyDefined(pt)
+ val ownType = inferTypedPattern(tptTyped, tptTyped.tpe, ptDefined, canRemedy = uncheckedTypeExtractor.nonEmpty)
+ treeTyped setType ownType
+
+ uncheckedTypeExtractor match {
+ case None => treeTyped
+ case Some(extractor) => wrapClassTagUnapply(treeTyped, extractor, tptTyped.tpe)
+ }
+ } else
+ treeTyped setType tptTyped.tpe
+ }
+ }
+
+ def typedTypeApply(tree: TypeApply) = {
+ val fun = tree.fun
+ val args = tree.args
+ // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
+ //@M! we must type fun in order to type the args, as that requires the kinds of fun's type parameters.
+ // However, args should apparently be done first, to save context.undetparams. Unfortunately, the args
+ // *really* have to be typed *after* fun. We escape from this classic Catch-22 by simply saving&restoring undetparams.
+
+ // @M TODO: the compiler still bootstraps&all tests pass when this is commented out..
+ //val undets = context.undetparams
+
+ // @M: fun is typed in TAPPmode because it is being applied to its actual type parameters
+ val fun1 = typed(fun, forFunMode(mode) | TAPPmode, WildcardType)
+ val tparams = fun1.symbol.typeParams
+
+ //@M TODO: val undets_fun = context.undetparams ?
+ // "do args first" (by restoring the context.undetparams) in order to maintain context.undetparams on the function side.
+
+ // @M TODO: the compiler still bootstraps when this is commented out.. TODO: run tests
+ //context.undetparams = undets
+
+ // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds?
+ val args1 = if (sameLength(args, tparams)) map2Conserve(args, tparams) {
+ //@M! the polytype denotes the expected kind
+ (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe))
+ }
+ else {
+ //@M this branch is correctly hit for an overloaded polymorphic type. It also has to handle erroneous cases.
+ // Until the right alternative for an overloaded method is known, be very liberal,
+ // typedTypeApply will find the right alternative and then do the same check as
+ // in the then-branch above. (see pos/tcpoly_overloaded.scala)
+ // this assert is too strict: be tolerant for errors like trait A { def foo[m[x], g]=error(""); def x[g] = foo[g/*ERR: missing argument type*/] }
+ //assert(fun1.symbol.info.isInstanceOf[OverloadedType] || fun1.symbol.isError) //, (fun1.symbol,fun1.symbol.info,fun1.symbol.info.getClass,args,tparams))
+ args mapConserve (typedHigherKindedType(_, mode))
+ }
+
+ //@M TODO: context.undetparams = undets_fun ?
+ Typer.this.typedTypeApply(tree, mode, fun1, args1)
+ }
+
+ def typedApplyDynamic(tree: ApplyDynamic) = {
+ assert(phase.erasedTypes)
+ val reflectiveCalls = !(settings.refinementMethodDispatch.value == "invoke-dynamic")
+ val qual1 = typed(tree.qual, AnyRefClass.tpe)
+ val args1 = tree.args mapConserve (arg => if (reflectiveCalls) typed(arg, AnyRefClass.tpe) else typed(arg))
+ treeCopy.ApplyDynamic(tree, qual1, args1) setType (if (reflectiveCalls) AnyRefClass.tpe else tree.symbol.info.resultType)
+ }
+
+ def typedReferenceToBoxed(tree: ReferenceToBoxed) = {
+ val id = tree.ident
+ val id1 = typed1(id, mode, pt) match { case id: Ident => id }
+ // [Eugene] am I doing it right?
+ val erasedTypes = phaseId(currentPeriod) >= currentRun.erasurePhase.id
+ val tpe = capturedVariableType(id.symbol, erasedTypes = erasedTypes)
+ treeCopy.ReferenceToBoxed(tree, id1) setType tpe
+ }
+
+ def typedLiteral(tree: Literal) = {
+ val value = tree.value
+ tree setType (
+ if (value.tag == UnitTag) UnitClass.tpe
+ else ConstantType(value))
+ }
+
+ def typedSingletonTypeTree(tree: SingletonTypeTree) = {
+ val ref1 = checkStable(
+ typed(tree.ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe))
+ tree setType ref1.tpe.resultType
+ }
+
+ def typedSelectFromTypeTree(tree: SelectFromTypeTree) = {
+ val qual1 = typedType(tree.qualifier, mode)
+ if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual1)
+ else typedSelect(tree, qual1, tree.name)
+ }
+
+ def typedTypeBoundsTree(tree: TypeBoundsTree) = {
+ val lo1 = typedType(tree.lo, mode)
+ val hi1 = typedType(tree.hi, mode)
+ treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe)
+ }
+
+ def typedExistentialTypeTree(tree: ExistentialTypeTree) = {
+ val tree1 = typerWithLocalContext(context.makeNewScope(tree, context.owner)){
+ _.typedExistentialTypeTree(tree, mode)
+ }
+ checkExistentialsFeature(tree1.pos, tree1.tpe, "the existential type")
+ tree1
+ }
+
+ def typedTypeTree(tree: TypeTree) = {
+ if (tree.original != null)
+ tree setType typedType(tree.original, mode).tpe
+ else
+ // we should get here only when something before failed
+ // and we try again (@see tryTypedApply). In that case we can assign
+ // whatever type to tree; we just have to survive until a real error message is issued.
+ tree setType AnyClass.tpe
+ }
+
+ // begin typed1
+ //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG
+
+ tree match {
+ case tree: Ident =>
+ typedIdentOrWildcard(tree)
+
+ case tree: Select =>
+ typedSelectOrSuperCall(tree)
+
+ case tree: Apply =>
+ typedApply(tree)
+
+ case tree: TypeTree =>
+ typedTypeTree(tree)
+
+ case tree: Literal =>
+ typedLiteral(tree)
+
+ case tree: This =>
+ typedThis(tree)
+
+ case tree: ValDef =>
+ typedValDef(tree)
+
+ case tree: DefDef =>
+ // flag default getters for constructors. An actual flag would be nice. See SI-5543.
+ //val flag = ddef.mods.hasDefaultFlag && ddef.mods.hasFlag(PRESUPER)
+ defDefTyper(tree).typedDefDef(tree)
+
+ case tree: Block =>
typerWithLocalContext(context.makeNewScope(tree, context.owner)){
_.typedBlock(tree, mode, pt)
}
- case Alternative(alts) =>
- val alts1 = alts mapConserve (alt => typed(alt, mode | ALTmode, pt))
- treeCopy.Alternative(tree, alts1) setType pt
-
- case Star(elem) =>
- if ((mode & STARmode) == 0 && !isPastTyper)
- StarPatternWithVarargParametersError(tree)
- treeCopy.Star(tree, typed(elem, mode, pt)) setType makeFullyDefined(pt)
+ case tree: If =>
+ typedIf(tree)
- case Bind(name, body) =>
- typedBind(name, body)
+ case tree: TypeApply =>
+ typedTypeApply(tree)
- case UnApply(fun, args) =>
- val fun1 = typed(fun)
- val tpes = formalTypes(unapplyTypeList(fun.symbol, fun1.tpe, args.length), args.length)
- val args1 = map2(args, tpes)(typedPattern)
- treeCopy.UnApply(tree, fun1, args1) setType pt
+ case tree: AppliedTypeTree =>
+ typedAppliedTypeTree(tree)
- case ArrayValue(elemtpt, elems) =>
- typedArrayValue(elemtpt, elems)
+ case tree: Bind =>
+ typedBind(tree)
- case tree @ Function(_, _) =>
+ case tree: Function =>
if (tree.symbol == NoSymbol)
tree.symbol = context.owner.newAnonymousFunctionValue(tree.pos)
typerWithLocalContext(context.makeNewScope(tree, tree.symbol))(_.typedFunction(tree, mode, pt))
+ case tree: Match =>
+ typedVirtualizedMatch(tree)
+
+ case tree: New =>
+ typedNew(tree)
+
case Assign(lhs, rhs) =>
typedAssign(lhs, rhs)
case AssignOrNamedArg(lhs, rhs) => // called by NamesDefaults in silent typecheck
typedAssign(lhs, rhs)
- case If(cond, thenp, elsep) =>
- typedIf(cond, thenp, elsep)
+ case tree: Super =>
+ typedSuper(tree)
- case tree @ Match(selector, cases) =>
- typedVirtualizedMatch(tree, selector, cases)
+ case tree: TypeBoundsTree =>
+ typedTypeBoundsTree(tree)
- case Return(expr) =>
- typedReturn(expr)
+ case tree: Typed =>
+ typedTyped(tree)
- case Try(block, catches, finalizer) =>
- var block1 = typed(block, pt)
- var catches1 = typedCases(catches, ThrowableClass.tpe, pt)
+ case tree: ClassDef =>
+ newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree)
- for (cdef <- catches1 if cdef.guard.isEmpty) {
- def warn(name: Name) = context.warning(cdef.pat.pos, s"This catches all Throwables. If this is really intended, use `case ${name.decoded} : Throwable` to clear this warning.")
- def unbound(t: Tree) = t.symbol == null || t.symbol == NoSymbol
- cdef.pat match {
- case Bind(name, i@Ident(_)) if unbound(i) => warn(name)
- case i@Ident(name) if unbound(i) => warn(name)
- case _ =>
- }
- }
+ case tree: ModuleDef =>
+ newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree)
- val finalizer1 = if (finalizer.isEmpty) finalizer
- else typed(finalizer, UnitClass.tpe)
- val (owntype, needAdapt) = ptOrLub(block1.tpe :: (catches1 map (_.tpe)), pt)
- if (needAdapt) {
- block1 = adapt(block1, mode, owntype)
- catches1 = catches1 map (adaptCase(_, mode, owntype))
- }
+ case tree: TypeDef =>
+ typedTypeDef(tree)
- treeCopy.Try(tree, block1, catches1, finalizer1) setType owntype
-
- case Throw(expr) =>
- val expr1 = typed(expr, EXPRmode | BYVALmode, ThrowableClass.tpe)
- treeCopy.Throw(tree, expr1) setType NothingClass.tpe
-
- case New(tpt: Tree) =>
- typedNew(tpt)
-
- case Typed(expr, Function(List(), EmptyTree)) =>
- // find out whether the programmer is trying to eta-expand a macro def
- // to do that we need to typecheck the tree first (we need a symbol of the eta-expandee)
- // that typecheck must not trigger macro expansions, so we explicitly prohibit them
- // Q: "but, " - you may ask - ", `typed1` doesn't call adapt, which does macro expansion, so why explicit check?"
- // A: solely for robustness reasons. this mechanism might change in the future, which might break unprotected code
- val expr1 = context.withMacrosDisabled(typed1(expr, mode, pt))
- expr1 match {
- case macroDef if macroDef.symbol != null && macroDef.symbol.isTermMacro && !macroDef.symbol.isErroneous =>
- MacroEtaError(expr1)
- case _ =>
- typedEta(checkDead(expr1))
- }
+ case tree: LabelDef =>
+ labelTyper(tree).typedLabelDef(tree)
- case Typed(expr0, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
- val expr = typed(expr0, onlyStickyModes(mode), WildcardType)
- def subArrayType(pt: Type) =
- if (isPrimitiveValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
- else {
- val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
- newExistentialType(List(tparam), arrayType(tparam.tpe))
- }
+ case tree: PackageDef =>
+ typedPackageDef(tree)
- val (expr1, baseClass) = expr.tpe.typeSymbol match {
- case ArrayClass => (adapt(expr, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
- case _ => (adapt(expr, onlyStickyModes(mode), seqType(pt)), SeqClass)
- }
- expr1.tpe.baseType(baseClass) match {
- case TypeRef(_, _, List(elemtp)) =>
- treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp
- case _ =>
- setError(tree)
- }
+ case tree: DocDef =>
+ typedDocDef(tree)
- case Typed(expr, tpt) =>
- val tptTyped = typedType(tpt, mode)
- val exprTyped = typed(expr, onlyStickyModes(mode), tptTyped.tpe.deconst)
- val treeTyped = treeCopy.Typed(tree, exprTyped, tptTyped)
+ case tree: Annotated =>
+ typedAnnotated(tree)
- if (isPatternMode) {
- val uncheckedTypeExtractor = extractorForUncheckedType(tpt.pos, tptTyped.tpe)
+ case tree: SingletonTypeTree =>
+ typedSingletonTypeTree(tree)
- // make fully defined to avoid bounded wildcard types that may be in pt from calling dropExistential (SI-2038)
- val ptDefined = if (isFullyDefined(pt)) pt else makeFullyDefined(pt)
- val ownType = inferTypedPattern(tptTyped, tptTyped.tpe, ptDefined, canRemedy = uncheckedTypeExtractor.nonEmpty)
- treeTyped setType ownType
+ case tree: SelectFromTypeTree =>
+ typedSelectFromTypeTree(tree)
- uncheckedTypeExtractor match {
- case None => treeTyped
- case Some(extractor) => wrapClassTagUnapply(treeTyped, extractor, tptTyped.tpe)
- }
- } else
- treeTyped setType tptTyped.tpe
-
- case TypeApply(fun, args) =>
- // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
- //@M! we must type fun in order to type the args, as that requires the kinds of fun's type parameters.
- // However, args should apparently be done first, to save context.undetparams. Unfortunately, the args
- // *really* have to be typed *after* fun. We escape from this classic Catch-22 by simply saving&restoring undetparams.
-
- // @M TODO: the compiler still bootstraps&all tests pass when this is commented out..
- //val undets = context.undetparams
-
- // @M: fun is typed in TAPPmode because it is being applied to its actual type parameters
- val fun1 = typed(fun, forFunMode(mode) | TAPPmode, WildcardType)
- val tparams = fun1.symbol.typeParams
-
- //@M TODO: val undets_fun = context.undetparams ?
- // "do args first" (by restoring the context.undetparams) in order to maintain context.undetparams on the function side.
-
- // @M TODO: the compiler still bootstraps when this is commented out.. TODO: run tests
- //context.undetparams = undets
-
- // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds?
- val args1 = if (sameLength(args, tparams)) map2Conserve(args, tparams) {
- //@M! the polytype denotes the expected kind
- (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe))
- } else {
- //@M this branch is correctly hit for an overloaded polymorphic type. It also has to handle erroneous cases.
- // Until the right alternative for an overloaded method is known, be very liberal,
- // typedTypeApply will find the right alternative and then do the same check as
- // in the then-branch above. (see pos/tcpoly_overloaded.scala)
- // this assert is too strict: be tolerant for errors like trait A { def foo[m[x], g]=error(""); def x[g] = foo[g/*ERR: missing argument type*/] }
- //assert(fun1.symbol.info.isInstanceOf[OverloadedType] || fun1.symbol.isError) //, (fun1.symbol,fun1.symbol.info,fun1.symbol.info.getClass,args,tparams))
- args mapConserve (typedHigherKindedType(_, mode))
- }
+ case tree: CompoundTypeTree =>
+ typedCompoundTypeTree(tree)
- //@M TODO: context.undetparams = undets_fun ?
- typedTypeApply(tree, mode, fun1, args1)
+ case tree: ExistentialTypeTree =>
+ typedExistentialTypeTree(tree)
- case Apply(Block(stats, expr), args) =>
- typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt)
+ case tree: Return =>
+ typedReturn(tree)
- case Apply(fun, args) =>
- typedApply(fun, args) match {
- case Apply(Select(New(tpt), name), args)
- if (tpt.tpe != null &&
- tpt.tpe.typeSymbol == ArrayClass &&
- args.length == 1 &&
- erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor
- // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len)
- // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len), where Array HK gets applied (N-1) times
- // no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions)
- val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
- val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.toTypeConstructor, List(tpe))).last
- val newArrayApp = atPos(tree.pos) {
- val tag = resolveClassTag(tree.pos, tagType)
- if (tag.isEmpty) MissingClassTagError(tree, tagType)
- else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
- }
- typed(newArrayApp, mode, pt)
- case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => //SI-5696
- TooManyArgumentListsForConstructor(tree)
- case tree1 =>
- tree1
- }
+ case tree: Try =>
+ typedTry(tree)
- case ApplyDynamic(qual, args) =>
- assert(phase.erasedTypes)
- val reflectiveCalls = !(settings.refinementMethodDispatch.value == "invoke-dynamic")
- val qual1 = typed(qual, AnyRefClass.tpe)
- val args1 = args mapConserve (arg => if (reflectiveCalls) typed(arg, AnyRefClass.tpe) else typed(arg))
- treeCopy.ApplyDynamic(tree, qual1, args1) setType (if (reflectiveCalls) AnyRefClass.tpe else tree.symbol.info.resultType)
-
- case Super(qual, mix) =>
- typedSuper(qual, mix)
-
- case This(qual) =>
- typedThis(qual)
-
- case Select(qual @ Super(_, _), nme.CONSTRUCTOR) =>
- val qual1 =
- typed(qual, EXPRmode | QUALmode | POLYmode | SUPERCONSTRmode, WildcardType)
- // the qualifier type of a supercall constructor is its first parent class
- typedSelect(qual1, nme.CONSTRUCTOR)
-
- case Select(qual, name) =>
- Statistics.incCounter(typedSelectCount)
- var qual1 = checkDead(typedQualifier(qual, mode))
- if (name.isTypeName) qual1 = checkStable(qual1)
-
- val tree1 = // temporarily use `filter` and an alternative for `withFilter`
- if (name == nme.withFilter)
- silent(_ => typedSelect(qual1, name)) match {
- case SilentResultValue(result) =>
- result
- case _ =>
- silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match {
- case SilentResultValue(result2) =>
- unit.deprecationWarning(
- tree.pos, "`withFilter' method does not yet exist on "+qual1.tpe.widen+
- ", using `filter' method instead")
- result2
- case SilentTypeError(err) =>
- WithFilterError(tree, err)
- }
- }
- else
- typedSelect(qual1, name)
+ case tree: Throw =>
+ typedThrow(tree)
- if (tree.isInstanceOf[PostfixSelect])
- checkFeature(tree.pos, PostfixOpsFeature, name.decode)
- if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember)
- checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString)
+ case tree: Alternative =>
+ typedAlternative(tree)
- if (qual1.hasSymbolWhich(_.isRootPackage)) treeCopy.Ident(tree1, name)
- else tree1
+ case tree: Star =>
+ typedStar(tree)
- case Ident(name) =>
- Statistics.incCounter(typedIdentCount)
- if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
- (name == tpnme.WILDCARD && (mode & TYPEmode) != 0))
- tree setType makeFullyDefined(pt)
- else
- typedIdent(name)
-
- case ReferenceToBoxed(idt @ Ident(_)) =>
- val id1 = typed1(idt, mode, pt) match { case id: Ident => id }
- val tpe = capturedVariableType(idt.symbol, erasedTypes = phase.erasedTypes)
- treeCopy.ReferenceToBoxed(tree, id1) setType tpe
-
- case Literal(value) =>
- tree setType (
- if (value.tag == UnitTag) UnitClass.tpe
- else ConstantType(value))
-
- case SingletonTypeTree(ref) =>
- val ref1 = checkStable(
- typed(ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe))
- tree setType ref1.tpe.resultType
-
- case SelectFromTypeTree(qual, selector) =>
- val qual1 = typedType(qual, mode)
- if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual1)
- else typedSelect(qual1, selector)
-
- case CompoundTypeTree(templ) =>
- typedCompoundTypeTree(templ)
-
- case AppliedTypeTree(tpt, args) =>
- typedAppliedTypeTree(tpt, args)
-
- case TypeBoundsTree(lo, hi) =>
- val lo1 = typedType(lo, mode)
- val hi1 = typedType(hi, mode)
- treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe)
-
- case etpt @ ExistentialTypeTree(_, _) =>
- val tree1 = typerWithLocalContext(context.makeNewScope(tree, context.owner)){
- _.typedExistentialTypeTree(etpt, mode)
- }
- checkExistentialsFeature(tree1.pos, tree1.tpe, "the existential type")
- tree1
+ case tree: UnApply =>
+ typedUnApply(tree)
- case dc@TypeTreeWithDeferredRefCheck() => dc // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
- case tpt @ TypeTree() =>
- if (tpt.original != null)
- tree setType typedType(tpt.original, mode).tpe
- else
- // we should get here only when something before failed
- // and we try again (@see tryTypedApply). In that case we can assign
- // whatever type to tree; we just have to survive until a real error message is issued.
- tree setType AnyClass.tpe
- case Import(expr, selectors) =>
+ case tree: ArrayValue =>
+ typedArrayValue(tree)
+
+ case tree: ApplyDynamic =>
+ typedApplyDynamic(tree)
+
+ case tree: ReferenceToBoxed =>
+ typedReferenceToBoxed(tree)
+
+ case tree: TypeTreeWithDeferredRefCheck =>
+ tree // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
+
+ case tree: Import =>
assert(forInteractive, "!forInteractive") // should not happen in normal circumstances.
tree setType tree.symbol.tpe
+
case _ =>
abort("unexpected tree: " + tree.getClass + "\n" + tree)//debug
}
@@ -5242,8 +5386,8 @@ trait Typers extends Modes with Adaptations with Tags {
indentTyping()
var alreadyTyped = false
- val startByType = Statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass))
- Statistics.incCounter(visitsByType, tree.getClass)
+ val startByType = if (Statistics.canEnable) Statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass)) else null
+ if (Statistics.canEnable) Statistics.incCounter(visitsByType, tree.getClass)
try {
if (context.retyping &&
(tree.tpe ne null) && (tree.tpe.isErroneous || !(tree.tpe <:< pt))) {
@@ -5298,7 +5442,7 @@ trait Typers extends Modes with Adaptations with Tags {
}
finally {
deindentTyping()
- Statistics.popTimer(byTypeStack, startByType)
+ if (Statistics.canEnable) Statistics.popTimer(byTypeStack, startByType)
}
}
diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala
index 5e0bd010a6..188e0e8afd 100755
--- a/src/library/scala/collection/LinearSeqOptimized.scala
+++ b/src/library/scala/collection/LinearSeqOptimized.scala
@@ -82,17 +82,16 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea
false
}
- override /*TraversableLike*/
- def count(p: A => Boolean): Int = {
+ override /*SeqLike*/
+ def contains(elem: Any): Boolean = {
var these = this
- var cnt = 0
while (!these.isEmpty) {
- if (p(these.head)) cnt += 1
+ if (these.head == elem) return true
these = these.tail
}
- cnt
+ false
}
-
+
override /*IterableLike*/
def find(p: A => Boolean): Option[A] = {
var these = this
@@ -113,7 +112,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea
}
acc
}
-
+
override /*IterableLike*/
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index 0345f05355..b2051bf209 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -235,14 +235,19 @@ trait TraversableLike[+A, +Repr] extends Any
(that ++ seq)(breakOut)
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
- val b = bf(repr)
- b.sizeHint(this)
+ def builder = { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
+ val b = bf(repr)
+ b.sizeHint(this)
+ b
+ }
+ val b = builder
for (x <- this) b += f(x)
b.result
}
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
- val b = bf(repr)
+ def builder = bf(repr) // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
+ val b = builder
for (x <- this) b ++= f(x).seq
b.result
}
@@ -266,7 +271,12 @@ trait TraversableLike[+A, +Repr] extends Any
* @return a new $coll consisting of all elements of this $coll that do not satisfy the given
* predicate `p`. The order of the elements is preserved.
*/
- def filterNot(p: A => Boolean): Repr = filter(!p(_))
+ def filterNot(p: A => Boolean): Repr = {
+ val b = newBuilder
+ for (x <- this)
+ if (!p(x)) b += x
+ b.result
+ }
def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 74dc385f99..87b58005cf 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -302,6 +302,15 @@ sealed abstract class List[+A] extends AbstractSeq[A]
if (isEmpty) Stream.Empty
else new Stream.Cons(head, tail.toStream)
+ @inline override final
+ def foreach[B](f: A => B) {
+ var these = this
+ while (!these.isEmpty) {
+ f(these.head)
+ these = these.tail
+ }
+ }
+
@deprecated("use `distinct` instead", "2.8.0")
def removeDuplicates: List[A] = distinct
}
@@ -378,7 +387,6 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend
while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail }
out.writeObject(ListSerializeEnd)
}
-
}
/** $factoryInfo
diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala
index bbf4f5889d..b6887df61e 100644
--- a/src/library/scala/collection/mutable/Builder.scala
+++ b/src/library/scala/collection/mutable/Builder.scala
@@ -62,9 +62,27 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
* wrong, i.e. a different number of elements is added.
*
* @param coll the collection which serves as a hint for the result's size.
+ */
+ def sizeHint(coll: TraversableLike[_, _]) {
+ if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) {
+ sizeHint(coll.size)
+ }
+ }
+
+ /** Gives a hint that one expects the `result` of this builder
+ * to have the same size as the given collection, plus some delta. This will
+ * provide a hint only if the collection is known to have a cheap
+ * `size` method. Currently this is assumed to be the case if and only if
+ * the collection is of type `IndexedSeqLike`.
+ * Some builder classes
+ * will optimize their representation based on the hint. However,
+ * builder implementations are still required to work correctly even if the hint is
+ * wrong, i.e. a different number of elements is added.
+ *
+ * @param coll the collection which serves as a hint for the result's size.
* @param delta a correction to add to the `coll.size` to produce the size hint.
*/
- def sizeHint(coll: TraversableLike[_, _], delta: Int = 0) {
+ def sizeHint(coll: TraversableLike[_, _], delta: Int) {
if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) {
sizeHint(coll.size + delta)
}
diff --git a/src/library/scala/util/hashing/MurmurHash3.scala b/src/library/scala/util/hashing/MurmurHash3.scala
index 3efd5b5e72..1cfb8276fe 100644
--- a/src/library/scala/util/hashing/MurmurHash3.scala
+++ b/src/library/scala/util/hashing/MurmurHash3.scala
@@ -157,6 +157,20 @@ private[hashing] class MurmurHash3 {
// Finalization
finalizeHash(h, data.length)
}
+
+ final def listHash(xs: collection.immutable.List[_], seed: Int): Int = {
+ var n = 0
+ var h = seed
+ var elems = xs
+ while (!elems.isEmpty) {
+ val head = elems.head
+ val tail = elems.tail
+ h = mix(h, head.##)
+ n += 1
+ elems = tail
+ }
+ finalizeHash(h, n)
+ }
}
/**
@@ -199,7 +213,11 @@ object MurmurHash3 extends MurmurHash3 {
/** To offer some potential for optimization.
*/
- def seqHash(xs: collection.Seq[_]): Int = orderedHash(xs, seqSeed)
+ def seqHash(xs: collection.Seq[_]): Int = xs match {
+ case xs: List[_] => listHash(xs, seqSeed)
+ case xs => orderedHash(xs, seqSeed)
+ }
+
def mapHash(xs: collection.Map[_, _]): Int = unorderedHash(xs, mapSeed)
def setHash(xs: collection.Set[_]): Int = unorderedHash(xs, setSeed)
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 229570dafd..a444c786f7 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -8,6 +8,7 @@ package internal
import util._
import pickling.ByteCodecs
+import scala.annotation.tailrec
/** AnnotationInfo and its helpers */
trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
@@ -31,11 +32,27 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
case AnnotationInfo(tp, Literal(Constant(tpe: Type)) :: Nil, _) if tp.typeSymbol == ThrowsClass => tpe.typeSymbol
}
- /** Test for, get, or remove an annotation */
- def hasAnnotation(cls: Symbol) = annotations exists (_ matches cls)
- def getAnnotation(cls: Symbol) = annotations find (_ matches cls)
+ /** Tests for, get, or remove an annotation */
+ def hasAnnotation(cls: Symbol): Boolean =
+ //OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls)
+ dropOtherAnnotations(annotations, cls).nonEmpty
+
+ def getAnnotation(cls: Symbol): Option[AnnotationInfo] =
+ //OPT inlined from exists to save on #closures; was: annotations find (_ matches cls)
+ dropOtherAnnotations(annotations, cls) match {
+ case ann :: _ => Some(ann)
+ case _ => None
+ }
+
def removeAnnotation(cls: Symbol): Self = filterAnnotations(ann => !(ann matches cls))
+
final def withAnnotation(annot: AnnotationInfo): Self = withAnnotations(List(annot))
+
+ @tailrec private
+ def dropOtherAnnotations(anns: List[AnnotationInfo], cls: Symbol): List[AnnotationInfo] = anns match {
+ case ann :: rest => if (ann matches cls) anns else dropOtherAnnotations(rest, cls)
+ case Nil => Nil
+ }
}
/** Arguments to classfile annotations (which are written to
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
index fbee906b7b..554b3bfca6 100644
--- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -39,8 +39,8 @@ trait BaseTypeSeqs {
*/
class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
self =>
- Statistics.incCounter(baseTypeSeqCount)
- Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
+ if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqCount)
+ if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
/** The number of types in the sequence */
def length: Int = elems.length
diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala
index 25441f9812..d5baad8ab1 100644
--- a/src/reflect/scala/reflect/internal/Importers.scala
+++ b/src/reflect/scala/reflect/internal/Importers.scala
@@ -238,7 +238,7 @@ trait Importers { self: SymbolTable =>
case from.AntiPolyType(pre, targs) =>
AntiPolyType(importType(pre), targs map importType)
case x: from.TypeVar =>
- TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol)
+ TypeVar(importType(x.origin), importTypeConstraint(x.constr), x.typeArgs map importType, x.params map importSymbol)
case from.NotNullType(tpe) =>
NotNullType(importType(tpe))
case from.AnnotatedType(annots, tpe, selfsym) =>
@@ -448,4 +448,4 @@ trait Importers { self: SymbolTable =>
case _ => constant.value
})
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala
index 835a46f05d..2fdf27d847 100644
--- a/src/reflect/scala/reflect/internal/Names.scala
+++ b/src/reflect/scala/reflect/internal/Names.scala
@@ -415,9 +415,6 @@ trait Names extends api.Names with LowPriorityNames {
}
else toString
}
-
- @inline
- final def fingerPrint: Long = (1L << start)
/** TODO - find some efficiency. */
def append(ch: Char) = newName("" + this + ch)
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index ed75b5d855..385e45997b 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -43,13 +43,8 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeBase with MemberScopeBase {
- /** A bitset containing the last 6 bits of the start value of every name
- * stored in this scope.
- */
- var fingerPrints: Long = initFingerPrints
-
protected[Scopes] def this(base: Scope) = {
- this(base.elems, base.fingerPrints)
+ this(base.elems)
nestinglevel = base.nestinglevel + 1
}
@@ -119,7 +114,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
* @param sym ...
*/
def enter[T <: Symbol](sym: T): T = {
- fingerPrints |= sym.name.fingerPrint
enterEntry(newScopeEntry(sym, this))
sym
}
@@ -156,7 +150,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
def rehash(sym: Symbol, newname: Name) {
- fingerPrints |= newname.fingerPrint
if (hashtable ne null) {
val index = sym.name.start & HASHMASK
var e1 = hashtable(index)
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
index 761dcc0534..4100e97cdd 100644
--- a/src/reflect/scala/reflect/internal/SymbolTable.scala
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -72,11 +72,13 @@ abstract class SymbolTable extends macros.Universe
Console.err.println(msg + ": " + result)
result
}
- private[scala] def logResult[T](msg: String)(result: T): T = {
+ @inline
+ final private[scala] def logResult[T](msg: => String)(result: T): T = {
log(msg + ": " + result)
result
}
- private[scala] def logResultIf[T](msg: String, cond: T => Boolean)(result: T): T = {
+ @inline
+ final private[scala] def logResultIf[T](msg: => String, cond: T => Boolean)(result: T): T = {
if (cond(result))
log(msg + ": " + result)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 5da4942a89..09ac3e5f6f 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -11,6 +11,7 @@ import scala.collection.mutable.ListBuffer
import util.Statistics
import Flags._
import base.Attachments
+import scala.annotation.tailrec
trait Symbols extends api.Symbols { self: SymbolTable =>
import definitions._
@@ -1378,7 +1379,6 @@ 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:
@@ -1897,9 +1897,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @param ofclazz The class containing the symbol's definition
* @param site The base type from which member types are computed
*/
- final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol =
- ofclazz.info.nonPrivateDecl(name).filter(sym =>
- !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
+ final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol = {
+ //OPT cut down on #closures by special casing non-overloaded case
+ // was: ofclazz.info.nonPrivateDecl(name) filter (sym =>
+ // !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
+ val result = ofclazz.info.nonPrivateDecl(name)
+ def qualifies(sym: Symbol) = !sym.isTerm || (site.memberType(this) matches site.memberType(sym))
+ if ((result eq NoSymbol) || !result.isOverloaded && qualifies(result)) result
+ else result filter qualifies
+ }
/** The non-private member of `site` whose type and name match the type of this symbol. */
final def matchingSymbol(site: Type, admit: Long = 0L): Symbol =
@@ -2878,7 +2884,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
override def name: TypeName = {
- Statistics.incCounter(nameCount)
+ if (Statistics.canEnable) Statistics.incCounter(nameCount)
if (needsFlatClasses) {
if (flatname eq null)
flatname = nme.flattenedName(rawowner.name, rawname).toTypeName
@@ -3207,7 +3213,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
}
+// ----- Hoisted closures and convenience methods, for compile time reductions -------
+
+ private[scala] final val symbolIsPossibleInRefinement = (sym: Symbol) => sym.isPossibleInRefinement
+ private[scala] final val symbolIsNonVariant = (sym: Symbol) => sym.variance == 0
+
+ @tailrec private[scala] final
+ def allSymbolsHaveOwner(syms: List[Symbol], owner: Symbol): Boolean = syms match {
+ case sym :: rest => sym.owner == owner && allSymbolsHaveOwner(rest, owner)
+ case _ => true
+ }
+
+
+// -------------- Statistics --------------------------------------------------------
+
Statistics.newView("#symbols")(ids)
+
}
object SymbolsStats {
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index b21a28eea8..0180ed4c4f 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -19,7 +19,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
val id = nodeCount // TODO: add to attachment?
nodeCount += 1
- Statistics.incCounter(TreesStats.nodeByType, getClass)
+ if (Statistics.canEnable) Statistics.incCounter(TreesStats.nodeByType, getClass)
@inline final override def pos: Position = rawatt.pos
@@ -29,7 +29,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def setType(tp: Type): this.type = { rawtpe = tp; this }
def defineType(tp: Type): this.type = setType(tp)
- def symbol: Symbol = null
+ def symbol: Symbol = null //!!!OPT!!! symbol is about 3% of hot compile times -- megamorphic dispatch?
def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) }
def setSymbol(sym: Symbol): this.type = { symbol = sym; this }
def hasSymbol = false
@@ -210,7 +210,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
trait TypTree extends Tree with TypTreeApi
- trait SymTree extends Tree with SymTreeContextApi {
+ abstract class SymTree extends Tree with SymTreeContextApi {
override def hasSymbol = true
override var symbol: Symbol = NoSymbol
}
@@ -333,7 +333,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object ArrayValue extends ArrayValueExtractor
case class Function(vparams: List[ValDef], body: Tree)
- extends TermTree with SymTree with FunctionApi
+ extends SymTree with TermTree with FunctionApi
object Function extends FunctionExtractor
case class Assign(lhs: Tree, rhs: Tree)
@@ -353,7 +353,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object Match extends MatchExtractor
case class Return(expr: Tree)
- extends TermTree with SymTree with ReturnApi
+ extends SymTree with TermTree with ReturnApi
object Return extends ReturnExtractor
case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree)
@@ -401,7 +401,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def ApplyConstructor(tpt: Tree, args: List[Tree]) = Apply(Select(New(tpt), nme.CONSTRUCTOR), args)
case class ApplyDynamic(qual: Tree, args: List[Tree])
- extends TermTree with SymTree with ApplyDynamicApi
+ extends SymTree with TermTree with ApplyDynamicApi
object ApplyDynamic extends ApplyDynamicExtractor
case class Super(qual: Tree, mix: TypeName) extends TermTree with SuperApi {
@@ -411,7 +411,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object Super extends SuperExtractor
case class This(qual: TypeName)
- extends TermTree with SymTree with ThisApi
+ extends SymTree with TermTree with ThisApi
object This extends ThisExtractor
case class Select(qualifier: Tree, name: Name)
@@ -447,7 +447,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object SingletonTypeTree extends SingletonTypeTreeExtractor
case class SelectFromTypeTree(qualifier: Tree, name: TypeName)
- extends TypTree with RefTree with SelectFromTypeTreeApi
+ extends RefTree with TypTree with SelectFromTypeTreeApi
object SelectFromTypeTree extends SelectFromTypeTreeExtractor
case class CompoundTypeTree(templ: Template)
@@ -1145,29 +1145,25 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
}
+ //OPT ordered according to frequency to speed it up.
override protected def itransform(transformer: Transformer, tree: Tree): Tree = {
import transformer._
val treeCopy = transformer.treeCopy
+
+ // begin itransform
tree match {
- case EmptyTree =>
- tree
- case PackageDef(pid, stats) =>
- treeCopy.PackageDef(
- tree, transform(pid).asInstanceOf[RefTree],
- atOwner(mclass(tree.symbol)) {
- transformStats(stats, currentOwner)
- }
- )
- case ClassDef(mods, name, tparams, impl) =>
- atOwner(tree.symbol) {
- treeCopy.ClassDef(tree, transformModifiers(mods), name,
- transformTypeDefs(tparams), transformTemplate(impl))
- }
- case ModuleDef(mods, name, impl) =>
- atOwner(mclass(tree.symbol)) {
- treeCopy.ModuleDef(tree, transformModifiers(mods),
- name, transformTemplate(impl))
- }
+ case Ident(name) =>
+ treeCopy.Ident(tree, name)
+ case Select(qualifier, selector) =>
+ treeCopy.Select(tree, transform(qualifier), selector)
+ case Apply(fun, args) =>
+ treeCopy.Apply(tree, transform(fun), transformTrees(args))
+ case TypeTree() =>
+ treeCopy.TypeTree(tree)
+ case Literal(value) =>
+ treeCopy.Literal(tree, value)
+ case This(qual) =>
+ treeCopy.This(tree, qual)
case ValDef(mods, name, tpt, rhs) =>
atOwner(tree.symbol) {
treeCopy.ValDef(tree, transformModifiers(mods),
@@ -1179,73 +1175,70 @@ trait Trees extends api.Trees { self: SymbolTable =>
transformTypeDefs(tparams), transformValDefss(vparamss),
transform(tpt), transform(rhs))
}
- case TypeDef(mods, name, tparams, rhs) =>
- atOwner(tree.symbol) {
- treeCopy.TypeDef(tree, transformModifiers(mods), name,
- transformTypeDefs(tparams), transform(rhs))
- }
- case LabelDef(name, params, rhs) =>
- treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy'
- case Import(expr, selectors) =>
- treeCopy.Import(tree, transform(expr), selectors)
- case Template(parents, self, body) =>
- treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol))
case Block(stats, expr) =>
treeCopy.Block(tree, transformStats(stats, currentOwner), transform(expr))
+ case If(cond, thenp, elsep) =>
+ treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep))
case CaseDef(pat, guard, body) =>
treeCopy.CaseDef(tree, transform(pat), transform(guard), transform(body))
- case Alternative(trees) =>
- treeCopy.Alternative(tree, transformTrees(trees))
- case Star(elem) =>
- treeCopy.Star(tree, transform(elem))
+ case TypeApply(fun, args) =>
+ treeCopy.TypeApply(tree, transform(fun), transformTrees(args))
+ case AppliedTypeTree(tpt, args) =>
+ treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args))
case Bind(name, body) =>
treeCopy.Bind(tree, name, transform(body))
- case UnApply(fun, args) =>
- treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
- case ArrayValue(elemtpt, trees) =>
- treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
case Function(vparams, body) =>
atOwner(tree.symbol) {
treeCopy.Function(tree, transformValDefs(vparams), transform(body))
}
+ case Match(selector, cases) =>
+ treeCopy.Match(tree, transform(selector), transformCaseDefs(cases))
+ case New(tpt) =>
+ treeCopy.New(tree, transform(tpt))
case Assign(lhs, rhs) =>
treeCopy.Assign(tree, transform(lhs), transform(rhs))
case AssignOrNamedArg(lhs, rhs) =>
treeCopy.AssignOrNamedArg(tree, transform(lhs), transform(rhs))
- case If(cond, thenp, elsep) =>
- treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep))
- case Match(selector, cases) =>
- treeCopy.Match(tree, transform(selector), transformCaseDefs(cases))
- case Return(expr) =>
- treeCopy.Return(tree, transform(expr))
case Try(block, catches, finalizer) =>
treeCopy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer))
+ case EmptyTree =>
+ tree
case Throw(expr) =>
treeCopy.Throw(tree, transform(expr))
- case New(tpt) =>
- treeCopy.New(tree, transform(tpt))
- case Typed(expr, tpt) =>
- treeCopy.Typed(tree, transform(expr), transform(tpt))
- case TypeApply(fun, args) =>
- treeCopy.TypeApply(tree, transform(fun), transformTrees(args))
- case Apply(fun, args) =>
- treeCopy.Apply(tree, transform(fun), transformTrees(args))
- case ApplyDynamic(qual, args) =>
- treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args))
case Super(qual, mix) =>
treeCopy.Super(tree, transform(qual), mix)
- case This(qual) =>
- treeCopy.This(tree, qual)
- case Select(qualifier, selector) =>
- treeCopy.Select(tree, transform(qualifier), selector)
- case Ident(name) =>
- treeCopy.Ident(tree, name)
- case ReferenceToBoxed(idt) =>
- treeCopy.ReferenceToBoxed(tree, transform(idt) match { case idt1: Ident => idt1 })
- case Literal(value) =>
- treeCopy.Literal(tree, value)
- case TypeTree() =>
- treeCopy.TypeTree(tree)
+ case TypeBoundsTree(lo, hi) =>
+ treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi))
+ case Typed(expr, tpt) =>
+ treeCopy.Typed(tree, transform(expr), transform(tpt))
+ case Import(expr, selectors) =>
+ treeCopy.Import(tree, transform(expr), selectors)
+ case Template(parents, self, body) =>
+ treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol))
+ case ClassDef(mods, name, tparams, impl) =>
+ atOwner(tree.symbol) {
+ treeCopy.ClassDef(tree, transformModifiers(mods), name,
+ transformTypeDefs(tparams), transformTemplate(impl))
+ }
+ case ModuleDef(mods, name, impl) =>
+ atOwner(mclass(tree.symbol)) {
+ treeCopy.ModuleDef(tree, transformModifiers(mods),
+ name, transformTemplate(impl))
+ }
+ case TypeDef(mods, name, tparams, rhs) =>
+ atOwner(tree.symbol) {
+ treeCopy.TypeDef(tree, transformModifiers(mods), name,
+ transformTypeDefs(tparams), transform(rhs))
+ }
+ case LabelDef(name, params, rhs) =>
+ treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy'
+ case PackageDef(pid, stats) =>
+ treeCopy.PackageDef(
+ tree, transform(pid).asInstanceOf[RefTree],
+ atOwner(mclass(tree.symbol)) {
+ transformStats(stats, currentOwner)
+ }
+ )
case Annotated(annot, arg) =>
treeCopy.Annotated(tree, transform(annot), transform(arg))
case SingletonTypeTree(ref) =>
@@ -1254,12 +1247,22 @@ trait Trees extends api.Trees { self: SymbolTable =>
treeCopy.SelectFromTypeTree(tree, transform(qualifier), selector)
case CompoundTypeTree(templ) =>
treeCopy.CompoundTypeTree(tree, transformTemplate(templ))
- case AppliedTypeTree(tpt, args) =>
- treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args))
- case TypeBoundsTree(lo, hi) =>
- treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi))
case ExistentialTypeTree(tpt, whereClauses) =>
treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses))
+ case Return(expr) =>
+ treeCopy.Return(tree, transform(expr))
+ case Alternative(trees) =>
+ treeCopy.Alternative(tree, transformTrees(trees))
+ case Star(elem) =>
+ treeCopy.Star(tree, transform(elem))
+ case UnApply(fun, args) =>
+ treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
+ case ArrayValue(elemtpt, trees) =>
+ treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
+ case ApplyDynamic(qual, args) =>
+ treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args))
+ case ReferenceToBoxed(idt) =>
+ treeCopy.ReferenceToBoxed(tree, transform(idt) match { case idt1: Ident => idt1 })
case _ =>
xtransform(transformer, tree)
}
@@ -1540,6 +1543,8 @@ trait Trees extends api.Trees { self: SymbolTable =>
sys.error("Not a LabelDef: " + t + "/" + t.getClass)
}
+// -------------- Classtags --------------------------------------------------------
+
implicit val TreeTag = ClassTag[Tree](classOf[Tree])
implicit val TermTreeTag = ClassTag[TermTree](classOf[TermTree])
implicit val TypTreeTag = ClassTag[TypTree](classOf[TypTree])
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 9514898ce5..01f615c5cc 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -15,6 +15,7 @@ import scala.util.control.ControlThrowable
import scala.annotation.tailrec
import util.Statistics
import scala.runtime.ObjectRef
+import util.ThreeValues._
/* A standard type pattern match:
case ErrorType =>
@@ -117,13 +118,34 @@ trait Types extends api.Types { self: SymbolTable =>
class UndoLog extends Clearable {
private type UndoPairs = List[(TypeVar, TypeConstraint)]
- private var log: UndoPairs = List()
+ //OPT this method is public so we can do `manual inlining`
+ var log: UndoPairs = List()
+
+ /*
+ * These two methods provide explicit locking mechanism that is overridden in SynchronizedUndoLog.
+ *
+ * The idea behind explicit locking mechanism is that all public methods that access mutable state
+ * will have to obtain the lock for their entire execution so both reads and writes can be kept in
+ * right order. Originally, that was achieved by overriding those public methods in
+ * `SynchronizedUndoLog` which was fine but expensive. The reason is that those public methods take
+ * thunk as argument and if we keep them non-final there's no way to make them inlined so thunks
+ * can go away.
+ *
+ * By using explicit locking we can achieve inlining.
+ *
+ * NOTE: They are made public for now so we can apply 'manual inlining' (copy&pasting into hot
+ * places implementation of `undo` or `undoUnless`). This should be changed back to protected
+ * once inliner is fixed.
+ */
+ def lock(): Unit = ()
+ def unlock(): Unit = ()
// register with the auto-clearing cache manager
perRunCaches.recordCache(this)
/** Undo all changes to constraints to type variables upto `limit`. */
- private def undoTo(limit: UndoPairs) {
+ //OPT this method is public so we can do `manual inlining`
+ def undoTo(limit: UndoPairs) {
while ((log ne limit) && log.nonEmpty) {
val (tv, constr) = log.head
tv.constr = constr
@@ -140,30 +162,41 @@ trait Types extends api.Types { self: SymbolTable =>
}
def clear() {
- if (settings.debug.value)
- self.log("Clearing " + log.size + " entries from the undoLog.")
-
- log = Nil
+ lock()
+ try {
+ if (settings.debug.value)
+ self.log("Clearing " + log.size + " entries from the undoLog.")
+ log = Nil
+ } finally unlock()
+ }
+ def size = {
+ lock()
+ try log.size finally unlock()
}
- def size = log.size
// `block` should not affect constraints on typevars
def undo[T](block: => T): T = {
- val before = log
+ lock()
+ try {
+ val before = log
- try block
- finally undoTo(before)
+ try block
+ finally undoTo(before)
+ } finally unlock()
}
// if `block` evaluates to false, it should not affect constraints on typevars
def undoUnless(block: => Boolean): Boolean = {
- val before = log
- var result = false
+ lock()
+ try {
+ val before = log
+ var result = false
- try result = block
- finally if (!result) undoTo(before)
+ try result = block
+ finally if (!result) undoTo(before)
- result
+ result
+ } finally unlock()
}
}
@@ -293,7 +326,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,8 +376,8 @@ 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
@@ -363,7 +396,7 @@ trait Types extends api.Types { self: SymbolTable =>
* and all type parameters (if any) are invariant.
*/
def isFinalType =
- typeSymbol.isFinal && (typeSymbol.typeParams forall (_.variance == 0))
+ typeSymbol.isFinal && (typeSymbol.typeParams forall symbolIsNonVariant)
/** Is this type completed (i.e. not a lazy type)? */
def isComplete: Boolean = true
@@ -692,7 +725,8 @@ trait Types extends api.Types { self: SymbolTable =>
* = Int
*/
def asSeenFrom(pre: Type, clazz: Symbol): Type = {
- TypesStats.timedTypeOp(asSeenFromNanos) {
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, asSeenFromNanos) else null
+ try {
val trivial = (
this.isTrivial
|| phase.erasedTypes && pre.typeSymbol != ArrayClass
@@ -707,7 +741,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (m.capturedSkolems.isEmpty) tp1
else deriveType(m.capturedSkolems, _.cloneSymbol setFlag CAPTURED)(tp1)
}
- }
+ } finally if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
/** The info of `sym`, seen as a member of this type.
@@ -815,7 +849,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** Is this type a subtype of that type? */
def <:<(that: Type): Boolean = {
- if (util.Statistics.enabled) stat_<:<(that)
+ if (Statistics.canEnable) stat_<:<(that)
else {
(this eq that) ||
(if (explainSwitch) explain("<:", isSubType, this, that)
@@ -843,26 +877,26 @@ trait Types extends api.Types { self: SymbolTable =>
}
def stat_<:<(that: Type): Boolean = {
- Statistics.incCounter(subtypeCount)
- val start = Statistics.pushTimer(typeOpsStack, subtypeNanos)
+ if (Statistics.canEnable) Statistics.incCounter(subtypeCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, subtypeNanos) else null
val result =
(this eq that) ||
(if (explainSwitch) explain("<:", isSubType, this, that)
else isSubType(this, that, AnyDepth))
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, 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 = {
- Statistics.incCounter(subtypeCount)
- val start = Statistics.pushTimer(typeOpsStack, subtypeNanos)
+ if (Statistics.canEnable) Statistics.incCounter(subtypeCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, subtypeNanos) else null
val result =
((this eq that) ||
(if (explainSwitch) explain("weak_<:", isWeakSubType, this, that)
else isWeakSubType(this, that)))
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
result
}
@@ -1025,8 +1059,8 @@ trait Types extends api.Types { self: SymbolTable =>
// See (t0851) for a situation where this happens.
val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this)
- Statistics.incCounter(findMembersCount)
- val start = Statistics.pushTimer(typeOpsStack, findMembersNanos)
+ if (Statistics.canEnable) Statistics.incCounter(findMembersCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMembersNanos) else null
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var members: Scope = null
@@ -1078,7 +1112,7 @@ trait Types extends api.Types { self: SymbolTable =>
required |= DEFERRED
excluded &= ~(DEFERRED.toLong)
} // while (continue)
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
if (suspension ne null) suspension foreach (_.suspended = false)
if (members eq null) EmptyScope else members
}
@@ -1101,8 +1135,8 @@ trait Types extends api.Types { self: SymbolTable =>
// See (t0851) for a situation where this happens.
val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this)
- Statistics.incCounter(findMemberCount)
- val start = Statistics.pushTimer(typeOpsStack, findMemberNanos)
+ if (Statistics.canEnable) Statistics.incCounter(findMemberCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var member: Symbol = NoSymbol
@@ -1113,7 +1147,6 @@ trait Types extends api.Types { self: SymbolTable =>
var excluded = excludedFlags | DEFERRED
var continue = true
var self: Type = null
- val fingerPrint: Long = name.fingerPrint
while (continue) {
continue = false
@@ -1121,75 +1154,73 @@ trait Types extends api.Types { self: SymbolTable =>
var bcs = bcs0
while (!bcs.isEmpty) {
val decls = bcs.head.info.decls
- if ((fingerPrint & decls.fingerPrints) != 0) {
- var entry = decls.lookupEntry(name)
- while (entry ne null) {
- val sym = entry.sym
- val flags = sym.flags
- if ((flags & required) == required) {
- val excl = flags & excluded
- if (excl == 0L &&
+ var entry = decls.lookupEntry(name)
+ while (entry ne null) {
+ val sym = entry.sym
+ val flags = sym.flags
+ if ((flags & required) == required) {
+ val excl = flags & excluded
+ if (excl == 0L &&
(// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
- (bcs eq bcs0) ||
- (flags & PrivateLocal) != PrivateLocal ||
- (bcs0.head.hasTransOwner(bcs.head)))) {
- if (name.isTypeName || stableOnly && sym.isStable) {
- Statistics.popTimer(typeOpsStack, start)
- if (suspension ne null) suspension foreach (_.suspended = false)
- return sym
- } else if (member eq NoSymbol) {
- member = sym
- } else if (members eq null) {
- if ((member ne sym) &&
- ((member.owner eq sym.owner) ||
- (flags & PRIVATE) != 0 || {
- if (self eq null) self = this.narrow
- if (membertpe eq null) membertpe = self.memberType(member)
- !(membertpe matches self.memberType(sym))
- })) {
- lastM = new ::(sym, null)
- members = member :: lastM
- }
- } else {
- var others: List[Symbol] = members
- var symtpe: Type = null
- while ((others ne null) && {
- val other = others.head
- (other ne sym) &&
- ((other.owner eq sym.owner) ||
- (flags & PRIVATE) != 0 || {
- if (self eq null) self = this.narrow
- if (symtpe eq null) symtpe = self.memberType(sym)
- !(self.memberType(other) matches symtpe)
+ (bcs eq bcs0) ||
+ (flags & PrivateLocal) != PrivateLocal ||
+ (bcs0.head.hasTransOwner(bcs.head)))) {
+ if (name.isTypeName || stableOnly && sym.isStable) {
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
+ if (suspension ne null) suspension foreach (_.suspended = false)
+ return sym
+ } else if (member eq NoSymbol) {
+ member = sym
+ } else if (members eq null) {
+ if ((member ne sym) &&
+ ((member.owner eq sym.owner) ||
+ (flags & PRIVATE) != 0 || {
+ if (self eq null) self = this.narrow
+ if (membertpe eq null) membertpe = self.memberType(member)
+ !(membertpe matches self.memberType(sym))
+ })) {
+ lastM = new ::(sym, null)
+ members = member :: lastM
+ }
+ } else {
+ var others: List[Symbol] = members
+ var symtpe: Type = null
+ while ((others ne null) && {
+ val other = others.head
+ (other ne sym) &&
+ ((other.owner eq sym.owner) ||
+ (flags & PRIVATE) != 0 || {
+ if (self eq null) self = this.narrow
+ if (symtpe eq null) symtpe = self.memberType(sym)
+ !(self.memberType(other) matches symtpe)
})}) {
- others = others.tail
- }
- if (others eq null) {
- val lastM1 = new ::(sym, null)
- lastM.tl = lastM1
- lastM = lastM1
- }
+ others = others.tail
+ }
+ if (others eq null) {
+ val lastM1 = new ::(sym, null)
+ lastM.tl = lastM1
+ lastM = lastM1
}
- } else if (excl == DEFERRED) {
- continue = true
}
+ } else if (excl == DEFERRED) {
+ continue = true
}
- entry = decls lookupNextEntry entry
- } // while (entry ne null)
- } // if (fingerPrint matches)
+ }
+ entry = decls lookupNextEntry entry
+ } // while (entry ne null)
// excluded = excluded | LOCAL
bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail
} // while (!bcs.isEmpty)
required |= DEFERRED
excluded &= ~(DEFERRED.toLong)
} // while (continue)
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
if (suspension ne null) suspension foreach (_.suspended = false)
if (members eq null) {
- if (member == NoSymbol) Statistics.incCounter(noMemberCount)
+ if (member == NoSymbol) if (Statistics.canEnable) Statistics.incCounter(noMemberCount)
member
} else {
- Statistics.incCounter(multMemberCount)
+ if (Statistics.canEnable) Statistics.incCounter(multMemberCount)
lastM.tl = Nil
baseClasses.head.newOverloaded(this, members)
}
@@ -1238,14 +1269,18 @@ trait Types extends api.Types { self: SymbolTable =>
// Subclasses ------------------------------------------------------------
- trait UniqueType extends Product {
- final override val hashCode = scala.runtime.ScalaRunTime._hashCode(this)
+ /**
+ * A type that can be passed to unique(..) and be stored in the uniques map.
+ */
+ abstract class UniqueType extends Type with Product {
+ final override val hashCode = computeHashCode
+ protected def computeHashCode = scala.runtime.ScalaRunTime._hashCode(this)
}
/** A base class for types that defer some operations
* to their immediate supertype.
*/
- abstract class SubType extends Type {
+ abstract class SubType extends UniqueType {
def supertype: Type
override def parents: List[Type] = supertype.parents
override def decls: Scope = supertype.decls
@@ -1276,7 +1311,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def isVolatile = underlying.isVolatile
override def widen: Type = underlying.widen
override def baseTypeSeq: BaseTypeSeq = {
- Statistics.incCounter(singletonBaseTypeSeqCount)
+ if (Statistics.canEnable) Statistics.incCounter(singletonBaseTypeSeqCount)
underlying.baseTypeSeq prepend this
}
override def isHigherKinded = false // singleton type classifies objects, thus must be kind *
@@ -1386,7 +1421,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "ThisType"
}
- final class UniqueThisType(sym: Symbol) extends ThisType(sym) with UniqueType { }
+ final class UniqueThisType(sym: Symbol) extends ThisType(sym) { }
object ThisType extends ThisTypeExtractor {
def apply(sym: Symbol): Type =
@@ -1398,7 +1433,11 @@ trait Types extends api.Types { self: SymbolTable =>
* Cannot be created directly; one should always use `singleType` for creation.
*/
abstract case class SingleType(pre: Type, sym: Symbol) extends SingletonType with SingleTypeApi {
- override val isTrivial: Boolean = pre.isTrivial
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN) trivial = fromBoolean(pre.isTrivial)
+ toBoolean(trivial)
+ }
override def isGround = sym.isPackageClass || pre.isGround
// override def isNullable = underlying.isNullable
@@ -1443,7 +1482,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "SingleType"
}
- final class UniqueSingleType(pre: Type, sym: Symbol) extends SingleType(pre, sym) with UniqueType { }
+ final class UniqueSingleType(pre: Type, sym: Symbol) extends SingleType(pre, sym)
object SingleType extends SingleTypeExtractor {
def apply(pre: Type, sym: Symbol): Type = {
@@ -1464,7 +1503,11 @@ trait Types extends api.Types { self: SymbolTable =>
}
abstract case class SuperType(thistpe: Type, supertpe: Type) extends SingletonType with SuperTypeApi {
- override val isTrivial: Boolean = thistpe.isTrivial && supertpe.isTrivial
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN) trivial = fromBoolean(thistpe.isTrivial && supertpe.isTrivial)
+ toBoolean(trivial)
+ }
override def isNotNull = true;
override def typeSymbol = thistpe.typeSymbol
override def underlying = supertpe
@@ -1474,7 +1517,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "SuperType"
}
- final class UniqueSuperType(thistp: Type, supertp: Type) extends SuperType(thistp, supertp) with UniqueType { }
+ final class UniqueSuperType(thistp: Type, supertp: Type) extends SuperType(thistp, supertp)
object SuperType extends SuperTypeExtractor {
def apply(thistp: Type, supertp: Type): Type = {
@@ -1487,7 +1530,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
abstract case class TypeBounds(lo: Type, hi: Type) extends SubType with TypeBoundsApi {
def supertype = hi
- override val isTrivial: Boolean = lo.isTrivial && hi.isTrivial
+ override def isTrivial: Boolean = lo.isTrivial && hi.isTrivial
override def bounds: TypeBounds = this
def containsType(that: Type) = that match {
case TypeBounds(_, _) => that <:< this
@@ -1495,8 +1538,8 @@ trait Types extends api.Types { self: SymbolTable =>
}
private def lowerString = if (emptyLowerBound) "" else " >: " + lo
private def upperString = if (emptyUpperBound) "" else " <: " + hi
- private def emptyLowerBound = lo.typeSymbolDirect eq NothingClass
- private def emptyUpperBound = hi.typeSymbolDirect eq AnyClass
+ private def emptyLowerBound = typeIsNothing(lo)
+ private def emptyUpperBound = typeIsAny(hi)
def isEmptyBounds = emptyLowerBound && emptyUpperBound
// override def isNullable: Boolean = NullClass.tpe <:< lo;
@@ -1504,7 +1547,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "TypeBoundsType"
}
- final class UniqueTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) with UniqueType { }
+ final class UniqueTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi)
object TypeBounds extends TypeBoundsExtractor {
def empty: TypeBounds = apply(NothingClass.tpe, AnyClass.tpe)
@@ -1579,10 +1622,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 +1641,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]()
@@ -1625,8 +1668,8 @@ trait Types extends api.Types { self: SymbolTable =>
val bts = copyRefinedType(tpe.asInstanceOf[RefinedType], tpe.parents map varToParam, varToParam mapOver tpe.decls).baseTypeSeq
tpe.baseTypeSeqCache = bts lateMap paramToVar
} else {
- Statistics.incCounter(compoundBaseTypeSeqCount)
- val start = Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos)
+ if (Statistics.canEnable) Statistics.incCounter(compoundBaseTypeSeqCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos) else null
try {
tpe.baseTypeSeqCache = undetBaseTypeSeq
tpe.baseTypeSeqCache =
@@ -1635,7 +1678,7 @@ trait Types extends api.Types { self: SymbolTable =>
else
compoundBaseTypeSeq(tpe)
} finally {
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
// [Martin] suppressing memo-ization solves the problem with "same type after erasure" errors
// when compiling with
@@ -1683,12 +1726,12 @@ trait Types extends api.Types { self: SymbolTable =>
if (period != currentPeriod) {
tpe.baseClassesPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- val start = Statistics.pushTimer(typeOpsStack, baseClassesNanos)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseClassesNanos) else null
try {
tpe.baseClassesCache = null
tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail)
} finally {
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
}
@@ -1706,7 +1749,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def isHigherKinded = (
parents.nonEmpty &&
- (parents forall (_.isHigherKinded)) &&
+ (parents forall typeIsHigherKinded) &&
!phase.erasedTypes
)
@@ -1989,7 +2032,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "ConstantType"
}
- final class UniqueConstantType(value: Constant) extends ConstantType(value) with UniqueType {
+ final class UniqueConstantType(value: Constant) extends ConstantType(value) {
/** Save the type of `value`. For Java enums, it depends on finding the linked class,
* which might not be found after `flatten`. */
private lazy val _tpe: Type = value.tpe
@@ -2037,7 +2080,7 @@ trait Types extends api.Types { self: SymbolTable =>
private var volatileRecursions: Int = 0
private val pendingVolatiles = new mutable.HashSet[Symbol]
- class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType {
+ class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) {
require(args0.nonEmpty, this)
/** No unapplied type params size it has (should have) equally as many args. */
@@ -2090,7 +2133,7 @@ trait Types extends api.Types { self: SymbolTable =>
override protected def finishPrefix(rest: String) = "" + thisInfo
}
- class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType {
+ class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) {
// A reference (in a Scala program) to a type that has type parameters, but where the reference
// does not include type arguments. Note that it doesn't matter whether the symbol refers
// to a java or scala symbol, but it does matter whether it occurs in java or scala code.
@@ -2294,15 +2337,32 @@ trait Types extends api.Types { self: SymbolTable =>
*
* @M: a higher-kinded type is represented as a TypeRef with sym.typeParams.nonEmpty, but args.isEmpty
*/
- abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type with TypeRefApi {
- override val isTrivial: Boolean = !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial)
-
+ abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends UniqueType with TypeRefApi {
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN)
+ trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args))
+ toBoolean(trivial)
+ }
private[reflect] var parentsCache: List[Type] = _
private[reflect] var parentsPeriod = NoPeriod
private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
private[reflect] var baseTypeSeqPeriod = NoPeriod
private var normalized: Type = _
+ //OPT specialize hashCode
+ override final def computeHashCode = {
+ import scala.util.hashing.MurmurHash3._
+ val hasArgs = args.nonEmpty
+ var h = productSeed
+ h = mix(h, pre.hashCode)
+ h = mix(h, sym.hashCode)
+ if (hasArgs)
+ finalizeHash(mix(h, args.hashCode), 3)
+ else
+ finalizeHash(h, 2)
+ }
+
// @M: propagate actual type params (args) to `tp`, by replacing
// formal type parameters with actual ones. If tp is higher kinded,
// the "actual" type arguments are types that simply reference the
@@ -2399,7 +2459,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("[", ",", "]")
@@ -2500,13 +2560,13 @@ trait Types extends api.Types { self: SymbolTable =>
if (period != currentPeriod) {
tpe.baseTypeSeqPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- Statistics.incCounter(typerefBaseTypeSeqCount)
- val start = Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos)
+ if (Statistics.canEnable) Statistics.incCounter(typerefBaseTypeSeqCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos) else null
try {
tpe.baseTypeSeqCache = undetBaseTypeSeq
tpe.baseTypeSeqCache = tpe.baseTypeSeqImpl
} finally {
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
}
@@ -2523,14 +2583,22 @@ trait Types extends api.Types { self: SymbolTable =>
case class MethodType(override val params: List[Symbol],
override val resultType: Type) extends Type with MethodTypeApi {
- override lazy val isTrivial: Boolean =
- isTrivialResult && (params forall isTrivialParam)
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN) trivial = fromBoolean(isTrivialResult && areTrivialParams(params))
+ toBoolean(trivial)
+ }
private def isTrivialResult =
resultType.isTrivial && (resultType eq resultType.withoutAnnotations)
- private def isTrivialParam(p: Symbol) =
- p.tpe.isTrivial && !(params.exists(_.tpe contains p) || (resultType contains p))
+ private def areTrivialParams(ps: List[Symbol]): Boolean = ps match {
+ case p :: rest =>
+ p.tpe.isTrivial && !typesContain(paramTypes, p) && !(resultType contains p) &&
+ areTrivialParams(rest)
+ case _ =>
+ true
+ }
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 +2614,19 @@ 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)
+ private var isdepmeth: ThreeValue = UNKNOWN
+ override def isDependentMethodType: Boolean = {
+ if (isdepmeth == UNKNOWN) isdepmeth = fromBoolean(IsDependentCollector.collect(resultType))
+ toBoolean(isdepmeth)
+ }
+
// 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 +2641,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 +2729,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 +2833,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,14 +2944,13 @@ 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))
}
else new TypeConstraint
}
- def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr))
def untouchable(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = true)
def apply(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = false)
def apply(origin: Type, constr: TypeConstraint): TypeVar = apply(origin, constr, Nil, Nil)
@@ -2890,7 +2963,7 @@ trait Types extends api.Types { self: SymbolTable =>
val tv = (
if (args.isEmpty && params.isEmpty) {
if (untouchable) new TypeVar(origin, constr) with UntouchableTypeVar
- else new TypeVar(origin, constr)
+ else new TypeVar(origin, constr) {}
}
else if (args.size == params.size) {
if (untouchable) new AppliedTypeVar(origin, constr, params zip args) with UntouchableTypeVar
@@ -2916,13 +2989,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 (_.typeSymbol)
/** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.)
*/
@@ -2981,9 +3053,9 @@ trait Types extends api.Types { self: SymbolTable =>
*
* Precondition for this class, enforced structurally: args.isEmpty && params.isEmpty.
*/
- class TypeVar(
+ abstract case class TypeVar(
val origin: Type,
- val constr0: TypeConstraint
+ var constr: TypeConstraint
) extends Type {
def untouchable = false // by other typevars
override def params: List[Symbol] = Nil
@@ -2996,7 +3068,7 @@ trait Types extends api.Types { self: SymbolTable =>
* in operations that are exposed from types. Hence, no syncing of `constr`
* or `encounteredHigherLevel` or `suspended` accesses should be necessary.
*/
- var constr = constr0
+// var constr = constr0
def instValid = constr.instValid
override def isGround = instValid && constr.inst.isGround
@@ -3395,16 +3467,16 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- /** A temporary type representing the reasure of a user-defined value type.
- * Created during phase reasure, elimintaed again in posterasure.
+ /** A temporary type representing the erasure of a user-defined value type.
+ * Created during phase reasure, eliminated again in posterasure.
* @param sym The value class symbol
* @param underlying The underlying type before erasure
*/
- abstract case class ErasedValueType(original: TypeRef) extends Type {
+ abstract case class ErasedValueType(original: TypeRef) extends UniqueType {
override def safeToString = "ErasedValueType("+original+")"
}
- final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original) with UniqueType
+ final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original)
object ErasedValueType {
def apply(original: TypeRef): Type = {
@@ -3824,7 +3896,7 @@ trait Types extends api.Types { self: SymbolTable =>
private var uniqueRunId = NoRunId
protected def unique[T <: Type](tp: T): T = {
- Statistics.incCounter(rawTypeCount)
+ if (Statistics.canEnable) Statistics.incCounter(rawTypeCount)
if (uniqueRunId != currentRunId) {
uniques = util.HashSet[Type]("uniques", initialUniquesCapacity)
perRunCaches.recordCache(uniques)
@@ -3861,8 +3933,8 @@ trait Types extends api.Types { self: SymbolTable =>
* guarding addLoBound/addHiBound somehow broke raw types so it
* only guards against being created with them.]
*/
- private var lobounds = lo0 filterNot (_.typeSymbolDirect eq NothingClass)
- private var hibounds = hi0 filterNot (_.typeSymbolDirect eq AnyClass)
+ private var lobounds = lo0 filterNot typeIsNothing
+ private var hibounds = hi0 filterNot typeIsAny
private var numlo = numlo0
private var numhi = numhi0
private var avoidWidening = avoidWidening0
@@ -3918,8 +3990,8 @@ trait Types extends api.Types { self: SymbolTable =>
override def toString = {
val boundsStr = {
- val lo = loBounds filterNot (_.typeSymbolDirect eq NothingClass)
- val hi = hiBounds filterNot (_.typeSymbolDirect eq AnyClass)
+ val lo = loBounds filterNot typeIsNothing
+ val hi = hiBounds filterNot typeIsAny
val lostr = if (lo.isEmpty) Nil else List(lo.mkString(" >: (", ", ", ")"))
val histr = if (hi.isEmpty) Nil else List(hi.mkString(" <: (", ", ", ")"))
@@ -3966,15 +4038,18 @@ trait Types extends api.Types { self: SymbolTable =>
override def variance = _variance
def variance_=(x: Int) = _variance = x
- override protected def noChangeToSymbols(origSyms: List[Symbol]) = {
- origSyms forall { sym =>
- val v = variance
- if (sym.isAliasType) variance = 0
- val result = this(sym.info)
- variance = v
- result eq sym.info
+ override protected def noChangeToSymbols(origSyms: List[Symbol]) =
+ //OPT inline from forall to save on #closures
+ origSyms match {
+ case sym :: rest =>
+ val v = variance
+ if (sym.isAliasType) variance = 0
+ val result = this(sym.info)
+ variance = v
+ (result eq sym.info) && noChangeToSymbols(rest)
+ case _ =>
+ true
}
- }
override protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
map2Conserve(args, tparams) { (arg, tparam) =>
@@ -4479,7 +4554,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 +4605,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 +4746,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)
@@ -5104,14 +5181,21 @@ trait Types extends api.Types { self: SymbolTable =>
1
}
- private def maxDepth(tps: Seq[Type], by: Type => Int): Int = {
- var d = 0
- for (tp <- tps) d = d max by(tp)
- d
+ private def maxDepth(tps: List[Type], by: Type => Int): Int = {
+ //OPT replaced with tailrecursive function to save on #closures
+ // was:
+ // var d = 0
+ // for (tp <- tps) d = d max by(tp) //!!!OPT!!!
+ // d
+ def loop(tps: List[Type], acc: Int): Int = tps match {
+ case tp :: rest => loop(rest, acc max by(tp))
+ case _ => acc
+ }
+ loop(tps, 0)
}
- private def typeDepth(tps: Seq[Type]): Int = maxDepth(tps, typeDepth)
- private def baseTypeSeqDepth(tps: Seq[Type]): Int = maxDepth(tps, _.baseTypeSeqDepth)
+ private def typeDepth(tps: List[Type]): Int = maxDepth(tps, typeDepth)
+ private def baseTypeSeqDepth(tps: List[Type]): Int = maxDepth(tps, _.baseTypeSeqDepth)
/** Is intersection of given types populated? That is,
* for all types tp1, tp2 in intersection
@@ -5220,11 +5304,24 @@ trait Types extends api.Types { self: SymbolTable =>
/** Do `tp1` and `tp2` denote equivalent types? */
def isSameType(tp1: Type, tp2: Type): Boolean = try {
- Statistics.incCounter(sametypeCount)
+ if (Statistics.canEnable) Statistics.incCounter(sametypeCount)
subsametypeRecursions += 1
- undoLog undoUnless {
- isSameType1(tp1, tp2)
- }
+ //OPT cutdown on Function0 allocation
+ //was:
+// undoLog undoUnless {
+// isSameType1(tp1, tp2)
+// }
+
+ undoLog.lock()
+ try {
+ val before = undoLog.log
+ var result = false
+
+ try result = {
+ isSameType1(tp1, tp2)
+ } finally if (!result) undoLog.undoTo(before)
+ result
+ } finally undoLog.unlock()
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
@@ -5575,22 +5672,49 @@ trait Types extends api.Types { self: SymbolTable =>
def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = try {
subsametypeRecursions += 1
- undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars
- if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
- val p = new SubTypePair(tp1, tp2)
- if (pendingSubTypes(p))
- false
- else
- try {
- pendingSubTypes += p
- isSubType2(tp1, tp2, depth)
- } finally {
- pendingSubTypes -= p
- }
- } else {
- isSubType2(tp1, tp2, depth)
- }
- }
+ //OPT cutdown on Function0 allocation
+ //was:
+// undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars
+// if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+// val p = new SubTypePair(tp1, tp2)
+// if (pendingSubTypes(p))
+// false
+// else
+// try {
+// pendingSubTypes += p
+// isSubType2(tp1, tp2, depth)
+// } finally {
+// pendingSubTypes -= p
+// }
+// } else {
+// isSubType2(tp1, tp2, depth)
+// }
+// }
+
+ undoLog.lock()
+ try {
+ val before = undoLog.log
+ var result = false
+
+ try result = { // if subtype test fails, it should not affect constraints on typevars
+ if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+ val p = new SubTypePair(tp1, tp2)
+ if (pendingSubTypes(p))
+ false
+ else
+ try {
+ pendingSubTypes += p
+ isSubType2(tp1, tp2, depth)
+ } finally {
+ pendingSubTypes -= p
+ }
+ } else {
+ isSubType2(tp1, tp2, depth)
+ }
+ } finally if (!result) undoLog.undoTo(before)
+
+ result
+ } finally undoLog.unlock()
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
@@ -5897,9 +6021,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 +6277,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] =
@@ -6215,7 +6347,7 @@ trait Types extends api.Types { self: SymbolTable =>
private def lubList(ts: List[Type], depth: Int): List[Type] = {
// Matching the type params of one of the initial types means dummies.
val initialTypeParams = ts map (_.typeParams)
- def isHotForTs(xs: List[Type]) = initialTypeParams contains xs.map(_.typeSymbol)
+ def isHotForTs(xs: List[Type]) = initialTypeParams contains (xs map (_.typeSymbol))
def elimHigherOrderTypeParam(tp: Type) = tp match {
case TypeRef(pre, sym, args) if args.nonEmpty && isHotForTs(args) => tp.typeConstructor
@@ -6225,7 +6357,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 +6439,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 +6461,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 +6495,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 +6504,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)
}
@@ -6425,14 +6560,14 @@ trait Types extends api.Types { self: SymbolTable =>
case List() => NothingClass.tpe
case List(t) => t
case _ =>
- Statistics.incCounter(lubCount)
- val start = Statistics.pushTimer(typeOpsStack, lubNanos)
+ if (Statistics.canEnable) Statistics.incCounter(lubCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
try {
lub(ts, lubDepth(ts))
} finally {
lubResults.clear()
glbResults.clear()
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
@@ -6445,8 +6580,8 @@ trait Types extends api.Types { self: SymbolTable =>
val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
tparam.cloneSymbol.setInfo(glb(bounds, depth)))
PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1)))
- case ts @ MethodType(params, _) :: rest =>
- MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe))))
+ case ts @ (mt @ MethodType(params, _)) :: rest =>
+ MethodType(params, lub0(matchingRestypes(ts, mt.paramTypes)))
case ts @ NullaryMethodType(_) :: rest =>
NullaryMethodType(lub0(matchingRestypes(ts, Nil)))
case ts @ TypeBounds(_, _) :: rest =>
@@ -6548,13 +6683,13 @@ trait Types extends api.Types { self: SymbolTable =>
indent = indent + " "
assert(indent.length <= 100)
}
- Statistics.incCounter(nestedLubCount)
+ if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
val res = lub0(ts)
if (printLubs) {
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
@@ -6573,14 +6708,14 @@ trait Types extends api.Types { self: SymbolTable =>
case List() => AnyClass.tpe
case List(t) => t
case ts0 =>
- Statistics.incCounter(lubCount)
- val start = Statistics.pushTimer(typeOpsStack, lubNanos)
+ if (Statistics.canEnable) Statistics.incCounter(lubCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
try {
glbNorm(ts0, lubDepth(ts0))
} finally {
lubResults.clear()
glbResults.clear()
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
@@ -6600,8 +6735,8 @@ trait Types extends api.Types { self: SymbolTable =>
val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
tparam.cloneSymbol.setInfo(lub(bounds, depth)))
PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth))
- case ts @ MethodType(params, _) :: rest =>
- MethodType(params, glbNorm(matchingRestypes(ts, params map (_.tpe)), depth))
+ case ts @ (mt @ MethodType(params, _)) :: rest =>
+ MethodType(params, glbNorm(matchingRestypes(ts, mt.paramTypes), depth))
case ts @ NullaryMethodType(_) :: rest =>
NullaryMethodType(glbNorm(matchingRestypes(ts, Nil), depth))
case ts @ TypeBounds(_, _) :: rest =>
@@ -6695,12 +6830,12 @@ trait Types extends api.Types { self: SymbolTable =>
}
// if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG
- Statistics.incCounter(nestedLubCount)
+ if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
val res = glb0(ts)
// 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 +6877,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)
@@ -6864,7 +6999,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] =
tps map {
- case MethodType(params1, res) if (isSameTypes(params1 map (_.tpe), pts)) =>
+ case mt @ MethodType(params1, res) if isSameTypes(mt.paramTypes, pts) =>
res
case NullaryMethodType(res) if pts.isEmpty =>
res
@@ -6935,7 +7070,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 +7111,35 @@ trait Types extends api.Types { self: SymbolTable =>
tostringRecursions -= 1
}
+// ----- Hoisted closures and convenience methods, for compile time reductions -------
+
+ private[scala] val typeIsNotNull = (tp: Type) => tp.isNotNull
+ private[scala] val isTypeVar = (tp: Type) => tp.isInstanceOf[TypeVar]
+ private[scala] val typeContainsTypeVar = (tp: Type) => tp exists isTypeVar
+ private[scala] val typeIsNonClassType = (tp: Type) => tp.typeSymbolDirect.isNonClassType
+ private[scala] val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound
+ private[scala] val typeIsErroneous = (tp: Type) => tp.isErroneous
+ private[scala] val typeIsError = (tp: Type) => tp.isError
+ private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty
+ private[scala] val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp
+ private[scala] val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty
+ private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableClass.tpe
+ private[scala] val typeIsNothing = (tp: Type) => tp.typeSymbolDirect eq NothingClass
+ private[scala] val typeIsAny = (tp: Type) => tp.typeSymbolDirect eq AnyClass
+ private[scala] val typeIsHigherKinded = (tp: Type) => tp.isHigherKinded
+
+ @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 areTrivialTypes(tps: List[Type]): Boolean = tps match {
+ case tp :: rest => tp.isTrivial && areTrivialTypes(rest)
+ 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 +7158,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 {
@@ -7022,9 +7189,11 @@ object TypesStats {
val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount)
val typeOpsStack = Statistics.newTimerStack()
+ /** Commented out, because right now this does not inline, so creates a closure which will distort statistics
@inline final def timedTypeOp[T](c: Statistics.StackableTimer)(op: => T): T = {
val start = Statistics.pushTimer(typeOpsStack, c)
try op
- finally Statistics.popTimer(typeOpsStack, start)
+ finally
}
+ */
}
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 9234ccca7b..2e00316d5b 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -769,8 +769,21 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
}
/* Read a reference to a pickled item */
+ protected def readSymbolRef(): Symbol = {//OPT inlined from: at(readNat(), readSymbol) to save on closure creation
+ val i = readNat()
+ var r = entries(i)
+ if (r eq null) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ r = readSymbol()
+ assert(entries(i) eq null, entries(i))
+ entries(i) = r
+ readIndex = savedIndex
+ }
+ r.asInstanceOf[Symbol]
+ }
+
protected def readNameRef(): Name = at(readNat(), readName)
- protected def readSymbolRef(): Symbol = at(readNat(), readSymbol)
protected def readTypeRef(): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... ()
protected def readConstantRef(): Constant = at(readNat(), readConstant)
protected def readAnnotationRef(): AnnotationInfo = at(readNat(), readAnnotation)
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
index 368d55a59c..cc5b5bb406 100644
--- a/src/reflect/scala/reflect/internal/transform/Erasure.scala
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -141,7 +141,7 @@ trait Erasure {
if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
// this replaces each typeref that refers to an argument
// by the type `p.tpe` of the actual argument p (p in params)
- else apply(mt.resultType(params map (_.tpe))))
+ else apply(mt.resultType(mt.paramTypes)))
case RefinedType(parents, decls) =>
apply(mergeParents(parents))
case AnnotatedType(_, atp, _) =>
@@ -220,7 +220,7 @@ trait Erasure {
MethodType(
cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)),
if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
- else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
+ else specialErasureAvoiding(clazz, (mt.resultType(mt.paramTypes))))
case TypeRef(pre, `clazz`, args) =>
typeRef(pre, clazz, List())
case _ =>
diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala
index e503d812e6..f7b81ca252 100644
--- a/src/reflect/scala/reflect/internal/util/Statistics.scala
+++ b/src/reflect/scala/reflect/internal/util/Statistics.scala
@@ -237,6 +237,23 @@ quant)
private var _enabled = false
private val qs = new mutable.HashMap[String, Quantity]
+ /** replace with
+ *
+ * final val canEnable = false
+ *
+ * to remove all Statistics code from build
+ */
+ final val canEnable = _enabled
+
+ /** replace with
+ *
+ * final def hotEnabled = _enabled
+ *
+ * and rebuild, to also count tiny but super-hot methods
+ * such as phase, flags, owner, name.
+ */
+ final val hotEnabled = false
+
def enabled = _enabled
def enabled_=(cond: Boolean) = {
if (cond && !_enabled) {
@@ -253,9 +270,4 @@ quant)
_enabled = true
}
}
-
- /** replace rhs with enabled and rebuild to also count tiny but super-hot methods
- * such as phase, flags, owner, name.
- */
- final val hotEnabled = false
}
diff --git a/src/reflect/scala/reflect/internal/util/ThreeValues.scala b/src/reflect/scala/reflect/internal/util/ThreeValues.scala
new file mode 100644
index 0000000000..d89f11c407
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/ThreeValues.scala
@@ -0,0 +1,14 @@
+package scala.reflect.internal.util
+
+/** A simple three value type for booleans with an unknown value */
+object ThreeValues {
+
+ type ThreeValue = Byte
+
+ final val YES = 1
+ final val NO = -1
+ final val UNKNOWN = 0
+
+ @inline def fromBoolean(b: Boolean): ThreeValue = if (b) YES else NO
+ @inline def toBoolean(x: ThreeValue): Boolean = x == YES
+}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index e1eb7a57fe..de029ca658 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -14,15 +14,10 @@ trait SynchronizedTypes extends internal.Types { self: SymbolTable =>
override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { super.unique(tp) }
class SynchronizedUndoLog extends UndoLog {
+ private val actualLock = new java.util.concurrent.locks.ReentrantLock
- override def clear() =
- synchronized { super.clear() }
-
- override def undo[T](block: => T): T =
- synchronized { super.undo(block) }
-
- override def undoUnless(block: => Boolean): Boolean =
- synchronized { super.undoUnless(block) }
+ final override def lock(): Unit = actualLock.lock()
+ final override def unlock(): Unit = actualLock.unlock()
}
override protected def newUndoLog = new SynchronizedUndoLog
diff --git a/src/reflect/scala/tools/nsc/io/ZipArchive.scala b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
index 852dba9ec8..d1a91294a5 100644
--- a/src/reflect/scala/tools/nsc/io/ZipArchive.scala
+++ b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
@@ -96,14 +96,25 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq
}
}
- private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry = {
- dirs.getOrElseUpdate(path, {
- val parent = ensureDir(dirs, dirName(path), null)
- val dir = new DirEntry(path)
- parent.entries(baseName(path)) = dir
- dir
- })
- }
+ private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry =
+ //OPT inlined from getOrElseUpdate; saves ~50K closures on test run.
+ // was:
+ // dirs.getOrElseUpdate(path, {
+ // val parent = ensureDir(dirs, dirName(path), null)
+ // val dir = new DirEntry(path)
+ // parent.entries(baseName(path)) = dir
+ // dir
+ // })
+ dirs get path match {
+ case Some(v) => v
+ case None =>
+ val parent = ensureDir(dirs, dirName(path), null)
+ val dir = new DirEntry(path)
+ parent.entries(baseName(path)) = dir
+ dirs(path) = dir
+ dir
+ }
+
protected def getDir(dirs: mutable.Map[String, DirEntry], entry: ZipEntry): DirEntry = {
if (entry.isDirectory) ensureDir(dirs, entry.getName, entry)
else ensureDir(dirs, dirName(entry.getName), null)
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
+ }
+ }
+}