diff options
author | Antonio Cunei <antonio.cunei@epfl.ch> | 2011-03-20 03:02:15 +0000 |
---|---|---|
committer | Antonio Cunei <antonio.cunei@epfl.ch> | 2011-03-20 03:02:15 +0000 |
commit | ea94126e2dd5aa62d54ca894a785b1814c432441 (patch) | |
tree | cf51dd730619920806a8338eb115e447ddcec5a5 /src | |
parent | 1ca657a0a8e2c1d378b6344b1961042bc126e97e (diff) | |
download | scala-ea94126e2dd5aa62d54ca894a785b1814c432441.tar.gz scala-ea94126e2dd5aa62d54ca894a785b1814c432441.tar.bz2 scala-ea94126e2dd5aa62d54ca894a785b1814c432441.zip |
Merged revisions 24504-24516 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk
........
r24504 | extempore | 2011-03-19 01:31:59 +0100 (Sat, 19 Mar 2011) | 4 lines
rytz's patch for making our crazy long names a bit less crazy. You
can now use -Xmax-classfile-name to limit your filenames to as few as
72 characters. Watch out, nanotube gardens, we'll be stepping on your
tiny flowers before you know it. No review. ........ r24505 | kzys |
2011-03-19 13:14:14 +0100 (Sat, 19 Mar 2011) | 2 lines
[scaladoc] Closes #4361.
........
r24506 | kzys | 2011-03-19 14:02:35 +0100 (Sat, 19 Mar 2011) | 2 lines
[scaladoc] Closes #4357. Review by dubochet.
........
r24507 | extempore | 2011-03-19 16:27:01 +0100 (Sat, 19 Mar 2011) | 3 lines
A couple more minor tweaks to power mode, and more importantly, fix
for a jline NPE provoked if your classloaders loaded classes in a
way other than it expected. No review. ........ r24508 | extempore |
2011-03-19 16:27:19 +0100 (Sat, 19 Mar 2011) | 4 lines
Some boundary conditions in range. Also bit the bullet on getting
infix implicits to Integral and Fractional. As a bonus this patch
knocked 10,000 long boxings off a specialized test. Who knew. Closes
#4308, #4321, review by community. ........ r24509 | extempore |
2011-03-19 16:38:06 +0100 (Sat, 19 Mar 2011) | 1 line
Added a :type command to the repl, no review.
........
r24510 | extempore | 2011-03-19 18:32:37 +0100 (Sat, 19 Mar 2011) | 10 lines
Removed long deprecated and obscure CloneableCollection. Discovered
we have a scala.collection.mutable.Cloneable which does not extend
java.lang.Cloneable, which is why Array is not considered cloneable.
That seems wrong, but to be conservative I gave Array the Cloneable
interface without altering the scala trait.
Also, if @serializable is deprecated in favor of Serializable,
should not @cloneable be deprecated analogously? Closes #4307, and a
commit-question review by rytz. ........ r24511 | extempore | 2011-03-19
19:12:17 +0100 (Sat, 19 Mar 2011) | 2 lines
Fix for crasher with Class objects. Code by moors, comment by
extempore. References #4305, no review. ........ r24512 | extempore |
2011-03-19 20:55:42 +0100 (Sat, 19 Mar 2011) | 3 lines
Prevent a divergent implicit from terminating implicit search, so
that there can still be a winner, as endorsed by martin over a cheese
plate. Closes #3883, review by dmharrah. ........ r24513 | extempore |
2011-03-19 20:55:59 +0100 (Sat, 19 Mar 2011) | 3 lines
I'm going to assume the patch I dropped off five months ago for #3938
was merely overlooked. Fixes an issue with java types which extend inner
classes. Closes #3938, review by odersky. ........ r24514 | extempore |
2011-03-19 21:20:17 +0100 (Sat, 19 Mar 2011) | 1 line
Fix for a slice related array view regression. Closes #4352, no
review. ........ r24515 | extempore | 2011-03-19 21:29:02 +0100 (Sat, 19
Mar 2011) | 2 lines
Oh yeah, now I remember why I started with length overrides. Fix
for soon to be failing test, no review. ........ r24516 | extempore |
2011-03-20 00:20:19 +0100 (Sun, 20 Mar 2011) | 2 lines
Fix for a big bug in lastIndexOfSlice and some latent negative index
bugs in both that and indexOfSlice. This stuff is taxing. Closes #4348,
no review. ........
Diffstat (limited to 'src')
23 files changed, 352 insertions, 248 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index c97fdbf58e..9a1bafa27f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -237,13 +237,13 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid { for (annot <- c.symbol.annotations) annot match { case AnnotationInfo(tp, _, _) if tp.typeSymbol == SerializableAttr => - parents = parents ::: List(SerializableClass.tpe) + parents :+= SerializableClass.tpe case AnnotationInfo(tp, _, _) if tp.typeSymbol == CloneableAttr => - parents = parents ::: List(CloneableClass.tpe) + parents :+= CloneableClass.tpe case AnnotationInfo(tp, Literal(const) :: _, _) if tp.typeSymbol == SerialVersionUIDAttr => serialVUID = Some(const.longValue) case AnnotationInfo(tp, _, _) if tp.typeSymbol == RemoteAttr => - parents = parents ::: List(RemoteInterface.tpe) + parents :+= RemoteInterface.tpe isRemoteClass = true case _ => } diff --git a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala index 124fe54195..d82d5bfa5a 100644 --- a/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/comment/CommentFactory.scala @@ -172,7 +172,7 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => /** Safe HTML tags that can be kept. */ protected val SafeTags = - new Regex("""((&\w+;)|(<code( [^>]*)?>.*</code>)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""") + new Regex("""((&\w+;)|(&#\d+;)|(<code( [^>]*)?>.*</code>)|(</?(abbr|acronym|address|area|a|bdo|big|blockquote|br|button|b|caption|cite|col|colgroup|dd|del|dfn|em|fieldset|form|hr|img|input|ins|i|kbd|label|legend|link|map|object|optgroup|option|param|pre|q|samp|select|small|span|strong|sub|sup|table|tbody|td|textarea|tfoot|th|thead|tr|tt|var)( [^>]*)?/?>))""") protected val safeTagMarker = '\u000E' @@ -602,8 +602,11 @@ trait CommentFactory { thisFactory: ModelFactory with CommentFactory => def superscript(): Inline = { jump("^") val i = inline(check("^")) - jump("^") - Superscript(i) + if (jump("^")) { + Superscript(i) + } else { + Chain(Seq(Text("^"), i)) + } } def subscript(): Inline = { diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 53a3448c20..3d4ff7a20b 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -216,7 +216,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter) NoArgs("quit", "exit the interpreter", () => Result(false, None)), NoArgs("replay", "reset execution and replay all previous commands", replay), LineArg("sh", "fork a shell and run a command", shCommand), - NoArgs("silent", "disable/enable automatic printing of results", verbosity) + NoArgs("silent", "disable/enable automatic printing of results", verbosity), + LineArg("type", "display the type of an expression without evaluating it", typeCommand) ) } @@ -315,6 +316,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter) } } + private def typeCommand(line: String): Result = { + intp.typeOfExpression(line) match { + case Some(tp) => tp.toString + case _ => "Failed to determine type." + } + } + private def javapCommand(line: String): Result = { if (line == "") return ":javap [-lcsvp] [path1 path2 ...]" diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 33dcfa59e6..527a9b153a 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -993,7 +993,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { def asModule = safeModule(expr) map (_.tpe) def asExpr = beSilentDuring { val lhs = freshInternalVarName() - interpret("val " + lhs + " = { " + expr + " } ") match { + interpret("lazy val " + lhs + " = { " + expr + " } ") match { case IR.Success => typeOfExpression(lhs) case _ => None } diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala index 796934cd35..7430406306 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala @@ -201,7 +201,13 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput } // top level packages - object rootClass extends TypeMemberCompletion(RootClass.tpe) { } + object rootClass extends TypeMemberCompletion(RootClass.tpe) { + override def completions(verbosity: Int) = super.completions(verbosity) :+ "_root_" + override def follow(id: String) = id match { + case "_root_" => Some(this) + case _ => super.follow(id) + } + } // members of Predef object predef extends TypeMemberCompletion(PredefModule.tpe) { override def excludeEndsWith = super.excludeEndsWith ++ List("Wrapper", "ArrayOps") diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index 6dc8cee219..0933365d9e 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -125,12 +125,16 @@ class Power(repl: ILoop, intp: IMain) { object InternalInfo { implicit def apply[T: Manifest] : InternalInfo[T] = new InternalInfo[T](None) } - /** Todo: translate manifest type arguments into applied types. */ + /** Todos... + * translate manifest type arguments into applied types + * customizable symbol filter (had to hardcode no-spec to reduce noise) + */ class InternalInfo[T: Manifest](value: Option[T] = None) { def companion = symbol.companionSymbol def info = symbol.info def module = symbol.moduleClass def owner = symbol.owner + def owners = symbol.ownerChain drop 1 def symDef = symbol.defString def symName = symbol.name def tpe = symbol.tpe @@ -140,16 +144,18 @@ class Power(repl: ILoop, intp: IMain) { def types = members filter (_.name.isTypeName) def methods = members filter (_.isMethod) def overrides = declares filter (_.isOverride) + def inPackage = owners find (x => x.isPackageClass || x.isPackage) getOrElse definitions.RootPackage - def erasure = manifest[T].erasure - def symbol = getCompilerClass(erasure.getName) - def members = tpe.members - def bts = info.baseTypeSeq.toList - def btsmap = bts map (x => (x, x.decls.toList)) toMap - def pkgName = erasure.getPackage.getName - def pkg = getCompilerModule(pkgName) - def pkgmates = pkg.tpe.members - def pkgslurp = new PackageSlurper(pkgName) slurp() + def erasure = manifest[T].erasure + def symbol = getCompilerClass(erasure.getName) + def members = tpe.members filterNot (_.name.toString contains "$mc") + def allMembers = tpe.members + def bts = info.baseTypeSeq.toList + def btsmap = bts map (x => (x, x.decls.toList)) toMap + def pkgName = erasure.getPackage.getName + def pkg = getCompilerModule(pkgName) + def pkgmates = pkg.tpe.members + def pkgslurp = new PackageSlurper(pkgName) slurp() def ? = this @@ -167,28 +173,73 @@ class Power(repl: ILoop, intp: IMain) { trait PCFormatter extends (Any => List[String]) { def apply(x: Any): List[String] + + private var indentLevel = 0 + private def spaces = " " * indentLevel + def indented[T](body: => T): T = { + indentLevel += 1 + try body + finally indentLevel -= 1 + } + def show(x: Any): Unit = grep(x, _ => true) - def grep(x: Any, p: String => Boolean): Unit = apply(x) filter p foreach println + def grep(x: Any, p: String => Boolean): Unit = + apply(x) filter p foreach (x => println(spaces + x)) + } + class MultiPrintingConvenience[T](coll: Traversable[T])(implicit fmt: PCFormatter) { + import fmt._ + + def freqBy[U](p: T => U) = { + val map = coll.toList groupBy p + map.toList sortBy (-_._2.size) + } + def freqByFormatted[U](p: T => U) = { + val buf = new mutable.ListBuffer[String] + + freqBy(p) foreach { case (k, vs) => + buf += "%d: %s".format(vs.size, k) + vs flatMap fmt foreach (buf += " " + _) + } + buf.toList + } + + /** It makes sense. + * + * # means how many + * ? means "I said, HOW MANY?" + * > means print + * + * Now don't you feel silly for what you were thinking. + */ + def #?>[U](p: T => U) = this freqByFormatted p foreach println + def #?[U](p: T => U) = this freqByFormatted p } + class PrintingConvenience[T](value: T)(implicit fmt: PCFormatter) { def > : Unit = >(_ => true) def >(s: String): Unit = >(_ contains s) def >(r: Regex): Unit = >(_ matches r.pattern.toString) def >(p: String => Boolean): Unit = fmt.grep(value, p) } - object Implicits { - implicit lazy val powerNameOrdering: Ordering[Name] = Ordering[String] on (_.toString) - implicit object powerSymbolOrdering extends Ordering[Symbol] { + protected trait Implicits1 { + implicit def replPrinting[T](x: T)(implicit fmt: PCFormatter) = new PrintingConvenience[T](x) + } + object Implicits extends Implicits1 { + implicit lazy val powerNameOrdering: Ordering[Name] = Ordering[String] on (_.toString) + implicit lazy val powerSymbolOrdering: Ordering[Symbol] = Ordering[Name] on (_.name) + implicit lazy val powerTypeOrdering: Ordering[Type] = Ordering[Symbol] on (_.typeSymbol) + + object symbolSubtypeOrdering extends Ordering[Symbol] { def compare(s1: Symbol, s2: Symbol) = if (s1 eq s2) 0 else if (s1 isLess s2) -1 else 1 } - implicit def replPrinting[T](x: T)(implicit fmt: PCFormatter) = new PrintingConvenience[T](x) + implicit def replCollPrinting[T](xs: Traversable[T])(implicit fmt: PCFormatter) = new MultiPrintingConvenience[T](xs) implicit def replInternalInfo[T: Manifest](x: T): InternalInfo[T] = new InternalInfo[T](Some(x)) implicit object ReplDefaultFormatter extends PCFormatter { def apply(x: Any): List[String] = x match { - case Tuple2(k, v) => apply(k) + " -> " + apply(v) + case Tuple2(k, v) => List(apply(k) ++ Seq("->") ++ apply(v) mkString " ") case xs: Traversable[_] => (xs.toList flatMap apply).sorted.distinct case x => List("" + x) } diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 1670dfb94a..7405ca0b3d 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -57,6 +57,7 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings { val future = BooleanSetting ("-Xfuture", "Turn on future language features.") val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "") val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.") + val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some(72, 255), _ => None) val Xmigration28 = BooleanSetting ("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8.") val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.") val Xnojline = BooleanSetting ("-Xnojline", "Do not use JLine for editing.") diff --git a/src/compiler/scala/tools/nsc/symtab/NameManglers.scala b/src/compiler/scala/tools/nsc/symtab/NameManglers.scala index b24a064139..dae07a29d5 100644 --- a/src/compiler/scala/tools/nsc/symtab/NameManglers.scala +++ b/src/compiler/scala/tools/nsc/symtab/NameManglers.scala @@ -22,15 +22,28 @@ trait NameManglers { def flattenedName(segments: Name*): NameType = compactedString(segments mkString "$") - private final val MaxFileNameLength = 255 - private final val MaxNameLength = MaxFileNameLength - 6 // leave space for ".class" - - /** "COMPACTIFY" */ + /** + * COMPACTIFY + * + * The hashed name has the form (prefix + marker + md5 + marker + suffix), where + * - prefix/suffix.length = MaxNameLength / 4 + * - md5.length = 32 + * + * We obtain the formula: + * + * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6 + * + * (+6 for ".class"). MaxNameLength can therefore be computed as follows: + */ + private final val marker = "$$$$" + private final val MaxNameLength = math.min( + settings.maxClassfileName.value - 6, + 2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32) + 6 + ) private lazy val md5 = MessageDigest.getInstance("MD5") private def toMD5(s: String, edge: Int) = { val prefix = s take edge val suffix = s takeRight edge - val marker = "$$$$" val cs = s.toArray val bytes = Codec toUTF8 cs diff --git a/src/compiler/scala/tools/nsc/symtab/Names.scala b/src/compiler/scala/tools/nsc/symtab/Names.scala index 9e0348c2e3..a046058faf 100644 --- a/src/compiler/scala/tools/nsc/symtab/Names.scala +++ b/src/compiler/scala/tools/nsc/symtab/Names.scala @@ -23,9 +23,6 @@ trait Names extends reflect.generic.Names { private final val HASH_MASK = 0x7FFF private final val NAME_SIZE = 0x20000 - private final val MaxFileNameLength = 255 - private final val MaxClassNameLength = MaxFileNameLength - 6 // leave space for ".class" - final val nameDebug = false /** memory to store all names sequentially @@ -78,26 +75,6 @@ trait Names extends reflect.generic.Names { else nc = nc + len } - private lazy val md5 = MessageDigest.getInstance("MD5") - - /** "COMPACTIFY" */ - private def toMD5(s: String, edge: Int) = { - val prefix = s take edge - val suffix = s takeRight edge - val marker = "$$$$" - - val cs = s.toArray - val bytes = Codec toUTF8 cs - md5 update bytes - val md5chars = md5.digest() map (b => (b & 0xFF).toHexString) mkString - - prefix + marker + md5chars + marker + suffix - } - - def compactify(s: String): String = - if (s.length <= MaxClassNameLength) s - else toMD5(s, MaxClassNameLength / 4) - /** Create a term name from the characters in cs[offset..offset+len-1]. */ def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = { diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 8cc977fa65..fd86fb7345 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -3396,7 +3396,8 @@ A type's typeSymbol should never be inspected directly. else instParam(ps.tail, as.tail); val symclazz = sym.owner if (symclazz == clazz && !pre.isInstanceOf[TypeVar] && (pre.widen.typeSymbol isNonBottomSubClass symclazz)) { - pre.baseType(symclazz) match { + // have to deconst because it may be a Class[T]. + pre.baseType(symclazz).deconst match { case TypeRef(_, basesym, baseargs) => //Console.println("instantiating " + sym + " from " + basesym + " with " + basesym.typeParams + " and " + baseargs+", pre = "+pre+", symclazz = "+symclazz);//DEBUG if (sameLength(basesym.typeParams, baseargs)) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 655e5dfe09..3fc8344d8d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -591,7 +591,7 @@ trait Implicits { * If it is null, no shadowing. */ class ImplicitComputation(iss: Infoss, shadowed: util.HashSet[Name]) { - private var _best: SearchResult = SearchFailure + private var best: SearchResult = SearchFailure /** True if a given ImplicitInfo (already known isValid) is eligible. */ @@ -612,6 +612,18 @@ trait Implicits { */ private def checkValid(sym: Symbol) = isValid(sym) || { invalidImplicits += sym ; false } + /** Preventing a divergent implicit from terminating implicit search, + * so that if there is a best candidate it can still be selected. + */ + private var divergence = false + private val MaxDiverges = 1 // not sure if this should be > 1 + private val divergenceHandler = util.Exceptional.expiringHandler(MaxDiverges) { + case x: DivergentImplicit => + divergence = true + log("discarding divergent implicit during implicit search") + SearchFailure + } + /** Sorted list of eligible implicits. */ val eligible = { @@ -635,10 +647,14 @@ trait Implicits { @tailrec private def rankImplicits(pending: Infos, acc: Infos): Infos = pending match { case Nil => acc case i :: is => - typedImplicit(i, true) match { + def tryImplicitInfo(i: ImplicitInfo) = + try typedImplicit(i, true) + catch divergenceHandler + + tryImplicitInfo(i) match { case SearchFailure => rankImplicits(is, acc) case newBest => - _best = newBest + best = newBest val newPending = undoLog undo { is filterNot (alt => alt == i || { try improves(i, alt) @@ -671,13 +687,20 @@ trait Implicits { } } - if (_best == SearchFailure && invalidImplicits.nonEmpty) { - setAddendum(tree.pos, () => - "\n Note: implicit "+invalidImplicits.head+" is not applicable here"+ - " because it comes after the application point and it lacks an explicit result type") + if (best == SearchFailure) { + /** If there is no winner, and we witnessed and caught divergence, + * now we can throw it for the error message. + */ + if (divergence) + throw DivergentImplicit + + if (invalidImplicits.nonEmpty) + setAddendum(tree.pos, () => + "\n Note: implicit "+invalidImplicits.head+" is not applicable here"+ + " because it comes after the application point and it lacks an explicit result type") } - _best + best } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7ba561136d..fb8b0058eb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4267,7 +4267,7 @@ trait Typers extends Modes { val result = typed(tree, forTypeMode(mode) | FUNmode, WildcardType) val restpe = result.tpe.normalize // normalize to get rid of type aliases for the following check (#1241) - if (!phase.erasedTypes && restpe.isInstanceOf[TypeRef] && !restpe.prefix.isStable) { + if (!phase.erasedTypes && restpe.isInstanceOf[TypeRef] && !restpe.prefix.isStable && !context.unit.isJava) { error(tree.pos, restpe.prefix+" is not a legal prefix for a constructor") } diff --git a/src/compiler/scala/tools/nsc/util/Exceptional.scala b/src/compiler/scala/tools/nsc/util/Exceptional.scala index 4230f29eb5..459881bb64 100644 --- a/src/compiler/scala/tools/nsc/util/Exceptional.scala +++ b/src/compiler/scala/tools/nsc/util/Exceptional.scala @@ -64,6 +64,20 @@ class Exceptional(val ex: Throwable)(implicit prefs: ScalaPrefs) { object Exceptional { + type Catcher[+T] = PartialFunction[Throwable, T] + + /** Creates an exception handler which will only ever catch the given + * number of exceptions (if the given pf is defined there) and after + * that will disable itself. + */ + def expiringHandler[T](numCatches: Int)(pf: Catcher[T]): Catcher[T] = { + var remaining = numCatches; + { case ex: Throwable if remaining > 0 && pf.isDefinedAt(ex) => + remaining -= 1 + pf(ex) + } + } + /** The Throwable => Exceptional implicit plus the associated factory. */ implicit def throwableToExceptional(ex: Throwable)(implicit prefs: ScalaPrefs): Exceptional = apply(ex)(prefs) def apply(ex: Throwable)(implicit prefs: ScalaPrefs) = new Exceptional(ex)(prefs) diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java b/src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java index 002f36b52e..fa5bfd2777 100644 --- a/src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java +++ b/src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java @@ -181,12 +181,13 @@ public class CandidateListCompletionHandler private static final ResourceBundle bundle = - ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), - Locale.getDefault(), - CandidateListCompletionHandler.class.getClassLoader()); + ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault()); public String format(final Object... args) { - return String.format(bundle.getString(name()), args); + if (bundle == null) + return ""; + else + return String.format(bundle.getString(name()), args); } } } diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index 7183d9a473..1bdc5b23c9 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -415,7 +415,7 @@ object Array extends FallbackArrayBuilding { def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] = if (x == null) None else Some(x.toIndexedSeq) // !!! the null check should to be necessary, but without it 2241 fails. Seems to be a bug - // in pattern matcher. + // in pattern matcher. @PP: I noted in #4364 I think the behavior is correct. /** Creates an array containing several copies of an element. * @@ -483,7 +483,7 @@ object Array extends FallbackArrayBuilding { * @author Martin Odersky * @version 1.0 */ -final class Array[T](_length: Int) extends java.io.Serializable { +final class Array[T](_length: Int) extends java.io.Serializable with java.lang.Cloneable { /** Multidimensional array creation */ @deprecated("use `Array.ofDim' instead") @@ -545,43 +545,28 @@ final class Array[T](_length: Int) extends java.io.Serializable { def length: Int = throw new Error() /** The element at given index. - * <p> - * Indices start a `0`; `xs.apply(0)` is the first - * element of array `xs`. - * </p> - * <p> - * Note the indexing syntax `xs(i)` is a shorthand for - * `xs.apply(i)`. - * </p> * - * @param i the index - * @throws ArrayIndexOutOfBoundsException if `i < 0` or - * `length <= i` + * Indices start at `0`; `xs.apply(0)` is the first element of array `xs`. + * Note the indexing syntax `xs(i)` is a shorthand for `xs.apply(i)`. + * + * @param i the index + * @return the element at the given index + * @throws ArrayIndexOutOfBoundsException if `i < 0` or `length <= i` */ def apply(i: Int): T = throw new Error() - /** <p> - * Update the element at given index. - * </p> - * <p> - * Indices start a `0`; `xs.apply(0)` is the first - * element of array `xs`. - * </p> - * <p> - * Note the indexing syntax `xs(i) = x` is a shorthand - * for `xs.update(i, x)`. - * </p> + /** Update the element at given index. + * + * Indices start at `0`; `xs.apply(0)` is the first element of array `xs`. + * Note the indexing syntax `xs(i)` is a shorthand for `xs.apply(i)`. * - * @param i the index - * @param x the value to be written at index `i` - * @throws ArrayIndexOutOfBoundsException if `i < 0` or - * `length <= i` + * @param i the index + * @param x the value to be written at index `i` + * @throws ArrayIndexOutOfBoundsException if `i < 0` or `length <= i` */ def update(i: Int, x: T) { throw new Error() } - /** <p> - * Clone the Array. - * </p> + /** Clone the Array. * * @return A clone of the Array. */ diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 4936e652b2..0f336dd778 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -15,110 +15,6 @@ import immutable.{List, Range} import generic._ import parallel.ParSeq -/** The companion object for trait `SeqLike`. - */ -object SeqLike { - - /** A KMP implementation, based on the undoubtedly reliable wikipedia entry. - * - * @author paulp - * @since 2.8 - */ - private def KMP[B](S: Seq[B], W: Seq[B]): Option[Int] = { - // trivial cases - if (W.isEmpty) return Some(0) - else if (W drop 1 isEmpty) return (S indexOf W(0)) match { - case -1 => None - case x => Some(x) - } - - val T: Array[Int] = { - val arr = new Array[Int](W.length) - var pos = 2 - var cnd = 0 - arr(0) = -1 - arr(1) = 0 - while (pos < W.length) { - if (W(pos - 1) == W(cnd)) { - arr(pos) = cnd + 1 - pos += 1 - cnd += 1 - } - else if (cnd > 0) { - cnd = arr(cnd) - } - else { - arr(pos) = 0 - pos += 1 - } - } - arr - } - - var m, i = 0 - def mi = m + i - - while (mi < S.length) { - if (W(i) == S(mi)) { - i += 1 - if (i == W.length) - return Some(m) - } - else { - m = mi - T(i) - if (i > 0) - i = T(i) - } - } - None - } - - /** Finds a particular index at which one sequence occurs in another sequence. - * Both the source sequence and the target sequence are expressed in terms - * other sequences S' and T' with offset and length parameters. This - * function is designed to wrap the KMP machinery in a sufficiently general - * way that all library sequence searches can use it. It is unlikely you - * have cause to call it directly: prefer functions such as StringBuilder#indexOf - * and Seq#lastIndexOf. - * - * @param source the sequence to search in - * @param sourceOffset the starting offset in source - * @param sourceCount the length beyond sourceOffset to search - * @param target the sequence being searched for - * @param targetOffset the starting offset in target - * @param targetCount the length beyond targetOffset which makes up the target string - * @param fromIndex the smallest index at which the target sequence may start - * - * @return the applicable index in source where target exists, or -1 if not found - */ - def indexOf[B]( - source: Seq[B], sourceOffset: Int, sourceCount: Int, - target: Seq[B], targetOffset: Int, targetCount: Int, - fromIndex: Int): Int = - KMP(source.slice(sourceOffset, sourceCount) drop fromIndex, target.slice(targetOffset, targetCount)) match { - case None => -1 - case Some(x) => x + fromIndex - } - - /** Finds a particular index at which one sequence occurs in another sequence. - * Like indexOf, but finds the latest occurrence rather than earliest. - * - * @see SeqLike#indexOf - */ - def lastIndexOf[B]( - source: Seq[B], sourceOffset: Int, sourceCount: Int, - target: Seq[B], targetOffset: Int, targetCount: Int, - fromIndex: Int): Int = { - val src = (source.slice(sourceOffset, sourceCount) take fromIndex).reverse - val tgt = target.slice(targetOffset, targetCount).reverse - - KMP(src, tgt) match { - case None => -1 - case Some(x) => (src.length - tgt.length - x) + sourceOffset - } - } -} - /** A template trait for sequences of type `Seq[A]` * $seqInfo * @@ -1038,3 +934,115 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] with Parallelizable[A, Pa override def projection = view } +/** The companion object for trait `SeqLike`. + */ +object SeqLike { + /** A KMP implementation, based on the undoubtedly reliable wikipedia entry. + * + * @author paulp + * @since 2.8 + */ + private def KMP[B](S: Seq[B], W: Seq[B]): Option[Int] = { + // trivial cases + if (W.isEmpty) return Some(0) + else if (W drop 1 isEmpty) return (S indexOf W(0)) match { + case -1 => None + case x => Some(x) + } + + val T: Array[Int] = { + val arr = new Array[Int](W.length) + var pos = 2 + var cnd = 0 + arr(0) = -1 + arr(1) = 0 + while (pos < W.length) { + if (W(pos - 1) == W(cnd)) { + arr(pos) = cnd + 1 + pos += 1 + cnd += 1 + } + else if (cnd > 0) { + cnd = arr(cnd) + } + else { + arr(pos) = 0 + pos += 1 + } + } + arr + } + + var m, i = 0 + def mi = m + i + + while (mi < S.length) { + if (W(i) == S(mi)) { + i += 1 + if (i == W.length) + return Some(m) + } + else { + m = mi - T(i) + if (i > 0) + i = T(i) + } + } + None + } + + /** Finds a particular index at which one sequence occurs in another sequence. + * Both the source sequence and the target sequence are expressed in terms + * other sequences S' and T' with offset and length parameters. This + * function is designed to wrap the KMP machinery in a sufficiently general + * way that all library sequence searches can use it. It is unlikely you + * have cause to call it directly: prefer functions such as StringBuilder#indexOf + * and Seq#lastIndexOf. + * + * @param source the sequence to search in + * @param sourceOffset the starting offset in source + * @param sourceCount the length beyond sourceOffset to search + * @param target the sequence being searched for + * @param targetOffset the starting offset in target + * @param targetCount the length beyond targetOffset which makes up the target string + * @param fromIndex the smallest index at which the target sequence may start + * + * @return the applicable index in source where target exists, or -1 if not found + */ + def indexOf[B]( + source: Seq[B], sourceOffset: Int, sourceCount: Int, + target: Seq[B], targetOffset: Int, targetCount: Int, + fromIndex: Int): Int = { + val toDrop = fromIndex max 0 + val src = source.slice(sourceOffset, sourceCount) drop toDrop + val tgt = target.slice(targetOffset, targetCount) + + KMP(src, tgt) match { + case None => -1 + case Some(x) => x + toDrop + } + } + + /** Finds a particular index at which one sequence occurs in another sequence. + * Like indexOf, but finds the latest occurrence rather than earliest. + * + * @see SeqLike#indexOf + */ + def lastIndexOf[B]( + source: Seq[B], sourceOffset: Int, sourceCount: Int, + target: Seq[B], targetOffset: Int, targetCount: Int, + fromIndex: Int): Int = { + if (fromIndex < 0) return -1 + val toTake = (fromIndex + targetCount) min sourceCount + // Given seq 1234567 looking for abc, we need to take an extra + // abc.length chars to examine beyond what is dictated by fromIndex. + val src = source.slice(sourceOffset, sourceCount) take toTake reverse + val tgt = target.slice(targetOffset, targetCount).reverse + + // then we reverse the adjustment here on success. + KMP(src, tgt) match { + case None => -1 + case Some(x) => src.length - x - targetCount + } + } +} diff --git a/src/library/scala/collection/immutable/NumericRange.scala b/src/library/scala/collection/immutable/NumericRange.scala index 4db7d81fa8..e4b539f962 100644 --- a/src/library/scala/collection/immutable/NumericRange.scala +++ b/src/library/scala/collection/immutable/NumericRange.scala @@ -48,7 +48,8 @@ extends IndexedSeq[T] with Serializable { */ import num._ - private val numRangeElements: Int = + // See comment in Range for why this must be lazy. + private lazy val numRangeElements: Int = NumericRange.count(start, end, step, isInclusive) override def length = numRangeElements @@ -191,32 +192,44 @@ extends IndexedSeq[T] with Serializable { /** A companion object for numeric ranges. */ object NumericRange { + import Ordering.Implicits._ + import math.Integral.Implicits._ + /** Calculates the number of elements in a range given start, end, step, and * whether or not it is inclusive. Throws an exception if step == 0 or * the number of elements exceeds the maximum Int. */ def count[T: Integral](start: T, end: T, step: T, isInclusive: Boolean): Int = { - val num = implicitly[Integral[T]] - import num._ + val zero = implicitly[Integral[T]].zero + val upward = start < end + val posStep = step > zero + + if (step == zero) throw new IllegalArgumentException("step cannot be 0.") + else if (start == end) if (isInclusive) 1 else 0 + else if (upward != posStep) 0 + else { + val jumps = ((end - start) / step).toLong + val remainder = ((end - start) % step).toLong + val longCount = jumps + ( + if (!isInclusive && zero == remainder) 0 else 1 + ) - if (step == zero) - throw new IllegalArgumentException("step cannot be 0.") + /** The edge cases keep coming. Since e.g. + * Long.MaxValue + 1 == Long.MinValue + * we do some more improbable seeming checks lest + * overflow turn up as an empty range. + */ + // The second condition contradicts an empty result. + val isOverflow = longCount == 0 && (start + step < end) == upward - val longCount: Long = - if (start == end) { if (isInclusive) 1 else 0 } - else if (end > start != step > zero) 0 - else { - val jumps = toLong((end - start) / step) - val remainder = toLong((end - start) % step) + if (longCount > scala.Int.MaxValue || longCount < 0L || isOverflow) { + val word = if (isInclusive) "to" else "until" + val descr = List(start, word, end, "by", step) mkString " " - if (!isInclusive && zero == remainder) jumps - else jumps + 1L + throw new IllegalArgumentException(descr + ": seqs cannot contain more than Int.MaxValue elements.") } - - if (longCount > scala.Int.MaxValue || longCount < 0L) - throw new IllegalArgumentException("Seqs cannot contain more than Int.MaxValue elements.") - - longCount.toInt + longCount.toInt + } } class Inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T]) diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 90a1383353..435959a645 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -46,10 +46,14 @@ extends IndexedSeq[Int] { override def par = new ParRange(this) - // Note that this value is calculated eagerly intentionally: it also - // serves to enforce conditions (step != 0) && (length <= Int.MaxValue) - private val numRangeElements: Int = - Range.count(start, end, step, isInclusive) + // This member is designed to enforce conditions: + // (step != 0) && (length <= Int.MaxValue), + // but cannot be evaluated eagerly because we have a pattern where ranges + // are constructed like: "x to y by z" + // The "x to y" piece should not trigger an exception. So the calculation + // is delayed, which means it will not fail fast for those cases where failing + // was correct. + private lazy val numRangeElements: Int = Range.count(start, end, step, isInclusive) protected def copy(start: Int, end: Int, step: Int): Range = new Range(start, end, step) diff --git a/src/library/scala/collection/mutable/Cloneable.scala b/src/library/scala/collection/mutable/Cloneable.scala index 15c245fde0..28bf2ceb8e 100644 --- a/src/library/scala/collection/mutable/Cloneable.scala +++ b/src/library/scala/collection/mutable/Cloneable.scala @@ -18,6 +18,7 @@ package mutable * @tparam A Type of the elements contained in the collection, covariant and with reference types as upperbound. */ @cloneable -trait Cloneable[+A <: AnyRef] { +trait Cloneable[+A <: AnyRef] { + // !!! why doesn't this extend java.lang.Cloneable? override def clone: A = super.clone().asInstanceOf[A] } diff --git a/src/library/scala/collection/mutable/CloneableCollection.scala b/src/library/scala/collection/mutable/CloneableCollection.scala deleted file mode 100644 index 8659842b71..0000000000 --- a/src/library/scala/collection/mutable/CloneableCollection.scala +++ /dev/null @@ -1,22 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.collection -package mutable - -/** The J2ME version of the library defined this trait with a `clone` - * method to substitute for the lack of `Object.clone` there. - * - * @since 2.6 - */ -@deprecated("use Cloneable instead") -trait CloneableCollection { - override def clone(): AnyRef = super.clone() -} diff --git a/src/library/scala/collection/mutable/IndexedSeqView.scala b/src/library/scala/collection/mutable/IndexedSeqView.scala index 15306b727a..12b0229ae1 100644 --- a/src/library/scala/collection/mutable/IndexedSeqView.scala +++ b/src/library/scala/collection/mutable/IndexedSeqView.scala @@ -38,7 +38,6 @@ self => trait Transformed[B] extends IndexedSeqView[B, Coll] with super.Transformed[B] { def update(idx: Int, elem: B): Unit - override def length = self.length override def toString = viewToString } diff --git a/src/library/scala/math/Fractional.scala b/src/library/scala/math/Fractional.scala index c6a80d3ee6..de09b184e0 100644 --- a/src/library/scala/math/Fractional.scala +++ b/src/library/scala/math/Fractional.scala @@ -20,3 +20,10 @@ trait Fractional[T] extends Numeric[T] { override implicit def mkNumericOps(lhs: T): FractionalOps = new FractionalOps(lhs) } + +object Fractional { + trait ExtraImplicits { + implicit def infixFractionalOps[T](x: T)(implicit num: Fractional[T]): Fractional[T]#FractionalOps = new num.FractionalOps(x) + } + object Implicits extends ExtraImplicits +}
\ No newline at end of file diff --git a/src/library/scala/math/Integral.scala b/src/library/scala/math/Integral.scala index 9c1deaea33..bb364a79b4 100644 --- a/src/library/scala/math/Integral.scala +++ b/src/library/scala/math/Integral.scala @@ -24,3 +24,14 @@ trait Integral[T] extends Numeric[T] { } override implicit def mkNumericOps(lhs: T): IntegralOps = new IntegralOps(lhs) } + +object Integral { + trait ExtraImplicits { + /** The regrettable design of Numeric/Integral/Fractional has them all + * bumping into one another when searching for this implicit, so they + * are exiled into their own companions. + */ + implicit def infixIntegralOps[T](x: T)(implicit num: Integral[T]): Integral[T]#IntegralOps = new num.IntegralOps(x) + } + object Implicits extends ExtraImplicits +}
\ No newline at end of file |