diff options
Diffstat (limited to 'src')
56 files changed, 811 insertions, 982 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index fd05229088..d101337087 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -74,11 +74,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def this(settings: Settings) = this(settings, new ConsoleReporter(settings)) - // fulfilling requirements - // Renamed AbstractFile to AbstractFileType for backward compatibility: - // it is difficult for sbt to work around the ambiguity errors which result. - type AbstractFileType = scala.tools.nsc.io.AbstractFile - def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = gen.mkAttributedQualifier(tpe, termSym) def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 085ce82025..bd5c9b2f68 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -48,12 +48,12 @@ trait Trees extends reflect.internal.Trees { self: Global => override def isType = definition.isType } - /** Array selection <qualifier> . <name> only used during erasure */ + /** Array selection `<qualifier> . <name>` only used during erasure */ case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type) extends RefTree with TermTree - /** Derived value class injection (equivalent to: new C(arg) after easure); only used during erasure - * The class C is stored as the symbol of the tree node. + /** Derived value class injection (equivalent to: `new C(arg)` after erasure); only used during erasure. + * The class `C` is stored as a tree attachment. */ case class InjectDerivedValue(arg: Tree) extends SymTree diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index e6bf43fe93..dd0f8fdbe0 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -754,8 +754,12 @@ trait Scanners extends ScannersCommon { } else { val isUnclosedLiteral = !isUnicodeEscape && (ch == SU || (!multiLine && (ch == CR || ch == LF))) if (isUnclosedLiteral) { - syntaxError(if (!multiLine) "unclosed string literal" else "unclosed multi-line string literal") - } else { + if (multiLine) + incompleteInputError("unclosed multi-line string literal") + else + syntaxError("unclosed string literal") + } + else { putChar(ch) nextRawChar() getStringPart(multiLine) diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index d3a5975a2a..24662e2ac3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -121,11 +121,13 @@ abstract class GenICode extends SubComponent { m.native = m.symbol.hasAnnotation(definitions.NativeAttr) if (!m.isAbstractMethod && !m.native) { - if (m.symbol.isAccessor && m.symbol.accessed.hasStaticAnnotation) { + val staticfield = if (m.symbol.isAccessor && m.symbol.accessed.hasStaticAnnotation) { + val compClass = m.symbol.owner.companionClass + compClass.info.findMember(m.symbol.accessed.name, NoFlags, NoFlags, false) + } else NoSymbol + if (staticfield != NoSymbol) { // in companion object accessors to @static fields, we access the static field directly val hostClass = m.symbol.owner.companionClass - val staticfield = hostClass.info.findMember(m.symbol.accessed.name, NoFlags, NoFlags, false) - if (m.symbol.isGetter) { ctx1.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos) ctx1.bb.closeWith(RETURN(m.returnType)) diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index 6acd6d2382..3de2359ce3 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -257,12 +257,18 @@ trait CompilerControl { self: Global => */ def askForResponse[A](op: () => A): Response[A] = { val r = new Response[A] - val ir = scheduler askDoQuickly op - ir onComplete { - case Left(result) => r set result - case Right(exc) => r raise exc + if (self.onCompilerThread) { + try { r set op() } + catch { case exc: Throwable => r raise exc } + r + } else { + val ir = scheduler askDoQuickly op + ir onComplete { + case Left(result) => r set result + case Right(exc) => r raise exc + } + r } - r } def onCompilerThread = Thread.currentThread == compileRunner diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index 2d93c77ca4..afac5828e5 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -133,50 +133,6 @@ object REPL { iSourceName } - /** Compile instrumented source file - * @param iSourceName The name of the instrumented source file - * @param arguments Further argumenrs to pass to the compiler - * @return Optionallu, if no -d option is given, the virtual directory - * contained the generated bytecode classes - def compileInstrumented(iSourceName: String, arguments: List[String]): Option[AbstractFile] = { - println("compiling "+iSourceName) - val command = new CompilerCommand(iSourceName :: arguments, reporter.error(scala.reflect.internal.util.NoPosition, _)) - val virtualDirectoryOpt = - if (arguments contains "-d") - None - else { - val vdir = new VirtualDirectory("(memory)", None) - command.settings.outputDirs setSingleOutput vdir - Some(vdir) - } - val compiler = new scala.tools.nsc.Global(command.settings, reporter) - val run = new compiler.Run() - println("compiling: "+command.files) - run compile command.files - virtualDirectoryOpt - } - - /** Run instrumented bytecode file - * @param vdir Optionally, the virtual directory containing the generated bytecode classes - * @param iFullName The full name of the generated object - * @param stripped The contents original source file without any right hand column comments. - * @return The generated file content containing original source in the left column - * and outputs in the right column - */ - def runInstrumented(vdirOpt: Option[AbstractFile], iFullName: String, stripped: Array[Char]): Array[Char] = { - val defaultClassLoader = getClass.getClassLoader - val classLoader = vdirOpt match { - case Some(vdir) => new AbstractFileClassLoader(vdir, defaultClassLoader) - case None => defaultClassLoader - } - println("running "+iFullName) - val si = new SourceInserter(stripped) - Executor.execute(iFullName, si, classLoader) - println("done") - si.currentContents - } - */ - /** The method for implementing worksheet functionality. * @param arguments a file name, followed by optional command line arguments that are passed * to the compiler that processes the instrumented source. @@ -191,7 +147,7 @@ object REPL { // strip right hand side comment column and any trailing spaces from all lines val strippedContents = SourceInserter.stripRight(source.content) val strippedSource = new BatchSourceFile(source.file, strippedContents) - println("stripped source = "+strippedSource) + println("stripped source = "+strippedSource+":"+strippedContents.mkString) comp.askReload(List(strippedSource), reloadResult) comp.askInstrumented(strippedSource, line, instrumentedResult) using(instrumentedResult) { diff --git a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala index 2aed99657e..0080cfd753 100644 --- a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala +++ b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala @@ -4,6 +4,7 @@ package interactive import scala.reflect.internal.util.{SourceFile, BatchSourceFile, RangePosition} import collection.mutable.ArrayBuffer import reflect.internal.Chars.{isLineBreakChar, isWhitespace} +import ast.parser.Tokens._ trait ScratchPadMaker { self: Global => @@ -11,7 +12,7 @@ trait ScratchPadMaker { self: Global => private case class Patch(offset: Int, text: String) - private class Patcher(contents: Array[Char], endOffset: Int) extends Traverser { + private class Patcher(contents: Array[Char], lex: LexicalStructure, endOffset: Int) extends Traverser { var objectName: String = "" private val patches = new ArrayBuffer[Patch] @@ -24,9 +25,13 @@ trait ScratchPadMaker { self: Global => "res$"+resNum } - private def nameType(name: String, tpe: Type): String = name+": "+tpe + private def nameType(name: String, tpe: Type): String = { + // if name ends in symbol character, add a space to separate it from the following ':' + val pad = if (Character.isLetter(name.last) || Character.isDigit(name.last)) "" else " " + name+pad+": "+tpe + } - private def nameType(sym: Symbol): String = nameType(sym.name.toString, sym.tpe) + private def nameType(sym: Symbol): String = nameType(sym.name.decoded, sym.tpe) private def literal(str: String) = "\"\"\""+str+"\"\"\"" @@ -42,19 +47,19 @@ trait ScratchPadMaker { self: Global => /** The position where to insert an instrumentation statement in front of giuven statement. * This is at the latest `stat.pos.start`. But in order not to mess with column numbers - * in position we try to insert it at the end of the preceding line instead. - * To be safe, this can be done only if there's only whitespace between that position and - * statement's start position. + * in position we try to insert it at the end of the previous token instead. + * Furthermore, `(' tokens have to be skipped because they do not show up + * in statement range positions. */ - private def instrumentPos(stat: Tree): Int = { - var start = stat.pos.start - while (start > 0 && isWhitespace(contents(start - 1))) start -= 1 - if (start > 0 && isLineBreakChar(contents(start - 1))) start -= 1 - start + private def instrumentPos(start: Int): Int = { + val (prevToken, prevStart, prevEnd) = lex.locate(start - 1) + if (prevStart >= start) start + else if (prevToken == LPAREN) instrumentPos(prevStart) + else prevEnd } private def addSkip(stat: Tree): Unit = { - val ipos = instrumentPos(stat) + val ipos = instrumentPos(stat.pos.start) if (stat.pos.start > skipped) applyPendingPatches(ipos) if (stat.pos.start >= endOffset) patches += Patch(ipos, ";$stop()") @@ -98,7 +103,8 @@ trait ScratchPadMaker { self: Global => } else { val resName = nextRes() val dispResName = resName filter ('$' != _) - patches += Patch(stat.pos.start, "val " + resName + " = ") + val offset = instrumentPos(stat.pos.start) + patches += Patch(offset, "val " + resName + " = ") addSandbox(stat) toPrint += resultString(nameType(dispResName, stat.tpe), resName) } @@ -146,6 +152,33 @@ trait ScratchPadMaker { self: Global => } } + class LexicalStructure(source: SourceFile) { + val token = new ArrayBuffer[Int] + val startOffset = new ArrayBuffer[Int] + val endOffset = new ArrayBuffer[Int] + private val scanner = new syntaxAnalyzer.UnitScanner(new CompilationUnit(source)) + scanner.init() + while (scanner.token != EOF) { + startOffset += scanner.offset + token += scanner.token + scanner.nextToken + endOffset += scanner.lastOffset + } + + /** @return token that starts before or at offset, its startOffset, its endOffset + */ + def locate(offset: Int): (Int, Int, Int) = { + var lo = 0 + var hi = token.length - 1 + while (lo < hi) { + val mid = (lo + hi + 1) / 2 + if (startOffset(mid) <= offset) lo = mid + else hi = mid - 1 + } + (token(lo), startOffset(lo), endOffset(lo)) + } + } + /** Compute an instrumented version of a sourcefile. * @param source The given sourcefile. * @param line The line up to which results should be printed, -1 = whole document. @@ -158,7 +191,7 @@ trait ScratchPadMaker { self: Global => protected def instrument(source: SourceFile, line: Int): (String, Array[Char]) = { val tree = typedTree(source, true) val endOffset = if (line < 0) source.length else source.lineToOffset(line + 1) - val patcher = new Patcher(source.content, endOffset) + val patcher = new Patcher(source.content, new LexicalStructure(source), endOffset) patcher.traverse(tree) (patcher.objectName, patcher.result) } diff --git a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala index f49e8d6b59..0f5777d260 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala @@ -37,7 +37,7 @@ trait ExprTyper { } /** Parse a line into a sequence of trees. Returns None if the input is incomplete. */ - def parse(line: String): Option[List[Tree]] = { + def parse(line: String): Option[List[Tree]] = debugging(s"""parse("$line")""") { var isIncomplete = false reporter.withIncompleteHandler((_, _) => isIncomplete = true) { val trees = codeParser.stmts(line) diff --git a/src/compiler/scala/tools/nsc/scratchpad/CommentOutputStream.scala b/src/compiler/scala/tools/nsc/scratchpad/CommentOutputStream.scala deleted file mode 100644 index 92ccd79df9..0000000000 --- a/src/compiler/scala/tools/nsc/scratchpad/CommentOutputStream.scala +++ /dev/null @@ -1,18 +0,0 @@ -package scala.tools.nsc.scratchpad - -import java.io.OutputStream - -class CommentOutputStream(out: CommentWriter, encoding: String = "") extends OutputStream { - - override def write(bs: Array[Byte]) = - out.write(if (encoding.isEmpty) new String(bs) else new String(bs, encoding)) - - override def write(bs: Array[Byte], off: Int, len: Int) = - out.write(if (encoding.isEmpty) new String(bs, off, len) else new String(bs, off, len, encoding)) - - override def write(ch: Int) = - write(Array(ch.toByte)) - - override def close() = out.close() - override def flush() = out.flush() -}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/scratchpad/CommentWriter.scala b/src/compiler/scala/tools/nsc/scratchpad/CommentWriter.scala deleted file mode 100644 index eb8880e437..0000000000 --- a/src/compiler/scala/tools/nsc/scratchpad/CommentWriter.scala +++ /dev/null @@ -1,42 +0,0 @@ -package scala.tools.nsc.scratchpad - -import java.io.Writer -import reflect.internal.Chars._ - - -class CommentWriter(underlying: SourceInserter, startCol: Int = 40, endCol: Int = 152) extends Writer { - - private def rightCol(marker: String) = { - while (underlying.column < startCol) underlying.write(' ') - underlying.write(marker) - } - - private var lastWasNL = false - - private def writeChar(ch: Char) = { - if (underlying.column >= endCol) { - underlying.write('\n'); rightCol("//| ") - } - if (underlying.column < startCol) rightCol("//> ") - underlying.write(ch) - lastWasNL = isLineBreakChar(ch) - } - - override def write(chs: Array[Char], off: Int, len: Int) = { - for (i <- off until off + len) writeChar(chs(i)) - flush() - } - - def skip(len: Int) { - if (lastWasNL) { - underlying.backspace() - lastWasNL = false - } - underlying.skip(len) - if (underlying.column >= startCol) underlying.write('\n') - } - - override def close() = underlying.close() - override def flush() = underlying.flush() -} - diff --git a/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala b/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala index 42a35dc642..1c4fad5511 100644 --- a/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala +++ b/src/compiler/scala/tools/nsc/scratchpad/SourceInserter.scala @@ -21,92 +21,3 @@ object SourceInserter { (prefixes mkString "\n").toArray } } -class SourceInserter(contents: Array[Char], start: Int = 0, tabInc: Int = 8) extends Writer { - - private var buf = contents - private var offset = start - private var hilen = contents.length - - def length = offset + hilen - - private def currentColumn: Int = { - var i = offset - while (i > 0 && !isLineBreakChar(buf(i - 1))) i -= 1 - var col = 0 - while (i < offset) { - col = if (buf(i) == '\t') (col + tabInc) / tabInc * tabInc else col + 1 - i += 1 - } - col - } - - private var col = currentColumn - - def column = synchronized { col } - - private def addCapacity(n: Int) = { - val newlength = length + n - while (newlength > buf.length) { - val buf1 = Array.ofDim[Char](buf.length * 2) - Array.copy(buf, 0, buf1, 0, offset) - Array.copy(buf, buf.length - hilen, buf1, buf1.length - hilen, hilen) - buf = buf1 - } - } - - private def insertChar(ch: Char) = { -// Console.err.print("["+ch+"]") - buf(offset) = ch - offset += 1 - ch match { - case LF => col = 0 - case '\t' => col = (col + tabInc) / tabInc * tabInc - case _ => col += 1 - } - } - - override def write(ch: Int) = synchronized { - addCapacity(1) - insertChar(ch.toChar) - } - - override def write(chs: Array[Char], off: Int, len: Int) = synchronized { - addCapacity(len) - for (i <- off until off + len) insertChar(chs(i)) - } - - override def close() { - } - - override def flush() { - // signal buffer change - } - - def currentContents = synchronized { - if (length == buf.length) buf - else { - val res = Array.ofDim[Char](length) - Array.copy(buf, 0, res, 0, offset) - Array.copy(buf, buf.length - hilen, res, offset, hilen) - res - } - } - - def backspace() = synchronized { - offset -= 1 - if (offset > 0 && buf(offset) == LF && buf(offset - 1) == CR) offset -=1 - } - - def currentChar = synchronized { - buf(buf.length - hilen) - } - - def skip(len: Int) = synchronized { - for (i <- 0 until len) { - val ch = currentChar - hilen -= 1 - insertChar(ch) - } - } -} - diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 8af9fd6eb8..ae1a2c7e8e 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -326,7 +326,7 @@ abstract class Erasure extends AddInterfaces } // Methods on Any/Object which we rewrite here while we still know what // is a primitive and what arrived boxed. - private lazy val interceptedMethods = Set[Symbol](Any_##, Object_##, Any_getClass) ++ ( + private lazy val interceptedMethods = Set[Symbol](Any_##, Object_##, Any_getClass, AnyVal_getClass) ++ ( // Each value class has its own getClass for ultra-precise class object typing. ScalaValueClasses map (_.tpe member nme.getClass_) ) @@ -1069,9 +1069,11 @@ abstract class Erasure extends AddInterfaces case _ => global.typer.typed(gen.mkRuntimeCall(nme.hash_, List(qual))) } - } else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) { + } else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) { // Rewrite 5.getClass to ScalaRunTime.anyValClass(5) global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen)))) + } else if (fn.symbol == AnyVal_getClass) { + tree setSymbol Object_getClass } else { tree } @@ -1079,8 +1081,8 @@ abstract class Erasure extends AddInterfaces case New(tpt) if name == nme.CONSTRUCTOR && tpt.tpe.typeSymbol.isDerivedValueClass => // println("inject derived: "+arg+" "+tpt.tpe) val List(arg) = args - InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol - new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef]) + val attachment = new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef]) + InjectDerivedValue(arg) addAttachment attachment case _ => preEraseNormalApply(tree) } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 773d9a6f50..b7195b0349 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -85,10 +85,33 @@ trait ContextErrors { def typeErrorMsg(found: Type, req: Type, possiblyMissingArgs: Boolean) = { def missingArgsMsg = if (possiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else "" + "type mismatch" + foundReqMsg(found, req) + missingArgsMsg } } + def notAnyRefMessage(found: Type): String = { + val tp = found.widen + def name = tp.typeSymbol.nameString + def parents = tp.parents filterNot isTrivialTopType + def onlyAny = tp.parents forall (_.typeSymbol == AnyClass) + def parents_s = ( if (parents.isEmpty) tp.parents else parents ) mkString ", " + def what = ( + if (tp.typeSymbol.isAbstractType) { + val descr = if (onlyAny) "unbounded" else "bounded only by " + parents_s + s"$name is $descr, which means AnyRef is not a known parent" + } + else if (tp.typeSymbol.isAnonOrRefinementClass) + s"the parents of this type ($parents_s) extend Any, not AnyRef" + else + s"$name extends Any, not AnyRef" + ) + if (isPrimitiveValueType(found)) "" else "\n" + + s"""|Note that $what. + |Such types can participate in value classes, but instances + |cannot appear in singleton types or in reference comparisons.""".stripMargin + } + import ErrorUtils._ trait TyperContextErrors { @@ -296,12 +319,17 @@ trait ContextErrors { else "" ) - companion + semicolon + val notAnyRef = ( + if (ObjectClass.info.member(name).exists) notAnyRefMessage(target) + else "" + ) + companion + notAnyRef + semicolon } + def targetStr = targetKindString + target.directObjectString withAddendum(qual.pos)( - if (name == nme.CONSTRUCTOR) target + " does not have a constructor" - else nameString + " is not a member of " + targetKindString + target.directObjectString + addendum - ) + if (name == nme.CONSTRUCTOR) s"$target does not have a constructor" + else s"$nameString is not a member of $targetStr$addendum" + ) } issueNormalTypeError(sel, errMsg) // the error has to be set for the copied tree, otherwise @@ -1095,44 +1123,42 @@ trait ContextErrors { pre1: String, pre2: String, trailer: String) (isView: Boolean, pt: Type, tree: Tree)(implicit context0: Context) = { if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) { - val coreMsg = - pre1+" "+info1.sym.fullLocationString+" of type "+info1.tpe+"\n "+ - pre2+" "+info2.sym.fullLocationString+" of type "+info2.tpe+"\n "+ - trailer - val errMsg = - if (isView) { - val found = pt.typeArgs(0) - val req = pt.typeArgs(1) - def defaultExplanation = - "Note that implicit conversions are not applicable because they are ambiguous:\n "+ - coreMsg+"are possible conversion functions from "+ found+" to "+req - - def explanation = { - val sym = found.typeSymbol - // Explain some common situations a bit more clearly. - if (AnyRefClass.tpe <:< req) { - if (sym == AnyClass || sym == UnitClass) { - "Note: " + sym.name + " is not implicitly converted to AnyRef. You can safely\n" + - "pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so." - } - else boxedClass get sym match { - case Some(boxed) => - "Note: an implicit exists from " + sym.fullName + " => " + boxed.fullName + ", but\n" + - "methods inherited from Object are rendered ambiguous. This is to avoid\n" + - "a blanket implicit which would convert any " + sym.fullName + " to any AnyRef.\n" + - "You may wish to use a type ascription: `x: " + boxed.fullName + "`." - case _ => - defaultExplanation - } - } - else defaultExplanation - } - - typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req)) + "\n" + explanation - } else { - "ambiguous implicit values:\n "+coreMsg + "match expected type "+pt + def coreMsg = + s"""| $pre1 ${info1.sym.fullLocationString} of type ${info1.tpe} + | $pre2 ${info2.sym.fullLocationString} of type ${info2.tpe} + | $trailer""".stripMargin + def viewMsg = { + val found :: req :: _ = pt.typeArgs + def explanation = { + val sym = found.typeSymbol + // Explain some common situations a bit more clearly. Some other + // failures which have nothing to do with implicit conversions + // per se, but which manifest as implicit conversion conflicts + // involving Any, are further explained from foundReqMsg. + if (AnyRefClass.tpe <:< req) ( + if (sym == AnyClass || sym == UnitClass) ( + s"""|Note: ${sym.name} is not implicitly converted to AnyRef. You can safely + |pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so.""".stripMargin + ) + else boxedClass get sym map (boxed => + s"""|Note: an implicit exists from ${sym.fullName} => ${boxed.fullName}, but + |methods inherited from Object are rendered ambiguous. This is to avoid + |a blanket implicit which would convert any ${sym.fullName} to any AnyRef. + |You may wish to use a type ascription: `x: ${boxed.fullName}`.""".stripMargin + ) getOrElse "" + ) + else + s"""|Note that implicit conversions are not applicable because they are ambiguous: + |${coreMsg}are possible conversion functions from $found to $req""".stripMargin } - context.issueAmbiguousError(AmbiguousTypeError(tree, tree.pos, errMsg)) + typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req)) + ( + if (explanation == "") "" else "\n" + explanation + ) + } + context.issueAmbiguousError(AmbiguousTypeError(tree, tree.pos, + if (isView) viewMsg + else s"ambiguous implicit values:\n${coreMsg}match expected type $pt") + ) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 9e175fa516..b04a736fd3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -47,7 +47,7 @@ trait EtaExpansion { self: Analyzer => * tree is already attributed * </p> */ - def etaExpand(unit : CompilationUnit, tree: Tree): Tree = { + def etaExpand(unit : CompilationUnit, tree: Tree, typer: Typer): Tree = { val tpe = tree.tpe var cnt = 0 // for NoPosition def freshName() = { @@ -69,7 +69,11 @@ trait EtaExpansion { self: Analyzer => val vname: Name = freshName() // Problem with ticket #2351 here defs += atPos(tree.pos) { - val rhs = if (byName) Function(List(), tree) else tree + val rhs = if (byName) { + val res = typer.typed(Function(List(), tree)) + new ChangeOwnerTraverser(typer.context.owner, res.symbol) traverse tree // SI-6274 + res + } else tree ValDef(Modifiers(SYNTHETIC), vname.toTermName, TypeTree(), rhs) } atPos(tree.pos.focus) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 28636fc76e..803fb2857e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -280,7 +280,16 @@ trait Infer { def issue(err: AbsTypeError): Unit = context.issue(err) - def isPossiblyMissingArgs(found: Type, req: Type) = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req) + def isPossiblyMissingArgs(found: Type, req: Type) = ( + false + /** However it is that this condition is expected to imply + * "is possibly missing args", it is too weak. It is + * better to say nothing than to offer misleading guesses. + + (found.resultApprox ne found) + && isWeaklyCompatible(found.resultApprox, req) + */ + ) def explainTypes(tp1: Type, tp2: Type) = withDisambiguation(List(), tp1, tp2)(global.explainTypes(tp1, tp2)) @@ -914,10 +923,13 @@ trait Infer { /** Is sym1 (or its companion class in case it is a module) a subclass of * sym2 (or its companion class in case it is a module)? */ - def isProperSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean = - sym1 != sym2 && sym1 != NoSymbol && (sym1 isSubClass sym2) || - sym1.isModuleClass && isProperSubClassOrObject(sym1.linkedClassOfClass, sym2) || - sym2.isModuleClass && isProperSubClassOrObject(sym1, sym2.linkedClassOfClass) + def isProperSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean = ( + (sym1 != sym2) && (sym1 != NoSymbol) && ( + (sym1 isSubClass sym2) + || (sym1.isModuleClass && isProperSubClassOrObject(sym1.linkedClassOfClass, sym2)) + || (sym2.isModuleClass && isProperSubClassOrObject(sym1, sym2.linkedClassOfClass)) + ) + ) /** is symbol `sym1` defined in a proper subclass of symbol `sym2`? */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 01e773e528..59935677a8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -630,7 +630,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { macroDef.owner) } else targ.tpe - if (tpe.isConcrete) context.TypeTag(tpe) else context.AbsTypeTag(tpe) + context.AbsTypeTag(tpe) }) macroTraceVerbose("tags: ")(tags) diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 4f597f97c9..83740f1658 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -369,7 +369,7 @@ trait MethodSynthesis { } /** A synthetic method which performs the implicit conversion implied by - * the declaration of an implicit class. Yet to be written. + * the declaration of an implicit class. */ case class ImplicitClassWrapper(tree: ClassDef) extends DerivedFromClassDef { def completer(sym: Symbol): Type = ??? // not needed @@ -377,7 +377,7 @@ trait MethodSynthesis { def derivedSym: Symbol = { // Only methods will do! Don't want to pick up any stray // companion objects of the same name. - val result = enclClass.info decl name suchThat (_.isMethod) + val result = enclClass.info decl name suchThat (x => x.isMethod && x.isSynthetic) assert(result != NoSymbol, "not found: "+name+" in "+enclClass+" "+enclClass.info.decls) result } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index adced9d8c9..62f01b8afa 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -359,10 +359,39 @@ trait Namers extends MethodSynthesis { } } + /** Given a ClassDef or ModuleDef, verifies there isn't a companion which + * has been defined in a separate file. + */ + private def validateCompanionDefs(tree: ImplDef) { + val sym = tree.symbol + if (sym eq NoSymbol) return + + val ctx = if (context.owner.isPackageObjectClass) context.outer else context + val module = if (sym.isModule) sym else ctx.scope lookup tree.name.toTermName + val clazz = if (sym.isClass) sym else ctx.scope lookup tree.name.toTypeName + val fails = ( + module.isModule + && clazz.isClass + && !module.isSynthetic + && !clazz.isSynthetic + && (clazz.sourceFile ne null) + && (module.sourceFile ne null) + && !(module isCoDefinedWith clazz) + ) + if (fails) { + context.unit.error(tree.pos, ( + s"Companions '$clazz' and '$module' must be defined in same file:\n" + + s" Found in ${clazz.sourceFile.canonicalPath} and ${module.sourceFile.canonicalPath}") + ) + } + } + def enterModuleDef(tree: ModuleDef) = { val sym = enterModuleSymbol(tree) sym.moduleClass setInfo namerOf(sym).moduleClassTypeCompleter(tree) sym setInfo completerOf(tree) + validateCompanionDefs(tree) + sym } /** Enter a module symbol. The tree parameter can be either @@ -635,6 +664,7 @@ trait Namers extends MethodSynthesis { } else context.unit.error(tree.pos, "implicit classes must accept exactly one primary constructor parameter") } + validateCompanionDefs(tree) } // this logic is needed in case typer was interrupted half @@ -699,7 +729,7 @@ trait Namers extends MethodSynthesis { // } } - def moduleClassTypeCompleter(tree: Tree) = { + def moduleClassTypeCompleter(tree: ModuleDef) = { mkTypeCompleter(tree) { sym => val moduleSymbol = tree.symbol assert(moduleSymbol.moduleClass == sym, moduleSymbol.moduleClass) @@ -1545,18 +1575,11 @@ trait Namers extends MethodSynthesis { * call this method? */ def companionSymbolOf(original: Symbol, ctx: Context): Symbol = { - try { - original.companionSymbol orElse { - ctx.lookup(original.name.companionName, original.owner).suchThat(sym => - (original.isTerm || sym.hasModuleFlag) && - (sym isCoDefinedWith original) - ) - } - } - catch { - case e: InvalidCompanions => - ctx.unit.error(original.pos, e.getMessage) - NoSymbol + original.companionSymbol orElse { + ctx.lookup(original.name.companionName, original.owner).suchThat(sym => + (original.isTerm || sym.hasModuleFlag) && + (sym isCoDefinedWith original) + ) } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 166bb2d18c..f1f2794a95 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -430,6 +430,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R overrideError("cannot override a macro") } else { checkOverrideTypes() + checkOverrideDeprecated() if (settings.warnNullaryOverride.value) { if (other.paramss.isEmpty && !member.paramss.isEmpty) { unit.warning(member.pos, "non-nullary method overrides nullary method") @@ -508,6 +509,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } } + + def checkOverrideDeprecated() { + if (other.hasDeprecatedOverridingAnnotation) { + val suffix = other.deprecatedOverridingMessage map (": " + _) getOrElse "" + val msg = s"overriding ${other.fullLocationString} is deprecated$suffix" + unit.deprecationWarning(member.pos, msg) + } + } } val opc = new overridingPairs.Cursor(clazz) @@ -1197,6 +1206,18 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R case _ => } + // SI-6276 warn for `def foo = foo` or `val bar: X = bar`, which come up more frequently than you might think. + def checkInfiniteLoop(valOrDef: ValOrDefDef) { + val trivialInifiniteLoop = ( + !valOrDef.isErroneous + && !valOrDef.symbol.isValueParameter + && valOrDef.symbol.paramss.isEmpty + && valOrDef.rhs.hasSymbolWhich(_.accessedOrSelf == valOrDef.symbol) + ) + if (trivialInifiniteLoop) + unit.warning(valOrDef.rhs.pos, s"${valOrDef.symbol.fullLocationString} does nothing other than call itself recursively") + } + // Transformation ------------------------------------------------------------ /* Convert a reference to a case factory of type `tpe` to a new of the class it produces. */ @@ -1640,6 +1661,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R case ValDef(_, _, _, _) | DefDef(_, _, _, _, _, _) => checkDeprecatedOvers(tree) + checkInfiniteLoop(tree.asInstanceOf[ValOrDefDef]) if (settings.warnNullaryUnit.value) checkNullaryMethodReturnType(sym) if (settings.warnInaccessible.value) { diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index f0dca64a00..f8a5c401df 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -252,6 +252,13 @@ trait TypeDiagnostics { } "" // no elaborable variance situation found } + + // For found/required errors where AnyRef would have sufficed: + // explain in greater detail. + def explainAnyVsAnyRef(found: Type, req: Type): String = { + if (AnyRefClass.tpe <:< req) notAnyRefMessage(found) else "" + } + // TODO - figure out how to avoid doing any work at all // when the message will never be seen. I though context.reportErrors // being false would do that, but if I return "<suppressed>" under @@ -261,7 +268,10 @@ trait TypeDiagnostics { ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) + "\n required: " + req + existentialContext(req) + explainAlias(req) ) - withDisambiguation(Nil, found, req)(baseMessage) + explainVariance(found, req) + ( withDisambiguation(Nil, found, req)(baseMessage) + + explainVariance(found, req) + + explainAnyVsAnyRef(found, req) + ) } case class TypeDiag(tp: Type, sym: Symbol) extends Ordered[TypeDiag] { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a9c31cfe1f..d90141b732 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -233,10 +233,11 @@ trait Typers extends Modes with Adaptations with Tags { * @param tree ... * @return ... */ - def checkStable(tree: Tree): Tree = + def checkStable(tree: Tree): Tree = ( if (treeInfo.isExprSafeToInline(tree)) tree else if (tree.isErrorTyped) tree else UnstableTreeError(tree) + ) /** Would tree be a stable (i.e. a pure expression) if the type * of its symbol was not volatile? @@ -578,7 +579,7 @@ trait Typers extends Modes with Adaptations with Tags { // to notice exhaustiveness and to generate good code when // List extractors are mixed with :: patterns. See Test5 in lists.scala. def dealias(sym: Symbol) = - (atPos(tree.pos) {gen.mkAttributedRef(sym)}, sym.owner.thisType) + (atPos(tree.pos.makeTransparent) {gen.mkAttributedRef(sym)} setPos tree.pos, sym.owner.thisType) sym.name match { case nme.List => return dealias(ListModule) case nme.Seq => return dealias(SeqModule) @@ -885,7 +886,7 @@ trait Typers extends Modes with Adaptations with Tags { if (!meth.isConstructor && !meth.isTermMacro && isFunctionType(pt)) { // (4.2) debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt) checkParamsConvertible(tree, tree.tpe) - val tree0 = etaExpand(context.unit, tree) + val tree0 = etaExpand(context.unit, tree, this) // println("eta "+tree+" ---> "+tree0+":"+tree0.tpe+" undet: "+context.undetparams+ " mode: "+Integer.toHexString(mode)) if (context.undetparams.nonEmpty) { @@ -1056,7 +1057,7 @@ trait Typers extends Modes with Adaptations with Tags { case other => other } - typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt) + typed(atPos(tree.pos)(Select(qual setPos tree.pos.makeTransparent, nme.apply)), mode, pt) } // begin adapt @@ -1576,6 +1577,12 @@ trait Typers extends Modes with Adaptations with Tags { if (psym.isFinal) pending += ParentFinalInheritanceError(parent, psym) + if (psym.hasDeprecatedInheritanceAnnotation) { + val suffix = psym.deprecatedInheritanceMessage map (": " + _) getOrElse "" + val msg = s"inheritance from ${psym.fullLocationString} is deprecated$suffix" + unit.deprecationWarning(parent.pos, msg) + } + if (psym.isSealed && !phase.erasedTypes) if (context.unit.source.file == psym.sourceFile) psym addChild context.owner @@ -2394,7 +2401,7 @@ trait Typers extends Modes with Adaptations with Tags { else targs.init def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = - if (formals.isEmpty) { MissingParameterTypeAnonMatchError(tree, pt); Nil } + if (formals.isEmpty || !formals.forall(isFullyDefined)) { MissingParameterTypeAnonMatchError(tree, pt); Nil } else methodSym newSyntheticValueParams formals def mkSel(params: List[Symbol]) = @@ -2531,7 +2538,7 @@ trait Typers extends Modes with Adaptations with Tags { * @param pt ... * @return ... */ - def typedFunction(fun: Function, mode: Int, pt: Type): Tree = { + private def typedFunction(fun: Function, mode: Int, pt: Type): Tree = { val numVparams = fun.vparams.length if (numVparams > definitions.MaxFunctionArity) return MaxFunctionArityError(fun) @@ -2742,12 +2749,18 @@ trait Typers extends Modes with Adaptations with Tags { // this code by associating defaults and companion objects // with the original tree instead of the new symbol. def matches(stat: Tree, synt: Tree) = (stat, synt) match { + // synt is default arg for stat case (DefDef(_, statName, _, _, _, _), DefDef(mods, syntName, _, _, _, _)) => mods.hasDefaultFlag && syntName.toString.startsWith(statName.toString) + // synt is companion module case (ClassDef(_, className, _, _), ModuleDef(_, moduleName, _)) => className.toTermName == moduleName + // synt is implicit def for implicit class (#6278) + case (ClassDef(cmods, cname, _, _), DefDef(dmods, dname, _, _, _, _)) => + cmods.isImplicit && dmods.isImplicit && cname.toTermName == dname + case _ => false } @@ -3810,18 +3823,23 @@ trait Typers extends Modes with Adaptations with Tags { * - simplest solution: have two method calls * */ - def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = + def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { + debuglog(s"mkInvoke($cxTree, $tree, $qual, $name)") acceptsApplyDynamicWithType(qual, name) map { tp => // tp eq NoType => can call xxxDynamic, but not passing any type args (unless specified explicitly by the user) // in scala-virtualized, when not NoType, tp is passed as type argument (for selection on a staged Struct) - // strip off type application -- we're not doing much with outer, so don't bother preserving cxTree's attributes etc - val (outer, explicitTargs) = cxTree match { - case TypeApply(fun, targs) => (fun, targs) - case Apply(TypeApply(fun, targs), args) => (Apply(fun, args), targs) - case t => (t, Nil) + // strip off type application -- we're not doing much with outer, + // so don't bother preserving cxTree's attributes etc + val cxTree1 = cxTree match { + case t: ValOrDefDef => t.rhs + case t => t + } + val (outer, explicitTargs) = cxTree1 match { + case TypeApply(fun, targs) => (fun, targs) + case Apply(TypeApply(fun, targs), args) => (Apply(fun, args), targs) + case t => (t, Nil) } - @inline def hasNamedArg(as: List[Tree]) = as.collectFirst{case AssignOrNamedArg(lhs, rhs) =>}.nonEmpty // note: context.tree includes at most one Apply node @@ -3846,6 +3864,7 @@ trait Typers extends Modes with Adaptations with Tags { atPos(qual.pos)(Apply(tappSel, List(Literal(Constant(name.decode))))) } + } } @inline final def deindentTyping() = context.typingIndentLevel -= 2 @@ -5201,7 +5220,10 @@ trait Typers extends Modes with Adaptations with Tags { def typedSingletonTypeTree(tree: SingletonTypeTree) = { val ref1 = checkStable( - typed(tree.ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe)) + context.withImplicitsDisabled( + typed(tree.ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe) + ) + ) tree setType ref1.tpe.resultType } @@ -5234,149 +5256,60 @@ trait Typers extends Modes with Adaptations with Tags { // whatever type to tree; we just have to survive until a real error message is issued. tree setType AnyClass.tpe } + def typedFunction(fun: Function) = { + if (fun.symbol == NoSymbol) + fun.symbol = context.owner.newAnonymousFunctionValue(fun.pos) + + typerWithLocalContext(context.makeNewScope(fun, fun.symbol))(_.typedFunction(fun, mode, pt)) + } // begin typed1 //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG - tree match { - case tree: Ident => - typedIdentOrWildcard(tree) - - case tree: Select => - typedSelectOrSuperCall(tree) - - case tree: Apply => - typedApply(tree) - - case tree: TypeTree => - typedTypeTree(tree) - - case tree: Literal => - typedLiteral(tree) - - case tree: This => - typedThis(tree) - - case tree: ValDef => - typedValDef(tree) - - case tree: DefDef => - // flag default getters for constructors. An actual flag would be nice. See SI-5543. - //val flag = ddef.mods.hasDefaultFlag && ddef.mods.hasFlag(PRESUPER) - defDefTyper(tree).typedDefDef(tree) - - case tree: Block => - typerWithLocalContext(context.makeNewScope(tree, context.owner)){ - _.typedBlock(tree, mode, pt) - } - - case tree: If => - typedIf(tree) - - case tree: TypeApply => - typedTypeApply(tree) - - case tree: AppliedTypeTree => - typedAppliedTypeTree(tree) - - case tree: Bind => - typedBind(tree) - - case tree: Function => - if (tree.symbol == NoSymbol) - tree.symbol = context.owner.newAnonymousFunctionValue(tree.pos) - typerWithLocalContext(context.makeNewScope(tree, tree.symbol))(_.typedFunction(tree, mode, pt)) - - case tree: Match => - typedVirtualizedMatch(tree) - - case tree: New => - typedNew(tree) - - case Assign(lhs, rhs) => - typedAssign(lhs, rhs) - - case AssignOrNamedArg(lhs, rhs) => // called by NamesDefaults in silent typecheck - typedAssign(lhs, rhs) - - case tree: Super => - typedSuper(tree) - - case tree: TypeBoundsTree => - typedTypeBoundsTree(tree) - - case tree: Typed => - typedTyped(tree) - - case tree: ClassDef => - newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree) - - case tree: ModuleDef => - newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree) - - case tree: TypeDef => - typedTypeDef(tree) - - case tree: LabelDef => - labelTyper(tree).typedLabelDef(tree) - - case tree: PackageDef => - typedPackageDef(tree) - - case tree: DocDef => - typedDocDef(tree) - - case tree: Annotated => - typedAnnotated(tree) - - case tree: SingletonTypeTree => - typedSingletonTypeTree(tree) - - case tree: SelectFromTypeTree => - typedSelectFromTypeTree(tree) - - case tree: CompoundTypeTree => - typedCompoundTypeTree(tree) - - case tree: ExistentialTypeTree => - typedExistentialTypeTree(tree) - - case tree: Return => - typedReturn(tree) - - case tree: Try => - typedTry(tree) - - case tree: Throw => - typedThrow(tree) - - case tree: Alternative => - typedAlternative(tree) - - case tree: Star => - typedStar(tree) - - case tree: UnApply => - typedUnApply(tree) - - case tree: ArrayValue => - typedArrayValue(tree) - - case tree: ApplyDynamic => - typedApplyDynamic(tree) - - case tree: ReferenceToBoxed => - typedReferenceToBoxed(tree) - - case tree: TypeTreeWithDeferredRefCheck => - tree // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure) - - case tree: Import => - assert(forInteractive, "!forInteractive") // should not happen in normal circumstances. - tree setType tree.symbol.tpe - - case _ => - abort("unexpected tree: " + tree.getClass + "\n" + tree)//debug + case tree: Ident => typedIdentOrWildcard(tree) + case tree: Select => typedSelectOrSuperCall(tree) + case tree: Apply => typedApply(tree) + case tree: TypeTree => typedTypeTree(tree) + case tree: Literal => typedLiteral(tree) + case tree: This => typedThis(tree) + case tree: ValDef => typedValDef(tree) + case tree: DefDef => defDefTyper(tree).typedDefDef(tree) + case tree: Block => typerWithLocalContext(context.makeNewScope(tree, context.owner))(_.typedBlock(tree, mode, pt)) + case tree: If => typedIf(tree) + case tree: TypeApply => typedTypeApply(tree) + case tree: AppliedTypeTree => typedAppliedTypeTree(tree) + case tree: Bind => typedBind(tree) + case tree: Function => typedFunction(tree) + case tree: Match => typedVirtualizedMatch(tree) + case tree: New => typedNew(tree) + case tree: Assign => typedAssign(tree.lhs, tree.rhs) + case tree: AssignOrNamedArg => typedAssign(tree.lhs, tree.rhs) // called by NamesDefaults in silent typecheck + case tree: Super => typedSuper(tree) + case tree: TypeBoundsTree => typedTypeBoundsTree(tree) + case tree: Typed => typedTyped(tree) + case tree: ClassDef => newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree) + case tree: ModuleDef => newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree) + case tree: TypeDef => typedTypeDef(tree) + case tree: LabelDef => labelTyper(tree).typedLabelDef(tree) + case tree: PackageDef => typedPackageDef(tree) + case tree: DocDef => typedDocDef(tree) + case tree: Annotated => typedAnnotated(tree) + case tree: SingletonTypeTree => typedSingletonTypeTree(tree) + case tree: SelectFromTypeTree => typedSelectFromTypeTree(tree) + case tree: CompoundTypeTree => typedCompoundTypeTree(tree) + case tree: ExistentialTypeTree => typedExistentialTypeTree(tree) + case tree: Return => typedReturn(tree) + case tree: Try => typedTry(tree) + case tree: Throw => typedThrow(tree) + case tree: Alternative => typedAlternative(tree) + case tree: Star => typedStar(tree) + case tree: UnApply => typedUnApply(tree) + case tree: ArrayValue => typedArrayValue(tree) + case tree: ApplyDynamic => typedApplyDynamic(tree) + case tree: ReferenceToBoxed => typedReferenceToBoxed(tree) + case tree: TypeTreeWithDeferredRefCheck => tree // TODO: retype the wrapped tree? TTWDRC would have to change to hold the wrapped tree (not a closure) + case tree: Import => assert(forInteractive, "!forInteractive") ; tree setType tree.symbol.tpe // should not happen in normal circumstances. + case _ => abort(s"unexpected tree: ${tree.getClass}\n$tree") } } diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index 2505c1afb7..85e2b6543f 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -12,7 +12,7 @@ trait ToolBox[U <: Universe] { /** Underlying mirror of a ToolBox */ - val mirror: MirrorOf[u.type] + val mirror: u.Mirror /** Front end of the toolbox. * diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 8cc5a4e531..b658491294 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -26,7 +26,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => private class ToolBoxImpl(val frontEnd: FrontEnd, val options: String) extends ToolBox[U] { toolBoxSelf => val u: factorySelf.u.type = factorySelf.u - val mirror: u.Mirror = factorySelf.mirror + + lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, factorySelf.mirror.classLoader) + lazy val mirror: u.Mirror = u.runtimeMirror(classLoader) class ToolBoxGlobal(settings: scala.tools.nsc.Settings, reporter: Reporter) extends ReflectGlobal(settings, reporter, toolBoxSelf.classLoader) { @@ -327,7 +329,6 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => lazy val importer = compiler.mkImporter(u) lazy val exporter = importer.reverse - lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, mirror.classLoader) def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = { if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType) diff --git a/src/library/scala/Dynamic.scala b/src/library/scala/Dynamic.scala index faf834d310..3bcb2f1c90 100644 --- a/src/library/scala/Dynamic.scala +++ b/src/library/scala/Dynamic.scala @@ -9,11 +9,11 @@ package scala /** A marker trait that enables dynamic invocations. Instances `x` of this - * trait allow method invocations `x.meth(args)` for arbitrary method - * names `meth` and argument lists `args` as well as field accesses + * trait allow method invocations `x.meth(args)` for arbitrary method + * names `meth` and argument lists `args` as well as field accesses * `x.field` for arbitrary field names `field`. * - * If a call is not natively supported by `x` (i.e. if type checking + * If a call is not natively supported by `x` (i.e. if type checking * fails), it is rewritten according to the following rules: * * {{{ @@ -23,12 +23,12 @@ package scala * foo.field ~~> foo.selectDynamic("field") * foo.varia = 10 ~~> foo.updateDynamic("varia")(10) * foo.arr(10) = 13 ~~> foo.selectDynamic("arr").update(10, 13) - * foo.arr(10) ~~> foo.applyDynamics("arr")(10) + * foo.arr(10) ~~> foo.applyDynamic("arr")(10) * }}} * * As of Scala 2.10, defining direct or indirect subclasses of this trait * is only possible if the language feature `dynamics` is enabled. */ -trait Dynamic +trait Dynamic extends Any diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index 723d95a499..453f29d9e6 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -19,7 +19,7 @@ case class StringContext(parts: String*) { import StringContext._ - /** Checks that the given arguments `args` number one less than the number + /** Checks that the length of the given argument `args` is one less than the number * of `parts` supplied to the enclosing `StringContext`. * @param `args` The arguments to be checked. * @throws An `IllegalArgumentException` if this is not the case. @@ -37,7 +37,7 @@ case class StringContext(parts: String*) { * @throws An `IllegalArgumentException` * if the number of `parts` in the enclosing `StringContext` does not exceed * the number of arguments `arg` by exactly 1. - * @throws A `StringContext.InvalidEscapeException` if if a `parts` string contains a backslash (`\`) character + * @throws A `StringContext.InvalidEscapeException` if a `parts` string contains a backslash (`\`) character * that does not start a valid escape sequence. */ def s(args: Any*): String = standardInterpolator(treatEscapes, args) @@ -51,7 +51,7 @@ case class StringContext(parts: String*) { * @throws An `IllegalArgumentException` * if the number of `parts` in the enclosing `StringContext` does not exceed * the number of arguments `arg` by exactly 1. - * @throws A `StringContext.InvalidEscapeException` if if a `parts` string contains a backslash (`\`) character + * @throws A `StringContext.InvalidEscapeException` if a `parts` string contains a backslash (`\`) character * that does not start a valid escape sequence. */ def raw(args: Any*): String = standardInterpolator(identity, args) @@ -102,7 +102,7 @@ case class StringContext(parts: String*) { object StringContext { - /** An exception that is thrown if a string contains a backslash (`\`) character that + /** An exception that is thrown if a string contains a backslash (`\`) character * that does not start a valid escape sequence. * @param str The offending string * @param idx The index of the offending backslash character in `str`. diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 26877a32b1..ef693ab7ca 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -453,7 +453,7 @@ self: ParIterableLike[T, Repr, Sequential] => def reduceRightOption[U >: T](op: (T, U) => U): Option[U] = seq.reduceRightOption(op) - /** Applies a function `f` to all the elements of $coll in a sequential order. + /** Applies a function `f` to all the elements of $coll in a undefined order. * * @tparam U the result type of the function applied to each element, which is always discarded * @param f function applied to each element diff --git a/src/library/scala/concurrent/util/Duration.scala b/src/library/scala/concurrent/util/Duration.scala index bab664727e..bf0f3006f1 100644 --- a/src/library/scala/concurrent/util/Duration.scala +++ b/src/library/scala/concurrent/util/Duration.scala @@ -26,76 +26,68 @@ object Deadline { def now: Deadline = Deadline(Duration(System.nanoTime, NANOSECONDS)) } +// TODO: "Inf", "PlusInf", "MinusInf", where did these names come from? +// TODO: Duration.create(n, DAYS) == Duration(Long.MaxValue, NANOSECONDS) forall (n: Double) >= 106752d object Duration { implicit def timeLeft(implicit d: Deadline): Duration = d.timeLeft - def apply(length: Long, unit: TimeUnit): FiniteDuration = new FiniteDuration(length, unit) def apply(length: Double, unit: TimeUnit): FiniteDuration = fromNanos(unit.toNanos(1) * length) - def apply(length: Long, unit: String): FiniteDuration = new FiniteDuration(length, Duration.timeUnit(unit)) + def apply(length: Long, unit: TimeUnit): FiniteDuration = new FiniteDuration(length, unit) + def apply(length: Long, unit: String): FiniteDuration = new FiniteDuration(length, Duration.timeUnit(unit)) /** - * Construct a Duration by parsing a String. In case of a format error, a - * RuntimeException is thrown. See `unapply(String)` for more information. - */ - def apply(s: String): Duration = unapply(s) getOrElse sys.error("format error " + s) - - private val RE = ("""^\s*([\+|-]?\d+(?:\.\d+)?)\s*""" + // length part - "(?:" + // units are distinguished in separate match groups - "(d|day|days)|" + - "(h|hour|hours)|" + - "(min|minute|minutes)|" + - "(s|sec|second|seconds)|" + - "(ms|milli|millis|millisecond|milliseconds)|" + - "(µs|micro|micros|microsecond|microseconds)|" + - "(ns|nano|nanos|nanosecond|nanoseconds)" + - """)\s*$""").r // close the non-capturing group - private val REinf = """^\s*(?:\+|Plus)?Inf\s*$""".r - private val REminf = """^\s*(?:-|Minus)Inf\s*""".r - - /** - * Deconstruct a Duration into `Long` length and [[java.util.concurrent.TimeUnit]] if it is a - * [[scala.util.concurrent.FiniteDuration]]. - * - * @param d Duration to be deconstructed. + * Parse String into Duration. Format is `"<length><unit>"`, where + * whitespace is allowed before, between and after the parts. Infinities are + * designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`. + * Throws exception if format is not parseable. */ - def unapply(d: Duration): Option[(Long, TimeUnit)] = { - if (d.finite_?) { - Some((d.length, d.unit)) - } else { - None + def apply(s: String): Duration = { + val s1: String = s filterNot (_.isWhitespace) + s1 match { + case "Inf" | "PlusInf" | "+Inf" => Inf + case "MinusInf" | "-Inf" => MinusInf + case _ => + val unitName = s1.reverse takeWhile (_.isLetter) reverse; + def length = JDouble.parseDouble(s1 dropRight unitName.length) + timeUnit get unitName match { + case Some(unit) => Duration(length, unit) + case _ => sys.error("format error " + s) + } } } - /** - * Parse String, return None if no match. Format is `"<length><unit>"`, where - * whitespace is allowed before, between and after the parts. Infinities are - * designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`. - */ - def unapply(s: String): Option[Duration] = s match { - case RE(length, d, h, m, s, ms, mus, ns) ⇒ - if (d ne null) - Some(Duration(JDouble.parseDouble(length), DAYS)) - else if (h ne null) - Some(Duration(JDouble.parseDouble(length), HOURS)) - else if (m ne null) - Some(Duration(JDouble.parseDouble(length), MINUTES)) - else if (s ne null) - Some(Duration(JDouble.parseDouble(length), SECONDS)) - else if (ms ne null) - Some(Duration(JDouble.parseDouble(length), MILLISECONDS)) - else if (mus ne null) - Some(Duration(JDouble.parseDouble(length), MICROSECONDS)) - else if (ns ne null) - Some(Duration(JDouble.parseDouble(length), NANOSECONDS)) - else - sys.error("made some error in regex (should not be possible)") - case REinf() ⇒ Some(Inf) - case REminf() ⇒ Some(MinusInf) - case _ ⇒ None + // "ms milli millisecond" -> List("ms", "milli", "millis", "millisecond", "milliseconds") + private def words(s: String) = (s.trim split "\\s+").toList + private def expandLabels(labels: String): List[String] = { + val hd :: rest = words(labels) + hd :: rest.flatMap(s => List(s, s + "s")) } + private val timeUnitLabels = List( + DAYS -> "d day", + HOURS -> "h hour", + MINUTES -> "min minute", + SECONDS -> "s sec second", + MILLISECONDS -> "ms milli millisecond", + MICROSECONDS -> "µs micro microsecond", + NANOSECONDS -> "ns nano nanosecond" + ) + + // TimeUnit => standard label + protected[util] val timeUnitName: Map[TimeUnit, String] = + timeUnitLabels.toMap mapValues (s => words(s).last) toMap + + // Label => TimeUnit + protected[util] val timeUnit: Map[String, TimeUnit] = + timeUnitLabels flatMap { case (unit, names) => expandLabels(names) map (_ -> unit) } toMap + + def unapply(s: String): Option[(Long, TimeUnit)] = + ( try Some(apply(s)) catch { case _: RuntimeException => None } ) flatMap unapply + + def unapply(d: Duration): Option[(Long, TimeUnit)] = + if (d.isFinite) Some((d.length, d.unit)) else None def fromNanos(nanos: Double): FiniteDuration = - fromNanos((nanos + 0.5).asInstanceOf[Long]) + fromNanos((nanos + 0.5).toLong) def fromNanos(nanos: Long): FiniteDuration = { if (nanos % 86400000000000L == 0) { @@ -118,72 +110,62 @@ object Duration { /** * Parse TimeUnit from string representation. */ - protected[util] def timeUnit(unit: String): TimeUnit = unit.toLowerCase match { - case "d" | "day" | "days" => DAYS - case "h" | "hour" | "hours" => HOURS - case "min" | "minute" | "minutes" => MINUTES - case "s" | "sec" | "second" | "seconds" => SECONDS - case "ms" | "milli" | "millis" | "millisecond" | "milliseconds" => MILLISECONDS - case "µs" | "micro" | "micros" | "microsecond" | "microseconds" => MICROSECONDS - case "ns" | "nano" | "nanos" | "nanosecond" | "nanoseconds" => NANOSECONDS - } val Zero: FiniteDuration = new FiniteDuration(0, NANOSECONDS) - val Undefined: Duration = new Duration with Infinite { + + object Undefined extends Infinite { + private def fail(what: String) = throw new IllegalArgumentException(s"cannot $what Undefined duration") + override def toString = "Duration.Undefined" - override def equals(other: Any) = other.asInstanceOf[AnyRef] eq this - override def +(other: Duration): Duration = throw new IllegalArgumentException("cannot add Undefined duration") - override def -(other: Duration): Duration = throw new IllegalArgumentException("cannot subtract Undefined duration") - override def *(factor: Double): Duration = throw new IllegalArgumentException("cannot multiply Undefined duration") - override def /(factor: Double): Duration = throw new IllegalArgumentException("cannot divide Undefined duration") - override def /(other: Duration): Double = throw new IllegalArgumentException("cannot divide Undefined duration") - def compare(other: Duration) = throw new IllegalArgumentException("cannot compare Undefined duration") - def unary_- : Duration = throw new IllegalArgumentException("cannot negate Undefined duration") + override def equals(other: Any) = this eq other.asInstanceOf[AnyRef] + override def +(other: Duration): Duration = fail("add") + override def -(other: Duration): Duration = fail("subtract") + override def *(factor: Double): Duration = fail("multiply") + override def /(factor: Double): Duration = fail("divide") + override def /(other: Duration): Double = fail("divide") + def compare(other: Duration) = fail("compare") + def unary_- : Duration = fail("negate") } - trait Infinite { - this: Duration => - - def +(other: Duration): Duration = - other match { - case _: this.type => this - case _: Infinite => throw new IllegalArgumentException("illegal addition of infinities") - case _ => this - } + sealed abstract class Infinite extends Duration { + def +(other: Duration): Duration = other match { + case x: Infinite if x ne this => throw new IllegalArgumentException("illegal addition of infinities") + case _ => this + } + // Is this really intended to throw if the argument is "this" but otherwise return this? def -(other: Duration): Duration = - other match { - case _: this.type => throw new IllegalArgumentException("illegal subtraction of infinities") - case _ => this - } + if (other ne this) this + else throw new IllegalArgumentException("illegal subtraction of infinities") + def *(factor: Double): Duration = this def /(factor: Double): Duration = this - def /(other: Duration): Double = - other match { - case _: Infinite => throw new IllegalArgumentException("illegal division of infinities") - // maybe questionable but pragmatic: Inf / 0 => Inf - case x => Double.PositiveInfinity * (if ((this > Zero) ^ (other >= Zero)) -1 else 1) - } - - def finite_? = false - - def length: Long = throw new IllegalArgumentException("length not allowed on infinite Durations") - def unit: TimeUnit = throw new IllegalArgumentException("unit not allowed on infinite Durations") - def toNanos: Long = throw new IllegalArgumentException("toNanos not allowed on infinite Durations") - def toMicros: Long = throw new IllegalArgumentException("toMicros not allowed on infinite Durations") - def toMillis: Long = throw new IllegalArgumentException("toMillis not allowed on infinite Durations") - def toSeconds: Long = throw new IllegalArgumentException("toSeconds not allowed on infinite Durations") - def toMinutes: Long = throw new IllegalArgumentException("toMinutes not allowed on infinite Durations") - def toHours: Long = throw new IllegalArgumentException("toHours not allowed on infinite Durations") - def toDays: Long = throw new IllegalArgumentException("toDays not allowed on infinite Durations") - def toUnit(unit: TimeUnit): Double = throw new IllegalArgumentException("toUnit not allowed on infinite Durations") + def /(other: Duration): Double = other match { + case _: Infinite => throw new IllegalArgumentException("illegal division of infinities") + // maybe questionable but pragmatic: Inf / 0 => Inf + case x => Double.PositiveInfinity * (if ((this > Zero) ^ (other >= Zero)) -1 else 1) + } + + final def isFinite() = false + private def fail(what: String) = throw new IllegalArgumentException(s"$what not allowed on infinite Durations") + def length: Long = fail("length") + def toNanos: Long = fail("toNanos") + def toMicros: Long = fail("toMicros") + def toMillis: Long = fail("toMillis") + def toSeconds: Long = fail("toSeconds") + def toMinutes: Long = fail("toMinutes") + def toHours: Long = fail("toHours") + def toDays: Long = fail("toDays") + + def unit: TimeUnit = fail("unit") + def toUnit(unit: TimeUnit): Double = fail("toUnit") } /** * Infinite duration: greater than any other and not equal to any other, * including itself. */ - val Inf: Duration = new Duration with Infinite { + val Inf: Infinite = new Infinite { override def toString = "Duration.Inf" def compare(other: Duration) = if (other eq this) 0 else 1 def unary_- : Duration = MinusInf @@ -193,17 +175,17 @@ object Duration { * Infinite negative duration: lesser than any other and not equal to any other, * including itself. */ - val MinusInf: Duration = new Duration with Infinite { + val MinusInf: Infinite = new Infinite { override def toString = "Duration.MinusInf" def compare(other: Duration) = if (other eq this) 0 else -1 def unary_- : Duration = Inf } // Java Factories - def create(length: Long, unit: TimeUnit): FiniteDuration = apply(length, unit) + def create(length: Long, unit: TimeUnit): FiniteDuration = apply(length, unit) def create(length: Double, unit: TimeUnit): FiniteDuration = apply(length, unit) - def create(length: Long, unit: String): FiniteDuration = apply(length, unit) - def parse(s: String): Duration = unapply(s).get + def create(length: Long, unit: String): FiniteDuration = apply(length, unit) + def create(s: String): Duration = apply(s) implicit object DurationIsOrdered extends Ordering[Duration] { def compare(a: Duration, b: Duration) = a compare b @@ -261,23 +243,22 @@ abstract class Duration extends Serializable with Ordered[Duration] { def /(factor: Double): Duration def /(other: Duration): Double def unary_- : Duration - def finite_? : Boolean + def isFinite(): Boolean def min(other: Duration): Duration = if (this < other) this else other def max(other: Duration): Duration = if (this > other) this else other def fromNow: Deadline = Deadline.now + this // Java API - def lt(other: Duration) = this < other - def lteq(other: Duration) = this <= other - def gt(other: Duration) = this > other - def gteq(other: Duration) = this >= other - def plus(other: Duration) = this + other + def div(factor: Double) = this / factor + def div(other: Duration) = this / other + def gt(other: Duration) = this > other + def gteq(other: Duration) = this >= other + def lt(other: Duration) = this < other + def lteq(other: Duration) = this <= other def minus(other: Duration) = this - other - def mul(factor: Double) = this * factor - def div(factor: Double) = this / factor - def div(other: Duration) = this / other - def neg() = -this - def isFinite() = finite_? + def mul(factor: Double) = this * factor + def neg() = -this + def plus(other: Duration) = this + other } object FiniteDuration { @@ -286,252 +267,121 @@ object FiniteDuration { } def apply(length: Long, unit: TimeUnit) = new FiniteDuration(length, unit) - - def apply(length: Long, unit: String) = new FiniteDuration(length, Duration.timeUnit(unit)) - + def apply(length: Long, unit: String) = new FiniteDuration(length, Duration.timeUnit(unit)) } class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration { import Duration._ - def toNanos = unit.toNanos(length) - def toMicros = unit.toMicros(length) - def toMillis = unit.toMillis(length) + def toNanos = unit.toNanos(length) + def toMicros = unit.toMicros(length) + def toMillis = unit.toMillis(length) def toSeconds = unit.toSeconds(length) def toMinutes = unit.toMinutes(length) - def toHours = unit.toHours(length) - def toDays = unit.toDays(length) + def toHours = unit.toHours(length) + def toDays = unit.toDays(length) def toUnit(u: TimeUnit) = toNanos.toDouble / NANOSECONDS.convert(1, u) - override def toString = this match { - case Duration(1, DAYS) => "1 day" - case Duration(x, DAYS) => x + " days" - case Duration(1, HOURS) => "1 hour" - case Duration(x, HOURS) => x + " hours" - case Duration(1, MINUTES) => "1 minute" - case Duration(x, MINUTES) => x + " minutes" - case Duration(1, SECONDS) => "1 second" - case Duration(x, SECONDS) => x + " seconds" - case Duration(1, MILLISECONDS) => "1 millisecond" - case Duration(x, MILLISECONDS) => x + " milliseconds" - case Duration(1, MICROSECONDS) => "1 microsecond" - case Duration(x, MICROSECONDS) => x + " microseconds" - case Duration(1, NANOSECONDS) => "1 nanosecond" - case Duration(x, NANOSECONDS) => x + " nanoseconds" - } - - def compare(other: Duration) = - if (other.finite_?) { - val me = toNanos - val o = other.toNanos - if (me > o) 1 else if (me < o) -1 else 0 - } else -other.compare(this) + private def unitString = timeUnitName(unit) + ( if (length == 1) "" else "s" ) + override def toString = "" + length + " " + unitString - def +(other: Duration) = { - if (!other.finite_?) { - other - } else { - val nanos = toNanos + other.asInstanceOf[FiniteDuration].toNanos - fromNanos(nanos) - } + def compare(other: Duration) = other match { + case x: FiniteDuration => toNanos compare x.toNanos + case _ => -(other compare this) } - - def -(other: Duration) = { - if (!other.finite_?) { - other - } else { - val nanos = toNanos - other.asInstanceOf[FiniteDuration].toNanos - fromNanos(nanos) - } + def +(other: Duration) = other match { + case x: FiniteDuration => fromNanos(toNanos + x.toNanos) + case _ => other + } + def -(other: Duration) = other match { + case x: FiniteDuration => fromNanos(toNanos - x.toNanos) + case _ => other } def *(factor: Double) = fromNanos(toNanos.toDouble * factor) def /(factor: Double) = fromNanos(toNanos.toDouble / factor) - def /(other: Duration) = if (other.finite_?) toNanos.toDouble / other.toNanos else 0 + def /(other: Duration) = if (other.isFinite) toNanos.toDouble / other.toNanos else 0 def unary_- = Duration(-length, unit) - def finite_? = true - - override def equals(other: Any) = - other.isInstanceOf[FiniteDuration] && - toNanos == other.asInstanceOf[FiniteDuration].toNanos + final def isFinite() = true - override def hashCode = toNanos.asInstanceOf[Int] + override def equals(other: Any) = other match { + case x: FiniteDuration => toNanos == x.toNanos + case _ => super.equals(other) + } + override def hashCode = toNanos.toInt } -class DurationInt(n: Int) { +trait DurationConversions extends Any { import duration.Classifier + protected def durationIn(unit: TimeUnit): FiniteDuration - def nanoseconds = Duration(n, NANOSECONDS) - def nanos = Duration(n, NANOSECONDS) - def nanosecond = Duration(n, NANOSECONDS) - def nano = Duration(n, NANOSECONDS) + def nanoseconds = durationIn(NANOSECONDS) + def nanos = nanoseconds + def nanosecond = nanoseconds + def nano = nanoseconds - def microseconds = Duration(n, MICROSECONDS) - def micros = Duration(n, MICROSECONDS) - def microsecond = Duration(n, MICROSECONDS) - def micro = Duration(n, MICROSECONDS) + def microseconds = durationIn(MICROSECONDS) + def micros = microseconds + def microsecond = microseconds + def micro = microseconds - def milliseconds = Duration(n, MILLISECONDS) - def millis = Duration(n, MILLISECONDS) - def millisecond = Duration(n, MILLISECONDS) - def milli = Duration(n, MILLISECONDS) + def milliseconds = durationIn(MILLISECONDS) + def millis = milliseconds + def millisecond = milliseconds + def milli = milliseconds - def seconds = Duration(n, SECONDS) - def second = Duration(n, SECONDS) + def seconds = durationIn(SECONDS) + def second = seconds - def minutes = Duration(n, MINUTES) - def minute = Duration(n, MINUTES) + def minutes = durationIn(MINUTES) + def minute = minutes - def hours = Duration(n, HOURS) - def hour = Duration(n, HOURS) + def hours = durationIn(HOURS) + def hour = hours - def days = Duration(n, DAYS) - def day = Duration(n, DAYS) + def days = durationIn(DAYS) + def day = days - def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) + def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(nanoseconds) + def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c) + def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c) + def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c) - def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) + def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(microseconds) + def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c) + def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c) + def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c) - def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) + def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(milliseconds) + def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c) + def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c) + def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c) - def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) - def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) + def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(seconds) + def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = seconds(c) - def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) - def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) + def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(minutes) + def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = minutes(c) - def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) - def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) + def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(hours) + def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = hours(c) - def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) - def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) + def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(days) + def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = days(c) } -class DurationLong(n: Long) { - import duration.Classifier - - def nanoseconds = Duration(n, NANOSECONDS) - def nanos = Duration(n, NANOSECONDS) - def nanosecond = Duration(n, NANOSECONDS) - def nano = Duration(n, NANOSECONDS) - - def microseconds = Duration(n, MICROSECONDS) - def micros = Duration(n, MICROSECONDS) - def microsecond = Duration(n, MICROSECONDS) - def micro = Duration(n, MICROSECONDS) - - def milliseconds = Duration(n, MILLISECONDS) - def millis = Duration(n, MILLISECONDS) - def millisecond = Duration(n, MILLISECONDS) - def milli = Duration(n, MILLISECONDS) - - def seconds = Duration(n, SECONDS) - def second = Duration(n, SECONDS) - - def minutes = Duration(n, MINUTES) - def minute = Duration(n, MINUTES) - - def hours = Duration(n, HOURS) - def hour = Duration(n, HOURS) - - def days = Duration(n, DAYS) - def day = Duration(n, DAYS) - - def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - - def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - - def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - - def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) - def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) - - def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) - def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) - - def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) - def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) - - def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) - def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) +final class DurationInt(val n: Int) extends AnyVal with DurationConversions { + override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit) } -class DurationDouble(d: Double) { - import duration.Classifier - - def nanoseconds = Duration(d, NANOSECONDS) - def nanos = Duration(d, NANOSECONDS) - def nanosecond = Duration(d, NANOSECONDS) - def nano = Duration(d, NANOSECONDS) - - def microseconds = Duration(d, MICROSECONDS) - def micros = Duration(d, MICROSECONDS) - def microsecond = Duration(d, MICROSECONDS) - def micro = Duration(d, MICROSECONDS) - - def milliseconds = Duration(d, MILLISECONDS) - def millis = Duration(d, MILLISECONDS) - def millisecond = Duration(d, MILLISECONDS) - def milli = Duration(d, MILLISECONDS) - - def seconds = Duration(d, SECONDS) - def second = Duration(d, SECONDS) - - def minutes = Duration(d, MINUTES) - def minute = Duration(d, MINUTES) - - def hours = Duration(d, HOURS) - def hour = Duration(d, HOURS) - - def days = Duration(d, DAYS) - def day = Duration(d, DAYS) - - def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - - def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - - def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - - def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, SECONDS)) - def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, SECONDS)) - - def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MINUTES)) - def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MINUTES)) - - def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, HOURS)) - def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, HOURS)) +final class DurationLong(val n: Long) extends AnyVal with DurationConversions { + override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit) +} - def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, DAYS)) - def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, DAYS)) +final class DurationDouble(val d: Double) extends AnyVal with DurationConversions { + override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(d, unit) } diff --git a/src/library/scala/deprecatedInheritance.scala b/src/library/scala/deprecatedInheritance.scala new file mode 100644 index 0000000000..ca1b586223 --- /dev/null +++ b/src/library/scala/deprecatedInheritance.scala @@ -0,0 +1,22 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** An annotation that designates that inheriting from a class is deprecated. + * + * This is usually done to warn about a non-final class being made final in a future version. + * Sub-classing such a class then generates a warning. + * + * @param message the message to print during compilation if the class was sub-classed + * @param since a string identifying the first version in which inheritance was deprecated + * @since 2.10 + * @see [[scala.deprecatedOverriding]] + */ +private[scala] // for now, this needs to be generalized to communicate other modifier deltas +class deprecatedInheritance(message: String = "", since: String = "") extends annotation.StaticAnnotation diff --git a/src/library/scala/deprecatedOverriding.scala b/src/library/scala/deprecatedOverriding.scala new file mode 100644 index 0000000000..566cb59431 --- /dev/null +++ b/src/library/scala/deprecatedOverriding.scala @@ -0,0 +1,21 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** An annotation that designates that overriding a member is deprecated. + * + * Overriding such a member in a sub-class then generates a warning. + * + * @param message the message to print during compilation if the member was overridden + * @param since a string identifying the first version in which overriding was deprecated + * @since 2.10 + * @see [[scala.deprecatedInheritance]] + */ +private[scala] // for the same reasons as deprecatedInheritance +class deprecatedOverriding(message: String = "", since: String = "") extends annotation.StaticAnnotation diff --git a/src/library/scala/io/BytePickle.scala b/src/library/scala/io/BytePickle.scala index 3bb5ea9c2b..a199986141 100644 --- a/src/library/scala/io/BytePickle.scala +++ b/src/library/scala/io/BytePickle.scala @@ -19,6 +19,7 @@ import scala.collection.mutable * @author Philipp Haller * @version 1.1 */ +@deprecated("This class will be removed.", "2.10.0") object BytePickle { abstract class SPU[T] { def appP(a: T, state: PicklerState): PicklerState diff --git a/src/library/scala/io/Position.scala b/src/library/scala/io/Position.scala index 5d1e695add..0d0d0d7648 100644 --- a/src/library/scala/io/Position.scala +++ b/src/library/scala/io/Position.scala @@ -32,6 +32,7 @@ package scala.io * }}} * @author Burak Emir (translated from work by Matthias Zenger and others) */ +@deprecated("This class will be removed.", "2.10.0") abstract class Position { /** Definable behavior for overflow conditions. */ diff --git a/src/library/scala/io/UTF8Codec.scala b/src/library/scala/io/UTF8Codec.scala index df0a36ef21..aa6cccf1d1 100644 --- a/src/library/scala/io/UTF8Codec.scala +++ b/src/library/scala/io/UTF8Codec.scala @@ -13,6 +13,7 @@ package scala.io * @author Martin Odersky * @version 1.0, 04/10/2004 */ +@deprecated("This class will be removed.", "2.10.0") object UTF8Codec { final val UNI_REPLACEMENT_CHAR: Int = 0x0000FFFD final val UNI_REPLACEMENT_BYTES = Array[Byte](-17, -65, -67) diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 8669b2e2e8..a475d663f4 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -159,6 +159,7 @@ object BigDecimal { * @author Stephane Micheloud * @version 1.0 */ +@deprecatedInheritance("This class will me made final.", "2.10.0") class BigDecimal( val bigDecimal: BigDec, val mc: MathContext) diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 09e8ae2026..e354117e14 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -114,6 +114,7 @@ object BigInt { * @author Martin Odersky * @version 1.0, 15/07/2003 */ +@deprecatedInheritance("This class will me made final.", "2.10.0") class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericConversions with Serializable { /** Returns the hash code for this BigInt. */ override def hashCode(): Int = diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 5255c44f10..e42c89d21f 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -2,7 +2,7 @@ package scala.reflect import java.lang.{ Class => jClass } import language.{implicitConversions, existentials} -import scala.runtime.ScalaRunTime.arrayClass +import scala.runtime.ScalaRunTime.{ arrayClass, arrayElementClass } /** A `ClassTag[T]` wraps a runtime class, which can be accessed via the `runtimeClass` method. * @@ -54,35 +54,59 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial * `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)` * is uncheckable, but we have an instance of `ClassTag[T]`. */ - def unapply(x: Any): Option[T] = if (x != null && runtimeClass.isAssignableFrom(x.getClass)) Some(x.asInstanceOf[T]) else None + def unapply(x: Any): Option[T] = unapply_impl(x) + def unapply(x: Byte): Option[T] = unapply_impl(x) + def unapply(x: Short): Option[T] = unapply_impl(x) + def unapply(x: Char): Option[T] = unapply_impl(x) + def unapply(x: Int): Option[T] = unapply_impl(x) + def unapply(x: Long): Option[T] = unapply_impl(x) + def unapply(x: Float): Option[T] = unapply_impl(x) + def unapply(x: Double): Option[T] = unapply_impl(x) + def unapply(x: Boolean): Option[T] = unapply_impl(x) + def unapply(x: Unit): Option[T] = unapply_impl(x) + + private def unapply_impl[U: ClassTag](x: U): Option[T] = + if (x == null) None + else { + val staticClass = classTag[U].runtimeClass + val dynamicClass = x.getClass + val effectiveClass = if (staticClass.isPrimitive) staticClass else dynamicClass + val conforms = runtimeClass.isAssignableFrom(effectiveClass) + if (conforms) Some(x.asInstanceOf[T]) else None + } /** case class accessories */ override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass override def hashCode = scala.runtime.ScalaRunTime.hash(runtimeClass) - override def toString = "ClassTag[" + runtimeClass + "]" + override def toString = { + def prettyprint(clazz: jClass[_]): String = + if (clazz.isArray) s"Array[${prettyprint(arrayElementClass(clazz))}]" else + clazz.getName + prettyprint(runtimeClass) + } } object ClassTag { + private val ObjectTYPE = classOf[java.lang.Object] private val NothingTYPE = classOf[scala.runtime.Nothing$] private val NullTYPE = classOf[scala.runtime.Null$] - private val ObjectTYPE = classOf[java.lang.Object] - val Byte : ClassTag[scala.Byte] = new ClassTag[scala.Byte]{ def runtimeClass = java.lang.Byte.TYPE; private def readResolve() = ClassTag.Byte } - val Short : ClassTag[scala.Short] = new ClassTag[scala.Short]{ def runtimeClass = java.lang.Short.TYPE; private def readResolve() = ClassTag.Short } - val Char : ClassTag[scala.Char] = new ClassTag[scala.Char]{ def runtimeClass = java.lang.Character.TYPE; private def readResolve() = ClassTag.Char } - val Int : ClassTag[scala.Int] = new ClassTag[scala.Int]{ def runtimeClass = java.lang.Integer.TYPE; private def readResolve() = ClassTag.Int } - val Long : ClassTag[scala.Long] = new ClassTag[scala.Long]{ def runtimeClass = java.lang.Long.TYPE; private def readResolve() = ClassTag.Long } - val Float : ClassTag[scala.Float] = new ClassTag[scala.Float]{ def runtimeClass = java.lang.Float.TYPE; private def readResolve() = ClassTag.Float } - val Double : ClassTag[scala.Double] = new ClassTag[scala.Double]{ def runtimeClass = java.lang.Double.TYPE; private def readResolve() = ClassTag.Double } - val Boolean : ClassTag[scala.Boolean] = new ClassTag[scala.Boolean]{ def runtimeClass = java.lang.Boolean.TYPE; private def readResolve() = ClassTag.Boolean } - val Unit : ClassTag[scala.Unit] = new ClassTag[scala.Unit]{ def runtimeClass = java.lang.Void.TYPE; private def readResolve() = ClassTag.Unit } - val Any : ClassTag[scala.Any] = new ClassTag[scala.Any]{ def runtimeClass = ObjectTYPE; private def readResolve() = ClassTag.Any } - val Object : ClassTag[java.lang.Object] = new ClassTag[java.lang.Object]{ def runtimeClass = ObjectTYPE; private def readResolve() = ClassTag.Object } - val AnyVal : ClassTag[scala.AnyVal] = ClassTag.Object.asInstanceOf[ClassTag[scala.AnyVal]] - val AnyRef : ClassTag[scala.AnyRef] = ClassTag.Object.asInstanceOf[ClassTag[scala.AnyRef]] - val Nothing : ClassTag[scala.Nothing] = new ClassTag[scala.Nothing]{ def runtimeClass = NothingTYPE; private def readResolve() = ClassTag.Nothing } - val Null : ClassTag[scala.Null] = new ClassTag[scala.Null]{ def runtimeClass = NullTYPE; private def readResolve() = ClassTag.Null } + val Byte : ClassTag[scala.Byte] = Manifest.Byte + val Short : ClassTag[scala.Short] = Manifest.Short + val Char : ClassTag[scala.Char] = Manifest.Char + val Int : ClassTag[scala.Int] = Manifest.Int + val Long : ClassTag[scala.Long] = Manifest.Long + val Float : ClassTag[scala.Float] = Manifest.Float + val Double : ClassTag[scala.Double] = Manifest.Double + val Boolean : ClassTag[scala.Boolean] = Manifest.Boolean + val Unit : ClassTag[scala.Unit] = Manifest.Unit + val Any : ClassTag[scala.Any] = Manifest.Any + val Object : ClassTag[java.lang.Object] = Manifest.Object + val AnyVal : ClassTag[scala.AnyVal] = Manifest.AnyVal + val AnyRef : ClassTag[scala.AnyRef] = Manifest.AnyRef + val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing + val Null : ClassTag[scala.Null] = Manifest.Null def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = runtimeClass1 match { @@ -96,6 +120,8 @@ object ClassTag { case java.lang.Boolean.TYPE => ClassTag.Boolean.asInstanceOf[ClassTag[T]] case java.lang.Void.TYPE => ClassTag.Unit.asInstanceOf[ClassTag[T]] case ObjectTYPE => ClassTag.Object.asInstanceOf[ClassTag[T]] + case NothingTYPE => ClassTag.Nothing.asInstanceOf[ClassTag[T]] + case NullTYPE => ClassTag.Null.asInstanceOf[ClassTag[T]] case _ => new ClassTag[T]{ def runtimeClass = runtimeClass1 } } diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 9347f5b6bb..f2a23f4372 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -155,28 +155,34 @@ object ManifestFactory { private def readResolve(): Any = Manifest.Unit } - val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any]("Any") { + private val ObjectTYPE = classOf[java.lang.Object] + private val NothingTYPE = classOf[scala.runtime.Nothing$] + private val NullTYPE = classOf[scala.runtime.Null$] + + val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any](ObjectTYPE, "Any") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) private def readResolve(): Any = Manifest.Any } - val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object]("Object") { + val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object](ObjectTYPE, "Object") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.Object } - val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal]("AnyVal") { + val AnyRef: Manifest[scala.AnyRef] = Object.asInstanceOf[Manifest[scala.AnyRef]] + + val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal](ObjectTYPE, "AnyVal") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.AnyVal } - val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null]("Null") { + val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null](NullTYPE, "Null") { override def <:<(that: ClassManifest[_]): Boolean = (that ne null) && (that ne Nothing) && !(that <:< AnyVal) private def readResolve(): Any = Manifest.Null } - val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing]("Nothing") { + val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing](NothingTYPE, "Nothing") { override def <:<(that: ClassManifest[_]): Boolean = (that ne null) private def readResolve(): Any = Manifest.Nothing } @@ -211,7 +217,8 @@ object ManifestFactory { def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = new ClassTypeManifest[T](Some(prefix), clazz, args.toList) - private abstract class PhantomManifest[T](override val toString: String) extends ClassTypeManifest[T](None, classOf[java.lang.Object], Nil) { + private abstract class PhantomManifest[T](_runtimeClass: Predef.Class[_], + override val toString: String) extends ClassTypeManifest[T](None, _runtimeClass, Nil) { override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] override val hashCode = System.identityHashCode(this) } diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index e5f5e9dc5d..a8635151ff 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -167,35 +167,6 @@ object ScalaRunTime { def checkInitialized[T <: AnyRef](x: T): T = if (x == null) throw new UninitializedError else x - abstract class Try[+A] { - def Catch[B >: A](handler: PartialFunction[Throwable, B]): B - def Finally(fin: => Unit): A - } - - def Try[A](block: => A): Try[A] = new Try[A] with Runnable { - private var result: A = _ - private var exception: Throwable = - try { run() ; null } - catch { - case e: ControlThrowable => throw e // don't catch non-local returns etc - case e: Throwable => e - } - - def run() { result = block } - - def Catch[B >: A](handler: PartialFunction[Throwable, B]): B = - if (exception == null) result - else if (handler isDefinedAt exception) handler(exception) - else throw exception - - def Finally(fin: => Unit): A = { - fin - - if (exception == null) result - else throw exception - } - } - def _toString(x: Product): String = x.productIterator.mkString(x.productPrefix + "(", ",", ")") diff --git a/src/library/scala/runtime/WorksheetSupport.scala b/src/library/scala/runtime/WorksheetSupport.scala index 6f2a4d382d..a003bba034 100644 --- a/src/library/scala/runtime/WorksheetSupport.scala +++ b/src/library/scala/runtime/WorksheetSupport.scala @@ -40,9 +40,9 @@ object WorksheetSupport { write((currentOffset+" ").getBytes) } out.write(c) - col = + col = if (c == '\n') -1 - else if (c == '\t') (col / tabInc) * tabInc + tabInc + else if (c == '\t') (col / tabInc) * tabInc + tabInc else col + 1 if (col >= width) writeOne('\n') } @@ -86,7 +86,7 @@ object WorksheetSupport { def $stop() = throw new StopException - def $show(x: Any): String = stringOf(x, scala.Int.MaxValue) + def $show(x: Any): String = stringOf(x) } class StopException extends Exception diff --git a/src/library/scala/testing/Benchmark.scala b/src/library/scala/testing/Benchmark.scala index 9acae34d4e..9c07fcab4f 100644 --- a/src/library/scala/testing/Benchmark.scala +++ b/src/library/scala/testing/Benchmark.scala @@ -33,6 +33,7 @@ import compat.Platform * * @author Iulian Dragos, Burak Emir */ +@deprecated("This class will be removed.", "2.10.0") trait Benchmark { /** this method should be implemented by the concrete benchmark. diff --git a/src/library/scala/testing/Show.scala b/src/library/scala/testing/Show.scala index 5ab46b8985..da1868c7f6 100644 --- a/src/library/scala/testing/Show.scala +++ b/src/library/scala/testing/Show.scala @@ -25,6 +25,7 @@ package scala.testing * where `<result>` is the result of evaluating the call. * */ +@deprecated("This class will be removed.", "2.10.0") trait Show { /** An implicit definition that adds an apply method to Symbol which forwards to `test`. diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index f381a18b0c..7afbfcdd66 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -52,6 +52,8 @@ import language.implicitConversions * ''Note'': only non-fatal exceptions are caught by the combinators on `Try` (see [[scala.util.control.NonFatal]]). * Serious system errors, on the other hand, will be thrown. * + * ''Note:'': all Try combinators will catch exceptions and return failure unless otherwise specified in the documentation. + * * `Try` comes to the Scala standard library after years of use as an integral part of Twitter's stack. * * @author based on Twitter's original implementation in com.twitter.util. @@ -68,12 +70,19 @@ sealed abstract class Try[+T] { def isSuccess: Boolean /** Returns the value from this `Success` or the given `default` argument if this is a `Failure`. + * + * ''Note:'': This will throw an exception if it is not a success and default throws an exception. */ - def getOrElse[U >: T](default: => U) = if (isSuccess) get else default + def getOrElse[U >: T](default: => U): U = + if (isSuccess) get else default /** Returns this `Try` if it's a `Success` or the given `default` argument if this is a `Failure`. */ - def orElse[U >: T](default: => Try[U]) = if (isSuccess) this else default + def orElse[U >: T](default: => Try[U]): Try[U] = + try if (isSuccess) this else default + catch { + case NonFatal(e) => Failure(e) + } /** Returns the value from this `Success` or throws the exception if this is a `Failure`. */ @@ -81,6 +90,8 @@ sealed abstract class Try[+T] { /** * Applies the given function `f` if this is a `Success`, otherwise returns `Unit` if this is a `Failure`. + * + * ''Note:'' If `f` throws, then this method may throw an exception. */ def foreach[U](f: T => U): Unit @@ -114,7 +125,7 @@ sealed abstract class Try[+T] { /** * Returns `None` if this is a `Failure` or a `Some` containing the value if this is a `Success`. */ - def toOption = if (isSuccess) Some(get) else None + def toOption: Option[T] = if (isSuccess) Some(get) else None /** * Transforms a nested `Try`, ie, a `Try` of type `Try[Try[T]]`, @@ -131,20 +142,25 @@ sealed abstract class Try[+T] { /** Completes this `Try` by applying the function `f` to this if this is of type `Failure`, or conversely, by applying * `s` if this is a `Success`. */ - def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = this match { - case Success(v) => s(v) - case Failure(e) => f(e) - } + def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = + try this match { + case Success(v) => s(v) + case Failure(e) => f(e) + } catch { + case NonFatal(e) => Failure(e) + } } object Try { - - def apply[T](r: => T): Try[T] = { - try { Success(r) } catch { + /** Constructs a `Try` using the by-name parameter. This + * method will ensure any non-fatal exception is caught and a + * `Failure` object is returned. + */ + def apply[T](r: => T): Try[T] = + try Success(r) catch { case NonFatal(e) => Failure(e) } - } } @@ -152,24 +168,25 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { def isFailure: Boolean = true def isSuccess: Boolean = false def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = - if (f.isDefinedAt(exception)) f(exception) else this + try { + if (f isDefinedAt exception) f(exception) else this + } catch { + case NonFatal(e) => Failure(e) + } def get: T = throw exception - def flatMap[U](f: T => Try[U]): Try[U] = Failure[U](exception) - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = Failure[U](exception) - def foreach[U](f: T => U): Unit = {} - def map[U](f: T => U): Try[U] = Failure[U](exception) + def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] + def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] + def foreach[U](f: T => U): Unit = () + def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] def filter(p: T => Boolean): Try[T] = this - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = { + def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = try { - if (rescueException.isDefinedAt(exception)) { + if (rescueException isDefinedAt exception) { Try(rescueException(exception)) - } else { - this - } + } else this } catch { case NonFatal(e) => Failure(e) } - } def failed: Try[Throwable] = Success(exception) } @@ -177,7 +194,7 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { final case class Success[+T](value: T) extends Try[T] { def isFailure: Boolean = false def isSuccess: Boolean = true - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = Success(value) + def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = this def get = value def flatMap[U](f: T => Try[U]): Try[U] = try f(value) diff --git a/src/library/scala/util/logging/ConsoleLogger.scala b/src/library/scala/util/logging/ConsoleLogger.scala index 58284797b4..1d9a4deb62 100644 --- a/src/library/scala/util/logging/ConsoleLogger.scala +++ b/src/library/scala/util/logging/ConsoleLogger.scala @@ -17,6 +17,7 @@ package scala.util.logging * @author Burak Emir * @version 1.0 */ +@deprecated("This class will be removed.", "2.10.0") trait ConsoleLogger extends Logged { /** logs argument to Console using [[scala.Console.println]] diff --git a/src/library/scala/util/logging/Logged.scala b/src/library/scala/util/logging/Logged.scala index d23b38c569..1476c8bf08 100644 --- a/src/library/scala/util/logging/Logged.scala +++ b/src/library/scala/util/logging/Logged.scala @@ -22,6 +22,7 @@ package scala.util.logging * }}} * and the logging is sent to the [[scala.util.logging.ConsoleLogger]] object. */ +@deprecated("This class will be removed.", "2.10.0") trait Logged { /** This method should log the message given as argument somewhere * as a side-effect. diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index 20d61d0831..376e0e9bdb 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -312,8 +312,8 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP val testFiles = dir.listFiles.toList filter isJavaOrScala def isInGroup(f: File, num: Int) = SFile(f).stripExtension endsWith ("_" + num) - val groups = (0 to 9).toList map (num => testFiles filter (f => isInGroup(f, num))) - val noGroupSuffix = testFiles filterNot (groups.flatten contains) + val groups = (0 to 9).toList map (num => (testFiles filter (f => isInGroup(f, num))).sorted) + val noGroupSuffix = (testFiles filterNot (groups.flatten contains)).sorted noGroupSuffix :: groups filterNot (_.isEmpty) } diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index b17377795b..1fbbc0c0a4 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -15,9 +15,10 @@ trait Symbols extends base.Symbols { self: Universe => /** The API of symbols */ trait SymbolApi extends SymbolBase { this: Symbol => - /** The position of this symbol + /** Source file if this symbol is created during this compilation run, + * or a class file if this symbol is loaded from a *.class or *.jar. */ - def pos: Position + def associatedFile: scala.tools.nsc.io.AbstractFile /** A list of annotations attached to this Symbol. */ @@ -139,18 +140,6 @@ trait Symbols extends base.Symbols { self: Universe => */ def isErroneous : Boolean - /** Can this symbol be loaded by a reflective mirror? - * - * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs. - * Such annotations (also called "pickles") are applied on top-level classes and include information - * about all symbols reachable from the annotee. However, local symbols (e.g. classes or definitions local to a block) - * are typically unreachable and information about them gets lost. - * - * This method is useful for macro writers who wish to save certain ASTs to be used at runtime. - * With `isLocatable' it's possible to check whether a tree can be retained as is, or it needs special treatment. - */ - def isLocatable: Boolean - /** Is this symbol static (i.e. with no outer instance)? * Q: When exactly is a sym marked as STATIC? * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep. @@ -182,6 +171,10 @@ trait Symbols extends base.Symbols { self: Universe => */ def isSpecialized: Boolean + /** Is this symbol defined by Java? + */ + def isJava: Boolean + /******************* helpers *******************/ /** ... @@ -204,16 +197,16 @@ trait Symbols extends base.Symbols { self: Universe => /** The API of term symbols */ trait TermSymbolApi extends SymbolApi with TermSymbolBase { this: TermSymbol => - /** Does this symbol represent a value, i.e. not a module and not a method? + /** Is this symbol introduced as `val`? */ - def isValue: Boolean + def isVal: Boolean /** Does this symbol denote a stable value? */ def isStable: Boolean - /** Does this symbol represent a mutable value? + /** Is this symbol introduced as `var`? */ - def isVariable: Boolean + def isVar: Boolean /** Does this symbol represent a getter or a setter? */ @@ -320,6 +313,9 @@ trait Symbols extends base.Symbols { self: Universe => */ def isConstructor: Boolean + /** Does this symbol denote the primary constructor of its enclosing class? */ + def isPrimaryConstructor: Boolean + /** For a polymorphic method, its type parameters, the empty list for all other methods */ def typeParams: List[Symbol] @@ -378,6 +374,22 @@ trait Symbols extends base.Symbols { self: Universe => */ def isSealed: Boolean + /** If this is a sealed class, its known direct subclasses. + * Otherwise, the empty set. + */ + def knownDirectSubclasses: Set[Symbol] + + /** The list of all base classes of this type (including its own typeSymbol) + * in reverse linearization order, starting with the class itself and ending + * in class Any. + */ + def baseClasses: List[Symbol] + + /** The module corresponding to this module class, + * or NoSymbol if this symbol is not a module class. + */ + def module: Symbol + /** If this symbol is a class or trait, its self type, otherwise the type * of the symbol itself. */ diff --git a/src/reflect/scala/reflect/internal/AbstractFileApi.scala b/src/reflect/scala/reflect/internal/AbstractFileApi.scala deleted file mode 100644 index 9f37f4536f..0000000000 --- a/src/reflect/scala/reflect/internal/AbstractFileApi.scala +++ /dev/null @@ -1,7 +0,0 @@ -package scala.reflect -package internal - -trait AbstractFileApi { - def path: String - def canonicalPath: String -} diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 98d42b724c..15b74058b7 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -218,6 +218,32 @@ trait Definitions extends api.StandardDefinitions { case _ => null } + /** Fully initialize the symbol, type, or scope. + */ + def fullyInitializeSymbol(sym: Symbol): Symbol = { + sym.initialize + fullyInitializeType(sym.info) + fullyInitializeType(sym.tpe) + sym + } + def fullyInitializeType(tp: Type): Type = { + tp.typeParams foreach fullyInitializeSymbol + tp.paramss.flatten foreach fullyInitializeSymbol + tp + } + def fullyInitializeScope(scope: Scope): Scope = { + scope.sorted foreach fullyInitializeSymbol + scope + } + /** Is this type equivalent to Any, AnyVal, or AnyRef? */ + def isTrivialTopType(tp: Type) = ( + tp =:= AnyClass.tpe + || tp =:= AnyValClass.tpe + || tp =:= AnyRefClass.tpe + ) + /** Does this type have a parent which is none of Any, AnyVal, or AnyRef? */ + def hasNonTrivialParent(tp: Type) = tp.parents exists (t => !isTrivialTopType(tp)) + private def fixupAsAnyTrait(tpe: Type): Type = tpe match { case ClassInfoType(parents, decls, clazz) => if (parents.head.typeSymbol == AnyClass) tpe @@ -251,6 +277,7 @@ trait Definitions extends api.StandardDefinitions { anyval }).asInstanceOf[ClassSymbol] lazy val AnyValTpe = definitions.AnyValClass.toTypeConstructor + def AnyVal_getClass = getMemberMethod(AnyValClass, nme.getClass_) // bottom types lazy val RuntimeNothingClass = getClassByName(fulltpnme.RuntimeNothing) @@ -383,7 +410,7 @@ trait Definitions extends api.StandardDefinitions { def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe) def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf - def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) + def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) def isJavaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe) def isScalaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe) def isVarArgsList(params: Seq[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe) @@ -914,6 +941,8 @@ trait Definitions extends api.StandardDefinitions { lazy val CloneableAttr = requiredClass[scala.annotation.cloneable] lazy val DeprecatedAttr = requiredClass[scala.deprecated] lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName] + lazy val DeprecatedInheritanceAttr = requiredClass[scala.deprecatedInheritance] + lazy val DeprecatedOverridingAttr = requiredClass[scala.deprecatedOverriding] lazy val NativeAttr = requiredClass[scala.native] lazy val RemoteAttr = requiredClass[scala.remote] lazy val ScalaInlineClass = requiredClass[scala.inline] diff --git a/src/reflect/scala/reflect/internal/Required.scala b/src/reflect/scala/reflect/internal/Required.scala index abbe8fbfb7..842491d56d 100644 --- a/src/reflect/scala/reflect/internal/Required.scala +++ b/src/reflect/scala/reflect/internal/Required.scala @@ -5,8 +5,6 @@ import settings.MutableSettings trait Required { self: SymbolTable => - type AbstractFileType >: Null <: AbstractFileApi - def picklerPhase: Phase def settings: MutableSettings diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index c0e6a66767..b1e81de037 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -12,6 +12,7 @@ import util.Statistics import Flags._ import base.Attachments import scala.annotation.tailrec +import scala.tools.nsc.io.AbstractFile trait Symbols extends api.Symbols { self: SymbolTable => import definitions._ @@ -67,12 +68,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isParamWithDefault: Boolean = this.hasDefault def isByNameParam: Boolean = this.isValueParameter && (this hasFlag BYNAMEPARAM) def isImplementationArtifact: Boolean = (this hasFlag BRIDGE) || (this hasFlag VBRIDGE) || (this hasFlag ARTIFACT) + def isJava: Boolean = this hasFlag JAVA + def isVal: Boolean = isTerm && !isModule && !isMethod && !isMutable + def isVar: Boolean = isTerm && !isModule && !isMethod && isMutable def newNestedSymbol(name: Name, pos: Position, newFlags: Long, isClass: Boolean): Symbol = name match { case n: TermName => newTermSymbol(n, pos, newFlags) case n: TypeName => if (isClass) newClassSymbol(n, pos, newFlags) else newNonClassSymbol(n, pos, newFlags) } + def knownDirectSubclasses = children + def baseClasses = info.baseClasses + def module = sourceModule def thisPrefix: Type = thisType def selfType: Type = typeOfThis def typeSignature: Type = info @@ -695,6 +702,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0) + def hasDeprecatedInheritanceAnnotation + = hasAnnotation(DeprecatedInheritanceAttr) + def deprecatedInheritanceMessage + = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 0) + def deprecatedInheritanceVersion + = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 1) + def hasDeprecatedOverridingAnnotation + = hasAnnotation(DeprecatedOverridingAttr) + def deprecatedOverridingMessage + = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 0) + def deprecatedOverridingVersion + = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 1) // !!! when annotation arguments are not literal strings, but any sort of // assembly of strings, there is a fair chance they will turn up here not as @@ -851,7 +870,16 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isInitialized: Boolean = validTo != NoPeriod - /** Determines whether this symbol can be loaded by subsequent reflective compilation */ + /** Can this symbol be loaded by a reflective mirror? + * + * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs. + * Such annotations (also called "pickles") are applied on top-level classes and include information + * about all symbols reachable from the annotee. However, local symbols (e.g. classes or definitions local to a block) + * are typically unreachable and information about them gets lost. + * + * This method is useful for macro writers who wish to save certain ASTs to be used at runtime. + * With `isLocatable' it's possible to check whether a tree can be retained as is, or it needs special treatment. + */ final def isLocatable: Boolean = { if (this == NoSymbol) return false if (isRoot || isRootPackage) return true @@ -1788,26 +1816,16 @@ trait Symbols extends api.Symbols { self: SymbolTable => } else owner.enclosingTopLevelClass /** Is this symbol defined in the same scope and compilation unit as `that` symbol? */ - def isCoDefinedWith(that: Symbol) = { - (this.rawInfo ne NoType) && - (this.effectiveOwner == that.effectiveOwner) && { - !this.effectiveOwner.isPackageClass || - (this.sourceFile eq null) || - (that.sourceFile eq null) || - (this.sourceFile == that.sourceFile) || { - // recognize companion object in separate file and fail, else compilation - // appears to succeed but highly opaque errors come later: see bug #1286 - if (this.sourceFile.path != that.sourceFile.path) { - // The cheaper check can be wrong: do the expensive normalization - // before failing. - if (this.sourceFile.canonicalPath != that.sourceFile.canonicalPath) - throw InvalidCompanions(this, that) - } - - false - } - } - } + def isCoDefinedWith(that: Symbol) = ( + (this.rawInfo ne NoType) + && (this.effectiveOwner == that.effectiveOwner) + && ( !this.effectiveOwner.isPackageClass + || (this.sourceFile eq null) + || (that.sourceFile eq null) + || (this.sourceFile.path == that.sourceFile.path) // Cheap possibly wrong check, then expensive normalization + || (this.sourceFile.canonicalPath == that.sourceFile.canonicalPath) + ) + ) /** The internal representation of classes and objects: * @@ -2063,21 +2081,21 @@ trait Symbols extends api.Symbols { self: SymbolTable => * of sourceFile (which is expected at least in the IDE only to * return actual source code.) So sourceFile has classfiles filtered out. */ - private def sourceFileOnly(file: AbstractFileType): AbstractFileType = + private def sourceFileOnly(file: AbstractFile): AbstractFile = if ((file eq null) || (file.path endsWith ".class")) null else file - private def binaryFileOnly(file: AbstractFileType): AbstractFileType = + private def binaryFileOnly(file: AbstractFile): AbstractFile = if ((file eq null) || !(file.path endsWith ".class")) null else file - final def binaryFile: AbstractFileType = binaryFileOnly(associatedFile) - final def sourceFile: AbstractFileType = sourceFileOnly(associatedFile) + final def binaryFile: AbstractFile = binaryFileOnly(associatedFile) + final def sourceFile: AbstractFile = sourceFileOnly(associatedFile) /** Overridden in ModuleSymbols to delegate to the module class. */ - def associatedFile: AbstractFileType = enclosingTopLevelClass.associatedFile - def associatedFile_=(f: AbstractFileType) { abort("associatedFile_= inapplicable for " + this) } + def associatedFile: AbstractFile = enclosingTopLevelClass.associatedFile + def associatedFile_=(f: AbstractFile) { abort("associatedFile_= inapplicable for " + this) } @deprecated("Use associatedFile_= instead", "2.10.0") - def sourceFile_=(f: AbstractFileType): Unit = associatedFile_=(f) + def sourceFile_=(f: AbstractFile): Unit = associatedFile_=(f) /** If this is a sealed class, its known direct subclasses. * Otherwise, the empty set. @@ -2461,7 +2479,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private var flatname: TermName = null override def associatedFile = moduleClass.associatedFile - override def associatedFile_=(f: AbstractFileType) { moduleClass.associatedFile = f } + override def associatedFile_=(f: AbstractFile) { moduleClass.associatedFile = f } override def moduleClass = referenced override def companionClass = @@ -2765,9 +2783,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => extends TypeSymbol(initOwner, initPos, initName) with ClassSymbolApi { type TypeOfClonedSymbol = ClassSymbol - private[this] var flatname: TypeName = _ - private[this] var _associatedFile: AbstractFileType = _ - private[this] var thissym: Symbol = this + private[this] var flatname: TypeName = _ + private[this] var _associatedFile: AbstractFile = _ + private[this] var thissym: Symbol = this private[this] var thisTypeCache: Type = _ private[this] var thisTypePeriod = NoPeriod @@ -2865,7 +2883,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } override def associatedFile = if (owner.isPackageClass) _associatedFile else super.associatedFile - override def associatedFile_=(f: AbstractFileType) { _associatedFile = f } + override def associatedFile_=(f: AbstractFile) { _associatedFile = f } override def reset(completer: Type): this.type = { super.reset(completer) @@ -3200,13 +3218,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (settings.debug.value) printStackTrace() } - case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable({ - "Companions '" + sym1 + "' and '" + sym2 + "' must be defined in same file:\n" + - " Found in " + sym1.sourceFile.canonicalPath + " and " + sym2.sourceFile.canonicalPath - }) { - override def toString = getMessage - } - /** A class for type histories */ private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) { assert((prev eq null) || phaseId(validFrom) > phaseId(prev.validFrom), this) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index b13b893635..df44cf234e 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -317,25 +317,6 @@ trait Types extends api.Types { self: SymbolTable => def substituteSymbols(from: List[Symbol], to: List[Symbol]): Type = substSym(from, to) def substituteTypes(from: List[Symbol], to: List[Type]): Type = subst(from, to) - def isConcrete = { - def notConcreteSym(sym: Symbol) = - sym.isAbstractType && !sym.isExistential - - def notConcreteTpe(tpe: Type): Boolean = tpe match { - case ThisType(_) => false - case SuperType(_, _) => false - case SingleType(pre, sym) => notConcreteSym(sym) - case ConstantType(_) => false - case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists notConcreteTpe) - case RefinedType(_, _) => false - case ExistentialType(_, _) => false - case AnnotatedType(_, tp, _) => notConcreteTpe(tp) - case _ => true - } - - !notConcreteTpe(this) - } - // the only thingies that we want to splice are: 1) type parameters, 2) abstract type members // the thingies that we don't want to splice are: 1) concrete types (obviously), 2) existential skolems def isSpliceable = { @@ -1010,7 +991,11 @@ trait Types extends api.Types { self: SymbolTable => def toLongString = { val str = toString if (str == "type") widen.toString - else if ((str endsWith ".type") && !typeSymbol.isModuleClass) str + " (with underlying type " + widen + ")" + else if ((str endsWith ".type") && !typeSymbol.isModuleClass) + widen match { + case RefinedType(_, _) => "" + widen + case _ => s"$str (with underlying type $widen)" + } else str } @@ -1632,7 +1617,7 @@ trait Types extends api.Types { self: SymbolTable => override def safeToString: String = parentsString(parents) + ( (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) - decls.mkString("{", "; ", "}") else "") + fullyInitializeScope(decls).mkString("{", "; ", "}") else "") ) } @@ -1819,7 +1804,6 @@ trait Types extends api.Types { self: SymbolTable => false })) } - override def kind = "RefinedType" } @@ -2005,9 +1989,11 @@ trait Types extends api.Types { self: SymbolTable => /** A nicely formatted string with newlines and such. */ def formattedToString: String = - parents.mkString("\n with ") + - (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) - decls.mkString(" {\n ", "\n ", "\n}") else "") + parents.mkString("\n with ") + ( + if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) + fullyInitializeScope(decls).mkString(" {\n ", "\n ", "\n}") + else "" + ) } object ClassInfoType extends ClassInfoTypeExtractor @@ -2466,7 +2452,7 @@ trait Types extends api.Types { self: SymbolTable => def refinementString = ( if (sym.isStructuralRefinement) ( - decls filter (sym => sym.isPossibleInRefinement && sym.isPublic) + fullyInitializeScope(decls) filter (sym => sym.isPossibleInRefinement && sym.isPublic) map (_.defString) mkString("{", "; ", "}") ) @@ -3468,9 +3454,9 @@ trait Types extends api.Types { self: SymbolTable => } /** A temporary type representing the erasure of a user-defined value type. - * Created during phase reasure, eliminated again in posterasure. - * @param sym The value class symbol - * @param underlying The underlying type before erasure + * Created during phase erasure, eliminated again in posterasure. + * + * @param original The underlying type before erasure */ abstract case class ErasedValueType(original: TypeRef) extends UniqueType { override def safeToString = "ErasedValueType("+original+")" diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala index 8d9711dedd..06428ee3fc 100644 --- a/src/reflect/scala/reflect/macros/Universe.scala +++ b/src/reflect/scala/reflect/macros/Universe.scala @@ -24,6 +24,12 @@ abstract class Universe extends scala.reflect.api.Universe { */ trait SymbolContextApi extends SymbolApi with AttachableApi { self: Symbol => + def deSkolemize: Symbol + + /** The position of this symbol + */ + def pos: Position + def setTypeSignature(tpe: Type): Symbol def setAnnotations(annots: AnnotationInfo*): Symbol diff --git a/src/reflect/scala/reflect/runtime/AbstractFile.scala b/src/reflect/scala/reflect/runtime/AbstractFile.scala deleted file mode 100644 index 0f88af1b0a..0000000000 --- a/src/reflect/scala/reflect/runtime/AbstractFile.scala +++ /dev/null @@ -1,7 +0,0 @@ -package scala.reflect -package runtime - -class AbstractFile(val jfile: java.io.File) extends internal.AbstractFileApi { - def path: String = jfile.getPath() - def canonicalPath: String = jfile.getCanonicalPath() -} diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 629df76178..77d65a7db2 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -8,8 +8,6 @@ import internal.{SomePhase, NoPhase, Phase, TreeGen} */ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self => - type AbstractFileType = AbstractFile - def picklerPhase = SomePhase lazy val settings = new Settings diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala index e87c6b339b..0125fa2c53 100644 --- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala +++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala @@ -49,7 +49,7 @@ object ReflectionUtils { case cl: java.net.URLClassLoader => (cl.getURLs mkString ",") case cl if cl != null && isAbstractFileClassLoader(cl.getClass) => - cl.asInstanceOf[{val root: scala.reflect.internal.AbstractFileApi}].root.canonicalPath + cl.asInstanceOf[{val root: scala.tools.nsc.io.AbstractFile}].root.canonicalPath case null => inferBootClasspath case _ => diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 12db7a7bf9..40346cad79 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -1,7 +1,7 @@ package scala.reflect package runtime -import internal.Flags.DEFERRED +import scala.tools.nsc.io.AbstractFile trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => @@ -123,7 +123,7 @@ trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol { override def associatedFile = synchronized { super.associatedFile } - override def associatedFile_=(f: AbstractFileType) = synchronized { super.associatedFile_=(f) } + override def associatedFile_=(f: AbstractFile) = synchronized { super.associatedFile_=(f) } override def thisSym: Symbol = synchronized { super.thisSym } override def thisType: Type = synchronized { super.thisType } override def typeOfThis: Type = synchronized { super.typeOfThis } diff --git a/src/reflect/scala/tools/nsc/io/AbstractFile.scala b/src/reflect/scala/tools/nsc/io/AbstractFile.scala index 8d55b708b1..018a017c6d 100644 --- a/src/reflect/scala/tools/nsc/io/AbstractFile.scala +++ b/src/reflect/scala/tools/nsc/io/AbstractFile.scala @@ -82,7 +82,7 @@ object AbstractFile { * <code>global.settings.encoding.value</code>. * </p> */ -abstract class AbstractFile extends reflect.internal.AbstractFileApi with Iterable[AbstractFile] { +abstract class AbstractFile extends Iterable[AbstractFile] { /** Returns the name of this abstract file. */ def name: String |