diff options
author | Antonio Cunei <antonio.cunei@epfl.ch> | 2010-09-02 11:54:06 +0000 |
---|---|---|
committer | Antonio Cunei <antonio.cunei@epfl.ch> | 2010-09-02 11:54:06 +0000 |
commit | 918fb944b611ee08b5f5596c2fbc5123d2f09917 (patch) | |
tree | b16a64b472f021b0f169ebf688b65f8492943691 | |
parent | 13387444da947f6a9fa3770ec2acb227333da6cf (diff) | |
download | scala-918fb944b611ee08b5f5596c2fbc5123d2f09917.tar.gz scala-918fb944b611ee08b5f5596c2fbc5123d2f09917.tar.bz2 scala-918fb944b611ee08b5f5596c2fbc5123d2f09917.zip |
Merged revisions 22108,22176-22177,22318,22589-...
Merged revisions
22108,22176-22177,22318,22589-22590,22595,22644,22657-22658,22723,22725,
22737-22738,22833-22835,22846,22858-22860,22872 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk
........
r22108 | odersky | 2010-05-31 19:23:38 +0200 (Mon, 31 May 2010) | 1 line
made hashset more robust for concurrent access to reduce eclipse race
conditions. ........ r22176 | odersky | 2010-06-06 09:46:43 +0200 (Sun,
06 Jun 2010) | 2 lines
Overwrote copyToArray for efficiency.
........
r22177 | odersky | 2010-06-06 09:47:21 +0200 (Sun, 06 Jun 2010) | 2 lines
Fixed a typo in a use case
........
r22318 | odersky | 2010-06-16 17:36:08 +0200 (Wed, 16 Jun 2010) | 1 line
Imporved printing of private[C] in TreePrinters. No review. ........
r22589 | odersky | 2010-07-19 15:55:09 +0200 (Mon, 19 Jul 2010) | 1 line
new test files.
........
r22590 | odersky | 2010-07-19 15:56:03 +0200 (Mon, 19 Jul 2010) | 1 line
Added `ask` method to compiler control to do fast trunaround
computations on presentation compiler thread. ........ r22595 | odersky
| 2010-07-19 17:19:45 +0200 (Mon, 19 Jul 2010) | 1 line
added missing file.
........
r22644 | odersky | 2010-07-28 18:33:16 +0200 (Wed, 28 Jul 2010) | 1 line
Fixes #3679. Review by milessabin.
........
r22657 | odersky | 2010-08-02 15:53:16 +0200 (Mon, 02 Aug 2010) | 1 line
Revamped ScalaConversions. Fixes #3688. Also added JavaConverters
object which allows for explicit asJava/asScala conversions in the
scalaj style. Review by milessabin. ........ r22658 | odersky |
2010-08-02 15:53:58 +0200 (Mon, 02 Aug 2010) | 1 line
Fixed some typoes/errors in doc comments. No review. ........ r22723 |
odersky | 2010-08-10 17:47:15 +0200 (Tue, 10 Aug 2010) | 1 line
Removed duplicate classes. No review.
........
r22725 | odersky | 2010-08-10 19:38:32 +0200 (Tue, 10 Aug 2010) | 1 line
Added missing file for last checkin.
........
r22737 | odersky | 2010-08-12 11:02:46 +0200 (Thu, 12 Aug 2010) | 1 line
Changes in docs and layout. No review.
........
r22738 | odersky | 2010-08-12 11:03:30 +0200 (Thu, 12 Aug 2010) | 1 line
Fixed type soundness problem someone raised on hackers news. Test in
override.scala. Review by moors. ........ r22833 | odersky | 2010-08-24
16:59:13 +0200 (Tue, 24 Aug 2010) | 1 line
Fixes #3780. No review.
........
r22834 | odersky | 2010-08-24 16:59:54 +0200 (Tue, 24 Aug 2010) | 1 line
new tests. No review.
........
r22835 | odersky | 2010-08-24 17:48:09 +0200 (Tue, 24 Aug 2010) | 1 line
Closes #3776. No review.
........
r22846 | moors | 2010-08-26 18:16:54 +0200 (Thu, 26 Aug 2010) | 1 line
this should fix our achy breaky build. no review
........
r22858 | odersky | 2010-08-30 17:56:13 +0200 (Mon, 30 Aug 2010) | 1 line
added doc comment which makes things clearer when seen from Map or
Set. ........ r22859 | odersky | 2010-08-30 17:59:05 +0200 (Mon, 30 Aug
2010) | 1 line
removed author attribution, since no code from Stepan remains here.
........ r22860 | odersky | 2010-08-30 18:02:34 +0200 (Mon, 30 Aug 2010)
| 1 line
New wider interface of presentation compiler. Allows for partial
responses and improves cancelling. See Response.scala for a usage
example. ........ r22872 | odersky | 2010-08-31 17:37:55 +0200 (Tue, 31
Aug 2010) | 1 line
Partial fix for #3774. The crash is gone but the program is rejected.
A full fix will have to wait until a re-implementation of LUB/GLB along
the lines of the DOT system. ........
40 files changed, 1218 insertions, 298 deletions
diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala index 948c5f6fb8..1e6699079d 100644 --- a/src/compiler/scala/tools/nsc/Main.scala +++ b/src/compiler/scala/tools/nsc/Main.scala @@ -8,8 +8,6 @@ package scala.tools.nsc import java.io.File import File.pathSeparator -import scala.concurrent.SyncVar - import scala.tools.nsc.interactive.{ RefinedBuildManager, SimpleBuildManager } import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} @@ -59,7 +57,7 @@ object Main extends AnyRef with EvalLoop { import compiler.{ reporter => _, _ } val sfs = command.files.map(getSourceFile(_)) - val reloaded = new SyncVar[Either[Unit, Throwable]] + val reloaded = new interactive.Response[Unit] askReload(sfs, reloaded) reloaded.get.right.toOption match { case Some(ex) => reporter.cancelled = true // Causes exit code to be non-0 diff --git a/src/compiler/scala/tools/nsc/Phase.scala b/src/compiler/scala/tools/nsc/Phase.scala index 882b96d84d..8cf93f6eea 100644 --- a/src/compiler/scala/tools/nsc/Phase.scala +++ b/src/compiler/scala/tools/nsc/Phase.scala @@ -24,7 +24,7 @@ abstract class Phase(val prev: Phase) { def flagMask: Long = fmask private var nx: Phase = this - if (prev ne null) prev.nx = this + if ((prev ne null) && (prev ne NoPhase)) prev.nx = this def next: Phase = nx diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index e1e7c90879..10b50db6d5 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -117,7 +117,7 @@ trait TreePrinters { trees: SymbolTable => def pw = tree.symbol.privateWithin val args = if (tree.symbol == NoSymbol) (mods.flags, mods.privateWithin) - else if (pw == NoSymbol || pw == tree.symbol.owner) (tree.symbol.flags, "") + else if (pw == NoSymbol) (tree.symbol.flags, "") else (tree.symbol.flags, pw.name) printFlags(args._1, args._2.toString) diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index 26f7fb1115..b00da77b46 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -1,7 +1,6 @@ package scala.tools.nsc package interactive -import scala.concurrent.SyncVar import scala.util.control.ControlThrowable import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.{SourceFile, Position, WorkScheduler} @@ -12,14 +11,6 @@ import scala.tools.nsc.ast._ */ trait CompilerControl { self: Global => - /** Response { - override def toString = "TypeMember("+sym+","+tpe+","+accessible+","+inherited+","+viaView+")" - }{ - override def toString = "TypeMember("+sym+","+tpe+","+accessible+","+inherited+","+viaView+")" - }wrapper to client - */ - type Response[T] = SyncVar[Either[T, Throwable]] - abstract class WorkItem extends (() => Unit) /** Info given for every member found by completion @@ -30,8 +21,18 @@ trait CompilerControl { self: Global => val accessible: Boolean } - case class TypeMember(sym: Symbol, tpe: Type, accessible: Boolean, inherited: Boolean, viaView: Symbol) extends Member - case class ScopeMember(sym: Symbol, tpe: Type, accessible: Boolean, viaImport: Tree) extends Member + case class TypeMember( + sym: Symbol, + tpe: Type, + accessible: Boolean, + inherited: Boolean, + viaView: Symbol) extends Member + + case class ScopeMember( + sym: Symbol, + tpe: Type, + accessible: Boolean, + viaImport: Tree) extends Member /** The scheduler by which client and compiler communicate * Must be initialized before starting compilerRunner @@ -82,7 +83,7 @@ trait CompilerControl { self: Global => override def toString = "reload "+sources } - /** Set sync var `result` to a fully attributed tree located at position `pos` + /** Set sync var `result` to the smallest fully attributed tree that encloses position `pos`. */ def askTypeAt(pos: Position, result: Response[Tree]) = scheduler postWorkItem new WorkItem { @@ -90,6 +91,8 @@ trait CompilerControl { self: Global => override def toString = "typeat "+pos.source+" "+pos.show } + /** Set sync var `result` to the fully attributed & typechecked tree contained in `source`. + */ def askType(source: SourceFile, forceReload: Boolean, result: Response[Tree]) = scheduler postWorkItem new WorkItem { def apply() = self.getTypedTree(source, forceReload, result) @@ -98,7 +101,6 @@ trait CompilerControl { self: Global => /** Set sync var `result' to list of members that are visible * as members of the tree enclosing `pos`, possibly reachable by an implicit. - * - if `selection` is false, as identifiers in the scope enclosing `pos` */ def askTypeCompletion(pos: Position, result: Response[List[Member]]) = scheduler postWorkItem new WorkItem { @@ -123,9 +125,6 @@ trait CompilerControl { self: Global => } } - /** Cancel currently pending high-priority jobs */ - def askCancel() = scheduler raise CancelActionReq - /** Cancel current compiler run and start a fresh one where everything will be re-typechecked * (but not re-loaded). */ @@ -134,9 +133,11 @@ trait CompilerControl { self: Global => /** Tell the compile server to shutdown, and do not restart again */ def askShutdown() = scheduler raise ShutdownReq + /** Ask for a computation to be done quickly on the presentation compiler thread */ + def ask[A](op: () => A): A = scheduler doQuickly op + // ---------------- Interpreted exceptions ------------------- - object CancelActionReq extends ControlThrowable object FreshRunReq extends ControlThrowable object ShutdownReq extends ControlThrowable } diff --git a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala index af50e4e468..af4052a2e2 100644 --- a/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala +++ b/src/compiler/scala/tools/nsc/interactive/ContextTrees.scala @@ -17,7 +17,7 @@ trait ContextTrees { self: Global => * 3. The `pos` field of a context is the same as `context.tree.pos`, unless that * position is transparent. In that case, `pos` equals the position of * one of the solid descendants of `context.tree`. - * 4. Children of a context have non-overlapping increasining positions. + * 4. Children of a context have non-overlapping increasing positions. * 5. No context in the tree has a transparent position. */ class ContextTree(val pos: Position, val context: Context, val children: ArrayBuffer[ContextTree]) { diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 2c174860e4..94322178b1 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -42,12 +42,17 @@ self => /** The currently active typer run */ private var currentTyperRun: TyperRun = _ - /** Is a background compiler run needed? */ + /** Is a background compiler run needed? + * Note: outOfDate is true as long as there is a backgroud compile scheduled or going on. + */ private var outOfDate = false /** Units compiled by a run with id >= minRunId are considered up-to-date */ private[interactive] var minRunId = 1 + private val NoResponse: Response[_] = new Response[Any] + private var pendingResponse: Response[_] = NoResponse + /** Is a reload/background compiler currently running? */ private var acting = false @@ -110,12 +115,19 @@ self => // ----------------- Polling --------------------------------------- /** Called from runner thread and signalDone: - * Poll for exceptions. - * Poll for work reload/typedTreeAt/doFirst commands during background checking. + * Poll for interrupts and execute them immediately. + * Then, poll for exceptions and execute them. + * Then, poll for work reload/typedTreeAt/doFirst commands during background checking. */ def pollForWork() { + scheduler.pollInterrupt() match { + case Some(ir) => + ir.execute(); pollForWork() + case _ => + } + if (pendingResponse.isCancelled) + throw CancelException scheduler.pollThrowable() match { - case Some(ex @ CancelActionReq) => if (acting) throw ex case Some(ex @ FreshRunReq) => currentTyperRun = newTyperRun minRunId = currentRunId @@ -131,9 +143,6 @@ self => if (debugIDE) println("picked up work item: "+action) action() if (debugIDE) println("done with work item: "+action) - } catch { - case CancelActionReq => - if (debugIDE) println("cancelled work item: "+action) } finally { if (debugIDE) println("quitting work item: "+action) acting = false @@ -220,10 +229,16 @@ self => private def backgroundCompile() { if (debugIDE) inform("Starting new presentation compiler type checking pass") reporter.reset + + // remove any files in first that are no longer maintained by presentation compiler (i.e. closed) firsts = firsts filter (s => unitOfFile contains (s.file)) + val prefix = firsts map unitOf + val units = prefix ::: (unitOfFile.values.toList diff prefix) filter (!_.isUpToDate) + recompile(units) + if (debugIDE) inform("Everything is now up to date") } @@ -261,6 +276,8 @@ self => activeLocks = 0 currentTyperRun.typeCheck(unit) unit.status = currentRunId + // todo: garbage collect any tyop-level symbols whose types are no longer valid for + // currentRunId } } @@ -271,18 +288,24 @@ self => // ----------------- Implementations of client commands ----------------------- - def respond[T](result: Response[T])(op: => T): Unit = + def respond[T](result: Response[T])(op: => T): Unit = { + val prevResponse = pendingResponse try { - result set Left(op) - return + pendingResponse = result + if (!result.isCancelled) result set op } catch { + case CancelException => + ; case ex @ FreshRunReq => scheduler.postWorkItem(() => respond(result)(op)) throw ex case ex => - result set Right(ex) + result raise ex throw ex + } finally { + pendingResponse = prevResponse } + } /** Make sure a set of compilation units is loaded and parsed */ def reloadSources(sources: List[SourceFile]) { @@ -298,8 +321,8 @@ self => /** Make sure a set of compilation units is loaded and parsed */ def reload(sources: List[SourceFile], result: Response[Unit]) { respond(result)(reloadSources(sources)) - if (outOfDate) throw FreshRunReq - else outOfDate = true + if (outOfDate) throw FreshRunReq // cancel background compile + else outOfDate = true // proceed normally and enable new background compile } /** A fully attributed tree located at position `pos` */ @@ -333,7 +356,7 @@ self => def stabilizedType(tree: Tree): Type = tree match { case Ident(_) if tree.symbol.isStable => singleType(NoPrefix, tree.symbol) - case Select(qual, _) if qual.tpe != null && tree.symbol.isStable => singleType(qual.tpe, tree.symbol) + case Select(qual, _) if qual.tpe != null && tree.symbol.isStable => singleType(qual.tpe, tree.symbol) case Import(expr, selectors) => tree.symbol.info match { case analyzer.ImportType(expr) => expr match { @@ -399,11 +422,16 @@ self => def typeMembers(pos: Position): List[TypeMember] = { var tree = typedTreeAt(pos) + + // Let's say you have something like val x: List[Int] and ypu want to get completion after List + // Then the tree found at first is a TypeTree, ???? tree match { - case tt : TypeTree => tree = tt.original + case tt : TypeTree if tt.original != null => tree = tt.original // ??? case _ => } + // if tree consists of just x. or x.fo where fo is not yet a full member name + // ignore the selection and look in just x. tree match { case Select(qual, name) if tree.tpe == ErrorType => tree = qual case _ => @@ -419,6 +447,7 @@ self => val superAccess = tree.isInstanceOf[Super] val scope = new Scope val members = new LinkedHashMap[Symbol, TypeMember] + def addTypeMember(sym: Symbol, pre: Type, inherited: Boolean, viaView: Symbol) { val symtpe = pre.memberType(sym) if (scope.lookupAll(sym.name) forall (sym => !(members(sym).tpe matches symtpe))) { @@ -431,22 +460,28 @@ self => viaView) } } + + /** Create a fucntion application of a given view function to `tree` and typechecked it. + */ def viewApply(view: SearchResult): Tree = { assert(view.tree != EmptyTree) try { - analyzer.newTyper(context.makeImplicit(false)).typed(Apply(view.tree, List(tree)) setPos tree.pos) + analyzer.newTyper(context.makeImplicit(reportAmbiguousErrors = false)) + .typed(Apply(view.tree, List(tree)) setPos tree.pos) } catch { case ex: TypeError => EmptyTree } } + val pre = stabilizedType(tree) val ownerTpe = if (tree.tpe != null) tree.tpe else pre + for (sym <- ownerTpe.decls) addTypeMember(sym, pre, false, NoSymbol) for (sym <- ownerTpe.members) addTypeMember(sym, pre, true, NoSymbol) val applicableViews: List[SearchResult] = - new ImplicitSearch(tree, functionType(List(ownerTpe), AnyClass.tpe), true, context.makeImplicit(false)) + new ImplicitSearch(tree, functionType(List(ownerTpe), AnyClass.tpe), isView = true, context.makeImplicit(reportAmbiguousErrors = false)) .allImplicits for (view <- applicableViews) { val vtree = viewApply(view) @@ -499,7 +534,7 @@ self => tree } else { val unit = unitOf(pos) - assert(unit.status >= JustParsed) + assert(unit.isParsed) unit.targetPos = pos try { println("starting targeted type check") @@ -515,7 +550,7 @@ self => } def typedTree(unit: RichCompilationUnit): Tree = { - assert(unit.status >= JustParsed) + assert(unit.isParsed) unit.targetPos = NoPosition typeCheck(unit) unit.body @@ -539,3 +574,5 @@ self => assert(globalPhase.id == 0) } +object CancelException extends Exception + diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index 5589ddb9b1..775b979851 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -80,9 +80,9 @@ object REPL { * complete file off1 off2? */ def run(comp: Global) { - val reloadResult = new comp.Response[Unit] - val typeatResult = new comp.Response[comp.Tree] - val completeResult = new comp.Response[List[comp.Member]] + val reloadResult = new Response[Unit] + val typeatResult = new Response[comp.Tree] + val completeResult = new Response[List[comp.Member]] def makePos(file: String, off1: String, off2: String) = { val source = toSourceFile(file) comp.rangePos(source, off1.toInt, off1.toInt, off2.toInt) @@ -118,11 +118,11 @@ object REPL { def toSourceFile(name: String) = new BatchSourceFile(new PlainFile(new java.io.File(name))) - def show[T](svar: SyncVar[Either[T, Throwable]]) { + def show[T](svar: Response[T]) { svar.get match { case Left(result) => println("==> "+result) - case Right(exc/*: Throwable ??*/) => exc.printStackTrace; println("ERROR: "+exc) + case Right(exc) => exc.printStackTrace; println("ERROR: "+exc) } - svar.unset() + svar.clear() } } diff --git a/src/compiler/scala/tools/nsc/interactive/Response.scala b/src/compiler/scala/tools/nsc/interactive/Response.scala new file mode 100644 index 0000000000..96e474a34a --- /dev/null +++ b/src/compiler/scala/tools/nsc/interactive/Response.scala @@ -0,0 +1,68 @@ +package scala.tools.nsc +package interactive + +import scala.concurrent.SyncVar + +/** Typical interaction, given a predicate <user-input>, a function <display>, + * and an exception handler <handle>: + * + * val TIMEOUT = 100 // (milliseconds) or something like that + * val r = new Response() + * while (!r.isComplete && !r.isCancelled) { + * if (<user-input>) r.cancel() + * else r.get(TIMEOUT) match { + * case Some(Left(data)) => <display>(data) + * case Some(Right(exc)) => <handle>(exc) + * case None => + * } + * } + */ +class Response[T] { + + private val data = new SyncVar[Either[T, Throwable]] + private var complete = false + private var cancelled = false + + /** Set provisional data, more to come + */ + def setProvisionally(x: T) = + data.set(Left(x)) + + /** Set final data, and mark resposne as complete. + */ + def set(x: T) = data.synchronized { + data.set(Left(x)) + complete = true + } + + def raise(exc: Throwable) = data.synchronized { + data.set(Right(exc)) + complete = true + } + + /** Get data, wait as long as necessary + */ + def get: Either[T, Throwable] = data.get + + /** Optionally get data within `timeout` milliseconds. + */ + def get(timeout: Long): Option[Either[T, Throwable]] = data.get(timeout) + + /** Final data set was stored + */ + def isComplete = data.synchronized { complete } + + /** Cancel action computing this response + */ + def cancel() = data.synchronized { cancelled = true } + + /** A cancel request for this response has been issued + */ + def isCancelled = data.synchronized { cancelled } + + def clear() = data.synchronized { + data.unset() + complete = false + cancelled = false + } +} diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala index 5d4f7b8464..6f350233e2 100644 --- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala +++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala @@ -107,9 +107,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { def underlyingSource: Option[AbstractFile] = None /** Does this abstract file denote an existing file? */ - def exists: Boolean = - if (file ne null) file.exists - else true + def exists: Boolean = (file eq null) || file.exists /** Does this abstract file represent something which can contain classfiles? */ def isClassContainer = isDirectory || (sfile exists (Path isJarOrZip _)) @@ -132,7 +130,7 @@ abstract class AbstractFile extends AnyRef with Iterable[AbstractFile] { /** Returns an output stream for writing the file */ def output: OutputStream - /** Returns an unbuffered output stream for writing the file - defaults to out */ + /** Returns a buffered output stream for writing the file - defaults to out */ def bufferedOutput: BufferedOutputStream = new BufferedOutputStream(output) /** size of this file if it is a concrete file. */ diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 7aed4cd648..b3d2c56285 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -8,7 +8,7 @@ package scala.tools.nsc package symtab import scala.collection.immutable -import scala.collection.mutable.{ListBuffer, WeakHashMap} +import scala.collection.mutable.{ListBuffer, HashMap, WeakHashMap} import ast.TreeGen import util.{HashSet, Position, NoPosition} import util.Statistics._ @@ -4864,7 +4864,15 @@ A type's typeSymbol should never be inspected directly. isNumericValueType(tp1) && isNumericValueType(tp2) && isNumericSubClass(tp1.typeSymbol, tp2.typeSymbol) - def lub(ts: List[Type]): Type = lub(ts, lubDepth(ts)) + private val lubResults = new HashMap[(Int, List[Type]), Type] + private val glbResults = new HashMap[(Int, List[Type]), Type] + + def lub(ts: List[Type]): Type = try { + lub(ts, lubDepth(ts)) + } finally { + lubResults.clear() + glbResults.clear() + } /** The least upper bound wrt <:< of a list of types */ def lub(ts: List[Type], depth: Int): Type = { @@ -4879,72 +4887,83 @@ A type's typeSymbol should never be inspected directly. MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe)))) case ts @ TypeBounds(_, _) :: rest => TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth)) - case ts0 => - val (ts, tparams) = stripExistentialsAndTypeVars(ts0) - val bts: List[BaseTypeSeq] = ts map (_.baseTypeSeq) - val lubBaseTypes: List[Type] = lubBaseTypeSeq(bts, depth) - val lubParents = spanningTypes(lubBaseTypes) - val lubOwner = commonOwner(ts) - val lubBase = intersectionType(lubParents, lubOwner) - val lubType = - if (phase.erasedTypes || depth == 0) lubBase - else { - val lubRefined = refinedType(lubParents, lubOwner) - val lubThisType = lubRefined.typeSymbol.thisType - val narrowts = ts map (_.narrow) - def lubsym(proto: Symbol): Symbol = { - val prototp = lubThisType.memberInfo(proto) - val syms = narrowts map (t => - t.nonPrivateMember(proto.name).suchThat(sym => - sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t))) - if (syms contains NoSymbol) NoSymbol + case ts => + lubResults get (depth, ts) match { + case Some(lubType) => + lubType + case None => + lubResults((depth, ts)) = AnyClass.tpe + val res = if (depth < 0) AnyClass.tpe else lub1(ts) + lubResults((depth, ts)) = res + res + } + } + def lub1(ts0: List[Type]): Type = { + val (ts, tparams) = stripExistentialsAndTypeVars(ts0) + val bts: List[BaseTypeSeq] = ts map (_.baseTypeSeq) + val lubBaseTypes: List[Type] = lubBaseTypeSeq(bts, depth) + val lubParents = spanningTypes(lubBaseTypes) + val lubOwner = commonOwner(ts) + val lubBase = intersectionType(lubParents, lubOwner) + val lubType = + if (phase.erasedTypes || depth == 0) lubBase + else { + val lubRefined = refinedType(lubParents, lubOwner) + val lubThisType = lubRefined.typeSymbol.thisType + val narrowts = ts map (_.narrow) + def lubsym(proto: Symbol): Symbol = { + val prototp = lubThisType.memberInfo(proto) + val syms = narrowts map (t => + t.nonPrivateMember(proto.name).suchThat(sym => + sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t))) + if (syms contains NoSymbol) NoSymbol + else { + val symtypes = + (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) + if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class + proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth))) + else if (symtypes.tail forall (symtypes.head =:=)) + proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(symtypes.head) else { - val symtypes = - (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) - if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class - proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth))) - else if (symtypes.tail forall (symtypes.head =:=)) - proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(symtypes.head) - else { - def lubBounds(bnds: List[TypeBounds]): TypeBounds = - TypeBounds(glb(bnds map (_.lo), decr(depth)), lub(bnds map (_.hi), decr(depth))) - lubRefined.typeSymbol.newAbstractType(proto.pos, proto.name) - .setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds))) - } + def lubBounds(bnds: List[TypeBounds]): TypeBounds = + TypeBounds(glb(bnds map (_.lo), decr(depth)), lub(bnds map (_.hi), decr(depth))) + lubRefined.typeSymbol.newAbstractType(proto.pos, proto.name) + .setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds))) } } - def refines(tp: Type, sym: Symbol): Boolean = { - val syms = tp.nonPrivateMember(sym.name).alternatives; - !syms.isEmpty && (syms forall (alt => - // todo alt != sym is strictly speaking not correct, but without it we lose - // efficiency. - alt != sym && !specializesSym(lubThisType, sym, tp, alt))) - } - for (sym <- lubBase.nonPrivateMembers) { - // add a refinement symbol for all non-class members of lubBase - // which are refined by every type in ts. - if (!sym.isClass && !sym.isConstructor && (narrowts forall (t => refines(t, sym)))) - try { - val lsym = lubsym(sym) - if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lubsym(sym)) - } catch { - case ex: NoCommonType => - } - } - if (lubRefined.decls.isEmpty) lubBase - else { + } + def refines(tp: Type, sym: Symbol): Boolean = { + val syms = tp.nonPrivateMember(sym.name).alternatives; + !syms.isEmpty && (syms forall (alt => + // todo alt != sym is strictly speaking not correct, but without it we lose + // efficiency. + alt != sym && !specializesSym(lubThisType, sym, tp, alt))) + } + for (sym <- lubBase.nonPrivateMembers) { + // add a refinement symbol for all non-class members of lubBase + // which are refined by every type in ts. + if (!sym.isClass && !sym.isConstructor && (narrowts forall (t => refines(t, sym)))) + try { + val lsym = lubsym(sym) + if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lubsym(sym)) + } catch { + case ex: NoCommonType => + } + } + if (lubRefined.decls.isEmpty) lubBase + else { // println("refined lub of "+ts+"/"+narrowts+" is "+lubRefined+", baseclasses = "+(ts map (_.baseTypeSeq) map (_.toList))) - lubRefined - } + lubRefined } - existentialAbstraction(tparams, lubType) + } + existentialAbstraction(tparams, lubType) } if (printLubs) { println(indent + "lub of " + ts + " at depth "+depth)//debug indent = indent + " " assert(indent.length <= 100) } - val res = if (depth < 0) AnyClass.tpe else lub0(ts) + val res = lub0(ts) if (printLubs) { indent = indent.substring(0, indent.length() - 2) println(indent + "lub of " + ts + " is " + res)//debug @@ -4963,7 +4982,12 @@ A type's typeSymbol should never be inspected directly. private var globalGlbDepth = 0 private final val globalGlbLimit = 2 - def glb(ts: List[Type]): Type = glb(ts, lubDepth(ts)) + def glb(ts: List[Type]): Type = try { + glb(ts, lubDepth(ts)) + } finally { + lubResults.clear() + glbResults.clear() + } /** The greatest lower bound wrt <:< of a list of types */ private def glb(ts: List[Type], depth: Int): Type = { @@ -4978,85 +5002,99 @@ A type's typeSymbol should never be inspected directly. MethodType(params, glb0(matchingRestypes(ts, params map (_.tpe)))) case ts @ TypeBounds(_, _) :: rest => TypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth)) - case ts0 => - try { - val (ts, tparams) = stripExistentialsAndTypeVars(ts0) - val glbOwner = commonOwner(ts) - def refinedToParents(t: Type): List[Type] = t match { - case RefinedType(ps, _) => ps flatMap refinedToParents - case _ => List(t) - } - def refinedToDecls(t: Type): List[Scope] = t match { - case RefinedType(ps, decls) => - val dss = ps flatMap refinedToDecls - if (decls.isEmpty) dss else decls :: dss - case _ => List() - } - val ts1 = ts flatMap refinedToParents - val glbBase = intersectionType(ts1, glbOwner) - val glbType = - if (phase.erasedTypes || depth == 0) glbBase - else { - val glbRefined = refinedType(ts1, glbOwner) - val glbThisType = glbRefined.typeSymbol.thisType - def glbsym(proto: Symbol): Symbol = { - val prototp = glbThisType.memberInfo(proto) - val syms = for (t <- ts; - alt <- (t.nonPrivateMember(proto.name).alternatives); - if glbThisType.memberInfo(alt) matches prototp - ) yield alt - val symtypes = syms map glbThisType.memberInfo - assert(!symtypes.isEmpty) - proto.cloneSymbol(glbRefined.typeSymbol).setInfoOwnerAdjusted( - if (proto.isTerm) glb(symtypes, decr(depth)) - else { - def isTypeBound(tp: Type) = tp match { - case TypeBounds(_, _) => true - case _ => false - } - def glbBounds(bnds: List[Type]): TypeBounds = { - val lo = lub(bnds map (_.bounds.lo), decr(depth)) - val hi = glb(bnds map (_.bounds.hi), decr(depth)) - if (lo <:< hi) TypeBounds(lo, hi) - else throw GlbFailure + case ts => + glbResults get (depth, ts) match { + case Some(glbType) => + glbType + case _ => + glbResults((depth, ts)) = NothingClass.tpe + val res = if (depth < 0) NothingClass.tpe else glb1(ts) + glbResults((depth, ts)) = res + res + } + } + def glb1(ts0: List[Type]): Type = { + try { + val (ts, tparams) = stripExistentialsAndTypeVars(ts0) + val glbOwner = commonOwner(ts) + def refinedToParents(t: Type): List[Type] = t match { + case RefinedType(ps, _) => ps flatMap refinedToParents + case _ => List(t) + } + def refinedToDecls(t: Type): List[Scope] = t match { + case RefinedType(ps, decls) => + val dss = ps flatMap refinedToDecls + if (decls.isEmpty) dss else decls :: dss + case _ => List() + } + val ts1 = ts flatMap refinedToParents + val glbBase = intersectionType(ts1, glbOwner) + val glbType = + if (phase.erasedTypes || depth == 0) glbBase + else { + val glbRefined = refinedType(ts1, glbOwner) + val glbThisType = glbRefined.typeSymbol.thisType + def glbsym(proto: Symbol): Symbol = { + val prototp = glbThisType.memberInfo(proto) + val syms = for (t <- ts; + alt <- (t.nonPrivateMember(proto.name).alternatives); + if glbThisType.memberInfo(alt) matches prototp + ) yield alt + val symtypes = syms map glbThisType.memberInfo + assert(!symtypes.isEmpty) + proto.cloneSymbol(glbRefined.typeSymbol).setInfoOwnerAdjusted( + if (proto.isTerm) glb(symtypes, decr(depth)) + else { + def isTypeBound(tp: Type) = tp match { + case TypeBounds(_, _) => true + case _ => false + } + def glbBounds(bnds: List[Type]): TypeBounds = { + val lo = lub(bnds map (_.bounds.lo), decr(depth)) + val hi = glb(bnds map (_.bounds.hi), decr(depth)) + if (lo <:< hi) TypeBounds(lo, hi) + else throw GlbFailure + } + val symbounds = symtypes filter isTypeBound + var result: Type = + if (symbounds.isEmpty) + TypeBounds(NothingClass.tpe, AnyClass.tpe) + else glbBounds(symbounds) + for (t <- symtypes if !isTypeBound(t)) + if (result.bounds containsType t) result = t + else throw GlbFailure + result + }) + } + if (globalGlbDepth < globalGlbLimit) + try { + globalGlbDepth += 1 + val dss = ts flatMap refinedToDecls + for (ds <- dss; val sym <- ds.iterator) + if (globalGlbDepth < globalGlbLimit && !(glbThisType specializes sym)) + try { + addMember(glbThisType, glbRefined, glbsym(sym)) + } catch { + case ex: NoCommonType => } - val symbounds = symtypes filter isTypeBound - var result: Type = - if (symbounds.isEmpty) - TypeBounds(NothingClass.tpe, AnyClass.tpe) - else glbBounds(symbounds) - for (t <- symtypes if !isTypeBound(t)) - if (result.bounds containsType t) result = t - else throw GlbFailure - result - }) + } finally { + globalGlbDepth -= 1 } - if (globalGlbDepth < globalGlbLimit) - try { - globalGlbDepth += 1 - val dss = ts flatMap refinedToDecls - for (ds <- dss; val sym <- ds.iterator) - if (globalGlbDepth < globalGlbLimit && !(glbThisType specializes sym)) - try { - addMember(glbThisType, glbRefined, glbsym(sym)) - } catch { - case ex: NoCommonType => - } - } finally { - globalGlbDepth -= 1 - } - if (glbRefined.decls.isEmpty) glbBase else glbRefined - } - existentialAbstraction(tparams, glbType) - } catch { - case GlbFailure => - if (ts forall (t => NullClass.tpe <:< t)) NullClass.tpe - else NothingClass.tpe - } + if (glbRefined.decls.isEmpty) glbBase else glbRefined + } + existentialAbstraction(tparams, glbType) + } catch { + case GlbFailure => + if (ts forall (t => NullClass.tpe <:< t)) NullClass.tpe + else NothingClass.tpe + } } // if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG - val res = if (depth < 0) NothingClass.tpe else glb0(ts) + + 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 } diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index f78022bdaa..72868774e5 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -161,7 +161,7 @@ abstract class ExplicitOuter extends InfoTransform // On the other hand, mixing in the trait into a separately compiled // class needs to have a common naming scheme, independently of whether // the field was accessed from an inner class or not. See #2946 - if (sym.owner.isTrait && (sym hasFlag LOCAL) && (sym.getter(sym.owner) == NoSymbol)) + if (sym.owner.isTrait && (sym hasFlag LOCAL) && (sym.getter(sym.owner.toInterface) == NoSymbol)) sym.makeNotPrivate(sym.owner) tp } diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 63e5a9fb25..80f833f03d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -74,7 +74,7 @@ trait Analyzer extends AnyRef val runsRightAfter = Some("packageobjects") def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) { override def keepsTypeParams = false - resetTyper() + resetTyper() // this does not in fact to the reset for each compilation run! override def run { val start = startTimer(typerNanos) currentRun.units foreach applyPhase diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 0056dcd917..63b971d2fd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -409,7 +409,7 @@ self: Analyzer => if (mt.isImplicit) matchesPtView(restpe, ptarg, ptres, undet) else params.length == 1 && matchesArgRes(params.head.tpe, restpe, ptarg, ptres, undet) case ExistentialType(tparams, qtpe) => - matchesPtView(normalize(tp), ptarg, ptres, undet) + matchesPtView(normalize(qtpe), ptarg, ptres, undet) case Function1(arg1, res1) => matchesArgRes(arg1, res1, ptarg, ptres, undet) case _ => false diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 74114b455e..c91bac3d7f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -80,6 +80,7 @@ abstract class RefChecks extends InfoTransform { var localTyper: analyzer.Typer = typer; var currentApplication: Tree = EmptyTree var inPattern: Boolean = false + var checkedCombinations = Set[List[Type]]() // only one overloaded alternative is allowed to define default arguments private def checkDefaultsInOverloaded(clazz: Symbol) { @@ -186,7 +187,7 @@ abstract class RefChecks extends InfoTransform { * 4. Check that every member with an `override' modifier * overrides some other member. */ - private def checkAllOverrides(clazz: Symbol) { + private def checkAllOverrides(clazz: Symbol, typesOnly: Boolean = false) { case class MixinOverrideError(member: Symbol, msg: String) @@ -299,56 +300,65 @@ abstract class RefChecks extends InfoTransform { def intersectionIsEmpty(syms1: List[Symbol], syms2: List[Symbol]) = !(syms1 exists (syms2 contains)) - if (member hasFlag PRIVATE) { // (1.1) - overrideError("has weaker access privileges; it should not be private") - } - val mb = member.accessBoundary(member.owner) - val ob = other.accessBoundary(member.owner) - if (mb != RootClass && mb != NoSymbol && // todo: change - (ob == RootClass || ob == NoSymbol || !ob.hasTransOwner(mb) || - (other hasFlag PROTECTED) && !(member hasFlag PROTECTED))) { - overrideAccessError() + if (typesOnly) checkOverrideTypes() + else { + if (member hasFlag PRIVATE) { // (1.1) + overrideError("has weaker access privileges; it should not be private") + } + val mb = member.accessBoundary(member.owner) + val ob = other.accessBoundary(member.owner) + if (mb != RootClass && mb != NoSymbol && // todo: change + (ob == RootClass || ob == NoSymbol || !ob.hasTransOwner(mb) || + (other hasFlag PROTECTED) && !(member hasFlag PROTECTED))) { + overrideAccessError() + } + else if (other.isClass || other.isModule) { + overrideError("cannot be used here - classes and objects cannot be overridden"); + } else if (!other.isDeferred && (member.isClass || member.isModule)) { + overrideError("cannot be used here - classes and objects can only override abstract types"); + } else if (other hasFlag FINAL) { // (1.2) + overrideError("cannot override final member"); + } else if (!other.isDeferred && !(member hasFlag (OVERRIDE | ABSOVERRIDE | SYNTHETIC))) { // (1.3), SYNTHETIC because of DEVIRTUALIZE + overrideError("needs `override' modifier"); + } else if ((other hasFlag ABSOVERRIDE) && other.isIncompleteIn(clazz) && !(member hasFlag ABSOVERRIDE)) { + overrideError("needs `abstract override' modifiers") + } else if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) && + (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.hasFlag(LAZY)) { + overrideError("cannot override a mutable variable") + } else if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) && + !(member.owner.thisType.baseClasses exists (_ isSubClass other.owner)) && + !member.isDeferred && !other.isDeferred && + intersectionIsEmpty(member.allOverriddenSymbols, other.allOverriddenSymbols)) { + overrideError("cannot override a concrete member without a third member that's overridden by both "+ + "(this rule is designed to prevent ``accidental overrides'')") + } else if (other.isStable && !member.isStable) { // (1.4) + overrideError("needs to be a stable, immutable value") + } else if (member.isValue && (member hasFlag LAZY) && + other.isValue && !other.isSourceMethod && !other.isDeferred && !(other hasFlag LAZY)) { + overrideError("cannot override a concrete non-lazy value") + } else if (other.isValue && (other hasFlag LAZY) && !other.isSourceMethod && !other.isDeferred && + member.isValue && !(member hasFlag LAZY)) { + overrideError("must be declared lazy to override a concrete lazy value") + } else { + checkOverrideTypes() + } } - else if (other.isClass || other.isModule) { - overrideError("cannot be used here - classes and objects cannot be overridden"); - } else if (!other.isDeferred && (member.isClass || member.isModule)) { - overrideError("cannot be used here - classes and objects can only override abstract types"); - } else if (other hasFlag FINAL) { // (1.2) - overrideError("cannot override final member"); - } else if (!other.isDeferred && !(member hasFlag (OVERRIDE | ABSOVERRIDE | SYNTHETIC))) { // (1.3), SYNTHETIC because of DEVIRTUALIZE - overrideError("needs `override' modifier"); - } else if ((other hasFlag ABSOVERRIDE) && other.isIncompleteIn(clazz) && !(member hasFlag ABSOVERRIDE)) { - overrideError("needs `abstract override' modifiers") - } else if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) && - (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.hasFlag(LAZY)) { - overrideError("cannot override a mutable variable") - } else if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) && - !(member.owner.thisType.baseClasses exists (_ isSubClass other.owner)) && - !member.isDeferred && !other.isDeferred && - intersectionIsEmpty(member.allOverriddenSymbols, other.allOverriddenSymbols)) { - overrideError("cannot override a concrete member without a third member that's overridden by both "+ - "(this rule is designed to prevent ``accidental overrides'')") - } else if (other.isStable && !member.isStable) { // (1.4) - overrideError("needs to be a stable, immutable value") - } else if (member.isValue && (member hasFlag LAZY) && - other.isValue && !other.isSourceMethod && !other.isDeferred && !(other hasFlag LAZY)) { - overrideError("cannot override a concrete non-lazy value") - } else if (other.isValue && (other hasFlag LAZY) && !other.isSourceMethod && !other.isDeferred && - member.isValue && !(member hasFlag LAZY)) { - overrideError("must be declared lazy to override a concrete lazy value") - } else { + + def checkOverrideTypes() { if (other.isAliasType) { - //if (!member.typeParams.isEmpty) // (1.5) @MAT + //if (!member.typeParams.isEmpty) (1.5) @MAT // overrideError("may not be parameterized"); - //if (!other.typeParams.isEmpty) // (1.5) @MAT + //if (!other.typeParams.isEmpty) (1.5) @MAT // overrideError("may not override parameterized type"); // @M: substSym + if (!(self.memberType(member).substSym(member.typeParams, other.typeParams) =:= self.memberType(other))) // (1.6) overrideTypeError(); } else if (other.isAbstractType) { //if (!member.typeParams.isEmpty) // (1.7) @MAT // overrideError("may not be parameterized"); - var memberTp = self.memberType(member) + + val memberTp = self.memberType(member) val otherTp = self.memberInfo(other) if (!(otherTp.bounds containsType memberTp)) { // (1.7.1) overrideTypeError(); // todo: do an explaintypes with bounds here @@ -369,7 +379,7 @@ abstract class RefChecks extends InfoTransform { // this overlaps somewhat with validateVariance if(member.isAliasType) { val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.normalize), self, member.owner) - +2 if(!kindErrors.isEmpty) unit.error(member.pos, "The kind of the right-hand side "+memberTp.normalize+" of "+member.keyString+" "+ @@ -381,10 +391,25 @@ abstract class RefChecks extends InfoTransform { } } else if (other.isTerm) { other.cookJavaRawInfo() // #2454 - - if (!overridesType(self.memberInfo(member), self.memberInfo(other))) { // 8 + val memberTp = self.memberType(member) + val otherTp = self.memberType(other) + if (!overridesType(memberTp, otherTp)) { // 8 overrideTypeError() - explainTypes(self.memberInfo(member), self.memberInfo(other)) + explainTypes(memberTp, otherTp) + } + + if (member.isStable && !otherTp.isVolatile) { + if (memberTp.isVolatile) + overrideError("has a volatile type; cannot override a member with non-volatile type") + else memberTp.normalize.resultType match { + case rt: RefinedType if !(rt =:= otherTp) && !(checkedCombinations contains rt.parents) => + // might mask some inconsistencies -- check overrides + checkedCombinations += rt.parents + val tsym = rt.typeSymbol; + if (tsym.pos == NoPosition) tsym setPos member.pos + checkAllOverrides(tsym, typesOnly = true) + case _ => + } } } } @@ -400,7 +425,7 @@ abstract class RefChecks extends InfoTransform { printMixinOverrideErrors() // Verifying a concrete class has nothing unimplemented. - if (clazz.isClass && !clazz.isTrait && !(clazz hasFlag ABSTRACT)) { + if (clazz.isClass && !clazz.isTrait && !(clazz hasFlag ABSTRACT) && !typesOnly) { val abstractErrors = new ListBuffer[String] def abstractErrorMessage = // a little formatting polish diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d05754e080..69349e191b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2087,6 +2087,8 @@ trait Typers { self: Analyzer => EmptyTree case _ => if (localTarget && !includesTargetPos(stat)) { + // skip typechecking of statements in a sequence where some other statement includes + // the targetposition stat } else { val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this diff --git a/src/compiler/scala/tools/nsc/util/HashSet.scala b/src/compiler/scala/tools/nsc/util/HashSet.scala index aa6e19538c..8e0c2e2e59 100644 --- a/src/compiler/scala/tools/nsc/util/HashSet.scala +++ b/src/compiler/scala/tools/nsc/util/HashSet.scala @@ -11,19 +11,17 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte def this(label: String) = this(label, 16) def this() = this(16) - private var capacity = initialCapacity private var used = 0 - private var table = new Array[AnyRef](capacity) + private var table = new Array[AnyRef](initialCapacity) // System.err.println("Created: " + this) def size: Int = used def clear() { - capacity = initialCapacity used = 0 - table = new Array[AnyRef](capacity) + table = new Array[AnyRef](initialCapacity) } - private def index(x: Int): Int = math.abs(x % capacity) + private def index(x: Int): Int = math.abs(x % table.length) def findEntryOrUpdate(x: T): T = { var h = index(x.##) @@ -37,7 +35,7 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte } table(h) = x used += 1 - if (used > (capacity >> 2)) growTable() + if (used > (table.length >> 2)) growTable() x } @@ -61,14 +59,14 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte } table(h) = x used += 1 - if (used > (capacity >> 2)) growTable() + if (used > (table.length >> 2)) growTable() } def iterator = new Iterator[T] { private var i = 0 def hasNext: Boolean = { - while (i < capacity && (table(i) eq null)) i += 1 - i < capacity + while (i < table.length && (table(i) eq null)) i += 1 + i < table.length } def next: T = if (hasNext) { i += 1; table(i - 1).asInstanceOf[T] } @@ -88,12 +86,11 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte private def growTable() { val oldtable = table val growthFactor = - if (capacity <= initialCapacity) 8 - else if (capacity <= (initialCapacity * 8)) 4 + if (table.length <= initialCapacity) 8 + else if (table.length <= (initialCapacity * 8)) 4 else 2 - capacity *= growthFactor - table = new Array[AnyRef](capacity) + table = new Array[AnyRef](table.length * growthFactor) var i = 0 while (i < oldtable.length) { val entry = oldtable(i) @@ -101,5 +98,5 @@ class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) exte i += 1 } } - override def toString() = "HashSet %s(%d / %d)".format(label, used, capacity) + override def toString() = "HashSet %s(%d / %d)".format(label, used, table.length) } diff --git a/src/compiler/scala/tools/nsc/util/InterruptReq.scala b/src/compiler/scala/tools/nsc/util/InterruptReq.scala new file mode 100644 index 0000000000..aa7804acbe --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/InterruptReq.scala @@ -0,0 +1,28 @@ +package scala.tools.nsc +package util + +/** A class of work items to be used in interrupt requests. + */ +abstract class InterruptReq { + /** The result type of the operation + */ + type R + + /** The operation to be performed */ + protected val todo: () => R + + /** The result provided */ + private var result: Option[R] = None + + /** To be called from interrupted server to execute demanded task */ + def execute(): Unit = synchronized { + result = Some(todo()) + notify() + } + + /** To be called from interrupting client to get result fo interrupt */ + def getResult(): R = synchronized { + while (result.isEmpty) wait() + result.get + } +} diff --git a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala index e309b19b76..5f33ea4aaa 100644 --- a/src/compiler/scala/tools/nsc/util/WorkScheduler.scala +++ b/src/compiler/scala/tools/nsc/util/WorkScheduler.scala @@ -9,22 +9,21 @@ class WorkScheduler { private var todo = new Queue[Action] private var throwables = new Queue[Throwable] + private var interruptReqs = new Queue[InterruptReq] - /** Called from server: block until todo list is nonempty */ + /** Called from server: block until one of todo list, throwables or interruptReqs is nonempty */ def waitForMoreWork() = synchronized { - while (todo.isEmpty) { wait() } + while (todo.isEmpty && throwables.isEmpty && interruptReqs.isEmpty) { wait() } } - /** called from Server: test whether todo list is nonempty */ + /** called from Server: test whether one of todo list, throwables, or InterruptReqs is nonempty */ def moreWork(): Boolean = synchronized { - todo.nonEmpty + todo.nonEmpty || throwables.nonEmpty || interruptReqs.nonEmpty } /** Called from server: get first action in todo list, and pop it off */ def nextWorkItem(): Option[Action] = synchronized { - if (!todo.isEmpty) { - Some(todo.dequeue()) - } else None + if (todo.isEmpty) None else Some(todo.dequeue()) } /** Called from server: return optional exception posted by client @@ -41,6 +40,22 @@ class WorkScheduler { } } + def pollInterrupt(): Option[InterruptReq] = synchronized { + if (interruptReqs.isEmpty) None else Some(interruptReqs.dequeue()) + } + + /** Called from client: have interrupt executed by server and return result */ + def doQuickly[A](op: () => A): A = { + val ir = new InterruptReq { + type R = A + val todo = op + } + synchronized { + interruptReqs enqueue ir + } + ir.getResult() + } + /** Called from client: have action executed by server */ def postWorkItem(action: Action) = synchronized { todo enqueue action @@ -60,3 +75,4 @@ class WorkScheduler { postWorkItem { () => } } } + diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 80fc28e234..bbd3976490 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -70,11 +70,14 @@ object JavaConversions { * @param i The <code>Iterator</code> to be converted. * @return A Java <code>Iterator</code> view of the argument. */ - implicit def asIterator[A](i : Iterator[A]): ju.Iterator[A] = i match { + implicit def asJavaIterator[A](i : Iterator[A]): ju.Iterator[A] = i match { case JIteratorWrapper(wrapped) => wrapped case _ => IteratorWrapper(i) } + @deprecated("use asJavaIterator instead") + def asIterator[A](i : Iterator[A]): ju.Iterator[A] = asJavaIterator[A](i) + /** * Implicitly converts a Scala <code>Iterator</code> to a Java <code>Enumeration</code>. * The returned Java <code>Enumeration</code> is backed by the provided Scala @@ -88,11 +91,14 @@ object JavaConversions { * @param i The <code>Iterator</code> to be converted. * @return A Java <code>Enumeration</code> view of the argument. */ - implicit def asEnumeration[A](i : Iterator[A]): ju.Enumeration[A] = i match { + implicit def asJavaEnumeration[A](i : Iterator[A]): ju.Enumeration[A] = i match { case JEnumerationWrapper(wrapped) => wrapped case _ => IteratorWrapper(i) } + @deprecated("use asJavaEnmeration instead") + def asEnumeration[A](i : Iterator[A]): ju.Enumeration[A] = asJavaEnumeration[A](i) + /** * Implicitly converts a Scala <code>Iterable</code> to a Java <code>Iterable</code>. * The returned Java <code>Iterable</code> is backed by the provided Scala @@ -106,11 +112,14 @@ object JavaConversions { * @param i The <code>Iterable</code> to be converted. * @return A Java <code>Iterable</code> view of the argument. */ - implicit def asIterable[A](i : Iterable[A]): jl.Iterable[A] = i match { + implicit def asJavaIterable[A](i : Iterable[A]): jl.Iterable[A] = i match { case JIterableWrapper(wrapped) => wrapped case _ => IterableWrapper(i) } + @deprecated("use asJavaIterable instead") + def asIterable[A](i : Iterable[A]): jl.Iterable[A] = asJavaIterable[A](i) + /** * Implicitly converts a Scala <code>Iterable</code> to an immutable Java * <code>Collection</code>. @@ -122,11 +131,14 @@ object JavaConversions { * @param i The <code>SizedIterable</code> to be converted. * @return A Java <code>Collection</code> view of the argument. */ - implicit def asCollection[A](i : Iterable[A]): ju.Collection[A] = i match { + implicit def asJavaCollection[A](i : Iterable[A]): ju.Collection[A] = i match { case JCollectionWrapper(wrapped) => wrapped case _ => new IterableWrapper(i) } + @deprecated("use asJavaCollection instead") + def asCollection[A](i : Iterable[A]): ju.Collection[A] = asJavaCollection[A](i) + /** * Implicitly converts a Scala mutable <code>Buffer</code> to a Java <code>List</code>. * The returned Java <code>List</code> is backed by the provided Scala @@ -140,11 +152,14 @@ object JavaConversions { * @param b The <code>Buffer</code> to be converted. * @return A Java <code>List</code> view of the argument. */ - implicit def asList[A](b : mutable.Buffer[A]): ju.List[A] = b match { + implicit def asJavaList[A](b : mutable.Buffer[A]): ju.List[A] = b match { case JListWrapper(wrapped) => wrapped case _ => new MutableBufferWrapper(b) } + @deprecated("use asJavaList instead") + def asList[A](b : mutable.Buffer[A]): ju.List[A] = asJavaList[A](b) + /** * Implicitly converts a Scala mutable <code>Seq</code> to a Java <code>List</code>. * The returned Java <code>List</code> is backed by the provided Scala @@ -158,11 +173,14 @@ object JavaConversions { * @param b The <code>Seq</code> to be converted. * @return A Java <code>List</code> view of the argument. */ - implicit def asList[A](b : mutable.Seq[A]): ju.List[A] = b match { + implicit def asJavaList[A](b : mutable.Seq[A]): ju.List[A] = b match { case JListWrapper(wrapped) => wrapped case _ => new MutableSeqWrapper(b) } + @deprecated("use asJavaList instead") + def asList[A](b : mutable.Seq[A]): ju.List[A] = asJavaList[A](b) + /** * Implicitly converts a Scala <code>Seq</code> to a Java <code>List</code>. * The returned Java <code>List</code> is backed by the provided Scala @@ -174,14 +192,16 @@ object JavaConversions { * Java <code>List</code> will be returned. * * @param b The <code>Seq</code> to be converted. - * @return A Java <code>List</co * -de> view of the argument. + * @return A Java <code>List</code> view of the argument. */ - implicit def asList[A](b : Seq[A]): ju.List[A] = b match { + implicit def asJavaList[A](b : Seq[A]): ju.List[A] = b match { case JListWrapper(wrapped) => wrapped case _ => new SeqWrapper(b) } + @deprecated("use asJavaList instead") + def asList[A](b : Seq[A]): ju.List[A] = asJavaList[A](b) + /** * Implicitly converts a Scala mutable <code>Set</code> to a Java <code>Set</code>. * The returned Java <code>Set</code> is backed by the provided Scala @@ -195,11 +215,14 @@ de> view of the argument. * @param s The <code>Set</code> to be converted. * @return A Java <code>Set</code> view of the argument. */ - implicit def asSet[A](s : mutable.Set[A]): ju.Set[A] = s match { + implicit def asJavaSet[A](s : mutable.Set[A]): ju.Set[A] = s match { case JSetWrapper(wrapped) => wrapped case _ => new MutableSetWrapper(s) } + @deprecated("use asJavaSet instead") + def asSet[A](s : mutable.Set[A]): ju.Set[A] = asJavaSet[A](s) + /** * Implicitly converts a Scala <code>Set</code> to a Java <code>Set</code>. * The returned Java <code>Set</code> is backed by the provided Scala @@ -213,11 +236,14 @@ de> view of the argument. * @param s The <code>Set</code> to be converted. * @return A Java <code>Set</code> view of the argument. */ - implicit def asSet[A](s: Set[A]): ju.Set[A] = s match { + implicit def asJavaSet[A](s: Set[A]): ju.Set[A] = s match { case JSetWrapper(wrapped) => wrapped case _ => new SetWrapper(s) } + @deprecated("use asJavaSet instead") + def asSet[A](s : Set[A]): ju.Set[A] = asJavaSet[A](s) + /** * Implicitly converts a Scala mutable <code>Map</code> to a Java <code>Map</code>. * The returned Java <code>Map</code> is backed by the provided Scala @@ -231,12 +257,15 @@ de> view of the argument. * @param m The <code>Map</code> to be converted. * @return A Java <code>Map</code> view of the argument. */ - implicit def asMap[A, B](m : mutable.Map[A, B]): ju.Map[A, B] = m match { + implicit def asJavaMap[A, B](m : mutable.Map[A, B]): ju.Map[A, B] = m match { //case JConcurrentMapWrapper(wrapped) => wrapped case JMapWrapper(wrapped) => wrapped case _ => new MutableMapWrapper(m) } + @deprecated("use asJavaMap instead") + def asMap[A, B](m : mutable.Map[A, B]): ju.Map[A, B] = asJavaMap[A, B](m) + /** * Implicitly converts a Scala mutable <code>Map</code> to a Java <code>Dictionary</code>. * The returned Java <code>Dictionary</code> is backed by the provided Scala @@ -250,24 +279,14 @@ de> view of the argument. * @param m The <code>Map</code> to be converted. * @return A Java <code>Dictionary</code> view of the argument. */ - implicit def asDictionary[A, B](m : mutable.Map[A, B]): ju.Dictionary[A, B] = m match { + implicit def asJavaDictionary[A, B](m : mutable.Map[A, B]): ju.Dictionary[A, B] = m match { //case JConcurrentMapWrapper(wrapped) => wrapped case JDictionaryWrapper(wrapped) => wrapped case _ => new DictionaryWrapper(m) } - /** - * Implicitly converts a Java <code>Properties</code> to a Scala mutable <code>Map[String, String]</code>. - * The returned Scala <code>Map[String, String]</code> is backed by the provided Java - * <code>Properties</code> and any side-effects of using it via the Scala interface will - * be visible via the Java interface and vice versa. - * - * @param m The <code>Properties</code> to be converted. - * @return A Scala mutable <code>Map[String, String]</code> view of the argument. - */ - implicit def asMap(p: ju.Properties): mutable.Map[String, String] = p match { - case _ => new JPropertiesWrapper(p) - } + @deprecated("use asJavaDictionary instead") + def asDictionary[A, B](m : mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary[A, B](m) /** * Implicitly converts a Scala <code>Map</code> to a Java <code>Map</code>. @@ -282,12 +301,15 @@ de> view of the argument. * @param m The <code>Map</code> to be converted. * @return A Java <code>Map</code> view of the argument. */ - implicit def asMap[A, B](m : Map[A, B]): ju.Map[A, B] = m match { + implicit def asJavaMap[A, B](m : Map[A, B]): ju.Map[A, B] = m match { //case JConcurrentMapWrapper(wrapped) => wrapped case JMapWrapper(wrapped) => wrapped case _ => new MapWrapper(m) } + @deprecated("use asJavaMap instead") + def asMap[A, B](m : Map[A, B]): ju.Map[A, B] = asJavaMap[A, B](m) + /** * Implicitly converts a Scala mutable `ConcurrentMap` to a Java `ConcurrentMap`. * The returned Java `ConcurrentMap` is backed by the provided Scala `ConcurrentMap` @@ -297,12 +319,18 @@ de> view of the argument. * If the Scala <code>ConcurrentMap</code> was previously obtained from an implicit or * explicit call of <code>asConcurrentMap(java.util.concurrect.ConcurrentMap)</code> then the original * Java <code>ConcurrentMap</code> will be returned. + * + * @param m The <code>ConcurrentMap</code> to be converted. + * @return A Java <code>ConcurrentMap</code> view of the argument. */ - implicit def asConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match { + implicit def asJavaConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match { case JConcurrentMapWrapper(wrapped) => wrapped case _ => new ConcurrentMapWrapper(m) } + @deprecated("use asJavaConcurrentMap instead") + def asConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = asJavaConcurrentMap[A, B](m) + // Java => Scala /** @@ -318,11 +346,14 @@ de> view of the argument. * @param i The <code>Iterator</code> to be converted. * @return A Scala <code>Iterator</code> view of the argument. */ - implicit def asIterator[A](i : ju.Iterator[A]): Iterator[A] = i match { + implicit def asScalaIterator[A](i : ju.Iterator[A]): Iterator[A] = i match { case IteratorWrapper(wrapped) => wrapped case _ => JIteratorWrapper(i) } + @deprecated("use asScalaIterator instead") + def asIterator[A](i : ju.Iterator[A]): Iterator[A] = asScalaIterator[A](i) + /** * Implicitly converts a Java <code>Enumeration</code> to a Scala <code>Iterator</code>. * The returned Scala <code>Iterator</code> is backed by the provided Java @@ -336,11 +367,14 @@ de> view of the argument. * @param i The <code>Enumeration</code> to be converted. * @return A Scala <code>Iterator</code> view of the argument. */ - implicit def asIterator[A](i : ju.Enumeration[A]): Iterator[A] = i match { + implicit def enumerationAsScalaIterator[A](i : ju.Enumeration[A]): Iterator[A] = i match { case IteratorWrapper(wrapped) => wrapped case _ => JEnumerationWrapper(i) } + @deprecated("use enumerationAsScalaIterator instead") + def asIterator[A](i : ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator[A](i) + /** * Implicitly converts a Java <code>Iterable</code> to a Scala <code>Iterable</code>. * The returned Scala <code>Iterable</code> is backed by the provided Java @@ -354,11 +388,14 @@ de> view of the argument. * @param i The <code>Iterable</code> to be converted. * @return A Scala <code>Iterable</code> view of the argument. */ - implicit def asIterable[A](i : jl.Iterable[A]): Iterable[A] = i match { + implicit def asScalaIterable[A](i : jl.Iterable[A]): Iterable[A] = i match { case IterableWrapper(wrapped) => wrapped case _ => JIterableWrapper(i) } + @deprecated("use asScalaIterable instead") + def asIterable[A](i : jl.Iterable[A]): Iterable[A] = asScalaIterable[A](i) + /** * Implicitly converts a Java <code>Collection</code> to an Scala <code>Iterable</code>. * <p> @@ -369,11 +406,14 @@ de> view of the argument. * @param i The <code>Collection</code> to be converted. * @return A Scala <code>SizedIterable</code> view of the argument. */ - implicit def asIterable[A](i : ju.Collection[A]): Iterable[A] = i match { + implicit def asScalaIterable[A](i : ju.Collection[A]): Iterable[A] = i match { case IterableWrapper(wrapped) => wrapped case _ => JCollectionWrapper(i) } + @deprecated("use asScalaIterable instead") + def asIterable[A](i : ju.Collection[A]): Iterable[A] = asScalaIterable[A](i) + /** * Implicitly converts a Java <code>List</code> to a Scala mutable <code>Buffer</code>. * The returned Scala <code>Buffer</code> is backed by the provided Java @@ -387,11 +427,14 @@ de> view of the argument. * @param l The <code>List</code> to be converted. * @return A Scala mutable <code>Buffer</code> view of the argument. */ - implicit def asBuffer[A](l : ju.List[A]): mutable.Buffer[A] = l match { + implicit def asScalaBuffer[A](l : ju.List[A]): mutable.Buffer[A] = l match { case MutableBufferWrapper(wrapped) => wrapped case _ =>new JListWrapper(l) } + @deprecated("use asScalaBuffer instead") + def asBuffer[A](l : ju.List[A]): mutable.Buffer[A] = asScalaBuffer[A](l) + /** * Implicitly converts a Java <code>Set</code> to a Scala mutable <code>Set</code>. * The returned Scala <code>Set</code> is backed by the provided Java @@ -405,11 +448,14 @@ de> view of the argument. * @param s The <code>Set</code> to be converted. * @return A Scala mutable <code>Set</code> view of the argument. */ - implicit def asSet[A](s : ju.Set[A]): mutable.Set[A] = s match { + implicit def asScalaSet[A](s : ju.Set[A]): mutable.Set[A] = s match { case MutableSetWrapper(wrapped) => wrapped case _ =>new JSetWrapper(s) } + @deprecated("use asScalaSet instead") + def asSet[A](s : ju.Set[A]): mutable.Set[A] = asScalaSet[A](s) + /** * Implicitly converts a Java <code>Map</code> to a Scala mutable <code>Map</code>. * The returned Scala <code>Map</code> is backed by the provided Java @@ -423,12 +469,15 @@ de> view of the argument. * @param m The <code>Map</code> to be converted. * @return A Scala mutable <code>Map</code> view of the argument. */ - implicit def asMap[A, B](m : ju.Map[A, B]): mutable.Map[A, B] = m match { + implicit def asScalaMap[A, B](m : ju.Map[A, B]): mutable.Map[A, B] = m match { //case ConcurrentMapWrapper(wrapped) => wrapped case MutableMapWrapper(wrapped) => wrapped case _ => new JMapWrapper(m) } + @deprecated("use asScalaMap instead") + def asMap[A, B](m : ju.Map[A, B]): mutable.Map[A, B] = asScalaMap[A, B](m) + /** * Implicitly converts a Java <code>ConcurrentMap</code> to a Scala mutable <code>ConcurrentMap</code>. * The returned Scala <code>ConcurrentMap</code> is backed by the provided Java @@ -442,11 +491,14 @@ de> view of the argument. * @param m The <code>ConcurrentMap</code> to be converted. * @return A Scala mutable <code>ConcurrrentMap</code> view of the argument. */ - implicit def asConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { + implicit def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying case _ => new JConcurrentMapWrapper(m) } + @deprecated("use asScalaConcurrentMap instead") + def asConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = asScalaConcurrentMap[A, B](m) + /** * Implicitly converts a Java <code>Dictionary</code> to a Scala mutable <code>Map[String, String]</code>. * The returned Scala <code>Map[String, String]</code> is backed by the provided Java @@ -456,12 +508,31 @@ de> view of the argument. * @param m The <code>Dictionary</code> to be converted. * @return A Scala mutable <code>Map[String, String]</code> view of the argument. */ - implicit def asMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { + implicit def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { case DictionaryWrapper(wrapped) => wrapped case _ => new JDictionaryWrapper(p) } - // Private implementations ... + @deprecated("use dictionaryAsScalaMap instead") + def asMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap[A, B](p) + + /** + * Implicitly converts a Java <code>Properties</code> to a Scala mutable <code>Map[String, String]</code>. + * The returned Scala <code>Map[String, String]</code> is backed by the provided Java + * <code>Properties</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * + * @param m The <code>Properties</code> to be converted. + * @return A Scala mutable <code>Map[String, String]</code> view of the argument. + */ + implicit def asScalaMap(p: ju.Properties): mutable.Map[String, String] = p match { + case _ => new JPropertiesWrapper(p) + } + + @deprecated("use asScalaMap instead") + def asMap(p: ju.Properties): mutable.Map[String, String] = asScalaMap(p) + + // Private implementations (shared by JavaConverters) ... case class IteratorWrapper[A](underlying : Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] { def hasNext = underlying.hasNext @@ -471,6 +542,10 @@ de> view of the argument. def remove = throw new UnsupportedOperationException } + class ToIteratorWrapper[A](underlying : Iterator[A]) { + def asJava = new IteratorWrapper(underlying) + } + case class JIteratorWrapper[A](underlying : ju.Iterator[A]) extends Iterator[A] { def hasNext = underlying.hasNext def next = underlying.next @@ -751,8 +826,8 @@ de> view of the argument. extends ju.Dictionary[A, B] { def size: Int = underlying.size def isEmpty: Boolean = underlying.isEmpty - def keys: ju.Enumeration[A] = asEnumeration(underlying.keysIterator) - def elements: ju.Enumeration[B] = asEnumeration(underlying.valuesIterator) + def keys: ju.Enumeration[A] = asJavaEnumeration(underlying.keysIterator) + def elements: ju.Enumeration[B] = asJavaEnumeration(underlying.valuesIterator) def get(key: AnyRef) = try { underlying.get(key.asInstanceOf[A]) match { case None => null.asInstanceOf[B] @@ -800,7 +875,7 @@ de> view of the argument. if (r != null) Some(r) else None } - def iterator = asIterator(underlying.keys) map (k => (k, underlying get k)) + def iterator = enumerationAsScalaIterator(underlying.keys) map (k => (k, underlying get k)) override def clear() = underlying.clear() } diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala new file mode 100755 index 0000000000..cb4c56fd59 --- /dev/null +++ b/src/library/scala/collection/JavaConverters.scala @@ -0,0 +1,456 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + + +package scala.collection + +/** <p> + * A collection of decorators that allow to convert between + * Scala and Java collections using `asScala` and `asJava` methods. + * </p> + * <p> + * The following conversions are supported via `asJava`, `asScala` + * </p> + * <ul> + * <li><code>scala.collection.Iterable</code> <=> <code>java.lang.Iterable</code></li> + * <li><code>scala.collection.Iterator</code> <=> <code>java.util.Iterator</code></li> + * <li><code>scala.collection.mutable.Buffer</code> <=> <code>java.util.List</code></li> + * <li><code>scala.collection.mutable.Set</code> <=> <code>java.util.Set</code></li> + * <li><code>scala.collection.mutable.Map</code> <=> <code>java.util.Map</code></li> + * <li><code>scala.collection.mutable.ConcurrentMap</code> <=> <code>java.util.concurrent.ConcurrentMap</code></li> + * </ul> + * <p> + * In all cases, converting from a source type to a target type and back + * again will return the original source object, e.g. + * </p> + * <pre> + * <b>import</b> scala.collection.JavaConverters._ + * + * <b>val</b> sl = <b>new</b> scala.collection.mutable.ListBuffer[Int] + * <b>val</b> jl : java.util.List[Int] = sl.asJava + * <b>val</b> sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala + * assert(sl eq sl2)g</pre> + * <p> + * <p> + * The following conversions also are supported, but the + * direction Scala to Java is done my a more specifically named method: + * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`. + * </p> + * <ul> + * <li><code>scala.collection.Iterable</code> <=> <code>java.util.Collection</code></li> + * <li><code>scala.collection.Iterator</code> <=> <code>java.util.Enumeration</code></li> + * <li><code>scala.collection.mutable.Map</code> <=> <code>java.util.Dictionary</code></li> + * </ul> + * In addition, the following one way conversions are provided via `asJava`: + * </p> + * <ul> + * <li><code>scala.collection.Seq => <code>java.util.List }</code></li> + * <li><code>scala.collection.mutable.Seq => <code>java.util.List</code></li> + * <li><code>scala.collection.Set</code> => <code>java.util.Set</code></li> + * <li><code>scala.collection.Map</code> => <code>java.util.Map</code></li> + * </ul> + * + * @author Martin Odersky + * @since 2.8.1 + */ +object JavaConverters { + import java.{ lang => jl, util => ju } + import java.util.{ concurrent => juc } + import JavaConversions._ + + // Conversion decorator classes + + /** Generic class containing the `asJava` converter method */ + class AsJava[C](op: => C) { + /** Converts a Scala collection to the corresponding Java collection */ + def asJava: C = op + } + + /** Generic class containing the `asScala` converter method */ + class AsScala[C](op: => C) { + /** Converts a Java collection to the corresponding Scala collection */ + def asScala: C = op + } + + /** Generic class containing the `asJavaCollection` converter method */ + class AsJavaCollection[A](i: Iterable[A]) { + /** Converts a Scala `Iterable` to a Java `Collection` */ + def asJavaCollection: ju.Collection[A] = JavaConversions.asJavaCollection(i) + } + + /** Generic class containing the `asJavaEnumeration` converter method */ + class AsJavaEnumeration[A](i: Iterator[A]) { + /** Converts a Scala `Iterator` to a Java `Enumeration` */ + def asJavaEnumeration: ju.Enumeration[A] = JavaConversions.asJavaEnumeration(i) + } + + /** Generic class containing the `asJavaDictionary` converter method */ + class AsJavaDictionary[A, B](m : mutable.Map[A, B]) { + /** Converts a Scala `Map` to a Java `Dictionary` */ + def asJavaDictionary: ju.Dictionary[A, B] = JavaConversions.asJavaDictionary(m) + } + + // Scala => Java + + /** + * Adds an `asJava` method that implicitly converts a Scala <code>Iterator</code> to a Java <code>Iterator</code>. + * The returned Java <code>Iterator</code> is backed by the provided Scala + * <code>Iterator</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Iterator</code> was previously obtained from an implicit or + * explicit call of <code>asIterator(java.util.Iterator)</code> then the original + * Java <code>Iterator</code> will be returned by the `asJava` method. + * + * @param i The <code>Iterator</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>Iterator</code> view of the argument. + */ + implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] = + new AsJava(asJavaIterator(i)) + + /** + * Adds an `asJavaEnumeration` method that implicitly converts a Scala <code>Iterator</code> to a Java <code>Enumeration</code>. + * The returned Java <code>Enumeration</code> is backed by the provided Scala + * <code>Iterator</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Iterator</code> was previously obtained from an implicit or + * explicit call of <code>asIterator(java.util.Enumeration)</code> then the + * original Java <code>Enumeration</code> will be returned. + * + * @param i The <code>Iterator</code> to be converted. + * @return An object with an `asJavaEnumeration` method that returns a Java <code>Enumeration</code> view of the argument. + */ + implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] = + new AsJavaEnumeration(i) + + /** + * Adds an `asJava` method that implicitly converts a Scala <code>Iterable</code> to a Java <code>Iterable</code>. + * The returned Java <code>Iterable</code> is backed by the provided Scala + * <code>Iterable</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Iterable</code> was previously obtained from an implicit or + * explicit call of <code>asIterable(java.lang.Iterable)</code> then the original + * Java <code>Iterable</code> will be returned. + * + * @param i The <code>Iterable</code> to be converted. + * @return An object with an `asJavaCollection` method that returns a Java <code>Iterable</code> view of the argument. + */ + implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] = + new AsJava(asJavaIterable(i)) + + /** + * Adds an `asJavaCollection` method that implicitly converts a Scala <code>Iterable</code> to an immutable Java + * <code>Collection</code>. + * <p> + * If the Scala <code>Iterable</code> was previously obtained from an implicit or + * explicit call of <code>asSizedIterable(java.util.Collection)</code> then the original + * Java <code>Collection</code> will be returned. + * + * @param i The <code>SizedIterable</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>Collection</code> view of the argument. + */ + implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] = + new AsJavaCollection(i) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable <code>Buffer</code> to a Java <code>List</code>. + * The returned Java <code>List</code> is backed by the provided Scala + * <code>Buffer</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Buffer</code> was previously obtained from an implicit or + * explicit call of <code>asBuffer(java.util.List)</code> then the original + * Java <code>List</code> will be returned. + * + * @param b The <code>Buffer</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>List</code> view of the argument. + */ + implicit def asJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] = + new AsJava(asJavaList(b)) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable <code>Seq</code> to a Java <code>List</code>. + * The returned Java <code>List</code> is backed by the provided Scala + * <code>Seq</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Seq</code> was previously obtained from an implicit or + * explicit call of <code>asSeq(java.util.List)</code> then the original + * Java <code>List</code> will be returned. + * + * @param b The <code>Seq</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>List</code> view of the argument. + */ + implicit def asJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] = + new AsJava(asJavaList(b)) + + /** + * Adds an `asJava` method that implicitly converts a Scala <code>Seq</code> to a Java <code>List</code>. + * The returned Java <code>List</code> is backed by the provided Scala + * <code>Seq</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Seq</code> was previously obtained from an implicit or + * explicit call of <code>asSeq(java.util.List)</code> then the original + * Java <code>List</code> will be returned. + * + * @param b The <code>Seq</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>List</code> view of the argument. + */ + implicit def asJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] = + new AsJava(asJavaList(b)) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable <code>Set</code> to a Java <code>Set</code>. + * The returned Java <code>Set</code> is backed by the provided Scala + * <code>Set</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Set</code> was previously obtained from an implicit or + * explicit call of <code>asSet(java.util.Set)</code> then the original + * Java <code>Set</code> will be returned. + * + * @param s The <code>Set</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>Set</code> view of the argument. + */ + implicit def asJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] = + new AsJava(asJavaSet(s)) + + /** + * Adds an `asJava` method that implicitly converts a Scala <code>Set</code> to a Java <code>Set</code>. + * The returned Java <code>Set</code> is backed by the provided Scala + * <code>Set</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Set</code> was previously obtained from an implicit or + * explicit call of <code>asSet(java.util.Set)</code> then the original + * Java <code>Set</code> will be returned. + * + * @param s The <code>Set</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>Set</code> view of the argument. + */ + implicit def asJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] = + new AsJava(asJavaSet(s)) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable <code>Map</code> to a Java <code>Map</code>. + * The returned Java <code>Map</code> is backed by the provided Scala + * <code>Map</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Map</code> was previously obtained from an implicit or + * explicit call of <code>asMap(java.util.Map)</code> then the original + * Java <code>Map</code> will be returned. + * + * @param m The <code>Map</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>Map</code> view of the argument. + */ + implicit def asJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] = + new AsJava(asJavaMap(m)) + + /** + * Adds an `asJavaDictionary` method that implicitly converts a Scala mutable <code>Map</code> to a Java <code>Dictionary</code>. + * The returned Java <code>Dictionary</code> is backed by the provided Scala + * <code>Dictionary</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Dictionary</code> was previously obtained from an implicit or + * explicit call of <code>asMap(java.util.Dictionary)</code> then the original + * Java <code>Dictionary</code> will be returned. + * + * @param m The <code>Map</code> to be converted. + * @return An object with an `asJavaDictionary` method that returns a Java <code>Dictionary</code> view of the argument. + */ + implicit def asJavaDictionaryConverter[A, B](m : mutable.Map[A, B]): AsJavaDictionary[A, B] = + new AsJavaDictionary(m) + + /** + * Adds an `asJava` method that implicitly converts a Scala <code>Map</code> to a Java <code>Map</code>. + * The returned Java <code>Map</code> is backed by the provided Scala + * <code>Map</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Map</code> was previously obtained from an implicit or + * explicit call of <code>asMap(java.util.Map)</code> then the original + * Java <code>Map</code> will be returned. + * + * @param m The <code>Map</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>Map</code> view of the argument. + */ + implicit def asJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] = + new AsJava(asJavaMap(m)) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable `ConcurrentMap` to a Java `ConcurrentMap`. + * The returned Java `ConcurrentMap` is backed by the provided Scala `ConcurrentMap` + * and any side-effects of using it via the Java interface will be visible + * via the Scala interface and vice versa. + * <p> + * If the Scala <code>ConcurrentMap</code> was previously obtained from an implicit or + * explicit call of <code>asConcurrentMap(java.util.concurrect.ConcurrentMap)</code> then the original + * Java <code>ConcurrentMap</code> will be returned. + * + * @param m The <code>ConcurrentMap</code> to be converted. + * @return An object with an `asJava` method that returns a Java <code>ConcurrentMap</code> view of the argument. + */ + implicit def asJavaConcurrentMapConverter[A, B](m: mutable.ConcurrentMap[A, B]): AsJava[juc.ConcurrentMap[A, B]] = + new AsJava(asJavaConcurrentMap(m)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Iterator</code> to a Scala <code>Iterator</code>. + * The returned Scala <code>Iterator</code> is backed by the provided Java + * <code>Iterator</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>Iterator</code> was previously obtained from an implicit or + * explicit call of <code>asIterator(scala.collection.Iterator)</code> then the original + * Scala <code>Iterator</code> will be returned. + * + * @param i The <code>Iterator</code> to be converted. + * @return An object with an `asScala` method that returns a Scala <code>Iterator</code> view of the argument. + */ + implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] = + new AsScala(asScalaIterator(i)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Enumeration</code> to a Scala <code>Iterator</code>. + * The returned Scala <code>Iterator</code> is backed by the provided Java + * <code>Enumeration</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>Enumeration</code> was previously obtained from an implicit or + * explicit call of <code>asEnumeration(scala.collection.Iterator)</code> then the + * original Scala <code>Iterator</code> will be returned. + * + * @param i The <code>Enumeration</code> to be converted. + * @return An object with an `asScala` method that returns a Scala <code>Iterator</code> view of the argument. + */ + implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] = + new AsScala(enumerationAsScalaIterator(i)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Iterable</code> to a Scala <code>Iterable</code>. + * The returned Scala <code>Iterable</code> is backed by the provided Java + * <code>Iterable</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>Iterable</code> was previously obtained from an implicit or + * explicit call of <code>asIterable(scala.collection.Iterable)</code> then the original + * Scala <code>Iterable</code> will be returned. + * + * @param i The <code>Iterable</code> to be converted. + * @return An object with an `asScala` method that returns a Scala <code>Iterable</code> view of the argument. + */ + implicit def asScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] = + new AsScala(asScalaIterable(i)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Collection</code> to an Scala <code>Iterable</code>. + * <p> + * If the Java <code>Collection</code> was previously obtained from an implicit or + * explicit call of <code>asCollection(scala.collection.SizedIterable)</code> then + * the original Scala <code>SizedIterable</code> will be returned. + * + * @param i The <code>Collection</code> to be converted. + * @return An object with an `asScala` method that returns a Scala <code>SizedIterable</code> view of the argument. + */ + implicit def asScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] = + new AsScala(asScalaIterable(i)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>List</code> to a Scala mutable <code>Buffer</code>. + * The returned Scala <code>Buffer</code> is backed by the provided Java + * <code>List</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>List</code> was previously obtained from an implicit or + * explicit call of <code>asList(scala.collection.mutable.Buffer)</code> then the original + * Scala <code>Buffer</code> will be returned. + * + * @param l The <code>List</code> to be converted. + * @return An object with an `asScala` method that returns a Scala mutable <code>Buffer</code> view of the argument. + */ + implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] = + new AsScala(asScalaBuffer(l)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Set</code> to a Scala mutable <code>Set</code>. + * The returned Scala <code>Set</code> is backed by the provided Java + * <code>Set</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>Set</code> was previously obtained from an implicit or + * explicit call of <code>asSet(scala.collection.mutable.Set)</code> then the original + * ScalaThe reported problems have to do with dependent method types, which is currently an experimental feature in Scala and is still under development. We emphasize that these problems are related to type-inference and, as stated in the paper, it is possible to run and type-check the programs with additional annotations. <code>Set</code> will be returned. + * + * @param s The <code>Set</code> to be converted. + * @return An object with an `asScala` method that returns a Scala mutable <code>Set</code> view of the argument. + */ + implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] = + new AsScala(asScalaSet(s)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Map</code> to a Scala mutable <code>Map</code>. + * The returned Scala <code>Map</code> is backed by the provided Java + * <code>Map</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>Map</code> was previously obtained from an implicit or + * explicit call of <code>asMap(scala.collection.mutable.Map)</code> then the original + * Scala <code>Map</code> will be returned. + * + * @param m The <code>Map</code> to be converted. + * @return An object with an `asScala` method that returns a Scala mutable <code>Map</code> view of the argument. + */ + implicit def asScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] = + new AsScala(asScalaMap(m)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>ConcurrentMap</code> to a Scala mutable <code>ConcurrentMap</code>. + * The returned Scala <code>ConcurrentMap</code> is backed by the provided Java + * <code>ConcurrentMap</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * <p> + * If the Java <code>ConcurrentMap</code> was previously obtained from an implicit or + * explicit call of <code>asConcurrentMap(scala.collection.mutable.ConcurrentMap)</code> then the original + * Scala <code>ConcurrentMap</code> will be returned. + * + * @param m The <code>ConcurrentMap</code> to be converted. + * @return An object with an `asScala` method that returns a Scala mutable <code>ConcurrrentMap</code> view of the argument. + */ + implicit def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] = + new AsScala(asScalaConcurrentMap(m)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Dictionary</code> to a Scala mutable <code>Map[String, String]</code>. + * The returned Scala <code>Map[String, String]</code> is backed by the provided Java + * <code>Dictionary</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * + * @param m The <code>Dictionary</code> to be converted. + * @return An object with an `asScala` method that returns a Scala mutable <code>Map[String, String]</code> view of the argument. + */ + implicit def dictionaryAsScalaMapConverter[A, B](p: ju.Dictionary[A, B]): AsScala[mutable.Map[A, B]] = + new AsScala(dictionaryAsScalaMap(p)) + + /** + * Adds an `asScala` method that implicitly converts a Java <code>Properties</code> to a Scala mutable <code>Map[String, String]</code>. + * The returned Scala <code>Map[String, String]</code> is backed by the provided Java + * <code>Properties</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * + * @param m The <code>Properties</code> to be converted. + * @return An object with an `asScala` method that returns a Scala mutable <code>Map[String, String]</code> view of the argument. + */ + implicit def asScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = + new AsScala(asScalaMap(p)) + +} diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index b6c0ce146e..6656b05083 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -277,7 +277,7 @@ trait TraversableOnce[+A] { * @tparam B the result type of the `+` operator. * @return the sum of all elements of this $coll with respect to the `+` operator in `num`. * - * @usecase def sum: Int + * @usecase def sum: A * * @return the sum of all elements in this $coll of numbers of type `Int`. * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation @@ -294,7 +294,7 @@ trait TraversableOnce[+A] { * @tparam B the result type of the `*` operator. * @return the product of all elements of this $coll with respect to the `*` operator in `num`. * - * @usecase def product: Int + * @usecase def product: A * * @return the product of all elements in this $coll of numbers of type `Int`. * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation @@ -442,6 +442,9 @@ trait TraversableOnce[+A] { * is undefined. * $willNotTerminateInf * @return a map containing all elements of this $coll. + * @usecase def toMap: Map[K, V] + * @return a map of type `immutable.Map[K, V]` + * containing all key/value pairs of type `(K, V)` of this $coll. */ def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = { val b = immutable.Map.newBuilder[T, U] diff --git a/src/library/scala/collection/generic/GenericTraversableTemplate.scala b/src/library/scala/collection/generic/GenericTraversableTemplate.scala index 54f4a07c10..5f009b6742 100644 --- a/src/library/scala/collection/generic/GenericTraversableTemplate.scala +++ b/src/library/scala/collection/generic/GenericTraversableTemplate.scala @@ -51,6 +51,7 @@ trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBui def isEmpty: Boolean /** The factory companion object that builds instances of class $Coll. + * (or its `Iterable` superclass where class $Coll is not a `Seq`.) */ def companion: GenericCompanion[CC] diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index d7072c0661..00e8697b53 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -10,6 +10,7 @@ package scala.collection package mutable +import compat.Platform.arraycopy import scala.reflect.ClassManifest @@ -38,6 +39,13 @@ abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] { ClassManifest.fromClass( repr.getClass.getComponentType.getComponentType.asInstanceOf[Predef.Class[U]])) + override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) { + var l = len + if (repr.length < l) l = repr.length + if (xs.length - start < l) l = xs.length - start max 0 + Array.copy(repr, 0, xs, start, l) + } + override def toArray[U >: T : ClassManifest]: Array[U] = if (implicitly[ClassManifest[U]].erasure eq repr.getClass.getComponentType) repr.asInstanceOf[Array[U]] diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala index 46dc415e1f..dce770ce43 100644 --- a/src/library/scala/concurrent/SyncVar.scala +++ b/src/library/scala/concurrent/SyncVar.scala @@ -13,7 +13,7 @@ package scala.concurrent /** The class <code>SyncVar</code> ... * - * @author Martin Odersky, Stepan Koltsov + * @author Martin Odersky * @version 1.0, 10/03/2003 */ class SyncVar[A] { diff --git a/src/library/scala/reflect/generic/UnPickler.scala b/src/library/scala/reflect/generic/UnPickler.scala index ee021446bc..54ac1acc3d 100755 --- a/src/library/scala/reflect/generic/UnPickler.scala +++ b/src/library/scala/reflect/generic/UnPickler.scala @@ -42,7 +42,7 @@ abstract class UnPickler { } } - /** To ne implemented in subclasses. Like `unpickle` but without the catch-all error handling. + /** To be implemented in subclasses. Like `unpickle` but without the catch-all error handling. */ def scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) diff --git a/src/library/scala/runtime/TraitSetter.java b/src/library/scala/runtime/TraitSetter.java new file mode 100755 index 0000000000..d9907c0ac0 --- /dev/null +++ b/src/library/scala/runtime/TraitSetter.java @@ -0,0 +1,6 @@ +package scala.runtime; + +/** A marker annotation to tag a setter of a mutable variable in a trait + */ +public @interface TraitSetter { +}
\ No newline at end of file diff --git a/test/files/neg/override.check b/test/files/neg/override.check new file mode 100644 index 0000000000..0336fb2b11 --- /dev/null +++ b/test/files/neg/override.check @@ -0,0 +1,5 @@ +override.scala:9: error: overriding type T in trait A with bounds >: Int <: Int; + type T in trait B with bounds >: String <: String has incompatible type + lazy val x : A with B = x + ^ +one error found diff --git a/test/files/neg/override.scala b/test/files/neg/override.scala new file mode 100755 index 0000000000..764b06603a --- /dev/null +++ b/test/files/neg/override.scala @@ -0,0 +1,15 @@ +trait X { + trait A { type T >: Int <: Int } + val x : A + var n : x.T = 3 +} + +trait Y extends X { + trait B { type T >: String <: String } + lazy val x : A with B = x + n = "foo" +} + +object Test extends Application { + new Y {} +} diff --git a/test/files/neg/t3774.check b/test/files/neg/t3774.check new file mode 100644 index 0000000000..d73166bff9 --- /dev/null +++ b/test/files/neg/t3774.check @@ -0,0 +1,7 @@ +t3774.scala:4: error: overloaded method value ++ with alternatives: + [B1 >: List[Int]](xs: scala.collection.TraversableOnce[((Int, Int), B1)])scala.collection.immutable.Map[(Int, Int),B1] <and> + [B >: ((Int, Int), List[Int]),That](that: scala.collection.TraversableOnce[B])(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Map[(Int, Int),List[Int]],B,That])That + cannot be applied to (scala.collection.immutable.IndexedSeq[((Int, Int), scala.collection.immutable.Range.Inclusive)]) + Map[(Int,Int),List[Int]]() ++ (for(x <- 0 to 1 ; y <- 0 to 1) yield {(x,y)-> (0 to 1)}) + ^ +one error found diff --git a/test/files/neg/t3774.scala b/test/files/neg/t3774.scala new file mode 100644 index 0000000000..2869925b01 --- /dev/null +++ b/test/files/neg/t3774.scala @@ -0,0 +1,5 @@ +// This used to hang the lub process. Now it rejects the file. This is still not correct, +// but we can solve this only after a redesign of lub a la dot. +object Hang { + Map[(Int,Int),List[Int]]() ++ (for(x <- 0 to 1 ; y <- 0 to 1) yield {(x,y)-> (0 to 1)}) +} diff --git a/test/files/neg/t3776.check b/test/files/neg/t3776.check new file mode 100644 index 0000000000..e8798df6f3 --- /dev/null +++ b/test/files/neg/t3776.check @@ -0,0 +1,4 @@ +t3776.scala:8: error: value someOperation is not a member of _$1 + def parsedAs[T](v: T) = MyParser.parse(pattern, a).get someOperation v + ^ +one error found diff --git a/test/files/neg/t3776.scala b/test/files/neg/t3776.scala new file mode 100644 index 0000000000..6e368165aa --- /dev/null +++ b/test/files/neg/t3776.scala @@ -0,0 +1,10 @@ +import util.parsing.combinator.{PackratParsers, RegexParsers} + +object MyParser extends RegexParsers with PackratParsers { +} + +object Test { + class ParsedAs(a: String) (implicit pattern: MyParser.Parser[_]) { + def parsedAs[T](v: T) = MyParser.parse(pattern, a).get someOperation v + } +} diff --git a/test/files/pos/t2133.scala b/test/files/pos/t2133.scala new file mode 100644 index 0000000000..c74d0a4bbf --- /dev/null +++ b/test/files/pos/t2133.scala @@ -0,0 +1,18 @@ +trait Foo { + object bar { + private[this] def fn() = 5 + } +} + +trait Foo2 { + object bip { + def fn() = 10 + } +} + +class Bob extends AnyRef with Foo with Foo2 { + import bip._ + import bar._ + + def go() = fn() +} diff --git a/test/files/pos/t3174.scala b/test/files/pos/t3174.scala new file mode 100755 index 0000000000..c3d90a4946 --- /dev/null +++ b/test/files/pos/t3174.scala @@ -0,0 +1,14 @@ +object test { + def method() { + class Foo extends AnyRef { + object Color { + object Blue + } + + class Board { + val grid = Color.Blue + } + } + new Foo + } + } diff --git a/test/files/pos/t3174b.scala b/test/files/pos/t3174b.scala new file mode 100755 index 0000000000..4df1bfe837 --- /dev/null +++ b/test/files/pos/t3174b.scala @@ -0,0 +1,12 @@ +trait Foo[X] { def foo : Map[String,Foo[X]] } + +object Test { + def f[T]() : Foo[T] = { + class Anon extends Foo[T] { + var foo: Map[String, Foo[T]] = Map[String,Foo[T]]() + //def foo = Map[String,Foo[T]]() + //def foo_=(x: Map[String,Foo[T]]) {} + } + new Anon + } +} diff --git a/test/files/pos/t3568.scala b/test/files/pos/t3568.scala new file mode 100755 index 0000000000..c8e3fcc4be --- /dev/null +++ b/test/files/pos/t3568.scala @@ -0,0 +1,46 @@ +import scala.annotation._ +import scala.annotation.unchecked._ +import scala.collection._ + + +package object buffer { + val broken = new ArrayVec2() // commenting out this line causes the file to compile. + + val works = Class.forName("buffer.ArrayVec2").newInstance().asInstanceOf[ArrayVec2] +} + +package buffer { + object Main { + // ArrayVec2 can be compiled, instantiated and used. + def main(args: Array[String]) { println(works) } + } + + trait ElemType { type Element; type Component <: ElemType } + trait Float1 extends ElemType { type Element = Float; type Component = Float1} + class Vec2 extends ElemType { type Element = Vec2; type Component = Float1 } + + abstract class BaseSeq[T <: ElemType, E] + extends IndexedSeq[E] with IndexedSeqOptimized[E, IndexedSeq[E]] { + def length = 1 + def apply(i: Int) :E + } + + abstract class GenericSeq[T <: ElemType] extends BaseSeq[T, T#Element] + trait DataArray[T <: ElemType] extends BaseSeq[T, T#Element] + trait DataView[T <: ElemType] extends BaseSeq[T, T#Element] + abstract class BaseFloat1 extends BaseSeq[Float1, Float] + + class ArrayFloat1 extends BaseFloat1 with DataArray[Float1] { + def apply(i: Int) :Float = 0f + } + + class ViewFloat1 extends BaseFloat1 with DataView[Float1] { + def apply(i: Int) :Float = 0f + } + + class ArrayVec2(val backingSeq: ArrayFloat1) + extends GenericSeq[Vec2] with DataArray[Vec2] { + def this() = this(new ArrayFloat1) + def apply(i: Int) :Vec2 = null + } +} diff --git a/test/files/pos/t3688.scala b/test/files/pos/t3688.scala new file mode 100644 index 0000000000..0ac1cfe514 --- /dev/null +++ b/test/files/pos/t3688.scala @@ -0,0 +1,9 @@ +import collection.mutable +import collection.JavaConversions._ +import java.{util => ju} + +object Test { + + implicitly[mutable.Map[Int, String] => ju.Dictionary[Int, String]] + +} diff --git a/test/files/run/t3763.scala b/test/files/run/t3763.scala new file mode 100644 index 0000000000..c8462b7437 --- /dev/null +++ b/test/files/run/t3763.scala @@ -0,0 +1,3 @@ +object Test extends Application { + val x = Array(Array(1), List(1)) +} diff --git a/test/files/run/weakconform.scala b/test/files/run/weakconform.scala new file mode 100755 index 0000000000..1ea81c9f64 --- /dev/null +++ b/test/files/run/weakconform.scala @@ -0,0 +1,4 @@ +object Test extends Application { + val x: Float = 10/3 + assert(x == 3.0) +} diff --git a/test/pending/run/t3609.scala b/test/pending/run/t3609.scala new file mode 100755 index 0000000000..262948137d --- /dev/null +++ b/test/pending/run/t3609.scala @@ -0,0 +1,11 @@ +object Test extends Application { + class A + class B extends A + def foo(x: A, y: B) = print(1) + val foo = new { + //def apply(x: B, y: A) = print(3) + def apply = (x: B, z: B) => print(4) + } + + foo(new B, new B) +} |