summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-06-24 15:37:16 +0000
committerMartin Odersky <odersky@gmail.com>2009-06-24 15:37:16 +0000
commit410efa8317f2a244f45f33b2ae7c17be5472f5d5 (patch)
tree0cddab6b90904718b8162797656ab7076bb920ce /src/compiler/scala/tools/nsc
parent1c9870541fb22ac032edaa0be0103cc1aa2c99b4 (diff)
downloadscala-410efa8317f2a244f45f33b2ae7c17be5472f5d5.tar.gz
scala-410efa8317f2a244f45f33b2ae7c17be5472f5d5.tar.bz2
scala-410efa8317f2a244f45f33b2ae7c17be5472f5d5.zip
fixed variance bug; added smart brace insertion...
fixed variance bug; added smart brace insertion to parser. moved interactive compiler interface along.
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala16
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/BracePair.scala12
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/BracePatch.scala11
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Parsers.scala64
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Scanners.scala218
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interactive/CompilerControl.scala8
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Global.scala81
-rw-r--r--src/compiler/scala/tools/nsc/reporters/Reporter.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala87
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala231
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala37
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala14
14 files changed, 568 insertions, 221 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 6db3bfd626..76507271c0 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -307,12 +307,15 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
final def applyPhase(unit: CompilationUnit) {
if (settings.debug.value) inform("[running phase " + name + " on " + unit + "]")
val unit0 = currentRun.currentUnit
- currentRun.currentUnit = unit
- reporter.setSource(unit.source)
- if (!cancelled(unit)) apply(unit)
- currentRun.advanceUnit
- assert(currentRun.currentUnit == unit)
- currentRun.currentUnit = unit0
+ try {
+ currentRun.currentUnit = unit
+ reporter.setSource(unit.source)
+ if (!cancelled(unit)) apply(unit)
+ currentRun.advanceUnit
+ } finally {
+ assert(currentRun.currentUnit == unit)
+ currentRun.currentUnit = unit0
+ }
}
}
@@ -397,6 +400,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val runsRightAfter = Some("tailcalls")
} with SpecializeTypes
+ // phaseName = "erasure"
object erasure extends {
val global: Global.this.type = Global.this
val runsAfter = List[String]("explicitouter")
diff --git a/src/compiler/scala/tools/nsc/ast/parser/BracePair.scala b/src/compiler/scala/tools/nsc/ast/parser/BracePair.scala
new file mode 100644
index 0000000000..44cf5e7f2c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/BracePair.scala
@@ -0,0 +1,12 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2009 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.tools.nsc.ast.parser
+
+/** A descriptor for a matching pair of braces.
+ * @param loff The offset of the opening brace (-1 means missing)
+ * @param roff The offset of the closing brace (-1 means missing)
+ * @param nested The brace pairs nested in this one
+ */
+case class BracePair(loff: Int, off: Int, nested: List[BracePair])
diff --git a/src/compiler/scala/tools/nsc/ast/parser/BracePatch.scala b/src/compiler/scala/tools/nsc/ast/parser/BracePatch.scala
new file mode 100644
index 0000000000..00d2e1a2ba
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/BracePatch.scala
@@ -0,0 +1,11 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2009 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.tools.nsc.ast.parser
+
+/** A patch that postulates that a brace needs to be inserted or deleted at a given position.
+ * @param off The offset where the brace needs to be inserted or deleted
+ * @param inserted If true, brace needs to be inserted, otherwise brace needs to be deleted.
+ */
+case class BracePatch(off: Int, inserted: Boolean)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index fc85f7a196..6246782e9f 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -59,8 +59,11 @@ self =>
case class OpInfo(operand: Tree, operator: Name, offset: Offset)
- class UnitParser(val unit: global.CompilationUnit) extends Parser {
- val in = new UnitScanner(unit)
+ class UnitParser(val unit: global.CompilationUnit, patches: List[BracePatch]) extends Parser {
+
+ def this(unit: global.CompilationUnit) = this(unit, List())
+
+ val in = new UnitScanner(unit, patches)
in.init()
def freshName(pos: Position, prefix: String): Name =
@@ -71,15 +74,45 @@ self =>
def warning(offset: Int, msg: String) { unit.warning(o2p(offset), msg) }
+ def deprecationWarning(offset: Int, msg: String) {
+ unit.deprecationWarning(o2p(offset), msg)
+ }
+
+ var smartParsing = false
+
+ val syntaxErrors = new ListBuffer[(Int, String)]
+
def incompleteInputError(msg: String) {
- unit.incompleteInputError(o2p(unit.source.asInstanceOf[BatchSourceFile].content.length - 1), msg)
+ val offset = unit.source.asInstanceOf[BatchSourceFile].content.length - 1
+ if (smartParsing) syntaxErrors += ((offset, msg))
+ else unit.incompleteInputError(o2p(offset), msg)
}
- def deprecationWarning(offset: Int, msg: String) {
- unit.deprecationWarning(o2p(offset), msg)
+ def syntaxError(offset: Int, msg: String) {
+ if (smartParsing) syntaxErrors += ((offset, msg))
+ else unit.error(o2p(offset), msg)
}
- def syntaxError(offset: Int, msg: String) { unit.error(o2p(offset), msg) }
+ /** parse unit. If there are inbalanced braces,
+ * try to correct them and reparse.
+ */
+ def smartParse(): Tree = try {
+ smartParsing = true
+ val firstTry = parse()
+ if (syntaxErrors.isEmpty) firstTry
+ else {
+ val patches = in.healBraces()
+ if (patches.isEmpty) {
+ for ((offset, msg) <- syntaxErrors) unit.error(o2p(offset), msg)
+ firstTry
+ } else {
+ println(patches)
+ new UnitParser(unit, patches).parse()
+ }
+ }
+ } finally {
+ smartParsing = false
+ }
/** the markup parser */
lazy val xmlp = new MarkupParser(this, true)
@@ -200,7 +233,9 @@ self =>
/* ------------- ERROR HANDLING ------------------------------------------- */
- protected def skip() {
+ var assumedClosingParens = collection.mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0)
+
+ protected def skip(targetToken: Int) {
var nparens = 0
var nbraces = 0
while (true) {
@@ -224,6 +259,7 @@ self =>
nbraces += 1
case _ =>
}
+ if (targetToken == in.token && nparens == 0 && nbraces == 0) return
in.nextToken()
}
}
@@ -248,7 +284,7 @@ self =>
lastErrorOffset = in.offset
}
if (skipIt)
- skip()
+ skip(UNDEF)
}
def warning(msg: String) { warning(in.offset, msg) }
@@ -268,13 +304,21 @@ self =>
if (in.token != token) {
val msg =
token2string(token) + " expected but " +token2string(in.token) + " found."
-
+ syntaxErrorOrIncomplete(msg, true)
if (in.token == EOF) incompleteInputError(msg)
- else syntaxError(in.offset, msg, true)
+ else syntaxError(in.offset, msg, false)
+ if ((token == RPAREN || token == RBRACE || token == RBRACKET))
+ if (in.parenBalance(token) + assumedClosingParens(token) < 0)
+ assumedClosingParens(token) += 1
+ else
+ skip(token)
+ else
+ skip(UNDEF)
}
if (in.token == token) in.nextToken()
offset
}
+
def surround[T](open: Int, close: Int)(f: => T, orElse: T): T = {
val wasOpened = in.token == open
accept(open)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index b15ec75cd7..6c40c1f0a6 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -10,6 +10,7 @@ import scala.tools.nsc.util._
import SourceFile.{LF, FF, CR, SU}
import Tokens._
import scala.annotation.switch
+import scala.collection.mutable.{ListBuffer, ArrayBuffer}
trait Scanners {
val global : Global
@@ -174,7 +175,7 @@ trait Scanners {
* - the current token can start a statement and the one before can end it
* insert NEWLINES if we are past a blank line, NEWLINE otherwise
*/
- if (afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) &&
+ if (!applyBracePatch() && afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) &&
(sepRegions.isEmpty || sepRegions.head == RBRACE)) {
next copyFrom this
offset = if (lineStartOffset <= offset) lineStartOffset else lastLineStartOffset
@@ -237,9 +238,10 @@ trait Scanners {
/** read next token, filling TokenData fields of Scanner.
*/
- private final def fetchToken() {
+ protected final def fetchToken() {
offset = charOffset - 1
(ch: @switch) match {
+
case ' ' | '\t' | CR | LF | FF =>
nextChar()
fetchToken()
@@ -801,6 +803,20 @@ trait Scanners {
token2string(token)
}
+ // ------------- brace counting and healing ------------------------------
+
+ /** overridden in UnitScanners:
+ * apply brace patch if one exists for this offset
+ * return true if subsequent end of line handling should be suppressed.
+ */
+ def applyBracePatch(): Boolean = false
+
+ /** overridden in UnitScanners */
+ def parenBalance(token: Int) = 0
+
+ /** overridden in UnitScanners */
+ def healBraces(): List[BracePatch] = List()
+
/** Initialization method: read first char, then first token
*/
def init() {
@@ -958,12 +974,208 @@ trait Scanners {
/** A scanner over a given compilation unit
*/
- class UnitScanner(unit: CompilationUnit) extends Scanner {
+ class UnitScanner(unit: CompilationUnit, patches: List[BracePatch]) extends Scanner {
+ def this(unit: CompilationUnit) = this(unit, List())
val buf = unit.source.asInstanceOf[BatchSourceFile].content
val decodeUnit = !settings.nouescape.value
+
def warning(off: Offset, msg: String) = unit.warning(unit.position(off), msg)
def error (off: Offset, msg: String) = unit.error(unit.position(off), msg)
def incompleteInputError(off: Offset, msg: String) = unit.incompleteInputError(unit.position(off), msg)
def deprecationWarning(off: Offset, msg: String) = unit.deprecationWarning(unit.position(off), msg)
+
+ private var bracePatches: List[BracePatch] = patches
+
+ lazy val parensAnalyzer = new ParensAnalyzer(unit, List())
+
+ override def parenBalance(token: Int) = parensAnalyzer.balance(token)
+
+ override def healBraces(): List[BracePatch] = {
+ var patches: List[BracePatch] = List()
+ if (!parensAnalyzer.tabSeen) {
+ var bal = parensAnalyzer.balance(RBRACE)
+ while (bal < 0) {
+ patches = new ParensAnalyzer(unit, patches).insertRBrace()
+ bal += 1
+ }
+ while (bal > 0) {
+ patches = new ParensAnalyzer(unit, patches).deleteRBrace()
+ bal -= 1
+ }
+ }
+ patches
+ }
+
+ /** Insert or delete a brace, if a patch exists for this offset */
+ override def applyBracePatch(): Boolean = {
+ if (bracePatches.isEmpty || bracePatches.head.off != offset) false
+ else {
+ val patch = bracePatches.head
+ bracePatches = bracePatches.tail
+// println("applying brace patch "+offset)//DEBUG
+ if (patch.inserted) {
+ next copyFrom this
+ error(offset, "Missing closing brace `}' assumed here")
+ token = RBRACE
+ true
+ } else {
+ error(offset, "Unmatched closing brace '}' ignored here")
+ fetchToken()
+ false
+ }
+ }
+ }
+ }
+
+ class ParensAnalyzer(unit: CompilationUnit, patches: List[BracePatch]) extends UnitScanner(unit, patches) {
+ var balance = collection.mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0)
+
+ init()
+
+ /** The offset of the first token on this line, or next following line if blank
+ */
+ val lineStart = new ArrayBuffer[Int]
+
+ /** The list of matching top-level brace pairs (each of which may contain nested brace pairs).
+ */
+ val bracePairs: List[BracePair] = {
+
+ var lineCount = 1
+ var lastOffset = 0
+
+ def scan(bpbuf: ListBuffer[BracePair]): Int = {
+ if (token != NEWLINE && token != NEWLINES) {
+ while (lastOffset < offset) {
+ if (buf(lastOffset) == LF) lineCount += 1
+ lastOffset += 1
+ }
+ while (lineCount > lineStart.length)
+ lineStart += offset
+ }
+ token match {
+ case LPAREN =>
+ balance(RPAREN) -= 1; nextToken(); scan(bpbuf)
+ case LBRACKET =>
+ balance(RBRACKET) -= 1; nextToken(); scan(bpbuf)
+ case RPAREN =>
+ balance(RPAREN) += 1; nextToken(); scan(bpbuf)
+ case RBRACKET =>
+ balance(RBRACKET) += 1; nextToken(); scan(bpbuf)
+ case LBRACE =>
+ balance(RBRACE) -= 1
+ val lc = lineCount
+ val loff = offset
+ val bpbuf1 = new ListBuffer[BracePair]
+ nextToken()
+ val roff = scan(bpbuf1)
+ if (lc != lineCount)
+ bpbuf += BracePair(loff, roff, bpbuf1.toList)
+ scan(bpbuf)
+ case RBRACE =>
+ balance(RBRACE) += 1
+ val off = offset; nextToken(); off
+ case EOF =>
+ -1
+ case _ =>
+ nextToken(); scan(bpbuf)
+ }
+ }
+
+ val bpbuf = new ListBuffer[BracePair]
+ while (token != EOF) {
+ val roff = scan(bpbuf)
+ if (roff != -1) {
+ val current = BracePair(-1, roff, bpbuf.toList)
+ bpbuf.clear()
+ bpbuf += current
+ }
+ }
+// println("lineStart = "+lineStart)//DEBUG
+// println("bracepairs = "+bpbuf.toList)//DEBUG
+ bpbuf.toList
+ }
+
+ var tabSeen = false
+
+ def line(offset: Int): Int = {
+ def findLine(lo: Int, hi: Int): Int = {
+ val mid = (lo + hi) / 2
+ if (offset < lineStart(mid)) findLine(lo, mid - 1)
+ else if (mid + 1 < lineStart.length && offset >= lineStart(mid + 1)) findLine(mid + 1, hi)
+ else mid
+ }
+ findLine(0, lineStart.length - 1)
+ }
+
+ def column(offset: Int): Int = {
+ var col = 0
+ var i = offset - 1
+ while (i >= 0 && buf(i) != CR && buf(i) != LF) {
+ if (buf(i) == '\t') tabSeen = true
+ col += 1
+ i -= 1
+ }
+ col
+ }
+
+ def insertPatch(patches: List[BracePatch], patch: BracePatch): List[BracePatch] = patches match {
+ case List() => List(patch)
+ case bp :: bps => if (patch.off < bp.off) patch :: patches
+ else bp :: insertPatch(bps, patch)
+ }
+
+ def leftColumn(offset: Int) =
+ if (offset == -1) -1 else column(lineStart(line(offset)))
+
+ def rightColumn(offset: Int, default: Int) =
+ if (offset == -1) -1
+ else {
+ val rlin = line(offset)
+ if (lineStart(rlin) == offset) column(offset)
+ else if (rlin + 1 < lineStart.length) column(lineStart(rlin + 1))
+ else default
+ }
+
+ def insertRBrace(): List[BracePatch] = {
+ def insert(bps: List[BracePair]): List[BracePatch] = bps match {
+ case List() => patches
+ case (bp @ BracePair(loff, roff, nested)) :: bps1 =>
+ val lcol = leftColumn(loff)
+ val rcol = rightColumn(roff, lcol)
+ if (lcol <= rcol) insert(bps1)
+ else {
+// println("patch inside "+bp+"/"+line(loff)+"/"+lineStart(line(loff))+"/"+lcol+"/"+rcol)//DEBUG
+ val patches1 = insert(nested)
+ if (patches1 ne patches) patches1
+ else {
+// println("patch for "+bp)//DEBUG
+ var lin = line(loff) + 1
+ while (lin < lineStart.length && column(lineStart(lin)) > lcol)
+ lin += 1
+ if (lin < lineStart.length)
+ insertPatch(patches, BracePatch(lineStart(lin), true))
+ else patches
+ }
+ }
+ }
+ insert(bracePairs)
+ }
+
+ def deleteRBrace(): List[BracePatch] = {
+ def delete(bps: List[BracePair]): List[BracePatch] = bps match {
+ case List() => patches
+ case BracePair(loff, roff, nested) :: bps1 =>
+ val lcol = leftColumn(loff)
+ val rcol = rightColumn(roff, lcol)
+ if (lcol >= rcol) delete(bps1)
+ else {
+ val patches1 = delete(nested)
+ if (patches1 ne patches) patches1
+ else insertPatch(patches, BracePatch(roff, false))
+ }
+ }
+ delete(bracePairs)
+ }
+ override def error(offset: Int, msg: String) {}
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
index 0c3350aedc..0e29853ade 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
@@ -22,6 +22,7 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse
global.informProgress("parsing " + unit)
unit.body =
if (unit.source.file.name.endsWith(".java")) new JavaUnitParser(unit).parse()
+ else if (!global.reporter.incompleteHandled) new UnitParser(unit).smartParse()
else new UnitParser(unit).parse()
}
}
diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
index d7b5c3eedb..c1e6747f8c 100644
--- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
+++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala
@@ -16,15 +16,9 @@ trait CompilerControl { self: Global =>
abstract class WorkItem extends (() => Unit)
- /** The status of a member that's returned by completion.
- */
- object MemberStatus extends Enumeration {
- val Accessible, Inherited, Implicit = Value
- }
-
/** Info given for every member found by completion
*/
- type Member = (Symbol, Type, MemberStatus.ValueSet)
+ case class Member(val sym: Symbol, val tpe: Type, val accessible: Boolean, val inherited: Boolean, val viaView: Symbol)
/** The scheduler by which client and compiler communicate
* Must be initialized before starting compilerRunner
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 43c5fecaf6..165c9b6896 100755
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -17,6 +17,8 @@ class Global(settings: Settings, reporter: Reporter)
with RichCompilationUnits {
self =>
+ import definitions._
+
override def onlyPresentation = true
/** A list indicating in which order some units should be typechecked.
@@ -45,16 +47,12 @@ self =>
/** The status value of a unit that has not yet been typechecked */
final val JustParsed = 0
- private var resultTree = EmptyTree
-
// ----------- Overriding hooks in nsc.Global -----------------------
/** Create a RangePosition */
override def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
new RangePosition(source, start, point, end)
-
-
/** Called from typechecker, which signal hereby that a node has been completely typechecked.
* If the node is included in unit.targetPos, abandons run and returns newly attributed tree.
* Otherwise, if there's some higher priority work to be done, also abandons run with a FreshRunReq.
@@ -66,15 +64,25 @@ self =>
def integrateNew() {
context.unit.body = new TreeReplacer(old, result) transform context.unit.body
}
- if ((context.unit != null) && !result.pos.isSynthetic && (result.pos includes context.unit.targetPos)) {
- integrateNew()
- throw new TyperResult(result)
- }
- val typerRun = currentTyperRun
- pollForWork()
- if (typerRun != currentTyperRun) {
- integrateNew()
- throw new FreshRunReq
+ if (activeLocks == 0) {
+ if (context.unit != null &&
+ !result.pos.isSynthetic &&
+ !isTransparent(result.pos) &&
+ (result.pos includes context.unit.targetPos)) {
+ integrateNew()
+ var located = new Locator(context.unit.targetPos) locateIn result
+ if (located == EmptyTree) {
+ println("something's wrong: no "+context.unit+" in "+result+result.pos)
+ located = result
+ }
+ throw new TyperResult(located)
+ }
+ val typerRun = currentTyperRun
+ pollForWork()
+ if (typerRun != currentTyperRun) {
+ integrateNew()
+ throw new FreshRunReq
+ }
}
}
@@ -193,6 +201,7 @@ self =>
}
for (unit <- units) {
inform("type checking: "+unit)
+ activeLocks = 0
currentTyperRun.typeCheck(unit)
unit.status = currentRunId
}
@@ -249,22 +258,36 @@ self =>
case _ => tree.tpe
}
+ import analyzer.{SearchResult, ImplicitSearch}
+
def completion(pos: Position, result: Response[List[Member]]) {
- import MemberStatus._
respond(result) {
val tree = typedTreeAt(pos)
locateContext(pos) match {
case Some(context) =>
val superAccess = tree.isInstanceOf[Super]
val pre = stabilizedType(tree)
- def withStatus(sym: Symbol, vs: ValueSet) = (
+ def member(sym: Symbol, inherited: Boolean) = new Member(
sym,
- pre.memberType(sym),
- if (context.isAccessible(sym, pre, superAccess)) vs + Accessible else vs
+ pre memberType sym,
+ context.isAccessible(sym, pre, superAccess),
+ inherited,
+ NoSymbol
)
- val decls = tree.tpe.decls.toList map (withStatus(_, ValueSet()))
- val inherited = tree.tpe.members.toList diff decls map (withStatus(_, ValueSet(Inherited)))
- val implicits = List() // not yet done
+ def implicitMembers(s: SearchResult): List[Member] = {
+ val vtree = viewApply(s, tree, context)
+ val vpre = stabilizedType(vtree)
+ vtree.tpe.members map { sym => new Member(
+ sym,
+ vpre memberType sym,
+ context.isAccessible(sym, vpre, false),
+ false,
+ s.tree.symbol
+ )}
+ }
+ val decls = tree.tpe.decls.toList map (member(_, false))
+ val inherited = tree.tpe.members.toList diff decls map (member(_, true))
+ val implicits = applicableViews(tree, context) flatMap implicitMembers
decls ::: inherited ::: implicits
case None =>
throw new FatalError("no context found for "+pos)
@@ -272,6 +295,19 @@ self =>
}
}
+ def applicableViews(tree: Tree, context: Context): List[SearchResult] =
+ new ImplicitSearch(tree, functionType(List(tree.tpe), AnyClass.tpe), true, context.makeImplicit(false))
+ .allImplicits
+
+ def viewApply(view: SearchResult, tree: Tree, context: Context): Tree = {
+ assert(view.tree != EmptyTree)
+ try {
+ analyzer.newTyper(context.makeImplicit(false)).typed(Apply(view.tree, List(tree)) setPos tree.pos)
+ } catch {
+ case ex: TypeError => EmptyTree
+ }
+ }
+
// ---------------- Helper classes ---------------------------
/** A transformer that replaces tree `from` with tree `to` in a given tree */
@@ -317,7 +353,7 @@ self =>
def typedTreeAt(pos: Position): Tree = {
println("starting typedTreeAt")
val tree = locateTree(pos)
- println("at pos "+pos+" was found: "+tree)
+ println("at pos "+pos+" was found: "+tree+tree.pos.show)
if (tree.tpe ne null) {
println("already attributed")
tree
@@ -331,8 +367,9 @@ self =>
throw new FatalError("tree not found")
} catch {
case ex: TyperResult =>
- println("result found")
ex.tree
+ } finally {
+ unit.targetPos = NoPosition
}
}
}
diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
index c12e32a026..e8fe26f1a0 100644
--- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
@@ -53,14 +53,18 @@ abstract class Reporter {
* Should be re-factored into a subclass.
*/
var incompleteInputError: (Position, String) => Unit = error
+ var incompleteHandled: Boolean = false
def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = {
val savedHandler = incompleteInputError
+ val savedHandled = incompleteHandled
try {
incompleteInputError = handler
+ incompleteHandled = true
thunk
} finally {
incompleteInputError = savedHandler
+ incompleteHandled = savedHandled
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 32c02ecbcc..af6f45e095 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -29,6 +29,8 @@ trait Symbols {
val emptySymbolArray = new Array[Symbol](0)
val emptySymbolSet = Set.empty[Symbol]
+ /** Used for deciding in the IDE whether we can interrupt the compiler */
+ protected var activeLocks = 0
/** Used to keep track of the recursion depth on locked symbols */
private var recursionTable = Map.empty[Symbol, Int]
@@ -299,49 +301,47 @@ trait Symbols {
// Locking and unlocking ------------------------------------------------------
- // True if the symbol is unlocked.
- // True if the symbol is locked but still below the allowed recursion depth.
- // False otherwise
- def lockOK: Boolean = {
- ((rawflags & LOCKED) == 0) ||
- ((settings.Yrecursion.value != 0) &&
- (recursionTable get this match {
- case Some(n) => (n <= settings.Yrecursion.value)
- case None => true }))
- }
-
- protected var activeLocks = 0
-
- // Lock a symbol, using the handler if the recursion depth becomes too great.
- def lock(handler: => Unit) = {
- if ((rawflags & LOCKED) != 0) {
- if (settings.Yrecursion.value != 0) {
- recursionTable get this match {
- case Some(n) =>
- if (n > settings.Yrecursion.value) {
- handler
- } else {
- recursionTable += (this -> (n + 1))
- }
- case None =>
- recursionTable += (this -> 1)
- }
- } else { handler }
- } else {
- rawflags |= LOCKED
- activeLocks += 1
+ // True if the symbol is unlocked.
+ // True if the symbol is locked but still below the allowed recursion depth.
+ // False otherwise
+ def lockOK: Boolean = {
+ ((rawflags & LOCKED) == 0) ||
+ ((settings.Yrecursion.value != 0) &&
+ (recursionTable get this match {
+ case Some(n) => (n <= settings.Yrecursion.value)
+ case None => true }))
+ }
+
+ // Lock a symbol, using the handler if the recursion depth becomes too great.
+ def lock(handler: => Unit) = {
+ if ((rawflags & LOCKED) != 0) {
+ if (settings.Yrecursion.value != 0) {
+ recursionTable get this match {
+ case Some(n) =>
+ if (n > settings.Yrecursion.value) {
+ handler
+ } else {
+ recursionTable += (this -> (n + 1))
+ }
+ case None =>
+ recursionTable += (this -> 1)
+ }
+ } else { handler }
+ } else {
+ rawflags |= LOCKED
+ activeLocks += 1
+ }
}
- }
- // Unlock a symbol
- def unlock() = {
- if ((rawflags & LOCKED) != 0) {
- activeLocks -= 1
- rawflags = rawflags & ~LOCKED
- if (settings.Yrecursion.value != 0)
- recursionTable -= this
+ // Unlock a symbol
+ def unlock() = {
+ if ((rawflags & LOCKED) != 0) {
+ activeLocks -= 1
+ rawflags = rawflags & ~LOCKED
+ if (settings.Yrecursion.value != 0)
+ recursionTable -= this
+ }
}
- }
// Tests ----------------------------------------------------------------------
@@ -1423,12 +1423,9 @@ trait Symbols {
* Never adds id.
*/
final def fullNameString(separator: Char): String = {
- if (this == NoSymbol) return "<NoSymbol>"
- assert(owner != NoSymbol, this)
var str =
- if (owner.isRoot ||
- owner.isEmptyPackageClass ||
- owner.isInterpreterWrapper) simpleName.toString
+ if (isRoot || isRootPackage || this == NoSymbol) this.toString
+ else if (owner.isRoot || owner.isEmptyPackageClass || owner.isInterpreterWrapper) simpleName.toString
else owner.enclClass.fullNameString(separator) + separator + simpleName
if (str.charAt(str.length - 1) == ' ') str = str.substring(0, str.length - 1)
str
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index c78eb333af..1c3f9692e2 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -2332,7 +2332,10 @@ A type's typeSymbol should never be inspected directly.
uniqueRunId = currentRunId
}
uniques.findEntry(tp) match {
- case null => uniques.addEntry(tp); tp
+ case null =>
+ //println("new unique type: "+tp)
+ uniques.addEntry(tp);
+ tp
case tp1 => tp1.asInstanceOf[T]
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 7d0268c6af..27c94c0883 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -44,21 +44,20 @@ self: Analyzer =>
* @param tree The tree for which the implicit needs to be inserted.
* (the inference might instantiate some of the undetermined
* type parameters of that tree.
- * @param pt0 The original expected type of the implicit. A method type
- * for `pt0` implies we are looking for a view, any other type implies
- * we are looking for an implicit parameter.
+ * @param pt The expected type of the implicit.
* @param reportAmbiguous Should ambiguous implicit errors be reported?
* False iff we search for a view to find out
* whether one type is coercible to another.
+ * @param isView We are looking for a view
* @param context The current context
* @return A search result
*/
- def inferImplicit(tree: Tree, pt0: Type, reportAmbiguous: Boolean, context: Context): SearchResult = {
+ def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult = {
if (traceImplicits && !tree.isEmpty && !context.undetparams.isEmpty)
println("typing implicit with undetermined type params: "+context.undetparams+"\n"+tree)
- val search = new ImplicitSearch(tree, pt0, context.makeImplicit(reportAmbiguous))
- context.undetparams = context.undetparams remove (search.result.subst.from contains _)
- search.result
+ val result = new ImplicitSearch(tree, pt, isView, context.makeImplicit(reportAmbiguous)).bestImplicit
+ context.undetparams = context.undetparams remove (result.subst.from contains _)
+ result
}
final val sizeLimit = 100
@@ -123,12 +122,11 @@ self: Analyzer =>
/** A class that sets up an implicit search. For more info, see comments for `inferImplicit`.
* @param tree The tree for which the implicit needs to be inserted.
- * @param pt0 The original expected type of the implicit. A method type
- * for `pt0` implies we are looking for a view, any other type implies
- * we are looking for an implicit parameter.
+ * @param pt The original expected type of the implicit.
+ * @param isView We are looking for a view
* @param context0 The context used for the implicit search
*/
- private class ImplicitSearch(tree: Tree, pt0: Type, context0: Context)
+ class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context)
extends Typer(context0) {
import infer._
@@ -211,17 +209,6 @@ self: Analyzer =>
overlaps(dtor1, dted1) && (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1))
}
- /** The normalized expected type (which is a value type). */
- private val pt = normalize(pt0)
-
- /** Are we looking for an implicit view? This is signalled by the original expected type
- * being a method or a polymorphic type.
- */
- private val isView = pt0 match {
- case MethodType(_, _) | PolyType(_, _) => true
- case _ => false
- }
-
if (util.Statistics.enabled) implcnt += 1
private val startTime = if (util.Statistics.enabled) currentTime else 0l
@@ -313,15 +300,15 @@ self: Analyzer =>
//if (traceImplicits) println("typed impl?? "+info.name+":"+info.tpe+" ==> "+itree+" with "+wildPt)
def fail(reason: String): SearchResult = {
if (settings.XlogImplicits.value)
- inform(itree+" is not a valid implicit value for "+pt0+" because:\n"+reason)
+ inform(itree+" is not a valid implicit value for "+pt+" because:\n"+reason)
SearchFailure
}
try {
val itree1 =
if (isView)
typed1(
- Apply(itree, List(Ident("<argument>").setType(approximate(pt0.paramTypes.head)))),
- EXPRmode, approximate(pt0.resultType))
+ Apply(itree, List(Ident("<argument>").setType(approximate(pt.typeArgs.head)))),
+ EXPRmode, approximate(pt.typeArgs.tail.head))
else
typed1(itree, EXPRmode, wildPt)
@@ -368,61 +355,56 @@ self: Analyzer =>
}
}
- /** Search list of implicit info lists for one matching prototype
- * <code>pt</code>. If found return a search result with a tree from found implicit info
- * which is typed with expected type <code>pt</code>.
- * Otherwise return SearchFailure.
- *
- * @param implicitInfoss The given list of lists of implicit infos
+ /** Should implicit definition symbol `sym' be considered for applicability testing?
+ * This is the case if one of the following holds:
+ * - the symbol's type is initialized
+ * - the symbol comes from a classfile
+ * - the symbol comes from a different sourcefile than the current one
+ * - the symbol's definition comes before, and does not contain the closest enclosing definition,
+ * - the symbol's definition is a val, var, or def with an explicit result type
+ * The aim of this method is to prevent premature cyclic reference errors
+ * by computing the types of only those implicitis for which one of these
+ * conditions is true.
+ */
+ def isValid(sym: Symbol) = {
+ def hasExplicitResultType(sym: Symbol) = {
+ def hasExplicitRT(tree: Tree) = tree match {
+ case ValDef(_, _, tpt, _) => !tpt.isEmpty
+ case DefDef(_, _, _, _, tpt, _) => !tpt.isEmpty
+ case _ => false
+ }
+ sym.rawInfo match {
+ case tc: TypeCompleter => hasExplicitRT(tc.tree)
+ case PolyType(_, tc: TypeCompleter) => hasExplicitRT(tc.tree)
+ case _ => true
+ }
+ }
+ def comesBefore(sym: Symbol, owner: Symbol) =
+ sym.pos.offset.getOrElse(0) < owner.pos.offset.getOrElse(Integer.MAX_VALUE) &&
+ !(owner.ownerChain contains sym)
+
+ sym.isInitialized ||
+ sym.sourceFile == null ||
+ (sym.sourceFile ne context.unit.source.file) ||
+ hasExplicitResultType(sym) ||
+ comesBefore(sym, context.owner)
+ }
+
+ /** Computes from a list of lists of implicit infos a map which takes
+ * infos which are applicable for given expected type `pt` to their attributed trees.
+ * Computes invalid implicits as a side effect (used for better error message).
+ * @param iss The given list of lists of implicit infos
* @param isLocal Is implicit definition visible without prefix?
* If this is the case then symbols in preceding lists shadow
* symbols of the same name in succeeding lists.
*/
- def searchImplicit(implicitInfoss: List[List[ImplicitInfo]], isLocal: Boolean): SearchResult = {
+ def applicableInfos(iss: List[List[ImplicitInfo]],
+ isLocal: Boolean,
+ invalidImplicits: ListBuffer[Symbol]): Map[ImplicitInfo, SearchResult] = {
/** A set containing names that are shadowed by implicit infos */
val shadowed = new HashSet[Name](8)
- /** Should implicit definition symbol `sym' be considered for applicability testing?
- * This is the case if one of the following holds:
- * - the symbol's type is initialized
- * - the symbol comes from a classfile
- * - the symbol comes from a different sourcefile than the current one
- * - the symbol's definition comes before, and does not contain the closest enclosing definition,
- * - the symbol's definition is a val, var, or def with an explicit result type
- * The aim of this method is to prevent premature cyclic reference errors
- * by computing the types of only those implicitis for which one of these
- * conditions is true.
- */
- def isValid(sym: Symbol) = {
- def hasExplicitResultType(sym: Symbol) = {
- def hasExplicitRT(tree: Tree) = tree match {
- case ValDef(_, _, tpt, _) => !tpt.isEmpty
- case DefDef(_, _, _, _, tpt, _) => !tpt.isEmpty
- case _ => false
- }
- sym.rawInfo match {
- case tc: TypeCompleter => hasExplicitRT(tc.tree)
- case PolyType(_, tc: TypeCompleter) => hasExplicitRT(tc.tree)
- case _ => true
- }
- }
- def comesBefore(sym: Symbol, owner: Symbol) =
- sym.pos.offset.getOrElse(0) < owner.pos.offset.getOrElse(Integer.MAX_VALUE) &&
- !(owner.ownerChain contains sym)
-
- sym.isInitialized ||
- sym.sourceFile == null ||
- (sym.sourceFile ne context.unit.source.file) ||
- hasExplicitResultType(sym) ||
- comesBefore(sym, context.owner)
- }
-
- /** The implicits that are not valid because they come later in the source
- * and lack an explicit result type. Used for error diagnostics only.
- */
- val invalidImplicits = new ListBuffer[Symbol]
-
/** Try implicit `info` to see whether it is applicable for expected type `pt`.
* This is the case if all of the following holds:
* - the info's type is not erroneous,
@@ -438,11 +420,7 @@ self: Analyzer =>
(!isView || info.sym != Predef_identity)) typedImplicit(info)
else SearchFailure
- /** Computes from a list of implicit infos a map which takes
- * infos which are applicable for given expected type `pt` to their attributed trees.
- * Computes invalid implicits as a side effect (used for better error message).
- */
- def applicableInfos(is: List[ImplicitInfo]): Map[ImplicitInfo, SearchResult] = {
+ def appInfos(is: List[ImplicitInfo]): Map[ImplicitInfo, SearchResult] = {
var applicable = Map[ImplicitInfo, SearchResult]()
for (i <- is)
if (!isValid(i.sym)) invalidImplicits += i.sym
@@ -455,9 +433,28 @@ self: Analyzer =>
applicable
}
+ (Map[ImplicitInfo, SearchResult]() /: (iss map appInfos))(_ ++ _)
+ }
+
+ /** Search list of implicit info lists for one matching prototype
+ * <code>pt</code>. If found return a search result with a tree from found implicit info
+ * which is typed with expected type <code>pt</code>.
+ * Otherwise return SearchFailure.
+ *
+ * @param implicitInfoss The given list of lists of implicit infos
+ * @param isLocal Is implicit definition visible without prefix?
+ * If this is the case then symbols in preceding lists shadow
+ * symbols of the same name in succeeding lists.
+ */
+ def searchImplicit(implicitInfoss: List[List[ImplicitInfo]], isLocal: Boolean): SearchResult = {
+
+ /** The implicits that are not valid because they come later in the source
+ * and lack an explicit result type. Used for error diagnostics only.
+ */
+ val invalidImplicits = new ListBuffer[Symbol]
+
/** A map which takes applicable infos to their attributed trees. */
- val applicable: Map[ImplicitInfo, SearchResult] =
- (Map[ImplicitInfo, SearchResult]() /: (implicitInfoss map applicableInfos))(_ ++ _)
+ val applicable = applicableInfos(implicitInfoss, isLocal, invalidImplicits)
if (applicable.isEmpty && !invalidImplicits.isEmpty) {
infer.setAddendum(tree.pos, () =>
@@ -477,6 +474,7 @@ self: Analyzer =>
// Also check that applicable infos that did not get selected are not
// in (a companion object of) a subclass of (a companion object of) the class
// containing the winning info.
+ // (no longer needed; rules have changed)
/*
for (alt <- applicable.keySet) {
if (isProperSubClassOrObject(alt.sym.owner, best.sym.owner)) {
@@ -609,7 +607,7 @@ self: Analyzer =>
/** Re-wraps a type in a manifest before calling inferImplicit on the result */
def findManifest(tp: Type): Tree =
- inferImplicit(tree, appliedType(ManifestClass.typeConstructor, List(tp)), true, context).tree
+ inferImplicit(tree, appliedType(ManifestClass.typeConstructor, List(tp)), true, false, context).tree
tp.normalize match {
case ThisType(_) | SingleType(_, _) =>
@@ -647,41 +645,50 @@ self: Analyzer =>
* If that fails, and `pt` is an instance of Manifest, try to construct a manifest.
* If all fails return SearchFailure
*/
- //val start = System.nanoTime()
- var result = searchImplicit(context.implicitss, true)
- //val timer1 = System.nanoTime()
- //if (result == SearchFailure) inscopeFail += timer1 - start else inscopeSucceed += timer1 - start
- if (result == SearchFailure) {
- if (pt.isInstanceOf[UniqueType])
- implicitsCache get pt match {
- case Some(r) =>
- hits += 1
- result = r
- case None =>
- misses += 1
- result = searchImplicit(implicitsOfExpectedType, false)
-// println("new fact: search implicit of "+pt+" = "+result)
-// if (implicitsCache.size >= sizeLimit)
-// implicitsCache -= implicitsCache.values.next
+ def bestImplicit: SearchResult = {
+ //val start = System.nanoTime()
+ var result = searchImplicit(context.implicitss, true)
+ //val timer1 = System.nanoTime()
+ //if (result == SearchFailure) inscopeFail += timer1 - start else inscopeSucceed += timer1 - start
+ if (result == SearchFailure) {
+ if (pt.isInstanceOf[UniqueType])
+ implicitsCache get pt match {
+ case Some(r) =>
+ hits += 1
+ result = r
+ case None =>
+ misses += 1
+ result = searchImplicit(implicitsOfExpectedType, false)
+ // println("new fact: search implicit of "+pt+" = "+result)
+ // if (implicitsCache.size >= sizeLimit)
+ // implicitsCache -= implicitsCache.values.next
implicitsCache(pt) = result
- }
- else
- result = searchImplicit(implicitsOfExpectedType, false)
- }
- //val timer2 = System.nanoTime()
- //if (result == SearchFailure) oftypeFail += timer2 - timer1 else oftypeSucceed += timer2 - timer1
- if (result == SearchFailure) {
- val resultTree = implicitManifest(pt)
- if (resultTree != EmptyTree) result = new SearchResult(resultTree, EmptyTreeTypeSubstituter)
+ }
+ else
+ result = searchImplicit(implicitsOfExpectedType, false)
+ }
+ //val timer2 = System.nanoTime()
+ //if (result == SearchFailure) oftypeFail += timer2 - timer1 else oftypeSucceed += timer2 - timer1
+ if (result == SearchFailure) {
+ val resultTree = implicitManifest(pt)
+ if (resultTree != EmptyTree) result = new SearchResult(resultTree, EmptyTreeTypeSubstituter)
+ }
+ //val timer3 = System.nanoTime()
+ //if (result == SearchFailure) manifFail += timer3 - timer2 else manifSucceed += timer3 - timer2
+ if (result == SearchFailure && settings.debug.value)
+ println("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+parts(pt)+implicitsOfExpectedType)
+ //implicitTime += System.nanoTime() - start
+
+ if (util.Statistics.enabled) impltime += (currentTime - startTime)
+ result
}
- //val timer3 = System.nanoTime()
- //if (result == SearchFailure) manifFail += timer3 - timer2 else manifSucceed += timer3 - timer2
- if (result == SearchFailure && settings.debug.value)
- println("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+parts(pt)+implicitsOfExpectedType)
- //implicitTime += System.nanoTime() - start
- if (util.Statistics.enabled) impltime += (currentTime - startTime)
- result
+ def allImplicits: List[SearchResult] = {
+ val invalidImplicits = new ListBuffer[Symbol]
+ def search(iss: List[List[ImplicitInfo]], isLocal: Boolean) =
+ applicableInfos(iss, isLocal, invalidImplicits).values.toList
+ search(context.implicitss, true) ::: search(implicitsOfExpectedType, false)
+ }
}
private val DivergentImplicit = new Exception()
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 2015716aae..f9ad690472 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -415,6 +415,7 @@ abstract class RefChecks extends InfoTransform {
val varianceValidator = new Traverser {
+ /** Validate variance of info of symbol `base` */
private def validateVariance(base: Symbol) {
def varianceString(variance: Int): String =
@@ -422,25 +423,46 @@ abstract class RefChecks extends InfoTransform {
else if (variance == -1) "contravariant"
else "invariant";
+ /** The variance of a symbol occurrence of `tvar`
+ * seen at the level of the definition of `base`.
+ * The search proceeds from `base` to the owner of `tvar`.
+ * Initially the state is covariant, but it might change along the search.
+ */
def relativeVariance(tvar: Symbol): Int = {
val clazz = tvar.owner
var sym = base
var state = CoVariance
while (sym != clazz && state != AnyVariance) {
//Console.println("flip: " + sym + " " + sym.isParameter());//DEBUG
+ // Flip occurrences of type parameters and parameters, unless
+ // - it's a constructor, or case class factory or extractor
+ // - it's a type parameter of tvar's owner.
if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseApplyOrUnapply &&
!(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem &&
tvar.owner == sym.owner)) state = -state;
else if (!sym.owner.isClass ||
- sym.isTerm && ((sym.isPrivateLocal || sym.isProtectedLocal) && !(escapedPrivateLocals contains sym)))
+ sym.isTerm && ((sym.isPrivateLocal || sym.isProtectedLocal) && !(escapedPrivateLocals contains sym))) {
+ // return AnyVariance if `sym` is local to a term
+ // or is private[this] or protected[this]
state = AnyVariance
- else if (sym.isAliasType)
- state = AnyVariance // was NoVariance, but now we always expand aliases.
+ } else if (sym.isAliasType) {
+ // return AnyVariance if `sym` is an alias type
+ // that does not override anything. This is OK, because we always
+ // expand aliases for variance checking.
+ // However, if `sym` does override a type in a base class
+ // we have to assume NoVariance, as there might then be
+ // references to the type parameter that are not variance checked.
+ state = if (sym.allOverriddenSymbols.isEmpty) AnyVariance
+ else NoVariance
+ }
sym = sym.owner
}
state
}
+ /** Validate that the type `tp` is variance-correct, assuming
+ * the type occurs itself at variance position given by `variance`
+ */
def validateVariance(tp: Type, variance: Int): Unit = tp match {
case ErrorType => ;
case WildcardType => ;
@@ -452,10 +474,10 @@ abstract class RefChecks extends InfoTransform {
case SingleType(pre, sym) =>
validateVariance(pre, variance)
case TypeRef(pre, sym, args) =>
- if (sym.isAliasType)
+ if (sym.isAliasType && relativeVariance(sym) == AnyVariance)
validateVariance(tp.normalize, variance)
else if (sym.variance != NoVariance) {
- val v = relativeVariance(sym);
+ val v = relativeVariance(sym)
if (v != AnyVariance && sym.variance != v * variance) {
//Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG
def tpString(tp: Type) = tp match {
@@ -476,6 +498,8 @@ abstract class RefChecks extends InfoTransform {
validateVariances(parents, variance)
case RefinedType(parents, decls) =>
validateVariances(parents, variance)
+ for (sym <- decls.toList)
+ validateVariance(sym.info, if (sym.isAliasType) NoVariance else variance)
case TypeBounds(lo, hi) =>
validateVariance(lo, -variance)
validateVariance(hi, variance)
@@ -507,7 +531,8 @@ abstract class RefChecks extends InfoTransform {
override def traverse(tree: Tree) {
tree match {
- case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) =>
+ case ClassDef(_, _, _, _) |
+ TypeDef(_, _, _, _) =>
validateVariance(tree.symbol)
super.traverse(tree)
// ModuleDefs need not be considered because they have been eliminated already
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 71e0af421f..d82c995e05 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -176,11 +176,8 @@ trait Typers { self: Analyzer =>
*/
def applyImplicitArgs(fun: Tree): Tree = fun.tpe match {
case MethodType(params, _) =>
- def implicitArg(pt: Type): SearchResult =
- inferImplicit(fun, pt, true, context)
-
var positional = true
- val argResults = params map (_.tpe) map implicitArg
+ val argResults = params map (_.tpe) map (inferImplicit(fun, _, true, false, context))
val args = argResults.zip(params) flatMap {
case (arg, param) =>
if (arg != SearchFailure) {
@@ -218,15 +215,14 @@ trait Typers { self: Analyzer =>
case OverloadedType(_, _) => EmptyTree
case PolyType(_, _) => EmptyTree
case _ =>
- val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "typer$dummy")
- def wrapImplicit(from: Symbol): Tree = {
- val result = inferImplicit(tree, MethodType(List(from), to), reportAmbiguous, context)
+ def wrapImplicit(from: Type): Tree = {
+ val result = inferImplicit(tree, functionType(List(from), to), reportAmbiguous, true, context)
if (result.subst != EmptyTreeTypeSubstituter) result.subst traverse tree
result.tree
}
- val result = wrapImplicit(dummyMethod.newSyntheticValueParam(from))
+ val result = wrapImplicit(from)
if (result != EmptyTree) result
- else wrapImplicit(dummyMethod.newSyntheticValueParam(appliedType(ByNameParamClass.typeConstructor, List(from))))
+ else wrapImplicit(appliedType(ByNameParamClass.typeConstructor, List(from)))
}
}