diff options
136 files changed, 1613 insertions, 1697 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index d4db9962e7..b88fa64584 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -32,6 +32,22 @@ filter { { matchName="scala.sys.process.ProcessImpl#CompoundProcess.getExitValue" problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashTrieMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMap1.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMapCollision1.contains0" + problemName=DirectMissingMethodProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 533f1b2467..bb9078c362 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -42,6 +42,22 @@ filter { { matchName="scala.util.hashing.MurmurHash3.wrappedArrayHash" problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashTrieMap.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMap1.contains0" + problemName=DirectMissingMethodProblem + }, + { + matchName="scala.collection.immutable.HashMap#HashMapCollision1.contains0" + problemName=DirectMissingMethodProblem } ] } diff --git a/project/PartestUtil.scala b/project/PartestUtil.scala index 2609c5ee76..23570a88ec 100644 --- a/project/PartestUtil.scala +++ b/project/PartestUtil.scala @@ -64,9 +64,9 @@ object PartestUtil { } val matchingFileName = try { val filter = GlobFilter("*" + x + "*") - testFiles.allTestCases.filter(x => filter.accept(x._1.name)) + testFiles.allTestCases.filter(x => filter.accept(x._1.asFile.getPath)) } catch { - case t: Throwable => Nil + case _: Throwable => Nil } (matchingFileContent ++ matchingFileName).map(_._2).distinct.sorted } diff --git a/scripts/jobs/integrate/bootstrap b/scripts/jobs/integrate/bootstrap index 3933854e4f..71936abf71 100755 --- a/scripts/jobs/integrate/bootstrap +++ b/scripts/jobs/integrate/bootstrap @@ -178,8 +178,7 @@ sbtResolve() { 'show update' >> $baseDir/logs/resolution 2>&1 } -# Oh boy... can't use scaladoc to document scala-xml/scala-parser-combinators -# if scaladoc depends on the same version of scala-xml/scala-parser-combinators. +# Oh boy... can't use scaladoc to document scala-xml if scaladoc depends on the same version of scala-xml. # Even if that version is available through the project's resolvers, sbt won't look past this project. # SOOOOO, we set the version to a dummy (-DOC), generate documentation, # then set the version to the right one and publish (which won't re-gen the docs). @@ -216,17 +215,6 @@ buildXML() { fi } -buildParsers() { - if [ "$PARSERS_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-parser-combinators" $PARSERS_VER ) - then echo "Found scala-parser-combinators $PARSERS_VER; not building." - else - update scala scala-parser-combinators "$PARSERS_REF" && gfxd - doc="$(docTask $PARSERS_BUILT)" - sbtBuild 'set version := "'$PARSERS_VER'-DOC"' $clean "$doc" 'set version := "'$PARSERS_VER'"' test "${buildTasks[@]}" - PARSERS_BUILT="yes" - fi -} - buildPartest() { if [ "$PARTEST_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-partest" $PARTEST_VER ) then echo "Found scala-partest $PARTEST_VER; not building." @@ -238,17 +226,6 @@ buildPartest() { fi } -buildSwing() { - if [ "$SWING_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scala-lang.modules" "scala-swing" $SWING_VER ) - then echo "Found scala-swing $SWING_VER; not building." - else - update scala scala-swing "$SWING_REF" && gfxd - doc="$(docTask $SWING_BUILT)" - sbtBuild 'set version := "'$SWING_VER'"' $clean "$doc" test "${buildTasks[@]}" - SWING_BUILT="yes" - fi -} - # should only be called with publishTasks publishing to private-repo buildScalaCheck(){ if [ "$SCALACHECK_BUILT" != "yes" ] && [ "$forceRebuild" != "yes" ] && ( sbtResolve "org.scalacheck" "scalacheck" $SCALACHECK_VER ) @@ -266,8 +243,6 @@ buildModules() { publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-private-repo")' "set every publishTo := Some(\"private-repo\" at \"$releaseTempRepoUrl\")") buildTasks=($publishPrivateTask) buildXML - buildParsers - buildSwing # buildScalaCheck buildPartest } @@ -276,8 +251,6 @@ buildPublishedModules() { publishTasks=('set credentials += Credentials(Path.userHome / ".credentials-sonatype")' "set pgpPassphrase := Some(Array.empty)") buildTasks=($publishSonatypeTaskModules) buildXML - buildParsers - buildSwing buildPartest } @@ -381,36 +354,26 @@ deriveModuleVersions() { if [ "$moduleVersioning" == "versions.properties" ]; then # use versions.properties as defaults when no version specified on the command line XML_VER=${XML_VER-$scala_xml_version_number} - PARSERS_VER=${PARSERS_VER-$scala_parser_combinators_version_number} - SWING_VER=${SWING_VER-$scala_swing_version_number} PARTEST_VER=${PARTEST_VER-$partest_version_number} SCALACHECK_VER=${SCALACHECK_VER-$scalacheck_version_number} XML_REF="v$XML_VER" - PARSERS_REF="v$PARSERS_VER" - SWING_REF="v$SWING_VER" PARTEST_REF="v$PARTEST_VER" SCALACHECK_REF="$SCALACHECK_VER" # no `v` in their tags else # use HEAD as default when no revision is specified on the command line XML_REF=${XML_REF-"HEAD"} - PARSERS_REF=${PARSERS_REF-"HEAD"} - SWING_REF=${SWING_REF-"HEAD"} PARTEST_REF=${PARTEST_REF-"HEAD"} SCALACHECK_REF=${SCALACHECK_REF-"HEAD"} XML_VER=$(deriveVersion scala scala-xml "$XML_REF") - PARSERS_VER=$(deriveVersion scala scala-parser-combinators "$PARSERS_REF") - SWING_VER=$(deriveVersion scala scala-swing "$SWING_REF") PARTEST_VER=$(deriveVersion scala scala-partest "$PARTEST_REF") SCALACHECK_VER=$(deriveVersionAnyTag rickynils scalacheck "$SCALACHECK_REF") fi echo "Module versions (versioning strategy: $moduleVersioning):" - echo "PARSERS = $PARSERS_VER at $PARSERS_REF" echo "PARTEST = $PARTEST_VER at $PARTEST_REF" # echo "SCALACHECK = $SCALACHECK_VER at $SCALACHECK_REF" - echo "SWING = $SWING_VER at $SWING_REF" echo "XML = $XML_VER at $XML_REF" } @@ -444,8 +407,6 @@ constructUpdatedModuleVersions() { # force the new module versions for building the core. these may be different from the values in versions.properties, # either because the variables (XML_VER) were provided, or because we're building the modules from HEAD. # in the common case, the values are the same as in versions.properties. - updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-parser-combinators.version.number=$PARSERS_VER") - updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-swing.version.number=$SWING_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dscala-xml.version.number=$XML_VER") updatedModuleVersions=("${updatedModuleVersions[@]}" "-Dpartest.version.number=$PARTEST_VER") diff --git a/spec/05-classes-and-objects.md b/spec/05-classes-and-objects.md index 75620f57d4..6738c7a5b7 100644 --- a/spec/05-classes-and-objects.md +++ b/spec/05-classes-and-objects.md @@ -709,7 +709,7 @@ Here, value parameter may not form part of the types of any of the parent classes or members of the class template $t$. It is illegal to define two formal value parameters with the same name. - If no formal parameter sections are given, an empty parameter section `()` is assumed. + If a class has no formal parameter section that is not implicit, an empty parameter section `()` is assumed. If a formal parameter declaration $x: T$ is preceded by a `val` or `var` keyword, an accessor (getter) [definition](04-basic-declarations-and-definitions.html#variable-declarations-and-definitions) @@ -842,12 +842,13 @@ TmplDef ::= ‘case’ ‘class’ ClassDef If a class definition is prefixed with `case`, the class is said to be a _case class_. -The formal parameters in the first parameter section of a case class -are called _elements_; they are treated -specially. First, the value of such a parameter can be extracted as a +A case class is required to have a parameter section that is not implicit. +The formal parameters in the first parameter section +are called _elements_ and are treated specially. +First, the value of such a parameter can be extracted as a field of a constructor pattern. Second, a `val` prefix is -implicitly added to such a parameter, unless the parameter carries -already a `val` or `var` modifier. Hence, an accessor +implicitly added to such a parameter, unless the parameter already carries +a `val` or `var` modifier. Hence, an accessor definition for the parameter is [generated](#class-definitions). A case class definition of `$c$[$\mathit{tps}\,$]($\mathit{ps}_1\,$)$\ldots$($\mathit{ps}_n$)` with type diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index 9cac497a85..ffe95ba9dc 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -47,7 +47,7 @@ class StandardCompileServer(fixPort: Int = 0) extends SocketServer(fixPort) { } def printMemoryStats() { - def mb(bytes: Long) = "%dMB".format(bytes / 1000000) + def mb(bytes: Long) = "%10.2fMB".format(bytes / 1048576.0) info("New session: total memory = %s, max memory = %s, free memory = %s".format( mb(totalMemory), mb(maxMemory), mb(freeMemory))) } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 873a5947ed..c1b0733895 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -989,7 +989,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) ) private def formatExplain(pairs: (String, Any)*): String = ( - pairs.toList collect { case (k, v) if v != null => "%20s: %s".format(k, v) } mkString "\n" + pairs collect { case (k, v) if v != null => f"$k%20s: $v" } mkString "\n" ) /** Don't want to introduce new errors trying to report errors, @@ -1002,9 +1002,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val site = lastSeenContext.enclClassOrMethod.owner val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "<unknown>" val context_s = try { + import scala.reflect.io.{File => SFile} // Taking 3 before, 3 after the fingered line. - val start = 0 max (tree.pos.line - 3) - val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7 + val start = 1 max (tree.pos.line - 3) + val xs = SFile(tree.pos.source.file.file).lines.drop(start-1).take(7) val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" } strs.mkString("== Source file context for tree position ==\n\n", "\n", "") } @@ -1197,7 +1198,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) first } - // --------------- Miscellania ------------------------------- + // --------------- Miscellanea ------------------------------- /** Progress tracking. Measured in "progress units" which are 1 per * compilation unit per phase completed. diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index ef9818c62d..df72c37e53 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -17,7 +17,7 @@ trait PhaseAssembly { self: Global => /** - * Aux datastructure for solving the constraint system + * Aux data structure for solving the constraint system * The dependency graph container with helper methods for node and edge creation */ private class DependencyGraph { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index cf66e0a7dc..0cdba861a5 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1263,8 +1263,8 @@ self => case CHARLIT => in.charVal case INTLIT => in.intVal(isNegated).toInt case LONGLIT => in.intVal(isNegated) - case FLOATLIT => in.floatVal(isNegated).toFloat - case DOUBLELIT => in.floatVal(isNegated) + case FLOATLIT => in.floatVal(isNegated) + case DOUBLELIT => in.doubleVal(isNegated) case STRINGLIT | STRINGPART => in.strVal.intern() case TRUE => true case FALSE => false @@ -2236,31 +2236,57 @@ self => * }}} */ def paramClauses(owner: Name, contextBounds: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = { - var implicitmod = 0 - var caseParam = ofCaseClass - def paramClause(): List[ValDef] = { - if (in.token == RPAREN) - return Nil - - if (in.token == IMPLICIT) { - in.nextToken() - implicitmod = Flags.IMPLICIT - } - commaSeparated(param(owner, implicitmod, caseParam )) - } - val vds = new ListBuffer[List[ValDef]] + var implicitSection = -1 + var implicitOffset = -1 + var warnAt = -1 + var caseParam = ofCaseClass + val vds = new ListBuffer[List[ValDef]] val start = in.offset + def paramClause(): List[ValDef] = if (in.token == RPAREN) Nil else { + val implicitmod = + if (in.token == IMPLICIT) { + if (implicitOffset == -1) { implicitOffset = in.offset ; implicitSection = vds.length } + else if (warnAt == -1) warnAt = in.offset + in.nextToken() + Flags.IMPLICIT + } else 0 + commaSeparated(param(owner, implicitmod, caseParam)) + } newLineOptWhenFollowedBy(LPAREN) - if (ofCaseClass && in.token != LPAREN) - syntaxError(in.lastOffset, "case classes without a parameter list are not allowed;\n"+ - "use either case objects or case classes with an explicit `()' as a parameter list.") - while (implicitmod == 0 && in.token == LPAREN) { + while (in.token == LPAREN) { in.nextToken() vds += paramClause() accept(RPAREN) caseParam = false newLineOptWhenFollowedBy(LPAREN) } + if (ofCaseClass) { + if (vds.isEmpty) + syntaxError(start, s"case classes must have a parameter list; try 'case class ${owner.encoded + }()' or 'case object ${owner.encoded}'") + else if (vds.head.nonEmpty && vds.head.head.mods.isImplicit) { + if (settings.isScala213) + syntaxError(start, s"case classes must have a non-implicit parameter list; try 'case class ${ + owner.encoded}()${ vds.map(vs => "(...)").mkString }'") + else { + deprecationWarning(start, s"case classes should have a non-implicit parameter list; adapting to 'case class ${ + owner.encoded}()${ vds.map(vs => "(...)").mkString }'", "2.12.2") + vds.insert(0, List.empty[ValDef]) + vds(1) = vds(1).map(vd => copyValDef(vd)(mods = vd.mods & ~Flags.CASEACCESSOR)) + if (implicitSection != -1) implicitSection += 1 + } + } + } + if (implicitSection != -1 && implicitSection != vds.length - 1) + syntaxError(implicitOffset, "an implicit parameter section must be last") + if (warnAt != -1) + syntaxError(warnAt, "multiple implicit parameter sections are not allowed") + else if (settings.warnExtraImplicit) { + // guard against anomalous class C(private implicit val x: Int)(implicit s: String) + val ttl = vds.count { case ValDef(mods, _, _, _) :: _ => mods.isImplicit ; case _ => false } + if (ttl > 1) + warning(in.offset, s"$ttl parameter sections are effectively implicit") + } val result = vds.toList if (owner == nme.CONSTRUCTOR && (result.isEmpty || (result.head take 1 exists (_.mods.isImplicit)))) { in.token match { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index a8cc7f91c2..226c49ec07 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -386,6 +386,17 @@ trait Scanners extends ScannersCommon { next copyFrom this this copyFrom prev } + } else if (token == COMMA) { + // SIP-27 Trailing Comma (multi-line only) support + // If a comma is followed by a new line & then a closing paren, bracket or brace + // then it is a trailing comma and is ignored + val saved = new ScannerData {} copyFrom this + fetchToken() + if (afterLineEnd() && (token == RPAREN || token == RBRACKET || token == RBRACE)) { + /* skip the trailing comma */ + } else if (token == EOF) { // e.g. when the REPL is parsing "val List(x, y, _*," + /* skip the trailing comma */ + } else this copyFrom saved } // print("["+this+"]") @@ -972,23 +983,45 @@ trait Scanners extends ScannersCommon { def intVal: Long = intVal(negated = false) - /** Convert current strVal, base to double value + /** Convert current strVal, base to float value. */ - def floatVal(negated: Boolean): Double = { - val limit: Double = if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue + def floatVal(negated: Boolean): Float = { try { - val value: Double = java.lang.Double.valueOf(strVal).doubleValue() - if (value > limit) + val value: Float = java.lang.Float.parseFloat(strVal) + if (value > Float.MaxValue) syntaxError("floating point number too large") + val zeroly = "0.fF" + if (value == 0.0f && strVal.exists(c => !zeroly.contains(c))) + syntaxError("floating point number too small") if (negated) -value else value } catch { case _: NumberFormatException => syntaxError("malformed floating point number") + 0.0f + } + } + + def floatVal: Float = floatVal(negated = false) + + /** Convert current strVal, base to double value. + */ + def doubleVal(negated: Boolean): Double = { + try { + val value: Double = java.lang.Double.parseDouble(strVal) + if (value > Double.MaxValue) + syntaxError("double precision floating point number too large") + val zeroly = "0.dD" + if (value == 0.0d && strVal.exists(c => !zeroly.contains(c))) + syntaxError("double precision floating point number too small") + if (negated) -value else value + } catch { + case _: NumberFormatException => + syntaxError("malformed double precision floating point number") 0.0 } } - def floatVal: Double = floatVal(negated = false) + def doubleVal: Double = doubleVal(negated = false) def checkNoLetter(): Unit = { if (isIdentifierPart(ch) && ch >= ' ') diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala index 1982c7f643..402dc66a7f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala @@ -33,7 +33,7 @@ object AsmUtils { final val traceClassPattern = "" /** - * Print the bytedcode of classes as they are serialized by the ASM library. The serialization + * Print the bytecode of classes as they are serialized by the ASM library. The serialization * performed by `asm.ClassWriter` can change the code generated by GenBCode. For example, it * introduces stack map frames, it computes the maximal stack sizes, and it replaces dead * code by NOPs (see also https://github.com/scala/scala/pull/3726#issuecomment-42861780). diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index c7952ffe94..76d042ce3b 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -918,7 +918,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { (args zip params) filterNot isTrivial } - // first push *all* arguments. This makes sure muliple uses of the same labelDef-var will all denote the (previous) value. + // first push *all* arguments. This makes sure multiple uses of the same labelDef-var will all denote the (previous) value. aps foreach { case (arg, param) => genLoad(arg, locals(param).tk) } // `locals` is known to contain `param` because `genDefDef()` visited `labelDefsAtOrUnder` // second assign one by one to the LabelDef's variables. diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 18e7500172..a74c70a684 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -188,7 +188,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { * Data for emitting an EnclosingMethod attribute. None if `classSym` is a member class (not * an anonymous or local class). See doc in BTypes. * - * The class is parametrized by two functions to obtain a bytecode class descriptor for a class + * The class is parameterized by two functions to obtain a bytecode class descriptor for a class * symbol, and to obtain a method signature descriptor fro a method symbol. These function depend * on the implementation of GenASM / GenBCode, so they need to be passed in. */ @@ -332,7 +332,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") else if (companion.isTrait) failNoForwarder("companion is a trait") - // Now either succeeed, or issue some additional warnings for things which look like + // Now either succeed, or issue some additional warnings for things which look like // attempts to be java main methods. else (possibles exists definitions.isJavaMainMethod) || { possibles exists { m => @@ -541,9 +541,9 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { * symbol (sym.annotations) or type (as an AnnotatedType, eliminated by erasure). * * For Scala annotations this is OK: they are stored in the pickle and ignored by the backend. - * Java annoations on the other hand are additionally emitted to the classfile in Java's format. + * Java annotations on the other hand are additionally emitted to the classfile in Java's format. * - * This means that [[Type]] instances within an AnnotaionInfo reach the backend non-erased. Examples: + * This means that [[Type]] instances within an AnnotationInfo reach the backend non-erased. Examples: * - @(javax.annotation.Resource @annotation.meta.getter) val x = 0 * Here, annotationInfo.atp is an AnnotatedType. * - @SomeAnnotation[T] val x = 0 diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index 121091fe4f..3e3229d2c3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -83,7 +83,7 @@ abstract class BTypes { val callsitePositions: concurrent.Map[MethodInsnNode, Position] = recordPerRunCache(TrieMap.empty) /** - * Stores callsite instructions of invocatinos annotated `f(): @inline/noinline`. + * Stores callsite instructions of invocations annotated `f(): @inline/noinline`. * Instructions are added during code generation (BCodeBodyBuilder). The maps are then queried * when building the CallGraph, every Callsite object has an annotated(No)Inline field. */ @@ -287,7 +287,7 @@ abstract class BTypes { } // The InlineInfo is built from the classfile (not from the symbol) for all classes that are NOT - // being compiled. For those classes, the info is only needed if the inliner is enabled, othewise + // being compiled. For those classes, the info is only needed if the inliner is enabled, otherwise // we can save the memory. if (!compilerSettings.optInlinerEnabled) BTypes.EmptyInlineInfo else fromClassfileAttribute getOrElse fromClassfileWithoutAttribute @@ -653,7 +653,7 @@ abstract class BTypes { * Fields in the InnerClass entries: * - inner class: the (nested) class C we are talking about * - outer class: the class of which C is a member. Has to be null for non-members, i.e. for - * local and anonymous classes. NOTE: this co-incides with the presence of an + * local and anonymous classes. NOTE: this coincides with the presence of an * EnclosingMethod attribute (see below) * - inner name: A string with the simple name of the inner class. Null for anonymous classes. * - flags: access property flags, details in JVMS, table in 4.7.6. Static flag: see @@ -702,7 +702,7 @@ abstract class BTypes { * local and anonymous classes, no matter if there is an enclosing method or not. Accordingly, the * "class" field (see below) must be always defined, while the "method" field may be null. * - * NOTE: When an EnclosingMethod attribute is requried (local and anonymous classes), the "outer" + * NOTE: When an EnclosingMethod attribute is required (local and anonymous classes), the "outer" * field in the InnerClass table must be null. * * Fields: @@ -1144,7 +1144,7 @@ object BTypes { /** * Metadata about a ClassBType, used by the inliner. * - * More information may be added in the future to enable more elaborate inlinine heuristics. + * More information may be added in the future to enable more elaborate inline heuristics. * Note that this class should contain information that can only be obtained from the ClassSymbol. * Information that can be computed from the ClassNode should be added to the call graph instead. * diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index 84f6d87c5c..2cf5cfcb8d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -78,7 +78,7 @@ trait BytecodeWriters { } /* - * The ASM textual representation for bytecode overcomes disadvantages of javap ouput in three areas: + * The ASM textual representation for bytecode overcomes disadvantages of javap output in three areas: * (a) pickle dingbats undecipherable to the naked eye; * (b) two constant pools, while having identical contents, are displayed differently due to physical layout. * (c) stack maps (classfile version 50 and up) are displayed in encoded form by javap, diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala index e25b55e7ab..90da570f01 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala @@ -382,7 +382,8 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { * but not for writing in the classfile. We let the ClassWriter recompute max's. * * NOTE 2: the maxStack value computed here may be larger than the smallest correct value - * that would allow running an analyzer, see `InstructionStackEffect.forAsmAnalysisConservative`. + * that would allow running an analyzer, see `InstructionStackEffect.forAsmAnalysis` and + * `InstructionStackEffect.maxStackGrowth`. * * NOTE 3: the implementation doesn't look at instructions that cannot be reached, it computes * the max local / stack size in the reachable code. These max's work just fine for running an diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala index ef961941a0..999c686aac 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/package.scala @@ -110,7 +110,7 @@ package scala.tools.nsc.backend.jvm * - Use YourKit for finding hotspots (cpu profiling). when it comes to drilling down into the details * of a hotspot, don't pay too much attention to the percentages / time counts. * - Should also try other profilers. - * - Use timers. When a method showed up as a hotspot, i added a timer around that method, and a + * - Use timers. When a method showed up as a hotspot, I added a timer around that method, and a * second one within the method to measure specific parts. The timers slow things down, but the * relative numbers show what parts of a method are slow. * diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index a4cd8fce1e..78fc7e1ecf 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -69,7 +69,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { * E1: M1 only works if there's a single boxing operation. * def e1(b: Boolean) = { * val i: Integer = box(10) // 10 is stored into a new local, box operation and i removed - * val j: Integer = box(20) // 20 is stored into a new local, box operation adn j removed + * val j: Integer = box(20) // 20 is stored into a new local, box operation and j removed * val r = if (b) i else j // loads and stores of the box are eliminated, r no longer exists * unbox(r) // cannot rewrite: we don't know which local to load * } @@ -138,7 +138,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { * - note that the MatchError creation is dead code: local2 is never null. However, our nullness * analysis cannot identify this: it does not track nullness through tuple stores and loads. * - if we re-write the non-escaping consumers of the outer tuple, but keep the tuple allocation - * and the escaping consumer, we get the follwoing: + * and the escaping consumer, we get the following: * * load 1, load 2 * val newLocal1 = new Tuple2; load newLocal1 // stack: Tuple2 @@ -188,7 +188,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { var maxStackGrowth = 0 - /** Mehtod M1 for eliminating box-unbox pairs (see doc comment in the beginning of this file) */ + /** Method M1 for eliminating box-unbox pairs (see doc comment in the beginning of this file) */ def replaceBoxOperationsSingleCreation(creation: BoxCreation, finalCons: Set[BoxConsumer], boxKind: BoxKind, keepBox: Boolean): Unit = { /** * If the box is eliminated, all copy operations (loads, stores, others) of the box need to diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala index 78acd72dba..f2ff73c44d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala @@ -167,7 +167,7 @@ class ByteCodeRepository[BT <: BTypes](val classPath: ClassPath, val btypes: BT) * the users (e.g. the inliner) have to be aware of method selection. * * Note that the returned method may be abstract (ACC_ABSTRACT), native (ACC_NATIVE) or signature - * polymorphic (methods `invoke` and `invokeExact` in class `MehtodHandles`). + * polymorphic (methods `invoke` and `invokeExact` in class `MethodHandles`). * * @return The [[MethodNode]] of the requested method and the [[InternalName]] of its declaring * class, or an error message if the method could not be found. An error message is also @@ -204,8 +204,8 @@ class ByteCodeRepository[BT <: BTypes](val classPath: ClassPath, val btypes: BT) visited += i // abstract and static methods are excluded, see jvms-5.4.3.3 for (m <- findMethod(c) if !isPrivateMethod(m) && !isStaticMethod(m)) found += ((m, c)) - val recusionResult = findIn(c) - if (recusionResult.isDefined) return recusionResult + val recursionResult = findIn(c) + if (recursionResult.isDefined) return recursionResult } None } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala index 9c0dfb0ee2..a740ca525c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala @@ -285,7 +285,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) { // final case class :: / final case object Nil // (l: List).map // can be inlined // we need to know that - // - the recevier is sealed + // - the receiver is sealed // - what are the children of the receiver // - all children are final // - none of the children overrides map diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala index b05669ce89..518646812e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CopyProp.scala @@ -273,7 +273,7 @@ class CopyProp[BT <: BTypes](val btypes: BT) { } /** - * Eliminate the `numArgs` inputs of the instruction `prod` (which was eliminated). Fo + * Eliminate the `numArgs` inputs of the instruction `prod` (which was eliminated). For * each input value * - if the `prod` instruction is the single consumer, enqueue the producers of the input * - otherwise, insert a POP instruction to POP the input value @@ -465,7 +465,7 @@ class CopyProp[BT <: BTypes](val btypes: BT) { } /** - * Remove `xSTORE n; xLOAD n` paris if + * Remove `xSTORE n; xLOAD n` pairs if * - the local variable n is not used anywhere else in the method (1), and * - there are no executable instructions and no live labels (jump targets) between the two (2) * diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala index 16ed9da0e4..7bc4ea2392 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlineInfoAttribute.scala @@ -82,7 +82,7 @@ case class InlineInfoAttribute(inlineInfo: InlineInfo) extends Attribute(InlineI } /** - * De-serialize the attribute into an InlineInfo. The attribute starts at cr.b(off), but we don't + * Deserialize the attribute into an InlineInfo. The attribute starts at cr.b(off), but we don't * need to access that array directly, we can use the `read` methods provided by the ClassReader. * * `buf` is a pre-allocated character array that is guaranteed to be long enough to hold any diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala index b9f593a4d8..0ae8347dc5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -683,7 +683,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { * (A2) C and D are members of the same run-time package */ def classIsAccessible(accessed: BType, from: ClassBType): Either[OptimizerWarning, Boolean] = (accessed: @unchecked) match { - // TODO: A2 requires "same run-time package", which seems to be package + classloader (JMVS 5.3.). is the below ok? + // TODO: A2 requires "same run-time package", which seems to be package + classloader (JVMS 5.3.). is the below ok? case c: ClassBType => c.isPublic.map(_ || c.packageInternalName == from.packageInternalName) case a: ArrayBType => classIsAccessible(a.elementType, from) case _: PrimitiveBType => Right(true) @@ -725,7 +725,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { * type from there (https://github.com/scala-opt/scala/issues/13). */ def memberIsAccessible(memberFlags: Int, memberDeclClass: ClassBType, memberRefClass: ClassBType, from: ClassBType): Either[OptimizerWarning, Boolean] = { - // TODO: B3 requires "same run-time package", which seems to be package + classloader (JMVS 5.3.). is the below ok? + // TODO: B3 requires "same run-time package", which seems to be package + classloader (JVMS 5.3.). is the below ok? def samePackageAsDestination = memberDeclClass.packageInternalName == from.packageInternalName def targetObjectConformsToDestinationClass = false // needs type propagation analysis, see above diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala index 4744cb9ab1..63360e17ff 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/InlinerHeuristics.scala @@ -125,7 +125,7 @@ class InlinerHeuristics[BT <: BTypes](val bTypes: BT) { if (callsite.isInlineAnnotated && callee.canInlineFromSource) { // By default, we only emit inliner warnings for methods annotated @inline. However, we don't // want to be unnecessarily noisy with `-opt-warnings:_`: for example, the inliner heuristic - // would attempty to inline `Function1.apply$sp$II`, as it's higher-order (the receiver is + // would attempt to inline `Function1.apply$sp$II`, as it's higher-order (the receiver is // a function), and it's concrete (forwards to `apply`). But because it's non-final, it cannot // be inlined. So we only create warnings here for methods annotated @inline. Some(Left(CalleeNotFinal( diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala index 65d1e20d69..9c22b09cdd 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala @@ -61,7 +61,7 @@ import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._ * - empty local variable descriptors (local variables that were holding the box may become unused) * * copy propagation (replaces LOAD n to the LOAD m for the smallest m that is an alias of n) - * + enables downstrem: + * + enables downstream: * - stale stores (a stored value may not be loaded anymore) * - store-load pairs (a load n may now be right after a store n) * + NOTE: copy propagation is only executed once, in the first fixpoint loop iteration. none of diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala index 133a656206..1ea152b29c 100644 --- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala +++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala @@ -106,7 +106,7 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo // as the type of `case class C(); case class D(); List(C(), D()).head`, rather than the opposite order. // On Mac, the HFS performs this sorting transparently, but on Linux the order is unspecified. // - // Note this behaviour can be enabled with in javac with `javac -XDsortfiles`, but that's only + // Note this behaviour can be enabled in javac with `javac -XDsortfiles`, but that's only // intended to improve determinism of the compiler for compiler hackers. util.Arrays.sort(listing, (o1: File, o2: File) => o1.getName.compareTo(o2.getName)) listing diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 947af55724..3ef75679ee 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -276,7 +276,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { // SelectFromTypeTree otherwise. See #3567. // Select nodes can be later // converted in the typechecker to SelectFromTypeTree if the class - // turns out to be an instance ionner class instead of a static inner class. + // turns out to be an instance inner class instead of a static inner class. def typeSelect(t: Tree, name: Name) = t match { case Ident(_) | Select(_, _) => Select(t, name) case _ => SelectFromTypeTree(t, name.toTypeName) diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index 342031b601..99263bf834 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -7,9 +7,10 @@ package scala package tools.nsc package reporters -import java.io.{ BufferedReader, PrintWriter } -import scala.reflect.internal.util._ -import StringOps._ +import java.io.{BufferedReader, PrintWriter} +import scala.reflect.internal.util.{Position, StringOps} +import Position.formatMessage +import StringOps.{countElementsAsString => countAs, trimAllTrailingSpace => trimTrailing} /** This class implements a Reporter that displays messages on a text console. */ @@ -26,47 +27,35 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr private def label(severity: Severity): String = severity match { case ERROR => "error" case WARNING => "warning" - case INFO => null + case INFO => "" } - protected def clabel(severity: Severity): String = { - val label0 = label(severity) - if (label0 eq null) "" else label0 + ": " + protected def clabel(severity: Severity): String = label(severity) match { + case "" => "" + case s => s"$s: " } - /** Returns the number of errors issued totally as a string. - */ - private def getCountString(severity: Severity): String = - StringOps.countElementsAsString((severity).count, label(severity)) - /** Prints the message. */ - def printMessage(msg: String) { - writer print trimAllTrailingSpace(msg) + "\n" + def printMessage(msg: String): Unit = { + writer.println(trimTrailing(msg)) writer.flush() } /** Prints the message with the given position indication. */ - def printMessage(posIn: Position, msg: String) { - printMessage(Position.formatMessage(posIn, msg, shortname)) - } - def print(pos: Position, msg: String, severity: Severity) { - printMessage(pos, clabel(severity) + msg) - } + def printMessage(posIn: Position, msg: String): Unit = printMessage(formatMessage(posIn, msg, shortname)) - /** Prints the column marker of the given position. - */ - def printColumnMarker(pos: Position) = - if (pos.isDefined) { printMessage(" " * (pos.column - 1) + "^") } + def print(pos: Position, msg: String, severity: Severity): Unit = printMessage(pos, s"${clabel(severity)}${msg}") - /** Prints the number of errors and warnings if their are non-zero. */ - def printSummary() { - if (WARNING.count > 0) printMessage(getCountString(WARNING) + " found") - if ( ERROR.count > 0) printMessage(getCountString(ERROR ) + " found") - } + /** Prints the column marker of the given position. */ + def printColumnMarker(pos: Position): Unit = if (pos.isDefined) printMessage(" " * (pos.column - 1) + "^") + + /** Prints the number of warnings and errors if there are any. */ + def printSummary(): Unit = + for (k <- List(WARNING, ERROR) if k.count > 0) printMessage(s"${countAs(k.count, label(k))} found") def display(pos: Position, msg: String, severity: Severity): Unit = { val ok = severity match { - case ERROR => ERROR.count <= settings.maxerrs.value + case ERROR => ERROR.count <= settings.maxerrs.value case WARNING => WARNING.count <= settings.maxwarns.value case _ => true } @@ -74,17 +63,19 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr } def displayPrompt(): Unit = { - writer.print("\na)bort, s)tack, r)esume: ") + writer.println() + writer.print("a)bort, s)tack, r)esume: ") writer.flush() if (reader != null) { - val response = reader.read().asInstanceOf[Char].toLower - if (response == 'a' || response == 's') { - (new Exception).printStackTrace() - if (response == 'a') - sys exit 1 - - writer.print("\n") - writer.flush() + reader.read match { + case 'a' | 'A' => + new Throwable().printStackTrace() + System.exit(1) + case 's' | 'S' => + new Throwable().printStackTrace() + writer.println() + writer.flush() + case _ => } } } diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 839e734abc..87534656f9 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -25,6 +25,8 @@ trait Warnings { // currently considered too noisy for general use val warnUnusedImport = BooleanSetting("-Ywarn-unused-import", "Warn when imports are unused.") + val warnExtraImplicit = BooleanSetting("-Ywarn-extra-implicit", "Warn when more than one implicit parameter section is defined.") + // Experimental lint warnings that are turned off, but which could be turned on programmatically. // They are not activated by -Xlint and can't be enabled on the command line because they are not // created using the standard factory methods. diff --git a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala index a0bba46398..e027b065ac 100644 --- a/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala +++ b/src/compiler/scala/tools/nsc/transform/AccessorSynthesis.scala @@ -99,7 +99,7 @@ trait AccessorSynthesis extends Transform with ast.TreeDSL { } - // TODO: better way to communicate from info transform to tree transfor? + // TODO: better way to communicate from info transform to tree transform? private[this] val _bitmapInfo = perRunCaches.newMap[Symbol, BitmapInfo] private[this] val _slowPathFor = perRunCaches.newMap[Symbol, Symbol]() diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index 855e53710b..2e7ab8a887 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -152,7 +152,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre val resTpOk = ( samResultType =:= UnitTpe || functionResultType =:= samResultType - || (isReferenceType(samResultType) && isReferenceType(functionResultType))) // yes, this is what the spec says -- no further correspondance required + || (isReferenceType(samResultType) && isReferenceType(functionResultType))) // yes, this is what the spec says -- no further correspondence required if (resTpOk && (samParamTypes corresponds functionParamTypes){ (samParamTp, funParamTp) => funParamTp =:= samParamTp || (isReferenceType(funParamTp) && isReferenceType(samParamTp) && funParamTp <:< samParamTp) }) target else { @@ -165,7 +165,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre // whenever a type in the sam's signature is (erases to) a primitive type, we must pick the sam's version, // as we don't implement the logic regarding widening that's performed by LMF -- we require =:= for primitives // - // We use the sam's type for the check whether we're dealin with a reference type, as it could be a generic type, + // We use the sam's type for the check whether we're dealing with a reference type, as it could be a generic type, // which means the function's parameter -- even if it expects a value class -- will need to be // boxed on the generic call to the sam method. diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index fbf1e8cec1..b2bf9fad3f 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -58,7 +58,7 @@ import symtab.Flags._ * * In the even longer term (Scala 3?), I agree with @DarkDimius that it would make sense * to hide the difference between strict and lazy vals. All vals are lazy, - * but the memoization overhead is removed when we statically know they are forced during initialiation. + * but the memoization overhead is removed when we statically know they are forced during initialization. * We could still expose the low-level field semantics through `private[this] val`s. * * In any case, the current behavior of overriding vals is pretty surprising. diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 798cfcd072..169fe7588e 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -113,7 +113,7 @@ abstract class LambdaLift extends InfoTransform { * * For DelayedInit subclasses, constructor statements end up in the synthetic init method * instead of the constructor itself, so the access should go to the field. This method changes - * `logicallyEnclosingMember` in this case to return a temprorary symbol corresponding to that + * `logicallyEnclosingMember` in this case to return a temporary symbol corresponding to that * method. */ private def logicallyEnclosingMember(sym: Symbol): Symbol = { diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index de0db51b6c..96e2135c52 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -32,7 +32,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthes * we cannot emit PROTECTED methods in interfaces on the JVM, * but knowing that these trait methods are protected means we won't emit static forwarders. * - * JVMLS: "Methods of interfaces may have any of the flags in Table 4.6-A set + * JVMS: "Methods of interfaces may have any of the flags in Table 4.6-A set * except ACC_PROTECTED, ACC_FINAL, ACC_SYNCHRONIZED, and ACC_NATIVE (JLS §9.4)." * * TODO: can we just set the right flags from the start?? @@ -137,7 +137,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL with AccessorSynthes */ def addMember(clazz: Symbol, member: Symbol): Symbol = { debuglog(s"mixing into $clazz: ${member.defString}") - // This attachment is used to instruct the backend about which methids in traits require + // This attachment is used to instruct the backend about which methods in traits require // a static trait impl method. We remove this from the new symbol created for the method // mixed into the subclass. member.removeAttachment[NeedStaticImpl.type] diff --git a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala index ba303f7c2b..4c1705e386 100644 --- a/src/compiler/scala/tools/nsc/transform/SampleTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/SampleTransform.scala @@ -35,7 +35,7 @@ abstract class SampleTransform extends Transform { atPos(tree1.pos)( // `atPos` fills in position of its tree argument Select( // The `Select` factory method is defined in class `Trees` sup, - currentOwner.newValue( // creates a new term symbol owned by `currentowner` + currentOwner.newValue( // creates a new term symbol owned by `currentOwner` newTermName("sample"), // The standard term name creator tree1.pos))))) case _ => diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 84f47c1caa..9161786d76 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -1992,7 +1992,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { else exitingSpecialize(specializeCalls(unit).transform(tree)) // Remove the final modifier and @inline annotation from anything in the - // original class (since it's being overridden in at least onesubclass). + // original class (since it's being overridden in at least one subclass). // // We do this here so that the specialized subclasses will correctly copy // final and @inline. diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 096b6b9263..dcffd7a6ab 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -363,7 +363,7 @@ abstract class UnCurry extends InfoTransform * mark the method symbol SYNCHRONIZED for bytecode generation. * * Delambdafy targets are deemed ineligible as the Delambdafy phase will - * replace `this.synchronized` with `$this.synchronzed` now that it emits + * replace `this.synchronized` with `$this.synchronized` now that it emits * all lambda impl methods as static. */ private def translateSynchronized(tree: Tree) = tree match { @@ -705,7 +705,7 @@ abstract class UnCurry extends InfoTransform // // So what we need to do is to use the pre-uncurry type when creating `l$1`, which is `c.Tree` and is // correct. Now, there are two additional problems: - // 1. when varargs and byname params are involved, the uncurry transformation desugares these special + // 1. when varargs and byname params are involved, the uncurry transformation desugars these special // cases to actual typerefs, eg: // ``` // T* ~> Seq[T] (Scala-defined varargs) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index cb3759e5fa..db6eac34cb 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -184,8 +184,8 @@ trait Logic extends Debugging { // push negation inside formula def negationNormalFormNot(p: Prop): Prop = p match { - case And(ops) => Or(ops.map(negationNormalFormNot)) // De'Morgan - case Or(ops) => And(ops.map(negationNormalFormNot)) // De'Morgan + case And(ops) => Or(ops.map(negationNormalFormNot)) // De Morgan + case Or(ops) => And(ops.map(negationNormalFormNot)) // De Morgan case Not(p) => negationNormalForm(p) case True => False case False => True diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index 89c793ec94..794d3d442a 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -564,11 +564,11 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { else scrut match { case Typed(tree, tpt) => val suppressExhaustive = tpt.tpe hasAnnotation UncheckedClass - val supressUnreachable = tree match { + val suppressUnreachable = tree match { case Ident(name) if name startsWith nme.CHECK_IF_REFUTABLE_STRING => true // SI-7183 don't warn for withFilter's that turn out to be irrefutable. case _ => false } - val suppression = Suppression(suppressExhaustive, supressUnreachable) + val suppression = Suppression(suppressExhaustive, suppressUnreachable) val hasSwitchAnnotation = treeInfo.isSwitchAnnotation(tpt.tpe) // matches with two or fewer cases need not apply for switchiness (if-then-else will do) // `case 1 | 2` is considered as two cases. diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 2d8d591b6d..0910dca445 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -1211,7 +1211,7 @@ trait ContextErrors { "pass-by-name arguments not allowed for case class parameters" case AbstractVar => - "only classes can have declared but undefined members" + abstractVarMessage(sym) + "only traits and abstract classes can have declared but undefined members" + abstractVarMessage(sym) } issueSymbolTypeError(sym, msg) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index fde2f7bb03..d349597b14 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -1194,7 +1194,8 @@ trait Contexts { self: Analyzer => } final def lookupCompanionOf(original: Symbol): Symbol = { - lookupScopeEntry(original) match { + if (original.isModuleClass) original.sourceModule + else lookupScopeEntry(original) match { case null => NoSymbol case entry => entry.owner.lookupCompanion(original) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index df014b5161..ea82739504 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -240,10 +240,6 @@ abstract class Duplicators extends Analyzer { result.symbol.updateAttachment(DelambdafyTarget) result - case fun: Function => - debuglog("Clearing the type and retyping Function: " + fun) - super.typed(fun.clearType, mode, pt) - case vdef @ ValDef(mods, name, tpt, rhs) => // log("vdef fixing tpe: " + tree.tpe + " with sym: " + tree.tpe.typeSymbol + " and " + invalidSyms) //if (mods.hasFlag(Flags.LAZY)) vdef.symbol.resetFlag(Flags.MUTABLE) // Martin to Iulian: lazy vars can now appear because they are no longer boxed; Please check that deleting this statement is OK. diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index e8147dbf3a..9dd260b274 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -495,21 +495,22 @@ trait Infer extends Checkable { } /** Return inferred type arguments, given type parameters, formal parameters, - * argument types, result type and expected result type. - * If this is not possible, throw a `NoInstance` exception. - * Undetermined type arguments are represented by `definitions.NothingTpe`. - * No check that inferred parameters conform to their bounds is made here. - * - * @param tparams the type parameters of the method - * @param formals the value parameter types of the method - * @param restpe the result type of the method - * @param argtpes the argument types of the application - * @param pt the expected return type of the application - * @return @see adjustTypeArgs - * - * @throws NoInstance - */ - def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type, + * argument types, result type and expected result type. + * If this is not possible, throw a `NoInstance` exception. + * Undetermined type arguments are represented by `definitions.NothingTpe`. + * No check that inferred parameters conform to their bounds is made here. + * + * @param fn the function for reporting, may be empty + * @param tparams the type parameters of the method + * @param formals the value parameter types of the method + * @param restpe the result type of the method + * @param argtpes the argument types of the application + * @param pt the expected return type of the application + * @return @see adjustTypeArgs + * + * @throws NoInstance + */ + def methTypeArgs(fn: Tree, tparams: List[Symbol], formals: List[Type], restpe: Type, argtpes: List[Type], pt: Type): AdjustedTypeArgs.Result = { val tvars = tparams map freshVar if (!sameLength(formals, argtpes)) @@ -559,21 +560,12 @@ trait Infer extends Checkable { val hasAny = pt :: restpe :: formals ::: argtpes ::: loBounds exists (_.dealiasWidenChain exists containsAny) !hasAny } - def argumentPosition(idx: Int): Position = context.tree match { - case x: ValOrDefDef => x.rhs match { - case Apply(fn, args) if idx < args.size => args(idx).pos - case _ => context.tree.pos - } - case _ => context.tree.pos - } - if (settings.warnInferAny && context.reportErrors && canWarnAboutAny) { - foreachWithIndex(targs) ((targ, idx) => - targ.typeSymbol match { - case sym @ (AnyClass | AnyValClass) => - reporter.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") - case _ => - } - ) + if (settings.warnInferAny && context.reportErrors && !fn.isEmpty && canWarnAboutAny) { + targs.foreach(_.typeSymbol match { + case sym @ (AnyClass | AnyValClass) => + reporter.warning(fn.pos, s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") + case _ => + }) } adjustTypeArgs(tparams, tvars, targs, restpe) } @@ -735,7 +727,7 @@ trait Infer extends Checkable { ) def tryInstantiating(args: List[Type]) = falseIfNoInstance { val restpe = mt resultType args - val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, args, pt) + val AdjustedTypeArgs.Undets(okparams, okargs, leftUndet) = methTypeArgs(EmptyTree, undetparams, formals, restpe, args, pt) val restpeInst = restpe.instantiateTypeParams(okparams, okargs) // #2665: must use weak conformance, not regular one (follow the monomorphic case above) exprTypeArgs(leftUndet, restpeInst, pt, useWeaklyCompatible = true) match { @@ -989,7 +981,7 @@ trait Infer extends Checkable { val restpe = fn.tpe.resultType(argtpes) val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = - methTypeArgs(undetparams, formals, restpe, argtpes, pt) + methTypeArgs(fn, undetparams, formals, restpe, argtpes, pt) if (checkBounds(fn, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")) { val treeSubst = new TreeTypeSubstituter(okparams, okargs) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 296d9c6bca..a787a7bc12 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1130,7 +1130,7 @@ abstract class RefChecks extends Transform { } /** Sensibility check examines flavors of equals. */ def checkSensible(pos: Position, fn: Tree, args: List[Tree]) = fn match { - case Select(qual, name @ (nme.EQ | nme.NE | nme.eq | nme.ne)) if args.length == 1 && isObjectOrAnyComparisonMethod(fn.symbol) && !currentOwner.isSynthetic => + case Select(qual, name @ (nme.EQ | nme.NE | nme.eq | nme.ne)) if args.length == 1 && isObjectOrAnyComparisonMethod(fn.symbol) && (!currentOwner.isSynthetic || currentOwner.isAnonymousFunction) => checkSensibleEquals(pos, qual, name, fn.symbol, args.head) case _ => } @@ -1158,6 +1158,7 @@ abstract class RefChecks extends Transform { } } checkUndesiredProperties(rtpe.typeSymbol, tree.pos) + checkUndesiredProperties(rtpe.typeSymbol.primaryConstructor, tree.pos) tree } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 58a44d3ac0..837ccf7e06 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -864,11 +864,24 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case _ => } debuglog(s"fallback on implicits: ${tree}/$resetTree") - val tree1 = typed(resetTree, mode) - // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that - // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. - tree1 setType pluginsTyped(tree1.tpe, this, tree1, mode, pt) - if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree) + // SO-10066 Need to patch the enclosing tree in the context to make translation of Dynamic + // work during fallback typechecking below. + val resetContext: Context = { + object substResetForOriginal extends Transformer { + override def transform(tree: Tree): Tree = { + if (tree eq original) resetTree + else super.transform(tree) + } + } + context.make(substResetForOriginal.transform(context.tree)) + } + typerWithLocalContext(resetContext) { typer1 => + val tree1 = typer1.typed(resetTree, mode) + // Q: `typed` already calls `pluginsTyped` and `adapt`. the only difference here is that + // we pass `EmptyTree` as the `original`. intended? added in 2009 (53d98e7d42) by martin. + tree1 setType pluginsTyped(tree1.tpe, typer1, tree1, mode, pt) + if (tree1.isEmpty) tree1 else typer1.adapt(tree1, mode, pt, EmptyTree) + } } ) else diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index bd95fdbb50..80e82c85d8 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -89,7 +89,7 @@ package object util { implicit class StackTraceOps(private val e: Throwable) extends AnyVal with StackTracing { /** Format the stack trace, returning the prefix consisting of frames that satisfy * a given predicate. - * The format is similar to the typical case described in the JavaDoc + * The format is similar to the typical case described in the Javadoc * for [[java.lang.Throwable#printStackTrace]]. * If a stack trace is truncated, it will be followed by a line of the form * `... 3 elided`, by analogy to the lines `... 3 more` which indicate diff --git a/src/library/rootdoc.txt b/src/library/rootdoc.txt index d78df01046..0aef41c4da 100644 --- a/src/library/rootdoc.txt +++ b/src/library/rootdoc.txt @@ -44,8 +44,7 @@ Additional parts of the standard library are shipped as separate libraries. Thes - [[scala.reflect `scala.reflect`]] - Scala's reflection API (scala-reflect.jar) - [[scala.xml `scala.xml`]] - XML parsing, manipulation, and serialization (scala-xml.jar) - [[scala.swing `scala.swing`]] - A convenient wrapper around Java's GUI framework called Swing (scala-swing.jar) - - [[scala.util.parsing `scala.util.parsing`]] - [[scala.util.parsing.combinator Parser combinators]], including an - example implementation of a [[scala.util.parsing.json JSON parser]] (scala-parser-combinators.jar) + - [[scala.util.parsing `scala.util.parsing`]] - Parser combinators (scala-parser-combinators.jar) == Automatic imports == diff --git a/src/library/scala/annotation/showAsInfix.scala b/src/library/scala/annotation/showAsInfix.scala new file mode 100644 index 0000000000..6c25e08efa --- /dev/null +++ b/src/library/scala/annotation/showAsInfix.scala @@ -0,0 +1,27 @@ +package scala.annotation + +/** + * This annotation configures how Scala prints two-parameter generic types. + * + * By default, types with symbolic names are printed infix; while types without + * them are printed using the regular generic type syntax. + * + * Example of usage: + {{{ + scala> class Map[T, U] + defined class Map + + scala> def foo: Int Map Int = ??? + foo: Map[Int,Int] + + scala> @showAsInfix class Map[T, U] + defined class Map + + scala> def foo: Int Map Int = ??? + foo: Int Map Int + }}} + * + * @param enabled whether to show this type as an infix type operator. + * @since 2.12.2 + */ +class showAsInfix(enabled: Boolean = true) extends annotation.StaticAnnotation
\ No newline at end of file diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala index 1cd126f94f..0ee5542e30 100644 --- a/src/library/scala/collection/GenTraversableLike.scala +++ b/src/library/scala/collection/GenTraversableLike.scala @@ -249,30 +249,6 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with * @param bf $bfinfo * @return a new collection of type `That` which contains all elements * of this $coll followed by all elements of `that`. - * - * @usecase def ++[B](that: GenTraversableOnce[B]): $Coll[B] - * @inheritdoc - * - * Example: - * {{{ - * scala> val a = List(1) - * a: List[Int] = List(1) - * - * scala> val b = List(2) - * b: List[Int] = List(2) - * - * scala> val c = a ++ b - * c: List[Int] = List(1, 2) - * - * scala> val d = List('a') - * d: List[Char] = List(a) - * - * scala> val e = c ++ d - * e: List[AnyVal] = List(1, 2, a) - * }}} - * - * @return a new $coll which contains all elements of this $coll - * followed by all elements of `that`. */ def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala index b89720da78..419206c226 100644 --- a/src/library/scala/collection/IterableLike.scala +++ b/src/library/scala/collection/IterableLike.scala @@ -177,14 +177,14 @@ self => } /** Groups elements in fixed size blocks by passing a "sliding window" - * over them (as opposed to partitioning them, as is done in grouped.) - * "Sliding window" step is 1 by default. + * over them (as opposed to partitioning them, as is done in `grouped`.) + * The "sliding window" step is set to one. * @see [[scala.collection.Iterator]], method `sliding` * * @param size the number of elements per group * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int): Iterator[Repr] = sliding(size, 1) @@ -196,8 +196,8 @@ self => * @param step the distance between the first elements of successive * groups * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int, step: Int): Iterator[Repr] = for (xs <- iterator.sliding(size, step)) yield { diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index d000d22f72..809e851494 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -1091,7 +1091,7 @@ trait Iterator[+A] extends TraversableOnce[A] { extends AbstractIterator[Seq[B]] with Iterator[Seq[B]] { - require(size >= 1 && step >= 1, "size=%d and step=%d, but both must be positive".format(size, step)) + require(size >= 1 && step >= 1, f"size=$size%d and step=$step%d, but both must be positive") private[this] var buffer: ArrayBuffer[B] = ArrayBuffer() // the buffer private[this] var filled = false // whether the buffer is "hot" @@ -1099,30 +1099,30 @@ trait Iterator[+A] extends TraversableOnce[A] { private[this] var pad: Option[() => B] = None // what to pad short sequences with /** Public functions which can be used to configure the iterator before use. - * - * Pads the last segment if necessary so that all segments will - * have the same size. - * - * @param x The element that will be appended to the last segment, if necessary. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPartial(true)`. - */ + * + * Pads the last segment if necessary so that all segments will + * have the same size. + * + * @param x The element that will be appended to the last segment, if necessary. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPartial(true)`. + */ def withPadding(x: => B): this.type = { pad = Some(() => x) this } - /** Public functions which can be used to configure the iterator before use. - * - * Select whether the last segment may be returned with less than `size` - * elements. If not, some elements of the original iterator may not be - * returned at all. - * - * @param x `true` if partial segments may be returned, `false` otherwise. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPadding`. - */ + /** Public functions which can be used to configure the iterator before use. + * + * Select whether the last segment may be returned with less than `size` + * elements. If not, some elements of the original iterator may not be + * returned at all. + * + * @param x `true` if partial segments may be returned, `false` otherwise. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPadding`. + */ def withPartial(x: Boolean): this.type = { _partial = x if (_partial == true) // reset pad since otherwise it will take precedence @@ -1231,9 +1231,15 @@ trait Iterator[+A] extends TraversableOnce[A] { new GroupedIterator[B](self, size, size) /** Returns an iterator which presents a "sliding window" view of - * another iterator. The first argument is the window size, and - * the second is how far to advance the window on each iteration; - * defaults to `1`. Example usages: + * this iterator. The first argument is the window size, and + * the second argument `step` is how far to advance the window + * on each iteration. The `step` defaults to `1`. + * + * The default `GroupedIterator` can be configured to either + * pad a partial result to size `size` or suppress the partial + * result entirely. + * + * Example usages: * {{{ * // Returns List(List(1, 2, 3), List(2, 3, 4), List(3, 4, 5)) * (1 to 5).iterator.sliding(3).toList @@ -1247,6 +1253,11 @@ trait Iterator[+A] extends TraversableOnce[A] { * (1 to 5).iterator.sliding(4, 3).withPadding(it2.next).toList * }}} * + * @return An iterator producing `Seq[B]`s of size `size`, except the + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. + * This behavior can be configured. + * * @note Reuse: $consumesAndProducesIterator */ def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] = diff --git a/src/library/scala/collection/concurrent/TrieMap.scala b/src/library/scala/collection/concurrent/TrieMap.scala index 769d7b0dac..fe0b5c4f0e 100644 --- a/src/library/scala/collection/concurrent/TrieMap.scala +++ b/src/library/scala/collection/concurrent/TrieMap.scala @@ -932,6 +932,33 @@ extends scala.collection.concurrent.Map[K, V] if (nonReadOnly) readOnlySnapshot().iterator else new TrieMapIterator(0, this) + //////////////////////////////////////////////////////////////////////////// + // + // SI-10177 These methods need overrides as the inherited implementations + // call `.iterator` more than once, which doesn't guarantee a coherent + // view of the data if there is a concurrent writer + // Note that the we don't need overrides for keysIterator or valuesIterator + // TrieMapTest validates the behaviour. + override def values: Iterable[V] = { + if (nonReadOnly) readOnlySnapshot().values + else super.values + } + override def keySet: Set[K] = { + if (nonReadOnly) readOnlySnapshot().keySet + else super.keySet + } + override def filterKeys(p: K => Boolean): collection.Map[K, V] = { + if (nonReadOnly) readOnlySnapshot().filterKeys(p) + else super.filterKeys(p) + } + override def mapValues[W](f: V => W): collection.Map[K, W] = { + if (nonReadOnly) readOnlySnapshot().mapValues(f) + else super.mapValues(f) + } + // END extra overrides + /////////////////////////////////////////////////////////////////// + + private def cachedSize() = { val r = RDCSS_READ_ROOT() r.cachedSize(this) diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index 8371804b91..83fffa5940 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -18,91 +18,91 @@ import scala.language.implicitConversions trait DecorateAsJava extends AsJavaConverters { /** * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a Java `Iterator`. - * See [[asJavaIterator]]. + * @see [[asJavaIterator]] */ implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] = new AsJava(asJavaIterator(i)) /** - * Adds an `asJavaEnumeration` method that implicitly converts a Scala `Iterator` to a Java - * `Enumeration`. See [[asJavaEnumeration]]. + * Adds an `asJavaEnumeration` method that implicitly converts a Scala `Iterator` to a Java `Enumeration`. + * @see [[asJavaEnumeration]] */ implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] = new AsJavaEnumeration(i) /** * Adds an `asJava` method that implicitly converts a Scala `Iterable` to a Java `Iterable`. - * See [[asJavaIterable]]. + * @see [[asJavaIterable]] */ implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] = new AsJava(asJavaIterable(i)) /** - * Adds an `asJavaCollection` method that implicitly converts a Scala `Iterable` to an immutable - * Java `Collection`. See [[asJavaCollection]]. + * Adds an `asJavaCollection` method that implicitly converts a Scala `Iterable` to an immutable Java `Collection`. + * @see [[asJavaCollection]] */ implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] = new AsJavaCollection(i) /** * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer` to a Java `List`. - * See [[bufferAsJavaList]]. + * @see [[bufferAsJavaList]] */ implicit def bufferAsJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] = new AsJava(bufferAsJavaList(b)) /** * Adds an `asJava` method that implicitly converts a Scala mutable `Seq` to a Java `List`. - * See [[mutableSeqAsJavaList]]. + * @see [[mutableSeqAsJavaList]] */ implicit def mutableSeqAsJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] = new AsJava(mutableSeqAsJavaList(b)) /** * Adds an `asJava` method that implicitly converts a Scala `Seq` to a Java `List`. - * See [[seqAsJavaList]]. + * @see [[seqAsJavaList]] */ implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] = new AsJava(seqAsJavaList(b)) /** * Adds an `asJava` method that implicitly converts a Scala mutable `Set` to a Java `Set`. - * See [[mutableSetAsJavaSet]]. + * @see [[mutableSetAsJavaSet]] */ implicit def mutableSetAsJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] = new AsJava(mutableSetAsJavaSet(s)) /** * Adds an `asJava` method that implicitly converts a Scala `Set` to a Java `Set`. - * See [[setAsJavaSet]]. + * @see [[setAsJavaSet]] */ implicit def setAsJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] = new AsJava(setAsJavaSet(s)) /** * Adds an `asJava` method that implicitly converts a Scala mutable `Map` to a Java `Map`. - * See [[mutableMapAsJavaMap]]. + * @see [[mutableMapAsJavaMap]] */ implicit def mutableMapAsJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] = new AsJava(mutableMapAsJavaMap(m)) /** - * Adds an `asJavaDictionary` method that implicitly converts a Scala mutable `Map` to a Java - * `Dictionary`. See [[asJavaDictionary]]. + * Adds an `asJavaDictionary` method that implicitly converts a Scala mutable `Map` to a Java `Dictionary`. + * @see [[asJavaDictionary]] */ implicit def asJavaDictionaryConverter[A, B](m : mutable.Map[A, B]): AsJavaDictionary[A, B] = new AsJavaDictionary(m) /** * Adds an `asJava` method that implicitly converts a Scala `Map` to a Java `Map`. - * See [[mapAsJavaMap]]. + * @see [[mapAsJavaMap]] */ implicit def mapAsJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] = new AsJava(mapAsJavaMap(m)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `concurrent.Map` to a Java - * `ConcurrentMap`. See [[mapAsJavaConcurrentMap]]. + * Adds an `asJava` method that implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * @see [[mapAsJavaConcurrentMap]]. */ implicit def mapAsJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] = new AsJava(mapAsJavaConcurrentMap(m)) diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala index b74a06ece5..f680aa5267 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -18,70 +18,70 @@ import scala.language.implicitConversions trait DecorateAsScala extends AsScalaConverters { /** * Adds an `asScala` method that implicitly converts a Java `Iterator` to a Scala `Iterator`. - * See [[asScalaIterator]]. + * @see [[asScalaIterator]] */ implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] = new AsScala(asScalaIterator(i)) /** * Adds an `asScala` method that implicitly converts a Java `Enumeration` to a Scala `Iterator`. - * See [[enumerationAsScalaIterator]]. + * @see [[enumerationAsScalaIterator]] */ implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] = new AsScala(enumerationAsScalaIterator(i)) /** * Adds an `asScala` method that implicitly converts a Java `Iterable` to a Scala `Iterable`. - * See [[iterableAsScalaIterable]]. + * @see [[iterableAsScalaIterable]] */ implicit def iterableAsScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] = new AsScala(iterableAsScalaIterable(i)) /** * Adds an `asScala` method that implicitly converts a Java `Collection` to an Scala `Iterable`. - * See [[collectionAsScalaIterable]]. + * @see [[collectionAsScalaIterable]] */ implicit def collectionAsScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] = new AsScala(collectionAsScalaIterable(i)) /** * Adds an `asScala` method that implicitly converts a Java `List` to a Scala mutable `Buffer`. - * See [[asScalaBuffer]]. + * @see [[asScalaBuffer]] */ implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] = new AsScala(asScalaBuffer(l)) /** * Adds an `asScala` method that implicitly converts a Java `Set` to a Scala mutable `Set`. - * See [[asScalaSet]]. + * @see [[asScalaSet]] */ implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] = new AsScala(asScalaSet(s)) /** * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala mutable `Map`. - * See [[mapAsScalaMap]]. + * @see [[mapAsScalaMap]] */ implicit def mapAsScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] = new AsScala(mapAsScalaMap(m)) /** - * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` to a Scala mutable - * `concurrent.Map`. See [[mapAsScalaConcurrentMap]]. + * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` to a Scala mutable `concurrent.Map`. + * @see [[mapAsScalaConcurrentMap]] */ implicit def mapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] = new AsScala(mapAsScalaConcurrentMap(m)) /** * Adds an `asScala` method that implicitly converts a Java `Dictionary` to a Scala mutable `Map`. - * See [[dictionaryAsScalaMap]]. + * @see [[dictionaryAsScalaMap]] */ implicit def dictionaryAsScalaMapConverter[A, B](p: ju.Dictionary[A, B]): AsScala[mutable.Map[A, B]] = new AsScala(dictionaryAsScalaMap(p)) /** - * Adds an `asScala` method that implicitly converts a Java `Properties` to a Scala mutable - * `Map[String, String]`. See [[propertiesAsScalaMap]]. + * Adds an `asScala` method that implicitly converts a Java `Properties` to a Scala mutable `Map[String, String]`. + * @see [[propertiesAsScalaMap]] */ implicit def propertiesAsScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = new AsScala(propertiesAsScalaMap(p)) diff --git a/src/library/scala/collection/convert/ImplicitConversions.scala b/src/library/scala/collection/convert/ImplicitConversions.scala index 747e0606c8..35e6ce1616 100644 --- a/src/library/scala/collection/convert/ImplicitConversions.scala +++ b/src/library/scala/collection/convert/ImplicitConversions.scala @@ -17,76 +17,122 @@ import JavaConverters._ /** Defines implicit converter methods from Java to Scala collections. */ trait ToScalaImplicits { - /** Implicitly converts a Java `Iterator` to a Scala `Iterator`. See [[asScalaIterator]]. */ + /** Implicitly converts a Java `Iterator` to a Scala `Iterator`. + * @see [[AsScalaConverters.asScalaIterator]] + */ implicit def `iterator asScala`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it) - /** Implicitly converts a Java `Enumeration` to a Scala `Iterator`. See [[enumerationAsScalaIterator]]. */ + /** Implicitly converts a Java `Enumeration` to a Scala `Iterator`. + * @see [[AsScalaConverters.enumerationAsScalaIterator]] + */ implicit def `enumeration AsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i) - /** Implicitly converts a Java `Iterable` to a Scala `Iterable`. See [[iterableAsScalaIterable]]. */ + /** Implicitly converts a Java `Iterable` to a Scala `Iterable`. + * @see [[AsScalaConverters.iterableAsScalaIterable]] + */ implicit def `iterable AsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i) - /** Implicitly converts a Java `Collection` to an Scala `Iterable`. See [[collectionAsScalaIterable]]. */ + /** Implicitly converts a Java `Collection` to an Scala `Iterable`. + * @see [[AsScalaConverters.collectionAsScalaIterable]] + */ implicit def `collection AsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i) - /** Implicitly converts a Java `List` to a Scala mutable `Buffer`. See [[asScalaBuffer]]. */ + /** Implicitly converts a Java `List` to a Scala mutable `Buffer`. + * @see [[AsScalaConverters.asScalaBuffer]] + */ implicit def `list asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l) - /** Implicitly converts a Java `Set` to a Scala mutable `Set`. See [[asScalaSet]]. */ + /** Implicitly converts a Java `Set` to a Scala mutable `Set`. + * @see [[AsScalaConverters.asScalaSet]] + */ implicit def `set asScala`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s) - /** Implicitly converts a Java `Map` to a Scala mutable `Map`. See [[mapAsScalaMap]]. */ + /** Implicitly converts a Java `Map` to a Scala mutable `Map`. + * @see [[AsScalaConverters.mapAsScalaMap]] + */ implicit def `map AsScala`[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m) - /** Implicitly converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`. See [[mapAsScalaConcurrentMap]]. */ + /** Implicitly converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`. + * @see [[AsScalaConverters.mapAsScalaConcurrentMap]] + */ implicit def `map AsScalaConcurrentMap`[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m) - /** Implicitly converts a Java `Dictionary` to a Scala mutable `Map`. See [[dictionaryAsScalaMap]]. */ + /** Implicitly converts a Java `Dictionary` to a Scala mutable `Map`. + * @see [[AsScalaConverters.dictionaryAsScalaMap]] + */ implicit def `dictionary AsScalaMap`[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(p) - /** Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`. See [[propertiesAsScalaMap]]. */ + /** Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`. + * @see [[AsScalaConverters.propertiesAsScalaMap]] + */ implicit def `properties AsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) } /** Defines implicit conversions from Scala to Java collections. */ trait ToJavaImplicits { - /** Implicitly converts a Scala `Iterator` to a Java `Iterator`. See [[asJavaIterator]]. */ + /** Implicitly converts a Scala `Iterator` to a Java `Iterator`. + * @see [[AsJavaConverters.asJavaIterator]] + */ implicit def `iterator asJava`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it) - /** Implicitly converts a Scala `Iterator` to a Java `Enumeration`. See [[asJavaEnumeration]]. */ + /** Implicitly converts a Scala `Iterator` to a Java `Enumeration`. + * @see [[AsJavaConverters.asJavaEnumeration]] + */ implicit def `enumeration asJava`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it) - /** Implicitly converts a Scala `Iterable` to a Java `Iterable`. See [[asJavaIterable]]. */ + /** Implicitly converts a Scala `Iterable` to a Java `Iterable`. + * @see [[AsJavaConverters.asJavaIterable]] + */ implicit def `iterable asJava`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i) - /** Implicitly converts a Scala `Iterable` to an immutable Java `Collection`. See [[asJavaCollection]]. */ + /** Implicitly converts a Scala `Iterable` to an immutable Java `Collection`. + * @see [[AsJavaConverters.asJavaCollection]] + */ implicit def `collection asJava`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it) - /** Implicitly converts a Scala mutable `Buffer` to a Java `List`. See [[bufferAsJavaList]]. */ + /** Implicitly converts a Scala mutable `Buffer` to a Java `List`. + * @see [[AsJavaConverters.bufferAsJavaList]] + */ implicit def `buffer AsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b) - /** Implicitly converts a Scala mutable `Seq` to a Java `List`. See [[mutableSeqAsJavaList]]. */ + /** Implicitly converts a Scala mutable `Seq` to a Java `List`. + * @see [[AsJavaConverters.mutableSeqAsJavaList]] + */ implicit def `mutableSeq AsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq) - /** Implicitly converts a Scala `Seq` to a Java `List`. See [[seqAsJavaList]]. */ + /** Implicitly converts a Scala `Seq` to a Java `List`. + * @see [[AsJavaConverters.seqAsJavaList]] + */ implicit def `seq AsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq) - /** Implicitly converts a Scala mutable `Set` to a Java `Set`. See [[mutableSetAsJavaSet]]. */ + /** Implicitly converts a Scala mutable `Set` to a Java `Set`. + * @see [[AsJavaConverters.mutableSetAsJavaSet]] + */ implicit def `mutableSet AsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s) - /** Implicitly converts a Scala `Set` to a Java `Set`. See [[setAsJavaSet]]. */ + /** Implicitly converts a Scala `Set` to a Java `Set`. + * @see [[AsJavaConverters.setAsJavaSet]] + */ implicit def `set AsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s) - /** Implicitly converts a Scala mutable `Map` to a Java `Map`. See [[mutableMapAsJavaMap]]. */ + /** Implicitly converts a Scala mutable `Map` to a Java `Map`. + * @see [[AsJavaConverters.mutableMapAsJavaMap]] + */ implicit def `mutableMap AsJavaMap`[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap(m) - /** Implicitly converts a Scala mutable `Map` to a Java `Dictionary`. See [[asJavaDictionary]]. */ + /** Implicitly converts a Scala mutable `Map` to a Java `Dictionary`. + * @see [[AsJavaConverters.asJavaDictionary]] + */ implicit def `dictionary asJava`[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary(m) - /** Implicitly converts a Scala `Map` to a Java `Map`. See [[mapAsJavaMap]]. */ + /** Implicitly converts a Scala `Map` to a Java `Map`. + * @see [[AsJavaConverters.mapAsJavaMap]] + */ implicit def `map AsJavaMap`[A, B](m: Map[A, B]): ju.Map[A, B] = mapAsJavaMap(m) - /** Implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. See [[mapAsJavaConcurrentMap]]. */ + /** Implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * @see [[AsJavaConverters.mapAsJavaConcurrentMap]] + */ implicit def `map AsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m) } diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 6b29b084aa..627f723cb0 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -52,6 +52,9 @@ sealed class HashMap[A, +B] extends AbstractMap[A, B] def get(key: A): Option[B] = get0(key, computeHash(key), 0) + override final def contains(key: A): Boolean = + contains0(key, computeHash(key), 0) + override def updated [B1 >: B] (key: A, value: B1): HashMap[A, B1] = updated0(key, computeHash(key), 0, value, null, null) @@ -92,7 +95,7 @@ sealed class HashMap[A, +B] extends AbstractMap[A, B] import HashMap.{Merger, MergeFunction, liftMerger} private[collection] def get0(key: A, hash: Int, level: Int): Option[B] = None - + protected def contains0(key: A, hash: Int, level: Int): Boolean = false private[collection] def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = new HashMap.HashMap1(key, hash, value, kv) @@ -185,6 +188,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { override def size = 1 @@ -195,6 +199,8 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash && key == this.key) Some(value) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && key == this.key private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash && key == this.key ) { if (merger eq null) { @@ -239,6 +245,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash) kvs.get(key) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && kvs.contains(key) + private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash) { if ((merger eq null) || !kvs.contains(key)) new HashMapCollision1(hash, kvs.updated(key, value)) @@ -294,6 +303,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashTrieMap[A, +B]( private[collection] val bitmap: Int, private[collection] val elems: Array[HashMap[A, B @uV]], @@ -306,21 +316,41 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def size = size0 override def get0(key: A, hash: Int, level: Int): Option[B] = { + // Note: this code is duplicated with `contains0` + val index = (hash >>> level) & 0x1f + if (bitmap == - 1) { + elems(index).get0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).get0(key, hash, level + 5) + } else { + None + } + } + } + + override protected def contains0(key: A, hash: Int, level: Int): Boolean = { + // Note: this code is duplicated from `get0` val index = (hash >>> level) & 0x1f - val mask = (1 << index) if (bitmap == - 1) { - elems(index & 0x1f).get0(key, hash, level + 5) - } else if ((bitmap & mask) != 0) { - val offset = Integer.bitCount(bitmap & (mask-1)) - elems(offset).get0(key, hash, level + 5) - } else - None + elems(index).contains0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).contains0(key, hash, level + 5) + } else { + false + } + } } private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.updated0(key, hash, level + 5, value, kv, merger) @@ -342,7 +372,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.removed0(key, hash, level + 5) diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala index 1dd0d7683a..240b5c899e 100644 --- a/src/library/scala/collection/immutable/Queue.scala +++ b/src/library/scala/collection/immutable/Queue.scala @@ -106,6 +106,15 @@ sealed class Queue[+A] protected(protected val in: List[A], protected val out: L case _ => super.:+(elem)(bf) } + override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Queue[A], B, That]): That = { + if (bf eq Queue.ReusableCBF) { + val thatQueue = that.asInstanceOf[Queue[B]] + new Queue[B](thatQueue.in ++ (thatQueue.out reverse_::: this.in), this.out).asInstanceOf[That] + } else { + super.++(that)(bf) + } + } + /** Creates a new queue with element added at the end * of the old queue. * diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 3d4e32971c..8f26de153a 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -1119,11 +1119,11 @@ object Stream extends SeqFactory[Stream] { /** Construct a stream consisting of a given first element followed by elements * from a lazily evaluated Stream. */ - def #::(hd: A): Stream[A] = cons(hd, tl) + def #::[B >: A](hd: B): Stream[B] = cons(hd, tl) /** Construct a stream consisting of the concatenation of the given stream and * a lazily evaluated Stream. */ - def #:::(prefix: Stream[A]): Stream[A] = prefix append tl + def #:::[B >: A](prefix: Stream[B]): Stream[B] = prefix append tl } /** A wrapper method that adds `#::` for cons and `#:::` for concat as operations diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 3329e35042..29382134aa 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -177,9 +177,7 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara (a1, a2, a3) } - def seq = thisCollection - } /** @@ -189,7 +187,7 @@ sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomPara */ object ArrayOps { - /** A class of `ArrayOps` for arrays containing reference types. */ + /** A subclass of `ArrayOps` for arrays containing reference types. */ final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] { override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr) @@ -201,8 +199,8 @@ object ArrayOps { def update(index: Int, elem: T) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `byte`s. */ -final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { + /** A subclass of `ArrayOps` for arrays containing `Byte`s. */ + final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr) @@ -213,8 +211,8 @@ final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Byte) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `short`s. */ -final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { + /** A subclass of `ArrayOps` for arrays containing `Short`s. */ + final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr) @@ -225,8 +223,8 @@ final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOp def update(index: Int, elem: Short) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `char`s. */ -final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { + /** A subclass of `ArrayOps` for arrays containing `Char`s. */ + final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr) @@ -237,8 +235,8 @@ final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Char) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `int`s. */ -final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { + /** A subclass of `ArrayOps` for arrays containing `Int`s. */ + final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr) @@ -249,8 +247,8 @@ final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[In def update(index: Int, elem: Int) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `long`s. */ -final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { + /** A subclass of `ArrayOps` for arrays containing `Long`s. */ + final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr) @@ -261,8 +259,8 @@ final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Long) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `float`s. */ -final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { + /** A subclass of `ArrayOps` for arrays containing `Float`s. */ + final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr) @@ -273,8 +271,8 @@ final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOp def update(index: Int, elem: Float) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `double`s. */ -final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { + /** A subclass of `ArrayOps` for arrays containing `Double`s. */ + final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr) @@ -285,8 +283,8 @@ final class ofDouble(override val repr: Array[Double]) extends AnyVal with Array def update(index: Int, elem: Double) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `boolean`s. */ -final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { + /** A subclass of `ArrayOps` for arrays containing `Boolean`s. */ + final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) @@ -297,8 +295,8 @@ final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with Arr def update(index: Int, elem: Boolean) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays of `Unit` types. */ -final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { + /** A subclass of `ArrayOps` for arrays of `Unit` types. */ + final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr) diff --git a/src/library/scala/deprecated.scala b/src/library/scala/deprecated.scala index 60f0857550..a57745dbea 100644 --- a/src/library/scala/deprecated.scala +++ b/src/library/scala/deprecated.scala @@ -39,20 +39,18 @@ import scala.annotation.meta._ * '''`@deprecated` in the Scala language and its standard library'''<br/> * * A deprecated element of the Scala language or a definition in the Scala standard library will - * be preserved or at least another major version. + * be preserved at least for the current major version. * - * This means that an element deprecated since 2.12 will be preserved in 2.13, but will very likely - * not be part of 2.14. Sometimes a deprecated element might be kept for more than a major - * release to ease migration and upgrades from older Scala versions.<br/> - * Developers should not rely on this. + * This means that an element deprecated in some 2.12.x release will be preserved in + * all 2.12.x releases, but may be removed in 2.13. (A deprecated element + * might be kept longer to ease migration. Developers should not rely on this.) * * '''Special deprecation policy for Scala 2.12'''<br> - * The Scala team has decided to enact a special deprecation policy for the 2.12 release:<br/> + * The Scala team has decided to enact a special deprecation policy for Scala 2.12:<br/> * - * As an upgrade from Scala 2.11 to Scala 2.12 also requires upgrading from Java 6 to Java 8, - * no deprecated elements will be removed in this release to ease migration and upgrades - * from older Scala versions. This means that elements deprecated since 2.11 (or earlier) - * will not be removed in Scala 2.12. + * As an upgrade from 2.11 to 2.12 also requires upgrading from Java 6 to Java 8, + * deprecated elements will not normally be removed in this release, to ease migration + * and cross-building. * * @see The official documentation on [[http://www.scala-lang.org/news/2.11.0/#binary-compatibility binary compatibility]]. * @param message the message to print during compilation if the definition is accessed diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index a6e584424b..8ba3e62ac2 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -316,8 +316,9 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => /** Check whether any of the arguments mention a symbol */ def refsSymbol(sym: Symbol) = hasArgWhich(_.symbol == sym) - def stringArg(index: Int) = constantAtIndex(index) map (_.stringValue) - def intArg(index: Int) = constantAtIndex(index) map (_.intValue) + def stringArg(index: Int) = constantAtIndex(index) map (_.stringValue) + def intArg(index: Int) = constantAtIndex(index) map (_.intValue) + def booleanArg(index: Int) = constantAtIndex(index) map (_.booleanValue) def symbolArg(index: Int) = argAtIndex(index) collect { case Apply(fun, Literal(str) :: Nil) if fun.symbol == definitions.Symbol_apply => newTermName(str.stringValue) diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 19460af27f..78a75c63d6 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -975,10 +975,10 @@ trait Definitions extends api.StandardDefinitions { } /** Given a class symbol C with type parameters T1, T2, ... Tn - * which have upper/lower bounds LB1/UB1, LB1/UB2, ..., LBn/UBn, + * which have upper/lower bounds LB1/UB1, LB2/UB2, ..., LBn/UBn, * returns an existential type of the form * - * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... en >: LBn <: UBn }. + * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... En >: LBn <: UBn }. */ // TODO Review the way this is used. I see two potential problems: // 1. `existentialAbstraction` here doesn't create fresh existential type symbols, it just @@ -1421,6 +1421,8 @@ trait Definitions extends api.StandardDefinitions { case _ => false } + lazy val ShowAsInfixAnnotationClass = rootMirror.getClassIfDefined("scala.annotation.showAsInfix") + // todo: reconcile with javaSignature!!! def signature(tp: Type): String = { def erasure(tp: Type): Type = tp match { diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index 95b3b7fb14..1a1aa2e721 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/src/reflect/scala/reflect/internal/Positions.scala @@ -255,7 +255,7 @@ trait Positions extends api.Positions { self: SymbolTable => val annTrees = mdef.mods.annotations match { case Nil if mdef.symbol != null => // After typechecking, annotations are moved from the modifiers - // to the annotation on the symbol of the anotatee. + // to the annotation on the symbol of the annotatee. mdef.symbol.annotations.map(_.original) case anns => anns } diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 9602a2859b..bb352e9d31 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -775,7 +775,7 @@ trait Printers extends api.Printers { self: SymbolTable => } // constructor's params processing (don't print single empty constructor param list) vparamss match { - case Nil | List(Nil) if (!mods.isCase && !ctorMods.hasFlag(AccessFlags)) => + case Nil | List(Nil) if !mods.isCase && !ctorMods.hasFlag(AccessFlags) => case _ => vparamss foreach printConstrParams } parents diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index 026438e421..1b2be64654 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -266,7 +266,7 @@ trait ReificationSupport { self: SymbolTable => } // undo gen.mkTemplate - protected object UnMkTemplate { + protected class UnMkTemplate(isCaseClass: Boolean) { def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = { val Template(parents, selfType, _) = templ val tbody = treeInfo.untypecheckedTemplBody(templ) @@ -296,8 +296,9 @@ trait ReificationSupport { self: SymbolTable => result(ctorMods, Nil, edefs, body) else { // undo conversion from (implicit ... ) to ()(implicit ... ) when it's the only parameter section + // except that case classes require the explicit leading empty parameter list val vparamssRestoredImplicits = ctorVparamss match { - case Nil :: (tail @ ((head :: _) :: _)) if head.mods.isImplicit => tail + case Nil :: (tail @ ((head :: _) :: _)) if head.mods.isImplicit && !isCaseClass => tail case other => other } // undo flag modifications by merging flag info from constructor args and fieldDefs @@ -314,7 +315,9 @@ trait ReificationSupport { self: SymbolTable => } } } + def asCase = new UnMkTemplate(isCaseClass = true) } + protected object UnMkTemplate extends UnMkTemplate(isCaseClass = false) protected def mkSelfType(tree: Tree) = tree match { case vd: ValDef => @@ -346,9 +349,11 @@ trait ReificationSupport { self: SymbolTable => def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]], List[Tree], List[Tree], ValDef, List[Tree])] = tree match { - case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body)) - if !ctorMods.isTrait && !ctorMods.hasFlag(JAVA) => - Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfType, body)) + case ClassDef(mods, name, tparams, impl) => + val X = if (mods.isCase) UnMkTemplate.asCase else UnMkTemplate + val X(parents, selfType, ctorMods, vparamss, earlyDefs, body) = impl + if (ctorMods.isTrait || ctorMods.hasFlag(JAVA)) None + else Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfType, body)) case _ => None } diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index 19804fc5f3..51fb31d36d 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -298,7 +298,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => var e = lookupEntry(original.name.companionName) while (e != null) { // 1) Must be owned by the same Scope, to ensure that in - // `{ class C; { ...; object C } }`, the class is not seen as a comaniopn of the object. + // `{ class C; { ...; object C } }`, the class is not seen as a companion of the object. // 2) Must be a class and module symbol, so that `{ class C; def C }` or `{ type T; object T }` are not companions. def isClassAndModule(sym1: Symbol, sym2: Symbol) = sym1.isClass && sym2.isModule if ((e.owner eq entry.owner) && (isClassAndModule(original, e.sym) || isClassAndModule(e.sym, original))) { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index ad7e3ffe8f..2a0fb5298b 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -309,6 +309,9 @@ trait Types /** Is this type completed (i.e. not a lazy type)? */ def isComplete: Boolean = true + /** Should this be printed as an infix type (@showAsInfix class &&[T, U])? */ + def isShowAsInfixType: Boolean = false + /** If this is a lazy type, assign a new type to `sym`. */ def complete(sym: Symbol) {} @@ -2102,6 +2105,15 @@ trait Types trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args)) toBoolean(trivial) } + + /* It only makes sense to show 2-ary type constructors infix. + * By default we do only if it's a symbolic name. */ + override def isShowAsInfixType: Boolean = + hasLength(args, 2) && + sym.getAnnotation(ShowAsInfixAnnotationClass) + .map(_ booleanArg 0 getOrElse true) + .getOrElse(!Character.isUnicodeIdentifierStart(sym.decodedName.head)) + private[Types] def invalidateTypeRefCaches(): Unit = { parentsCache = null parentsPeriod = NoPeriod @@ -2327,6 +2339,22 @@ trait Types case arg :: Nil => s"($arg,)" case _ => args.mkString("(", ", ", ")") } + private def infixTypeString: String = { + /* SLS 3.2.8: all infix types have the same precedence. + * In A op B op' C, op and op' need the same associativity. + * Therefore, if op is left associative, anything on its right + * needs to be parenthesized if it's an infix type, and vice versa. */ + // we should only get here after `isShowInfixType` says we have 2 args + val l :: r :: Nil = args + + val isRightAssoc = typeSymbol.decodedName endsWith ":" + + val lstr = if (isRightAssoc && l.isShowAsInfixType) s"($l)" else l.toString + + val rstr = if (!isRightAssoc && r.isShowAsInfixType) s"($r)" else r.toString + + s"$lstr ${sym.decodedName} $rstr" + } private def customToString = sym match { case RepeatedParamClass | JavaRepeatedParamClass => args.head + "*" case ByNameParamClass => "=> " + args.head @@ -2350,6 +2378,8 @@ trait Types xs.init.mkString("(", ", ", ")") + " => " + xs.last } } + else if (isShowAsInfixType) + infixTypeString else if (isTupleTypeDirect(this)) tupleTypeString else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (this ne dealias)) @@ -4152,7 +4182,7 @@ trait Types * The specification-enumerated non-value types are method types, polymorphic * method types, and type constructors. Supplements to the specified set of * non-value types include: types which wrap non-value symbols (packages - * abd statics), overloaded types. Varargs and by-name types T* and (=>T) are + * and statics), overloaded types. Varargs and by-name types T* and (=>T) are * not designated non-value types because there is code which depends on using * them as type arguments, but their precise status is unclear. */ @@ -4251,7 +4281,7 @@ trait Types case mt1 @ MethodType(params1, res1) => tp2 match { case mt2 @ MethodType(params2, res2) => - // sameLength(params1, params2) was used directly as pre-screening optimization (now done by matchesQuantified -- is that ok, performancewise?) + // sameLength(params1, params2) was used directly as pre-screening optimization (now done by matchesQuantified -- is that ok, performance-wise?) mt1.isImplicit == mt2.isImplicit && matchingParams(params1, params2, mt1.isJava, mt2.isJava) && matchesQuantified(params1, params2, res1, res2) @@ -4696,7 +4726,7 @@ trait Types case _ => Depth(1) } - //OPT replaced with tailrecursive function to save on #closures + //OPT replaced with tail recursive function to save on #closures // was: // var d = 0 // for (tp <- tps) d = d max by(tp) //!!!OPT!!! diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index fe1de91662..08ccac8069 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -385,7 +385,7 @@ abstract class UnPickler { // We're stuck with the order types are pickled in, but with judicious use // of named parameters we can recapture a declarative flavor in a few cases. - // But it's still a rat's nest of adhockery. + // But it's still a rat's nest of ad-hockery. (tag: @switch) match { case NOtpe => NoType case NOPREFIXtpe => NoPrefix diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala index 108ce45cca..6d9a9d6649 100644 --- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala +++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala @@ -136,7 +136,7 @@ private[internal] trait GlbLubs { mergePrefixAndArgs(ts1, Covariant, depth) match { case NoType => loop(pretypes, tails) case tp if strictInference && willViolateRecursiveBounds(tp, ts0, ts1) => - log(s"Breaking recursion in lublist, advancing frontier and discaring merged prefix/args from $tp") + log(s"Breaking recursion in lublist, advancing frontier and discarding merged prefix/args from $tp") loop(pretypes, tails) case tp => loop(tp :: pretypes, tails) diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index cf274f24bb..990092b749 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -404,7 +404,7 @@ trait TypeComparers { sym2.isClass && { val base = tr1 baseType sym2 // During bootstrap, `base eq NoType` occurs about 2.5 times as often as `base ne NoType`. - // The extra check seems like a worthwhile optimization (about 2.5M useless calls to isSubtype saved during that run). + // The extra check seems like a worthwhile optimization (about 2.5M useless calls to isSubType saved during that run). (base ne tr1) && (base ne NoType) && isSubType(base, tr2, depth) } || diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index e321a07f51..2697824fd5 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -25,7 +25,7 @@ private[internal] trait TypeConstraints { // register with the auto-clearing cache manager perRunCaches.recordCache(this) - /** Undo all changes to constraints to type variables upto `limit`. */ + /** Undo all changes to constraints to type variables up to `limit`. */ //OPT this method is public so we can do `manual inlining` def undoTo(limit: UndoPairs) { assertCorrectThread() diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index de065d0b5d..0601067d26 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -312,7 +312,7 @@ private[internal] trait TypeMaps { * the corresponding class file might still not be read, so we do not * know what the type parameters of the type are. Therefore * the conversion of raw types to existential types might not have taken place - * in ClassFileparser.sigToType (where it is usually done). + * in ClassFileParser.sigToType (where it is usually done). */ def rawToExistential = new TypeMap { private var expanded = immutable.Set[Symbol]() @@ -404,7 +404,7 @@ private[internal] trait TypeMaps { case _ => super.mapOver(tp) } - // Do not discard the types of existential ident's. The + // Do not discard the types of existential idents. The // symbol of the Ident itself cannot be listed in the // existential's parameters, so the resulting existential // type would be ill-formed. @@ -504,7 +504,7 @@ private[internal] trait TypeMaps { && isBaseClassOfEnclosingClass(sym.owner) ) - private var capturedThisIds= 0 + private var capturedThisIds = 0 private def nextCapturedThisId() = { capturedThisIds += 1; capturedThisIds } /** Creates an existential representing a type parameter which appears * in the prefix of a ThisType. diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index e2f1e74740..24f8aa88e6 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -19,7 +19,7 @@ trait Erasure { /* A Java Array<T> is erased to Array[Object] (T can only be a reference type), where as a Scala Array[T] is * erased to Object. However, there is only symbol for the Array class. So to make the distinction between * a Java and a Scala array, we check if the owner of T comes from a Java class. - * This however caused issue SI-5654. The additional test for EXSITENTIAL fixes it, see the ticket comments. + * This however caused issue SI-5654. The additional test for EXISTENTIAL fixes it, see the ticket comments. * In short, members of an existential type (e.g. `T` in `forSome { type T }`) can have pretty arbitrary * owners (e.g. when computing lubs, <root> is used). All packageClass symbols have `isJavaDefined == true`. */ diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala index 905f1bf26e..2d623f3367 100644 --- a/src/reflect/scala/reflect/internal/util/Statistics.scala +++ b/src/reflect/scala/reflect/internal/util/Statistics.scala @@ -78,7 +78,7 @@ object Statistics { /** Create a new stackable that shows as `prefix` and is active * in the same phases as its base timer. Stackable timers are subtimers - * that can be stacked ina timerstack, and that print aggregate, as well as specific + * that can be stacked in a timerstack, and that print aggregate, as well as specific * durations. */ def newStackableTimer(prefix: String, timer: Timer): StackableTimer = new StackableTimer(prefix, timer) diff --git a/src/reflect/scala/reflect/internal/util/StringOps.scala b/src/reflect/scala/reflect/internal/util/StringOps.scala index 79195e6eab..2fee6b0f82 100644 --- a/src/reflect/scala/reflect/internal/util/StringOps.scala +++ b/src/reflect/scala/reflect/internal/util/StringOps.scala @@ -11,7 +11,7 @@ package reflect package internal package util -import scala.compat.Platform.EOL +import java.lang.System.{lineSeparator => EOL} /** This object provides utility methods to extract elements * from Strings. @@ -45,7 +45,7 @@ trait StringOps { else s.substring(0, end) } /** Breaks the string into lines and strips each line before reassembling. */ - def trimAllTrailingSpace(s: String): String = s.lines map trimTrailingSpace mkString EOL + def trimAllTrailingSpace(s: String): String = s.lines.map(trimTrailingSpace).mkString(EOL) def decompose(str: String, sep: Char): List[String] = { def ws(start: Int): List[String] = @@ -69,18 +69,17 @@ trait StringOps { else Some((str take idx, str drop (if (doDropIndex) idx + 1 else idx))) /** Returns a string meaning "n elements". + * Don't try an element such as "index" with irregular plural. */ - def countElementsAsString(n: Int, elements: String): String = + def countElementsAsString(n: Int, element: String): String = n match { - case 0 => s"no ${elements}s" - case 1 => "one " + elements - case 2 => "two " + elements + "s" - case 3 => "three " + elements + "s" - case 4 => "four " + elements + "s" - case _ => s"$n ${elements}s" + case 0 => s"no ${element}s" + case 1 => s"one ${element}" + case _ => s"${countAsString(n)} ${element}s" } /** Turns a count into a friendly English description if n<=4. + * Otherwise, a scary math representation. */ def countAsString(n: Int): String = n match { @@ -89,8 +88,8 @@ trait StringOps { case 2 => "two" case 3 => "three" case 4 => "four" - case _ => "" + n + case _ => n.toString } } -object StringOps extends StringOps { } +object StringOps extends StringOps diff --git a/src/reflect/scala/reflect/io/Path.scala b/src/reflect/scala/reflect/io/Path.scala index 5f93506015..c5b5ae24ba 100644 --- a/src/reflect/scala/reflect/io/Path.scala +++ b/src/reflect/scala/reflect/io/Path.scala @@ -107,19 +107,20 @@ class Path private[io] (val jfile: JFile) { def /(child: Directory): Directory = /(child: Path).toDirectory def /(child: File): File = /(child: Path).toFile - /** If this path is a container, recursively iterate over its contents. + /** If this path is a directory, recursively iterate over its contents. * The supplied condition is a filter which is applied to each element, - * with that branch of the tree being closed off if it is true. So for - * example if the condition is true for some subdirectory, nothing - * under that directory will be in the Iterator; but otherwise each - * file and subdirectory underneath it will appear. + * with that branch of the tree being closed off if it is false. + * So for example if the condition is false for some subdirectory, nothing + * under that directory will be in the Iterator. If it's true, all files for + * which the condition holds and are directly in that subdirectory are in the + * Iterator, and all sub-subdirectories are recursively evaluated */ def walkFilter(cond: Path => Boolean): Iterator[Path] = if (isFile) toFile walkFilter cond else if (isDirectory) toDirectory walkFilter cond else Iterator.empty - /** Equivalent to walkFilter(_ => false). + /** Equivalent to walkFilter(_ => true). */ def walk: Iterator[Path] = walkFilter(_ => true) diff --git a/src/reflect/scala/reflect/macros/blackbox/Context.scala b/src/reflect/scala/reflect/macros/blackbox/Context.scala index ce28b5911e..205e3ad1c3 100644 --- a/src/reflect/scala/reflect/macros/blackbox/Context.scala +++ b/src/reflect/scala/reflect/macros/blackbox/Context.scala @@ -26,7 +26,7 @@ package blackbox * Refer to the documentation of top-level traits in this package to learn the details. * * If a macro def refers to a macro impl that uses `blackbox.Context`, then this macro def becomes a blackbox macro, - * which means that its expansion will be upcast to its return type, enforcing faithfullness of that macro to its + * which means that its expansion will be upcast to its return type, enforcing faithfulness of that macro to its * type signature. Whitebox macros, i.e. the ones defined with `whitebox.Context`, aren't bound by this restriction, * which enables a number of important use cases, but they are also going to enjoy less support than blackbox macros, * so choose wisely. See the [[http://docs.scala-lang.org/overviews/macros/overview.html Macros Guide]] for more information. diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 95d6662d14..9138ed3f02 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -429,6 +429,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.hijackedCoreClasses definitions.symbolsNotPresentInBytecode definitions.isPossibleSyntheticParent + definitions.ShowAsInfixAnnotationClass definitions.abbrvTag definitions.numericWeight definitions.boxedModule diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index d1096fda4e..9635f320fe 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -9,6 +9,7 @@ package interpreter import scala.language.{ implicitConversions, existentials } import scala.annotation.tailrec import Predef.{ println => _, _ } +import PartialFunction.{cond => when} import interpreter.session._ import StdReplTags._ import scala.tools.asm.ClassReader @@ -17,7 +18,7 @@ import scala.tools.nsc.util.{ ClassPath, stringFromStream } import scala.reflect.classTag import scala.reflect.internal.util.{ BatchSourceFile, ScalaClassLoader, NoPosition } import ScalaClassLoader._ -import scala.reflect.io.File +import scala.reflect.io.{Directory, File, Path} import scala.tools.util._ import io.AbstractFile import scala.concurrent.{ ExecutionContext, Await, Future } @@ -26,6 +27,8 @@ import java.io.BufferedReader import scala.util.{ Try, Success, Failure } +import Completion._ + /** The Scala interactive shell. It provides a read-eval-print loop * around the Interpreter class. * After instantiation, clients should call the main() method. @@ -119,37 +122,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) intp = new ILoopInterpreter } - /** print a friendly help message */ - def helpCommand(line: String): Result = line match { - case "" => helpSummary() - case CommandMatch(cmd) => echo(f"%n${cmd.help}") - case _ => ambiguousError(line) - } - private def helpSummary() = { - val usageWidth = commands map (_.usageMsg.length) max - val formatStr = s"%-${usageWidth}s %s" - - echo("All commands can be abbreviated, e.g., :he instead of :help.") - - for (cmd <- commands) echo(formatStr.format(cmd.usageMsg, cmd.help)) - } - private def ambiguousError(cmd: String): Result = { - matchingCommands(cmd) match { - case Nil => echo(cmd + ": no such command. Type :help for help.") - case xs => echo(cmd + " is ambiguous: did you mean " + xs.map(":" + _.name).mkString(" or ") + "?") - } - Result(keepRunning = true, None) - } - // this lets us add commands willy-nilly and only requires enough command to disambiguate - private def matchingCommands(cmd: String) = commands filter (_.name startsWith cmd) - private object CommandMatch { - def unapply(name: String): Option[LoopCommand] = - matchingCommands(name) match { - case x :: Nil => Some(x) - case xs => xs find (_.name == name) // accept an exact match - } - } - /** Show the history */ lazy val historyCommand = new LoopCommand("history", "show the history (optional num is commands to show)") { override def usage = "[num]" @@ -214,16 +186,16 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("implicits", "[-v]", "show the implicits in scope", intp.implicitsCommand), cmd("javap", "<path|class>", "disassemble a file or class name", javapCommand), cmd("line", "<id>|<line>", "place line(s) at the end of history", lineCommand), - cmd("load", "<path>", "interpret lines in a file", loadCommand), - cmd("paste", "[-raw] [path]", "enter paste mode or paste a file", pasteCommand), + cmd("load", "<path>", "interpret lines in a file", loadCommand, fileCompletion), + cmd("paste", "[-raw] [path]", "enter paste mode or paste a file", pasteCommand, fileCompletion), nullary("power", "enable power user mode", powerCmd), nullary("quit", "exit the interpreter", () => Result(keepRunning = false, None)), - cmd("replay", "[options]", "reset the repl and replay all previous commands", replayCommand), + cmd("replay", "[options]", "reset the repl and replay all previous commands", replayCommand, settingsCompletion), cmd("require", "<path>", "add a jar to the classpath", require), - cmd("reset", "[options]", "reset the repl to its initial state, forgetting all session entries", resetCommand), - cmd("save", "<path>", "save replayable session to a file", saveCommand), + cmd("reset", "[options]", "reset the repl to its initial state, forgetting all session entries", resetCommand, settingsCompletion), + cmd("save", "<path>", "save replayable session to a file", saveCommand, fileCompletion), shCommand, - cmd("settings", "<options>", "update compiler options, if possible; see reset", changeSettings), + cmd("settings", "<options>", "update compiler options, if possible; see reset", changeSettings, settingsCompletion), nullary("silent", "disable/enable automatic printing of results", verbosity), cmd("type", "[-v] <expr>", "display the type of an expression without evaluating it", typeCommand), cmd("kind", "[-v] <expr>", "display the kind of expression's type", kindCommand), @@ -235,6 +207,46 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("phase", "<phase>", "set the implicit phase for power commands", phaseCommand) ) + // complete filename + val fileCompletion: Completion = new Completion { + def resetVerbosity(): Unit = () + val emptyWord = """(\s+)$""".r.unanchored + val directorily = """(\S*/)$""".r.unanchored + val trailingWord = """(\S+)$""".r.unanchored + def listed(i: Int, dir: Option[Path]) = + dir.filter(_.isDirectory).map(d => Candidates(i, d.toDirectory.list.map(_.name).toList)).getOrElse(NoCandidates) + def listedIn(dir: Directory, name: String) = dir.list.filter(_.name.startsWith(name)).map(_.name).toList + def complete(buffer: String, cursor: Int): Candidates = + buffer.substring(0, cursor) match { + case emptyWord(s) => listed(cursor, Directory.Current) + case directorily(s) => listed(cursor, Option(Path(s))) + case trailingWord(s) => + val f = File(s) + val (i, maybes) = + if (f.isFile) (cursor - s.length, List(f.toAbsolute.path)) + else if (f.isDirectory) (cursor - s.length, List(s"${f.toAbsolute.path}/")) + else if (f.parent.exists) (cursor - f.name.length, listedIn(f.parent.toDirectory, f.name)) + else (-1, Nil) + if (maybes.isEmpty) NoCandidates else Candidates(i, maybes) + case _ => NoCandidates + } + } + + // complete settings name + val settingsCompletion: Completion = new Completion { + def resetVerbosity(): Unit = () + val trailingWord = """(\S+)$""".r.unanchored + def complete(buffer: String, cursor: Int): Candidates = { + buffer.substring(0, cursor) match { + case trailingWord(s) => + val maybes = settings.visibleSettings.filter(_.name.startsWith(s)).map(_.name) + .filterNot(when(_) { case "-"|"-X"|"-Y" => true }).toList.sorted + if (maybes.isEmpty) NoCandidates else Candidates(cursor - s.length, maybes) + case _ => NoCandidates + } + } + } + private def importsCommand(line: String): Result = { val tokens = words(line) val handlers = intp.languageWildcardHandlers ++ intp.importHandlers @@ -681,20 +693,11 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) * (1) whether to keep running, (2) the line to record for replay, if any. */ def command(line: String): Result = { - if (line startsWith ":") colonCommand(line.tail) + if (line startsWith ":") colonCommand(line) else if (intp.global == null) Result(keepRunning = false, None) // Notice failure to create compiler else Result(keepRunning = true, interpretStartingWith(line)) } - private val commandish = """(\S+)(?:\s+)?(.*)""".r - - private def colonCommand(line: String): Result = line.trim match { - case "" => helpSummary() - case commandish(CommandMatch(cmd), rest) => cmd(rest) - case commandish(name, _) => ambiguousError(name) - case _ => echo("?") - } - private def readWhile(cond: String => Boolean) = { Iterator continually in.readLine("") takeWhile (x => x != null && cond(x)) } @@ -849,6 +852,18 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } + // delegate to command completion or presentation compiler + class ReplCompletion(intp: IMain) extends Completion { + val pc = new PresentationCompilerCompleter(intp) + def resetVerbosity(): Unit = pc.resetVerbosity() + def complete(buffer: String, cursor: Int): Completion.Candidates = { + if (buffer.startsWith(":")) + colonCompletion(buffer, cursor).complete(buffer, cursor) + else + pc.complete(buffer, cursor) + } + } + /** Tries to create a jline.InteractiveReader, falling back to SimpleReader, * unless settings or properties are such that it should start with SimpleReader. * The constructor of the InteractiveReader must take a Completion strategy, @@ -868,7 +883,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } def mkReader(maker: ReaderMaker) = maker { () => - if (settings.noCompletion) NoCompletion else new PresentationCompilerCompleter(intp) + if (settings.noCompletion) NoCompletion else new ReplCompletion(intp) } def internalClass(kind: String) = s"scala.tools.nsc.interpreter.$kind.InteractiveReader" @@ -1014,6 +1029,7 @@ object ILoop { // like if you'd just typed it into the repl. def runForTranscript(code: String, settings: Settings, inSession: Boolean = false): String = { import java.io.{ BufferedReader, StringReader, OutputStreamWriter } + import java.lang.System.{lineSeparator => EOL} stringFromStream { ostream => Console.withOut(ostream) { @@ -1021,10 +1037,9 @@ object ILoop { // skip margin prefix for continuation lines, unless preserving session text for test // should test for repl.paste.ContinueString or replProps.continueText.contains(ch) override def write(str: String) = - if (!inSession && (str forall (ch => ch.isWhitespace || ch == '|'))) () - else super.write(str) + if (inSession || (str.exists(ch => ch != ' ' && ch != '|'))) super.write(str) } - val input = new BufferedReader(new StringReader(code.trim + "\n")) { + val input = new BufferedReader(new StringReader(s"${code.trim}${EOL}")) { override def readLine(): String = { mark(1) // default buffer is 8k val c = read() diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 980d12f9b8..a351d2da95 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -1105,7 +1105,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends def apply(line: String): Result = debugging(s"""parse("$line")""") { var isIncomplete = false - def parse = { + def parse = withoutWarnings { reporter.reset() val trees = newUnitParser(line, label).parseStats() if (reporter.hasErrors) Error(trees) diff --git a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala index 8c3b174513..a2ce63996b 100644 --- a/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala +++ b/src/repl/scala/tools/nsc/interpreter/LoopCommands.scala @@ -24,18 +24,21 @@ class ProcessResult(val line: String) { override def toString = "`%s` (%d lines, exit %d)".format(line, buffer.size, exitCode) } -trait LoopCommands { +trait LoopCommands { self: { def echo(msg: String): Unit } => protected def out: JPrintWriter // So outputs can be suppressed. - def echoCommandMessage(msg: String): Unit = out println msg + def echoCommandMessage(msg: String): Unit = out.println(msg) + + // available commands + def commands: List[LoopCommand] // a single interpreter command abstract class LoopCommand(val name: String, val help: String) extends (String => Result) { def usage: String = "" - def usageMsg: String = ":" + name + ( + def usageMsg: String = s":$name${ if (usage == "") "" else " " + usage - ) + }" def apply(line: String): Result // called if no args are given @@ -43,21 +46,88 @@ trait LoopCommands { "usage is " + usageMsg Result(keepRunning = true, None) } + + // subclasses may provide completions + def completion: Completion = NoCompletion } object LoopCommand { def nullary(name: String, help: String, f: () => Result): LoopCommand = new NullaryCmd(name, help, _ => f()) - def cmd(name: String, usage: String, help: String, f: String => Result): LoopCommand = + def cmd(name: String, usage: String, help: String, f: String => Result, completion: Completion = NoCompletion): LoopCommand = if (usage == "") new NullaryCmd(name, help, f) - else new LineCmd(name, usage, help, f) + else new LineCmd(name, usage, help, f, completion) + } + + /** print a friendly help message */ + def helpCommand(line: String): Result = line match { + case "" => helpSummary() + case CommandMatch(cmd) => echo(f"%n${cmd.help}") + case _ => ambiguousError(line) + } + + def helpSummary() = { + val usageWidth = commands map (_.usageMsg.length) max + val formatStr = s"%-${usageWidth}s %s" + + echo("All commands can be abbreviated, e.g., :he instead of :help.") + + for (cmd <- commands) echo(formatStr.format(cmd.usageMsg, cmd.help)) + } + def ambiguousError(cmd: String): Result = { + matchingCommands(cmd) match { + case Nil => echo(cmd + ": no such command. Type :help for help.") + case xs => echo(cmd + " is ambiguous: did you mean " + xs.map(":" + _.name).mkString(" or ") + "?") + } + Result(keepRunning = true, None) + } + + // all commands with given prefix + private def matchingCommands(cmd: String) = commands.filter(_.name.startsWith(cmd.stripPrefix(":"))) + + // extract command from partial name, or prefer exact match if multiple matches + private object CommandMatch { + def unapply(name: String): Option[LoopCommand] = + matchingCommands(name) match { + case Nil => None + case x :: Nil => Some(x) + case xs => xs find (_.name == name) + } + } + + // extract command name and rest of line + private val commandish = """(\S+)(?:\s+)?(.*)""".r + + def colonCommand(line: String): Result = line.trim match { + case "" => helpSummary() + case commandish(CommandMatch(cmd), rest) => cmd(rest) + case commandish(name, _) => ambiguousError(name) + case _ => echo("?") + } + + import Completion.Candidates + + def colonCompletion(line: String, cursor: Int): Completion = line.trim match { + case commandish(name @ CommandMatch(cmd), rest) => + if (name.length > cmd.name.length) cmd.completion + else + new Completion { + def resetVerbosity(): Unit = () + def complete(buffer: String, cursor: Int) = Candidates(cursor - name.length + 1, List(cmd.name)) + } + case commandish(name, _) if matchingCommands(name).nonEmpty => + new Completion { + def resetVerbosity(): Unit = () + def complete(buffer: String, cursor: Int) = Candidates(cursor - name.length + 1, matchingCommands(name).map(_.name)) + } + case _ => NoCompletion } class NullaryCmd(name: String, help: String, f: String => Result) extends LoopCommand(name, help) { def apply(line: String): Result = f(line) } - class LineCmd(name: String, argWord: String, help: String, f: String => Result) extends LoopCommand(name, help) { + class LineCmd(name: String, argWord: String, help: String, f: String => Result, override val completion: Completion) extends LoopCommand(name, help) { override def usage = argWord def apply(line: String): Result = f(line) } diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala index ac5fec80b3..7f4e52e88d 100644 --- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala @@ -11,8 +11,9 @@ package comment import scala.collection._ /** A body of text. A comment has a single body, which is composed of - * at least one block. Inside every body is exactly one summary (see - * [[scala.tools.nsc.doc.model.comment.Summary]]). */ + * at least one block. Inside every body is exactly one summary. + * @see [[Summary]] + */ final case class Body(blocks: Seq[Block]) { /** The summary text of the comment body. */ diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala index 5d0b6782bc..55527e43a1 100644 --- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala @@ -12,7 +12,7 @@ import scala.collection._ /** A Scaladoc comment and all its tags. * - * '''Note:''' the only instantiation site of this class is in [[CommentFactory]]. + * '''Note:''' the only instantiation site of this class is in [[model.CommentFactory]]. * * @author Manohar Jonnalagedda * @author Gilles Dubochet */ diff --git a/test/benchmarks/src/main/scala/scala/collection/immutable/HashMapBenchmark.scala b/test/benchmarks/src/main/scala/scala/collection/immutable/HashMapBenchmark.scala new file mode 100644 index 0000000000..134cd6879b --- /dev/null +++ b/test/benchmarks/src/main/scala/scala/collection/immutable/HashMapBenchmark.scala @@ -0,0 +1,56 @@ +package scala.collection.immutable + +import org.openjdk.jmh.annotations._ +import org.openjdk.jmh.infra._ +import org.openjdk.jmh.runner.IterationType +import benchmark._ +import java.util.concurrent.TimeUnit + +@BenchmarkMode(Array(Mode.AverageTime)) +@Fork(2) +@Threads(1) +@Warmup(iterations = 10) +@Measurement(iterations = 10) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +class HashMapBenchmark { + @Param(Array("10", "100", "1000")) + var size: Int = _ + + var existingKeys: Array[Any] = _ + var missingKeys: Array[Any] = _ + + @Setup(Level.Trial) def initKeys(): Unit = { + existingKeys = (0 to size).map(i => (i % 4) match { + case 0 => i.toString + case 1 => i.toChar + case 2 => i.toDouble + case 3 => i.toInt + }).toArray + missingKeys = (size to 2 * size).toArray + } + + var map: collection.immutable.HashMap[Any, Any] = null + + @Setup(Level.Trial) def initialize = { + map = collection.immutable.HashMap(existingKeys.map(x => (x, x)) : _*) + } + + @Benchmark def contains(bh: Blackhole): Unit = { + var i = 0; + while (i < size) { + bh.consume(map.contains(existingKeys(i))) + bh.consume(map.contains(missingKeys(i))) + i += 1 + } + } + + @Benchmark def get(bh: Blackhole): Unit = { + var i = 0; + while (i < size) { + bh.consume(map.get(existingKeys(i))) + bh.consume(map.get(missingKeys(i))) + i += 1 + } + } +} diff --git a/test/files/neg/literals.check b/test/files/neg/literals.check index 148a9346c5..79b6d47782 100644 --- a/test/files/neg/literals.check +++ b/test/files/neg/literals.check @@ -19,6 +19,18 @@ literals.scala:23: error: missing integer number literals.scala:27: error: Decimal integer literals may not have a leading zero. (Octal syntax is obsolete.) def tooManyZeros: Int = 00 // line 26: no leading zero ^ +literals.scala:40: error: floating point number too small + def tooTiny: Float = { 0.7e-45f } // floating point number too small + ^ +literals.scala:42: error: double precision floating point number too small + def twoTiny: Double = { 2.0e-324 } // double precision floating point number too small + ^ +literals.scala:44: error: floating point number too large + def tooHuge: Float = { 3.4028236E38f } // floating point number too large + ^ +literals.scala:46: error: double precision floating point number too large + def twoHuge: Double = { 1.7976931348623159e308 } // double precision floating point number too large + ^ literals.scala:14: error: identifier expected but '}' found. def orphanDot: Int = { 9. } // line 12: ident expected ^ @@ -37,4 +49,4 @@ literals.scala:29: error: ';' expected but 'def' found. literals.scala:33: error: identifier expected but 'def' found. def zeroOfNineDot: Int = 09. // line 32: malformed integer, ident expected ^ -13 errors found +17 errors found diff --git a/test/files/neg/literals.scala b/test/files/neg/literals.scala index 3df7f0b408..22d5d9acd1 100644 --- a/test/files/neg/literals.scala +++ b/test/files/neg/literals.scala @@ -1,6 +1,6 @@ /* This took me literally all day. -*/ + */ trait RejectedLiterals { def missingHex: Int = { 0x } // line 4: was: not reported, taken as zero @@ -34,3 +34,14 @@ trait Braceless { def noHexFloat: Double = 0x1.2 // line 34: ';' expected but double literal found. } + +trait MoreSadness { + + def tooTiny: Float = { 0.7e-45f } // floating point number too small + + def twoTiny: Double = { 2.0e-324 } // double precision floating point number too small + + def tooHuge: Float = { 3.4028236E38f } // floating point number too large + + def twoHuge: Double = { 1.7976931348623159e308 } // double precision floating point number too large +} diff --git a/test/files/neg/nested-fn-print.check b/test/files/neg/nested-fn-print.check index ea278554d4..feeac0733f 100644 --- a/test/files/neg/nested-fn-print.check +++ b/test/files/neg/nested-fn-print.check @@ -1,4 +1,4 @@ -nested-fn-print.scala:4: error: only classes can have declared but undefined members +nested-fn-print.scala:4: error: only traits and abstract classes can have declared but undefined members (Note that variables need to be initialized to be defined) var x3: Int => Double ^ diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check index 9fd6ce0417..b12a7d13d6 100644 --- a/test/files/neg/quasiquotes-syntax-error-position.check +++ b/test/files/neg/quasiquotes-syntax-error-position.check @@ -16,8 +16,7 @@ quasiquotes-syntax-error-position.scala:9: error: '{' expected but end of quote quasiquotes-syntax-error-position.scala:10: error: ';' expected but '@' found. q"foo@$a" ^ -quasiquotes-syntax-error-position.scala:11: error: case classes without a parameter list are not allowed; -use either case objects or case classes with an explicit `()' as a parameter list. +quasiquotes-syntax-error-position.scala:11: error: case classes must have a parameter list; try 'case class A()' or 'case object A' q"case class A" ^ quasiquotes-syntax-error-position.scala:12: error: identifier expected but ']' found. diff --git a/test/files/neg/t10066.check b/test/files/neg/t10066.check new file mode 100644 index 0000000000..3555205d83 --- /dev/null +++ b/test/files/neg/t10066.check @@ -0,0 +1,7 @@ +t10066.scala:33: error: could not find implicit value for parameter extractor: dynamicrash.Extractor[String] + println(storage.foo[String]) + ^ +t10066.scala:37: error: could not find implicit value for parameter extractor: dynamicrash.Extractor[A] + println(storage.foo) + ^ +two errors found diff --git a/test/files/neg/t10066.scala b/test/files/neg/t10066.scala new file mode 100644 index 0000000000..ef52f333dd --- /dev/null +++ b/test/files/neg/t10066.scala @@ -0,0 +1,38 @@ +package dynamicrash + +import scala.language.dynamics + +class Config + +trait Extractor[A] { + def extract(config: Config, name: String): A +} + +object Extractor { + // note missing "implicit" + val stringExtractor = new Extractor[String] { + override def extract(config: Config, name: String): String = ??? + } +} + +class Workspace extends Dynamic { + val config: Config = new Config + + def selectDynamic[A](name: String)(implicit extractor: Extractor[A]): A = + extractor.extract(config, name) +} + +object Main { + val storage = new Workspace + + // this line works fine + // val a = storage.foo + + // this line crashes the compiler ("head of empty list") + // in ContextErrors$InferencerContextErrors$InferErrorGen$.NotWithinBoundsErrorMessage + println(storage.foo[String]) + + // this line crashes the compiler in different way ("unknown type") + // in the backend, warning: an unexpected type representation reached the compiler backend while compiling Test.scala: <error> + println(storage.foo) +} diff --git a/test/files/neg/t10097.check b/test/files/neg/t10097.check new file mode 100644 index 0000000000..1f70546b57 --- /dev/null +++ b/test/files/neg/t10097.check @@ -0,0 +1,10 @@ +t10097.scala:2: error: case classes must have a non-implicit parameter list; try 'case class C()(...)' +case class C(implicit val c: Int) + ^ +t10097.scala:4: error: case classes must have a non-implicit parameter list; try 'case class D()(...)(...)' +case class D(implicit c: Int)(s: String) + ^ +t10097.scala:4: error: an implicit parameter section must be last +case class D(implicit c: Int)(s: String) + ^ +three errors found diff --git a/test/files/neg/t10097.flags b/test/files/neg/t10097.flags new file mode 100644 index 0000000000..714bbf5125 --- /dev/null +++ b/test/files/neg/t10097.flags @@ -0,0 +1 @@ +-Xsource:2.13 diff --git a/test/files/neg/t10097.scala b/test/files/neg/t10097.scala new file mode 100644 index 0000000000..b2f05e2972 --- /dev/null +++ b/test/files/neg/t10097.scala @@ -0,0 +1,4 @@ + +case class C(implicit val c: Int) + +case class D(implicit c: Int)(s: String) diff --git a/test/files/neg/t10097b.check b/test/files/neg/t10097b.check new file mode 100644 index 0000000000..14535fee34 --- /dev/null +++ b/test/files/neg/t10097b.check @@ -0,0 +1,6 @@ +t10097b.scala:2: warning: case classes should have a non-implicit parameter list; adapting to 'case class C()(...)' +case class C(implicit val c: Int) + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/t10097b.flags b/test/files/neg/t10097b.flags new file mode 100644 index 0000000000..c6bfaf1f64 --- /dev/null +++ b/test/files/neg/t10097b.flags @@ -0,0 +1 @@ +-deprecation -Xfatal-warnings diff --git a/test/files/neg/t10097b.scala b/test/files/neg/t10097b.scala new file mode 100644 index 0000000000..f166db6792 --- /dev/null +++ b/test/files/neg/t10097b.scala @@ -0,0 +1,3 @@ + +case class C(implicit val c: Int) + diff --git a/test/files/neg/t565.check b/test/files/neg/t565.check index 136cc94b6f..d7657c0f5d 100644 --- a/test/files/neg/t565.check +++ b/test/files/neg/t565.check @@ -1,4 +1,4 @@ -t565.scala:2: error: only classes can have declared but undefined members +t565.scala:2: error: only traits and abstract classes can have declared but undefined members (Note that variables need to be initialized to be defined) var s0: String ^ diff --git a/test/files/neg/t8217-local-alias-requires-rhs.check b/test/files/neg/t8217-local-alias-requires-rhs.check index d970400ff6..383b1f8d63 100644 --- a/test/files/neg/t8217-local-alias-requires-rhs.check +++ b/test/files/neg/t8217-local-alias-requires-rhs.check @@ -1,10 +1,10 @@ -t8217-local-alias-requires-rhs.scala:3: error: only classes can have declared but undefined members +t8217-local-alias-requires-rhs.scala:3: error: only traits and abstract classes can have declared but undefined members type A ^ -t8217-local-alias-requires-rhs.scala:6: error: only classes can have declared but undefined members +t8217-local-alias-requires-rhs.scala:6: error: only traits and abstract classes can have declared but undefined members type B ^ -t8217-local-alias-requires-rhs.scala:14: error: only classes can have declared but undefined members +t8217-local-alias-requires-rhs.scala:14: error: only traits and abstract classes can have declared but undefined members def this(a: Any) = { this(); type C } ^ three errors found diff --git a/test/files/neg/t8685.check b/test/files/neg/t8685.check index 685fd2e951..a31e2e265a 100644 --- a/test/files/neg/t8685.check +++ b/test/files/neg/t8685.check @@ -4,6 +4,9 @@ case class D @deprecated("ctor D is depr", since="now") (i: Int) t8685.scala:35: warning: class C is deprecated (since now): class C is depr def f = C(42) ^ +t8685.scala:36: warning: constructor D in class D is deprecated (since now): ctor D is depr + def g = D(42) + ^ t8685.scala:37: warning: object E is deprecated (since now): module E is depr def h = E(42) ^ @@ -41,5 +44,5 @@ t8685.scala:53: warning: class K in object J is deprecated (since now): Inner K def l = new J.K(42) ^ error: No warnings can be incurred under -Xfatal-warnings. -14 warnings found +15 warnings found one error found diff --git a/test/files/neg/t8704.check b/test/files/neg/t8704.check new file mode 100644 index 0000000000..b567a8bb17 --- /dev/null +++ b/test/files/neg/t8704.check @@ -0,0 +1,11 @@ +t8704.scala:7: warning: 2 parameter sections are effectively implicit +class D(private implicit val i: Int)(implicit s: String) + ^ +t8704.scala:3: error: an implicit parameter section must be last +class C(i: Int)(implicit j: Int)(implicit k: Int)(n: Int) { + ^ +t8704.scala:3: error: multiple implicit parameter sections are not allowed +class C(i: Int)(implicit j: Int)(implicit k: Int)(n: Int) { + ^ +one warning found +two errors found diff --git a/test/files/neg/t8704.flags b/test/files/neg/t8704.flags new file mode 100644 index 0000000000..f175a06c74 --- /dev/null +++ b/test/files/neg/t8704.flags @@ -0,0 +1 @@ +-Ywarn-extra-implicit diff --git a/test/files/neg/t8704.scala b/test/files/neg/t8704.scala new file mode 100644 index 0000000000..db43bfcaa5 --- /dev/null +++ b/test/files/neg/t8704.scala @@ -0,0 +1,7 @@ + + +class C(i: Int)(implicit j: Int)(implicit k: Int)(n: Int) { + def f = n +} + +class D(private implicit val i: Int)(implicit s: String) diff --git a/test/files/neg/t9636.check b/test/files/neg/t9636.check new file mode 100644 index 0000000000..f36d1d32b2 --- /dev/null +++ b/test/files/neg/t9636.check @@ -0,0 +1,6 @@ +t9636.scala:11: warning: a type was inferred to be `AnyVal`; this may indicate a programming error. + if (signature.sameElements(Array(0x1F, 0x8B))) { + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/t9636.flags b/test/files/neg/t9636.flags new file mode 100644 index 0000000000..7949c2afa2 --- /dev/null +++ b/test/files/neg/t9636.flags @@ -0,0 +1 @@ +-Xlint -Xfatal-warnings diff --git a/test/files/neg/t9636.scala b/test/files/neg/t9636.scala new file mode 100644 index 0000000000..7ad5fb3e9e --- /dev/null +++ b/test/files/neg/t9636.scala @@ -0,0 +1,17 @@ + +import java.io._ +import java.util.zip._ + +class C { + def isWrapper(is: FileInputStream): InputStream = { + val pb = new PushbackInputStream(is, 2) + val signature = new Array[Byte](2) + pb.read(signature) + pb.unread(signature) + if (signature.sameElements(Array(0x1F, 0x8B))) { + new GZIPInputStream(new BufferedInputStream(pb)) + } else { + pb + } + } +} diff --git a/test/files/neg/t9675.check b/test/files/neg/t9675.check new file mode 100644 index 0000000000..255477499c --- /dev/null +++ b/test/files/neg/t9675.check @@ -0,0 +1,27 @@ +t9675.scala:4: warning: comparing values of types Test.A and String using `!=' will always yield true + val func1 = (x: A) => { x != "x" } + ^ +t9675.scala:6: warning: comparing values of types Test.A and String using `!=' will always yield true + val func2 = (x: A) => { x != "x" }: Boolean + ^ +t9675.scala:8: warning: comparing values of types Test.A and String using `!=' will always yield true + val func3: Function1[A, Boolean] = (x) => { x != "x" } + ^ +t9675.scala:11: warning: comparing values of types Test.A and String using `!=' will always yield true + def apply(x: A): Boolean = { x != "x" } + ^ +t9675.scala:14: warning: comparing values of types Test.A and String using `!=' will always yield true + def method(x: A): Boolean = { x != "x" } + ^ +t9675.scala:18: warning: comparing values of types Test.A and String using `!=' will always yield true + A("x") != "x" + ^ +t9675.scala:20: warning: comparing values of types Test.A and String using `!=' will always yield true + val func5: Function1[A, Boolean] = (x) => { x != "x" } + ^ +t9675.scala:22: warning: comparing values of types Test.A and String using `!=' will always yield true + List(A("x")).foreach((item: A) => item != "x") + ^ +error: No warnings can be incurred under -Xfatal-warnings. +8 warnings found +one error found diff --git a/test/files/neg/t9675.flags b/test/files/neg/t9675.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t9675.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t9675.scala b/test/files/neg/t9675.scala new file mode 100644 index 0000000000..f76b74b6ac --- /dev/null +++ b/test/files/neg/t9675.scala @@ -0,0 +1,24 @@ +object Test { + case class A(x: String) + + val func1 = (x: A) => { x != "x" } + + val func2 = (x: A) => { x != "x" }: Boolean + + val func3: Function1[A, Boolean] = (x) => { x != "x" } + + val func4 = new Function1[A, Boolean] { + def apply(x: A): Boolean = { x != "x" } + } + + def method(x: A): Boolean = { x != "x" } + case class PersonInfo(rankPayEtc: Unit) + + def main(args: Array[String]) { + A("x") != "x" + + val func5: Function1[A, Boolean] = (x) => { x != "x" } + + List(A("x")).foreach((item: A) => item != "x") + } +} diff --git a/test/files/neg/trailing-commas.check b/test/files/neg/trailing-commas.check new file mode 100644 index 0000000000..e2677dc3f5 --- /dev/null +++ b/test/files/neg/trailing-commas.check @@ -0,0 +1,130 @@ +trailing-commas.scala:10: error: illegal start of simple expression +trait ArgumentExprs1 { f(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:10: error: ')' expected but '}' found. +trait ArgumentExprs1 { f(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:11: error: illegal start of simple expression +trait ArgumentExprs2 { f(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:11: error: ')' expected but '}' found. +trait ArgumentExprs2 { f(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:12: error: illegal start of simple expression +trait ArgumentExprs3 { new C(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:12: error: ')' expected but '}' found. +trait ArgumentExprs3 { new C(23, "bar", )(Ev0, Ev1) } + ^ +trailing-commas.scala:13: error: illegal start of simple expression +trait ArgumentExprs4 { new C(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:13: error: ')' expected but '}' found. +trait ArgumentExprs4 { new C(23, "bar")(Ev0, Ev1, ) } + ^ +trailing-commas.scala:15: error: identifier expected but ')' found. +trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:15: error: ':' expected but '}' found. +trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:16: error: identifier expected but ')' found. +trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:16: error: ':' expected but '}' found. +trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } + ^ +trailing-commas.scala:17: error: identifier expected but ')' found. +trait ClassParams1 { final class C(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1) } + ^ +trailing-commas.scala:17: error: ':' expected but '}' found. +trait ClassParams1 { final class C(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1) } + ^ +trailing-commas.scala:18: error: identifier expected but ')' found. +trait ClassParams2 { final class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1, ) } + ^ +trailing-commas.scala:18: error: ':' expected but '}' found. +trait ClassParams2 { final class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1, ) } + ^ +trailing-commas.scala:20: error: illegal start of simple expression +trait SimpleExpr { (23, "bar", ) } + ^ +trailing-commas.scala:20: error: ')' expected but '}' found. +trait SimpleExpr { (23, "bar", ) } + ^ +trailing-commas.scala:22: error: identifier expected but ']' found. +trait TypeArgs { def f: C[Int, String, ] } + ^ +trailing-commas.scala:22: error: ']' expected but '}' found. +trait TypeArgs { def f: C[Int, String, ] } + ^ +trailing-commas.scala:23: error: identifier expected but ']' found. +trait TypeParamClause { type C[A, B, ] } + ^ +trailing-commas.scala:23: error: ']' expected but '}' found. +trait TypeParamClause { type C[A, B, ] } + ^ +trailing-commas.scala:24: error: identifier expected but ']' found. +trait FunTypeParamClause { def f[A, B, ] } + ^ +trailing-commas.scala:24: error: ']' expected but '}' found. +trait FunTypeParamClause { def f[A, B, ] } + ^ +trailing-commas.scala:26: error: identifier expected but ')' found. +trait SimpleType { def f: (Int, String, ) } + ^ +trailing-commas.scala:26: error: ')' expected but '}' found. +trait SimpleType { def f: (Int, String, ) } + ^ +trailing-commas.scala:27: error: identifier expected but ')' found. +trait FunctionArgTypes { def f: (Int, String, ) => Boolean } + ^ +trailing-commas.scala:27: error: ')' expected but '}' found. +trait FunctionArgTypes { def f: (Int, String, ) => Boolean } + ^ +trailing-commas.scala:29: error: illegal start of simple pattern +trait SimplePattern { val (foo, bar, ) = null: Any } + ^ +trailing-commas.scala:31: error: identifier expected but '}' found. +trait ImportSelectors { import foo.{ Ev0, Ev1, } } + ^ +trailing-commas.scala:33: error: identifier expected but '}' found. +trait Import { import foo.Ev0, foo.Ev1, } + ^ +trailing-commas.scala:35: error: illegal start of simple pattern +trait ValDcl { val foo, bar, = 23 } + ^ +trailing-commas.scala:35: error: '=' expected but '}' found. +trait ValDcl { val foo, bar, = 23 } + ^ +trailing-commas.scala:36: error: illegal start of simple pattern +trait VarDcl { var foo, bar, = 23 } + ^ +trailing-commas.scala:36: error: '=' expected but '}' found. +trait VarDcl { var foo, bar, = 23 } + ^ +trailing-commas.scala:37: error: illegal start of simple pattern +trait VarDef { var foo, bar, = _ } + ^ +trailing-commas.scala:37: error: '=' expected but '}' found. +trait VarDef { var foo, bar, = _ } + ^ +trailing-commas.scala:38: error: illegal start of simple pattern +trait PatDef { val Foo(foo), Bar(bar), = bippy } + ^ +trailing-commas.scala:38: error: '=' expected but '}' found. +trait PatDef { val Foo(foo), Bar(bar), = bippy } + ^ +trailing-commas.scala:45: error: illegal start of simple expression +trait SimpleExpr2 { (23, ) } + ^ +trailing-commas.scala:45: error: ')' expected but '}' found. +trait SimpleExpr2 { (23, ) } + ^ +trailing-commas.scala:48: error: identifier expected but ')' found. +trait SimpleType2 { def f: (Int, ) } + ^ +trailing-commas.scala:48: error: ')' expected but '}' found. +trait SimpleType2 { def f: (Int, ) } + ^ +43 errors found diff --git a/test/files/neg/trailing-commas.scala b/test/files/neg/trailing-commas.scala new file mode 100644 index 0000000000..a873cb1e39 --- /dev/null +++ b/test/files/neg/trailing-commas.scala @@ -0,0 +1,56 @@ +package foo + +// Note: Using traits to get distinct errors +// (instead of sharing one single "')' expected but '}' found." at the end) + + + +//// Multi-line only cases: make sure trailing commas are only supported when multi-line + +trait ArgumentExprs1 { f(23, "bar", )(Ev0, Ev1) } +trait ArgumentExprs2 { f(23, "bar")(Ev0, Ev1, ) } +trait ArgumentExprs3 { new C(23, "bar", )(Ev0, Ev1) } +trait ArgumentExprs4 { new C(23, "bar")(Ev0, Ev1, ) } + +trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } +trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } +trait ClassParams1 { final class C(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1) } +trait ClassParams2 { final class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1, ) } + +trait SimpleExpr { (23, "bar", ) } + +trait TypeArgs { def f: C[Int, String, ] } +trait TypeParamClause { type C[A, B, ] } +trait FunTypeParamClause { def f[A, B, ] } + +trait SimpleType { def f: (Int, String, ) } +trait FunctionArgTypes { def f: (Int, String, ) => Boolean } + +trait SimplePattern { val (foo, bar, ) = null: Any } + +trait ImportSelectors { import foo.{ Ev0, Ev1, } } + +trait Import { import foo.Ev0, foo.Ev1, } + +trait ValDcl { val foo, bar, = 23 } +trait VarDcl { var foo, bar, = 23 } +trait VarDef { var foo, bar, = _ } +trait PatDef { val Foo(foo), Bar(bar), = bippy } + + + +//// The Tuple 1 cases + +// the Tuple1 value case: make sure that the possible "(23, )" syntax for Tuple1 doesn't compile to "23" +trait SimpleExpr2 { (23, ) } + +// the Tuple1 type case: make sure that the possible "(Int, )" syntax for Tuple1[Int] doesn't compile to "Int" +trait SimpleType2 { def f: (Int, ) } + + + +//// Test utilities +object `package` { + sealed trait Ev0; implicit object Ev0 extends Ev0 + sealed trait Ev1; implicit object Ev1 extends Ev1 +} diff --git a/test/files/neg/warn-inferred-any.check b/test/files/neg/warn-inferred-any.check index 8ad81d1529..2b321a83c9 100644 --- a/test/files/neg/warn-inferred-any.check +++ b/test/files/neg/warn-inferred-any.check @@ -9,7 +9,7 @@ warn-inferred-any.scala:17: warning: a type was inferred to be `AnyVal`; this ma ^ warn-inferred-any.scala:25: warning: a type was inferred to be `Any`; this may indicate a programming error. def za = f(1, "one") - ^ + ^ error: No warnings can be incurred under -Xfatal-warnings. four warnings found one error found diff --git a/test/files/pos/t10066.scala b/test/files/pos/t10066.scala new file mode 100644 index 0000000000..bef85cb08c --- /dev/null +++ b/test/files/pos/t10066.scala @@ -0,0 +1,38 @@ +package dynamicrash + +import scala.language.dynamics + +class Config + +trait Extractor[A] { + def extract(config: Config, name: String): A +} + +object Extractor { + // this has "implicit", unlike the corresponding neg test + implicit val stringExtractor = new Extractor[String] { + override def extract(config: Config, name: String): String = ??? + } +} + +class Workspace extends Dynamic { + val config: Config = new Config + + def selectDynamic[A](name: String)(implicit extractor: Extractor[A]): A = + extractor.extract(config, name) +} + +object Main { + val storage = new Workspace + + // this line works fine + // val a = storage.foo + + // this line crashes the compiler ("head of empty list") + // in ContextErrors$InferencerContextErrors$InferErrorGen$.NotWithinBoundsErrorMessage + println(storage.foo[String]) + + // this line crashes the compiler in different way ("unknown type") + // in the backend, warning: an unexpected type representation reached the compiler backend while compiling Test.scala: <error> + println(storage.foo) +} diff --git a/test/files/pos/t10154.scala b/test/files/pos/t10154.scala new file mode 100644 index 0000000000..51616b71d6 --- /dev/null +++ b/test/files/pos/t10154.scala @@ -0,0 +1,11 @@ +trait Bar2[T] + +object Test2 { + def wrap { + object Foo { + implicit def fooBar: Bar2[Foo.type] = ??? + } + + implicitly[Bar2[Foo.type]] + } +} diff --git a/test/files/pos/t10154b.scala b/test/files/pos/t10154b.scala new file mode 100644 index 0000000000..809a286c0e --- /dev/null +++ b/test/files/pos/t10154b.scala @@ -0,0 +1,16 @@ + import scala.language.existentials + + class Bar[T] + class Test { + def method = { + object Foo { + implicit def x: Bar[Foo.type] = new Bar[Foo.type] + } + type T = Foo.type + + { + object Foo + implicitly[Bar[T]] + } + } +} diff --git a/test/files/pos/trailing-commas.scala b/test/files/pos/trailing-commas.scala new file mode 100644 index 0000000000..b9401fe49d --- /dev/null +++ b/test/files/pos/trailing-commas.scala @@ -0,0 +1,155 @@ +package foo + +trait ArgumentExprs1 { + def f(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1) = 1 + f( + 23, + "bar", + )( + Ev0, + Ev1, + ) + + // test arg exprs in the presence of varargs + def g(x: Int, y: Int*) = 1 + g(1,2, + ) + g(1,List(2, 3): _*, + ) +} + +trait ArgumentExprs2 { + class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1) + new C( + 23, + "bar", + )( + Ev0, + Ev1, + ) +} + +trait Params { + def f( + foo: Int, + bar: String, + )(implicit + ev0: Ev0, + ev1: Ev1, + ) +} + +trait ClassParams { + class C( + foo: Int, + bar: String, + )(implicit + ev0: Ev0, + ev1: Ev1, + ) + + // test class params in the precense of varargs + case class D(i: Int*, + ) +} + +trait SimpleExpr1 { + def f: (Int, String) = ( + 23, + "bar", + ) + + // the Tuple1 value case, the trailing comma is ignored so the type is Int and the value 23 + def g: Int = ( + 23, + ) +} + +trait TypeArgs { + class C[A, B] + def f: C[ + Int, + String, + ] +} + +trait TypeParamClause { + class C[ + A, + B, + ] +} + +trait FunTypeParamClause { + def f[ + A, + B, + ] +} + +trait SimpleType { + def f: ( + Int, + String, + ) + + // the Tuple1 type case, the trailing comma is ignored so the type is Int and the value 23 + def g: ( + Int, + ) = 23 +} + +trait FunctionArgTypes { + def f: ( + Int, + String, + ) => Boolean +} + +trait SimplePattern { + val ( + foo, + bar, + ) = null: Any + + // test '@' syntax in patterns + Some(1) match { + case Some(x @ 1, + ) => x + } + + // test ': _*' syntax in patterns + List(1, 2, 3) match { + case List(1, 2, _ @ _*, + ) => 1 + } + + // test varargs in patterns + val List(x, y, _*, + ) = 42 :: 17 :: Nil +} + +trait ImportSelectors { + import foo.{ + Ev0, + Ev1, + } +} + +trait Bindings { + def g(f: (Int, String) => Boolean) + + g(( + foo, + bar, + ) => true) +} + +// Import, ids, ValDcl, VarDcl, VarDef, PatDef use commas, but not inside paren, bracket or brace, +// so they don't support an optional trailing comma + +// test utilities +object `package` { + sealed trait Ev0; implicit object Ev0 extends Ev0 + sealed trait Ev1; implicit object Ev1 extends Ev1 +} diff --git a/test/files/run/iq.scala b/test/files/run/iq.scala index 0ccf67a2e9..9929f0e1a0 100644 --- a/test/files/run/iq.scala +++ b/test/files/run/iq.scala @@ -25,12 +25,18 @@ object iq { assert(q2 == qb) val qc = 42 +: q :+ 0 assert(q2 == qc) + assert(q ++ qa == qa) + val qdr = 1 +: 2 +: 3 +: 4 +: q + val qcon1 = 1 +: 2 +: q + val qcon2 = q :+ 3 :+ 4 + val qd = qcon1 ++ qcon2 + assert(qd == qdr) Console.println("q2: " + q2) Console.println("qa: " + qa) Console.println("qb: " + qb) Console.println("qc: " + qc) - + /* Test is empty and dequeue. * Expected: Head: 42 */ diff --git a/test/files/run/literals.scala b/test/files/run/literals.scala index 13fda05876..25501123b5 100644 --- a/test/files/run/literals.scala +++ b/test/files/run/literals.scala @@ -84,6 +84,10 @@ object Test { check_success("3.14f == 3.14f", 3.14f, 3.14f) check_success("6.022e23f == 6.022e23f", 6.022e23f, 6.022e23f) check_success("09f == 9.0f", 09f, 9.0f) + check_success("1.00000017881393421514957253748434595763683319091796875001f == 1.0000001f", + 1.00000017881393421514957253748434595763683319091796875001f, + 1.0000001f) + check_success("3.4028235E38f == Float.MaxValue", 3.4028235E38f, Float.MaxValue) check_success("1.asInstanceOf[Float] == 1.0", 1.asInstanceOf[Float], 1.0f) check_success("1l.asInstanceOf[Float] == 1.0", 1l.asInstanceOf[Float], 1.0f) @@ -97,6 +101,7 @@ object Test { check_success("3.14 == 3.14", 3.14, 3.14) check_success("1e-9d == 1.0e-9", 1e-9d, 1.0e-9) check_success("1e137 == 1.0e137", 1e137, 1.0e137) + check_success("1.7976931348623157e308d == Double.MaxValue", 1.7976931348623157e308d, Double.MaxValue) check_success("1.asInstanceOf[Double] == 1.0", 1.asInstanceOf[Double], 1.0) check_success("1l.asInstanceOf[Double] == 1.0", 1l.asInstanceOf[Double], 1.0) diff --git a/test/files/run/patmat-exprs.scala b/test/files/run/patmat-exprs.scala index 7ca5fd3063..d18df9c714 100644 --- a/test/files/run/patmat-exprs.scala +++ b/test/files/run/patmat-exprs.scala @@ -344,13 +344,13 @@ trait Pattern { } - case class Zero[T] (implicit num: NumericOps[T]) extends Leaf[T] { + case class Zero[T]()(implicit num: NumericOps[T]) extends Leaf[T] { def derivative(variable: Var[T]) = Zero[T] def eval(f: Any => Any) = num.zero override def toString = "0" } - case class One[T] (implicit num: NumericOps[T]) extends Leaf[T] { + case class One[T]()(implicit num: NumericOps[T]) extends Leaf[T] { def derivative(variable: Var[T]) = Zero[T] def eval(f: Any => Any) = num.one override def toString = "1" diff --git a/test/files/run/t10072.scala b/test/files/run/t10072.scala new file mode 100644 index 0000000000..0f1dca1838 --- /dev/null +++ b/test/files/run/t10072.scala @@ -0,0 +1,18 @@ +trait T[A] { + def a: A + def foldLeft[B](zero: B, op: (B, A) => B): B = op(zero, a) + def sum[B >: A](zero: B): B +} + +class C[@specialized(Int) A](val a: A) extends T[A] { + override def sum[@specialized(Int) B >: A](zero: B): B = foldLeft(zero, (x: B, y: B) => x) +} + +object Test extends App { + def factory[T](a: T): C[T] = new C[T](a) + + assert(new C[Int](1).sum(2) == 2) + assert(new C[String]("ho").sum("hu") == "hu") + assert(factory[Int](1).sum(2) == 2) + assert(factory[String]("ho").sum("hu") == "hu") +} diff --git a/test/files/run/t10097.check b/test/files/run/t10097.check new file mode 100644 index 0000000000..0e8b96061c --- /dev/null +++ b/test/files/run/t10097.check @@ -0,0 +1,3 @@ +t10097.scala:2: warning: case classes should have a non-implicit parameter list; adapting to 'case class C()(...)' +case class C(implicit c: Int) + ^ diff --git a/test/files/run/t10097.flags b/test/files/run/t10097.flags new file mode 100644 index 0000000000..dcc59ebe32 --- /dev/null +++ b/test/files/run/t10097.flags @@ -0,0 +1 @@ +-deprecation diff --git a/test/files/run/t10097.scala b/test/files/run/t10097.scala new file mode 100644 index 0000000000..a16be897cc --- /dev/null +++ b/test/files/run/t10097.scala @@ -0,0 +1,6 @@ + +case class C(implicit c: Int) + +object Test extends App { + assert(C()(42).productArity == 0) +} diff --git a/test/files/run/t4700.check b/test/files/run/t4700.check new file mode 100644 index 0000000000..ae854b959d --- /dev/null +++ b/test/files/run/t4700.check @@ -0,0 +1,44 @@ + +scala> import scala.annotation.showAsInfix +import scala.annotation.showAsInfix + +scala> class &&[T,U] +defined class $amp$amp + +scala> def foo: Int && Boolean = ??? +foo: Int && Boolean + +scala> def foo: Int && Boolean && String = ??? +foo: Int && Boolean && String + +scala> def foo: Int && (Boolean && String) = ??? +foo: Int && (Boolean && String) + +scala> @showAsInfix type Mappy[T, U] = Map[T, U] +defined type alias Mappy + +scala> def foo: Int Mappy (Boolean && String) = ??? +foo: Int Mappy (Boolean && String) + +scala> @showAsInfix(false) class ||[T,U] +defined class $bar$bar + +scala> def foo: Int || Boolean = ??? +foo: ||[Int,Boolean] + +scala> class &:[L, R] +defined class $amp$colon + +scala> def foo: Int &: String = ??? +foo: Int &: String + +scala> def foo: Int &: Boolean &: String = ??? +foo: Int &: Boolean &: String + +scala> def foo: (Int && String) &: Boolean = ??? +foo: (Int && String) &: Boolean + +scala> def foo: Int && (Boolean &: String) = ??? +foo: Int && (Boolean &: String) + +scala> :quit diff --git a/test/files/run/t4700.scala b/test/files/run/t4700.scala new file mode 100644 index 0000000000..7c02676e89 --- /dev/null +++ b/test/files/run/t4700.scala @@ -0,0 +1,22 @@ +import scala.tools.nsc.interpreter._ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |import scala.annotation.showAsInfix + |class &&[T,U] + |def foo: Int && Boolean = ??? + |def foo: Int && Boolean && String = ??? + |def foo: Int && (Boolean && String) = ??? + |@showAsInfix type Mappy[T, U] = Map[T, U] + |def foo: Int Mappy (Boolean && String) = ??? + |@showAsInfix(false) class ||[T,U] + |def foo: Int || Boolean = ??? + |class &:[L, R] + |def foo: Int &: String = ??? + |def foo: Int &: Boolean &: String = ??? + |def foo: (Int && String) &: Boolean = ??? + |def foo: Int && (Boolean &: String) = ??? + |""".stripMargin +} + diff --git a/test/files/run/t5907.scala b/test/files/run/t5907.scala index a005e9fbd3..81fc43e3f5 100644 --- a/test/files/run/t5907.scala +++ b/test/files/run/t5907.scala @@ -86,7 +86,7 @@ object Test extends App { } } -case class C1(implicit x: Int) { +case class C1()(implicit x: Int) { override def toString = s"c1: $x" } case class C2()(y: Int) { diff --git a/test/files/run/trailing-commas.check b/test/files/run/trailing-commas.check new file mode 100644 index 0000000000..0dc4335ccd --- /dev/null +++ b/test/files/run/trailing-commas.check @@ -0,0 +1,9 @@ + +scala> // test varargs in patterns + +scala> val List(x, y, _*, +) = 42 :: 17 :: Nil +x: Int = 42 +y: Int = 17 + +scala> :quit diff --git a/test/files/run/trailing-commas.scala b/test/files/run/trailing-commas.scala new file mode 100644 index 0000000000..6a7f1bb55f --- /dev/null +++ b/test/files/run/trailing-commas.scala @@ -0,0 +1,7 @@ +object Test extends scala.tools.partest.ReplTest { + def code = """ +// test varargs in patterns +val List(x, y, _*, +) = 42 :: 17 :: Nil +""" +} diff --git a/test/junit/scala/collection/concurrent/TrieMapTest.scala b/test/junit/scala/collection/concurrent/TrieMapTest.scala new file mode 100644 index 0000000000..ed67f3e9a9 --- /dev/null +++ b/test/junit/scala/collection/concurrent/TrieMapTest.scala @@ -0,0 +1,54 @@ +package scala.collection.concurrent + +import org.junit.{Assert, Test} + +class TrieMapTest { + + private def check[T](result2: List[Any])(f: TrieMap[String, String] => TraversableOnce[Any]) = { + val m = TrieMap[String, String]() + val values = f(m) + m.put("k", "v") + Assert.assertEquals(Nil, values.toList) + Assert.assertEquals(result2, f(m).toList) + } + + @Test + def iterator(): Unit = { + check(List(("k", "v")))(_.iterator) + } + + @Test + def values(): Unit = { + check(List("v"))(_.values) + } + + @Test + def valuesIterator(): Unit = { + check(List("v"))(_.valuesIterator) + } + + @Test + def keySet(): Unit = { + check(List("k"))(_.keySet) + } + + @Test + def keysIterator(): Unit = { + check(List("k"))(_.keysIterator) + } + + @Test + def keys(): Unit = { + check(List("k"))(_.keys) + } + + @Test + def filterKeys(): Unit = { + check(List(("k", "v")))(_.filterKeys(_ => true)) + } + + @Test + def mapValues(): Unit = { + check(List(("k", "v")))(_.mapValues(x => x)) + } +} diff --git a/test/junit/scala/collection/immutable/StreamTest.scala b/test/junit/scala/collection/immutable/StreamTest.scala index 7046525f37..61f7b792e8 100644 --- a/test/junit/scala/collection/immutable/StreamTest.scala +++ b/test/junit/scala/collection/immutable/StreamTest.scala @@ -117,4 +117,10 @@ class StreamTest { assert((0 #:: 1 #:: s) == (0 #:: 1 #:: s), "Cons of referentially identical streams should be equal (==)") assert((0 #:: 1 #:: s) equals (0 #:: 1 #:: s), "Cons of referentially identical streams should be equal (equals)") } + + @Test + def t9886: Unit = { + assertEquals(Stream(None, Some(1)), None #:: Stream(Some(1))) + assertEquals(Stream(None, Some(1)), Stream(None) #::: Stream(Some(1))) + } } diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala index 722062ba21..c7cfe0dfbb 100644 --- a/test/junit/scala/reflect/internal/PrintersTest.scala +++ b/test/junit/scala/reflect/internal/PrintersTest.scala @@ -556,7 +556,7 @@ class ClassPrintTest { @Test def testCaseClassWithParams3 = assertPrintedCode(sm""" |{ - | case class X(implicit x: scala.Int, s: scala.Predef.String); + | case class X()(implicit x: scala.Int, s: scala.Predef.String); | () |}""") diff --git a/test/simplejson/__init__.py b/test/simplejson/__init__.py deleted file mode 100644 index d5b4d39913..0000000000 --- a/test/simplejson/__init__.py +++ /dev/null @@ -1,318 +0,0 @@ -r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of -JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data -interchange format. - -:mod:`simplejson` exposes an API familiar to users of the standard library -:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained -version of the :mod:`json` library contained in Python 2.6, but maintains -compatibility with Python 2.4 and Python 2.5 and (currently) has -significant performance advantages, even without using the optional C -extension for speedups. - -Encoding basic Python object hierarchies:: - - >>> import simplejson as json - >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) - '["foo", {"bar": ["baz", null, 1.0, 2]}]' - >>> print json.dumps("\"foo\bar") - "\"foo\bar" - >>> print json.dumps(u'\u1234') - "\u1234" - >>> print json.dumps('\\') - "\\" - >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True) - {"a": 0, "b": 0, "c": 0} - >>> from StringIO import StringIO - >>> io = StringIO() - >>> json.dump(['streaming API'], io) - >>> io.getvalue() - '["streaming API"]' - -Compact encoding:: - - >>> import simplejson as json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) - '[1,2,3,{"4":5,"6":7}]' - -Pretty printing:: - - >>> import simplejson as json - >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4) - >>> print '\n'.join([l.rstrip() for l in s.splitlines()]) - { - "4": 5, - "6": 7 - } - -Decoding JSON:: - - >>> import simplejson as json - >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] - >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj - True - >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar' - True - >>> from StringIO import StringIO - >>> io = StringIO('["streaming API"]') - >>> json.load(io)[0] == 'streaming API' - True - -Specializing JSON object decoding:: - - >>> import simplejson as json - >>> def as_complex(dct): - ... if '__complex__' in dct: - ... return complex(dct['real'], dct['imag']) - ... return dct - ... - >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', - ... object_hook=as_complex) - (1+2j) - >>> import decimal - >>> json.loads('1.1', parse_float=decimal.Decimal) == decimal.Decimal('1.1') - True - -Specializing JSON object encoding:: - - >>> import simplejson as json - >>> def encode_complex(obj): - ... if isinstance(obj, complex): - ... return [obj.real, obj.imag] - ... raise TypeError(repr(o) + " is not JSON serializable") - ... - >>> json.dumps(2 + 1j, default=encode_complex) - '[2.0, 1.0]' - >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j) - '[2.0, 1.0]' - >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j)) - '[2.0, 1.0]' - - -Using simplejson.tool from the shell to validate and pretty-print:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) -""" -__version__ = '2.0.9' -__all__ = [ - 'dump', 'dumps', 'load', 'loads', - 'JSONDecoder', 'JSONEncoder', -] - -__author__ = 'Bob Ippolito <bob@redivi.com>' - -from decoder import JSONDecoder -from encoder import JSONEncoder - -_default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8', - default=None, -) - -def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a - ``.write()``-supporting file-like object). - - If ``skipkeys`` is true then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the some chunks written to ``fp`` - may be ``unicode`` instances, subject to normal Python ``str`` to - ``unicode`` coercion rules. Unless ``fp.write()`` explicitly - understands ``unicode`` (as in ``codecs.getwriter()``) this is likely - to cause an error. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) - in strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and object - members will be pretty-printed with that indent level. An indent level - of 0 will only insert newlines. ``None`` is the most compact representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - iterable = _default_encoder.iterencode(obj) - else: - if cls is None: - cls = JSONEncoder - iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, - default=default, **kw).iterencode(obj) - # could accelerate with writelines in some versions of Python, at - # a debuggability cost - for chunk in iterable: - fp.write(chunk) - - -def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` to a JSON formatted ``str``. - - If ``skipkeys`` is false then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the return value will be a - ``unicode`` instance subject to normal Python ``str`` to ``unicode`` - coercion rules instead of being escaped to an ASCII ``str``. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in - strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a non-negative integer, then JSON array elements and - object members will be pretty-printed with that indent level. An indent - level of 0 will only insert newlines. ``None`` is the most compact - representation. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - return _default_encoder.encode(obj) - if cls is None: - cls = JSONEncoder - return cls( - skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, default=default, - **kw).encode(obj) - - -_default_decoder = JSONDecoder(encoding=None, object_hook=None) - - -def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): - """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing - a JSON document) to a Python object. - - If the contents of ``fp`` is encoded with an ASCII based encoding other - than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must - be specified. Encodings that are not ASCII based (such as UCS-2) are - not allowed, and should be wrapped with - ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode`` - object and passed to ``loads()`` - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - return loads(fp.read(), - encoding=encoding, cls=cls, object_hook=object_hook, - parse_float=parse_float, parse_int=parse_int, - parse_constant=parse_constant, **kw) - - -def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, **kw): - """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON - document) to a Python object. - - If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding - other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name - must be specified. Encodings that are not ASCII based (such as UCS-2) - are not allowed and should be decoded to ``unicode`` first. - - ``object_hook`` is an optional function that will be called with the - result of any object literal decode (a ``dict``). The return value of - ``object_hook`` will be used instead of the ``dict``. This feature - can be used to implement custom decoders (e.g. JSON-RPC class hinting). - - ``parse_float``, if specified, will be called with the string - of every JSON float to be decoded. By default this is equivalent to - float(num_str). This can be used to use another datatype or parser - for JSON floats (e.g. decimal.Decimal). - - ``parse_int``, if specified, will be called with the string - of every JSON int to be decoded. By default this is equivalent to - int(num_str). This can be used to use another datatype or parser - for JSON integers (e.g. float). - - ``parse_constant``, if specified, will be called with one of the - following strings: -Infinity, Infinity, NaN, null, true, false. - This can be used to raise an exception if invalid JSON numbers - are encountered. - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - if (cls is None and encoding is None and object_hook is None and - parse_int is None and parse_float is None and - parse_constant is None and not kw): - return _default_decoder.decode(s) - if cls is None: - cls = JSONDecoder - if object_hook is not None: - kw['object_hook'] = object_hook - if parse_float is not None: - kw['parse_float'] = parse_float - if parse_int is not None: - kw['parse_int'] = parse_int - if parse_constant is not None: - kw['parse_constant'] = parse_constant - return cls(encoding=encoding, **kw).decode(s) diff --git a/test/simplejson/decoder.py b/test/simplejson/decoder.py deleted file mode 100644 index b769ea486c..0000000000 --- a/test/simplejson/decoder.py +++ /dev/null @@ -1,354 +0,0 @@ -"""Implementation of JSONDecoder -""" -import re -import sys -import struct - -from simplejson.scanner import make_scanner -try: - from simplejson._speedups import scanstring as c_scanstring -except ImportError: - c_scanstring = None - -__all__ = ['JSONDecoder'] - -FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL - -def _floatconstants(): - _BYTES = '7FF80000000000007FF0000000000000'.decode('hex') - if sys.byteorder != 'big': - _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1] - nan, inf = struct.unpack('dd', _BYTES) - return nan, inf, -inf - -NaN, PosInf, NegInf = _floatconstants() - - -def linecol(doc, pos): - lineno = doc.count('\n', 0, pos) + 1 - if lineno == 1: - colno = pos - else: - colno = pos - doc.rindex('\n', 0, pos) - return lineno, colno - - -def errmsg(msg, doc, pos, end=None): - # Note that this function is called from _speedups - lineno, colno = linecol(doc, pos) - if end is None: - #fmt = '{0}: line {1} column {2} (char {3})' - #return fmt.format(msg, lineno, colno, pos) - fmt = '%s: line %d column %d (char %d)' - return fmt % (msg, lineno, colno, pos) - endlineno, endcolno = linecol(doc, end) - #fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})' - #return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end) - fmt = '%s: line %d column %d - line %d column %d (char %d - %d)' - return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end) - - -_CONSTANTS = { - '-Infinity': NegInf, - 'Infinity': PosInf, - 'NaN': NaN, -} - -STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) -BACKSLASH = { - '"': u'"', '\\': u'\\', '/': u'/', - 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', -} - -DEFAULT_ENCODING = "utf-8" - -def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match): - """Scan the string s for a JSON string. End is the index of the - character in s after the quote that started the JSON string. - Unescapes all valid JSON string escape sequences and raises ValueError - on attempt to decode an invalid string. If strict is False then literal - control characters are allowed in the string. - - Returns a tuple of the decoded string and the index of the character in s - after the end quote.""" - if encoding is None: - encoding = DEFAULT_ENCODING - chunks = [] - _append = chunks.append - begin = end - 1 - while 1: - chunk = _m(s, end) - if chunk is None: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - end = chunk.end() - content, terminator = chunk.groups() - # Content is contains zero or more unescaped string characters - if content: - if not isinstance(content, unicode): - content = unicode(content, encoding) - _append(content) - # Terminator is the end of string, a literal control character, - # or a backslash denoting that an escape sequence follows - if terminator == '"': - break - elif terminator != '\\': - if strict: - msg = "Invalid control character %r at" % (terminator,) - #msg = "Invalid control character {0!r} at".format(terminator) - raise ValueError(errmsg(msg, s, end)) - else: - _append(terminator) - continue - try: - esc = s[end] - except IndexError: - raise ValueError( - errmsg("Unterminated string starting at", s, begin)) - # If not a unicode escape sequence, must be in the lookup table - if esc != 'u': - try: - char = _b[esc] - except KeyError: - msg = "Invalid \\escape: " + repr(esc) - raise ValueError(errmsg(msg, s, end)) - end += 1 - else: - # Unicode escape sequence - esc = s[end + 1:end + 5] - next_end = end + 5 - if len(esc) != 4: - msg = "Invalid \\uXXXX escape" - raise ValueError(errmsg(msg, s, end)) - uni = int(esc, 16) - # Check for surrogate pair on UCS-4 systems - if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535: - msg = "Invalid \\uXXXX\\uXXXX surrogate pair" - if not s[end + 5:end + 7] == '\\u': - raise ValueError(errmsg(msg, s, end)) - esc2 = s[end + 7:end + 11] - if len(esc2) != 4: - raise ValueError(errmsg(msg, s, end)) - uni2 = int(esc2, 16) - uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) - next_end += 6 - char = unichr(uni) - end = next_end - # Append the unescaped character - _append(char) - return u''.join(chunks), end - - -# Use speedup if available -scanstring = c_scanstring or py_scanstring - -WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) -WHITESPACE_STR = ' \t\n\r' - -def JSONObject((s, end), encoding, strict, scan_once, object_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - pairs = {} - # Use a slice to prevent IndexError from being raised, the following - # check will raise a more specific ValueError if the string is empty - nextchar = s[end:end + 1] - # Normally we expect nextchar == '"' - if nextchar != '"': - if nextchar in _ws: - end = _w(s, end).end() - nextchar = s[end:end + 1] - # Trivial empty object - if nextchar == '}': - return pairs, end + 1 - elif nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end)) - end += 1 - while True: - key, end = scanstring(s, end, encoding, strict) - - # To skip some function call overhead we optimize the fast paths where - # the JSON key separator is ": " or just ":". - if s[end:end + 1] != ':': - end = _w(s, end).end() - if s[end:end + 1] != ':': - raise ValueError(errmsg("Expecting : delimiter", s, end)) - - end += 1 - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - try: - value, end = scan_once(s, end) - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - pairs[key] = value - - try: - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - end += 1 - - if nextchar == '}': - break - elif nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end - 1)) - - try: - nextchar = s[end] - if nextchar in _ws: - end += 1 - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - - end += 1 - if nextchar != '"': - raise ValueError(errmsg("Expecting property name", s, end - 1)) - - if object_hook is not None: - pairs = object_hook(pairs) - return pairs, end - -def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - values = [] - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - # Look-ahead for trivial empty array - if nextchar == ']': - return values, end + 1 - _append = values.append - while True: - try: - value, end = scan_once(s, end) - except StopIteration: - raise ValueError(errmsg("Expecting object", s, end)) - _append(value) - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - end += 1 - if nextchar == ']': - break - elif nextchar != ',': - raise ValueError(errmsg("Expecting , delimiter", s, end)) - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - return values, end - -class JSONDecoder(object): - """Simple JSON <http://json.org> decoder - - Performs the following translations in decoding by default: - - +---------------+-------------------+ - | JSON | Python | - +===============+===================+ - | object | dict | - +---------------+-------------------+ - | array | list | - +---------------+-------------------+ - | string | unicode | - +---------------+-------------------+ - | number (int) | int, long | - +---------------+-------------------+ - | number (real) | float | - +---------------+-------------------+ - | true | True | - +---------------+-------------------+ - | false | False | - +---------------+-------------------+ - | null | None | - +---------------+-------------------+ - - It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as - their corresponding ``float`` values, which is outside the JSON spec. - - """ - - def __init__(self, encoding=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, strict=True): - """``encoding`` determines the encoding used to interpret any ``str`` - objects decoded by this instance (utf-8 by default). It has no - effect when decoding ``unicode`` objects. - - Note that currently only encodings that are a superset of ASCII work, - strings of other encodings should be passed in as ``unicode``. - - ``object_hook``, if specified, will be called with the result - of every JSON object decoded and its return value will be used in - place of the given ``dict``. This can be used to provide custom - deserializations (e.g. to support JSON-RPC class hinting). - - ``parse_float``, if specified, will be called with the string - of every JSON float to be decoded. By default this is equivalent to - float(num_str). This can be used to use another datatype or parser - for JSON floats (e.g. decimal.Decimal). - - ``parse_int``, if specified, will be called with the string - of every JSON int to be decoded. By default this is equivalent to - int(num_str). This can be used to use another datatype or parser - for JSON integers (e.g. float). - - ``parse_constant``, if specified, will be called with one of the - following strings: -Infinity, Infinity, NaN. - This can be used to raise an exception if invalid JSON numbers - are encountered. - - """ - self.encoding = encoding - self.object_hook = object_hook - self.parse_float = parse_float or float - self.parse_int = parse_int or int - self.parse_constant = parse_constant or _CONSTANTS.__getitem__ - self.strict = strict - self.parse_object = JSONObject - self.parse_array = JSONArray - self.parse_string = scanstring - self.scan_once = make_scanner(self) - - def decode(self, s, _w=WHITESPACE.match): - """Return the Python representation of ``s`` (a ``str`` or ``unicode`` - instance containing a JSON document) - - """ - obj, end = self.raw_decode(s, idx=_w(s, 0).end()) - end = _w(s, end).end() - if end != len(s): - raise ValueError(errmsg("Extra data", s, end, len(s))) - return obj - - def raw_decode(self, s, idx=0): - """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning - with a JSON document) and return a 2-tuple of the Python - representation and the index in ``s`` where the document ended. - - This can be used to decode a JSON document from a string that may - have extraneous data at the end. - - """ - try: - obj, end = self.scan_once(s, idx) - except StopIteration: - raise ValueError("No JSON object could be decoded") - return obj, end diff --git a/test/simplejson/encoder.py b/test/simplejson/encoder.py deleted file mode 100644 index cf58290366..0000000000 --- a/test/simplejson/encoder.py +++ /dev/null @@ -1,440 +0,0 @@ -"""Implementation of JSONEncoder -""" -import re - -try: - from simplejson._speedups import encode_basestring_ascii as c_encode_basestring_ascii -except ImportError: - c_encode_basestring_ascii = None -try: - from simplejson._speedups import make_encoder as c_make_encoder -except ImportError: - c_make_encoder = None - -ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') -ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') -HAS_UTF8 = re.compile(r'[\x80-\xff]') -ESCAPE_DCT = { - '\\': '\\\\', - '"': '\\"', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', -} -for i in range(0x20): - #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) - ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) - -# Assume this produces an infinity on all machines (probably not guaranteed) -INFINITY = float('1e66666') -FLOAT_REPR = repr - -def encode_basestring(s): - """Return a JSON representation of a Python string - - """ - def replace(match): - return ESCAPE_DCT[match.group(0)] - return '"' + ESCAPE.sub(replace, s) + '"' - - -def py_encode_basestring_ascii(s): - """Return an ASCII-only JSON representation of a Python string - - """ - if isinstance(s, str) and HAS_UTF8.search(s) is not None: - s = s.decode('utf-8') - def replace(match): - s = match.group(0) - try: - return ESCAPE_DCT[s] - except KeyError: - n = ord(s) - if n < 0x10000: - #return '\\u{0:04x}'.format(n) - return '\\u%04x' % (n,) - else: - # surrogate pair - n -= 0x10000 - s1 = 0xd800 | ((n >> 10) & 0x3ff) - s2 = 0xdc00 | (n & 0x3ff) - #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) - return '\\u%04x\\u%04x' % (s1, s2) - return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' - - -encode_basestring_ascii = c_encode_basestring_ascii or py_encode_basestring_ascii - -class JSONEncoder(object): - """Extensible JSON <http://json.org> encoder for Python data structures. - - Supports the following objects and types by default: - - +-------------------+---------------+ - | Python | JSON | - +===================+===============+ - | dict | object | - +-------------------+---------------+ - | list, tuple | array | - +-------------------+---------------+ - | str, unicode | string | - +-------------------+---------------+ - | int, long, float | number | - +-------------------+---------------+ - | True | true | - +-------------------+---------------+ - | False | false | - +-------------------+---------------+ - | None | null | - +-------------------+---------------+ - - To extend this to recognize other objects, subclass and implement a - ``.default()`` method with another method that returns a serializable - object for ``o`` if possible, otherwise it should call the superclass - implementation (to raise ``TypeError``). - - """ - item_separator = ', ' - key_separator = ': ' - def __init__(self, skipkeys=False, ensure_ascii=True, - check_circular=True, allow_nan=True, sort_keys=False, - indent=None, separators=None, encoding='utf-8', default=None): - """Constructor for JSONEncoder, with sensible defaults. - - If skipkeys is false, then it is a TypeError to attempt - encoding of keys that are not str, int, long, float or None. If - skipkeys is True, such items are simply skipped. - - If ensure_ascii is true, the output is guaranteed to be str - objects with all incoming unicode characters escaped. If - ensure_ascii is false, the output will be unicode object. - - If check_circular is true, then lists, dicts, and custom encoded - objects will be checked for circular references during encoding to - prevent an infinite recursion (which would cause an OverflowError). - Otherwise, no such check takes place. - - If allow_nan is true, then NaN, Infinity, and -Infinity will be - encoded as such. This behavior is not JSON specification compliant, - but is consistent with most JavaScript based encoders and decoders. - Otherwise, it will be a ValueError to encode such floats. - - If sort_keys is true, then the output of dictionaries will be - sorted by key; this is useful for regression tests to ensure - that JSON serializations can be compared on a day-to-day basis. - - If indent is a non-negative integer, then JSON array - elements and object members will be pretty-printed with that - indent level. An indent level of 0 will only insert newlines. - None is the most compact representation. - - If specified, separators should be a (item_separator, key_separator) - tuple. The default is (', ', ': '). To get the most compact JSON - representation you should specify (',', ':') to eliminate whitespace. - - If specified, default is a function that gets called for objects - that can't otherwise be serialized. It should return a JSON encodable - version of the object or raise a ``TypeError``. - - If encoding is not None, then all input strings will be - transformed into unicode using that encoding prior to JSON-encoding. - The default is UTF-8. - - """ - - self.skipkeys = skipkeys - self.ensure_ascii = ensure_ascii - self.check_circular = check_circular - self.allow_nan = allow_nan - self.sort_keys = sort_keys - self.indent = indent - if separators is not None: - self.item_separator, self.key_separator = separators - if default is not None: - self.default = default - self.encoding = encoding - - def default(self, o): - """Implement this method in a subclass such that it returns - a serializable object for ``o``, or calls the base implementation - (to raise a ``TypeError``). - - For example, to support arbitrary iterators, you could - implement default like this:: - - def default(self, o): - try: - iterable = iter(o) - except TypeError: - pass - else: - return list(iterable) - return JSONEncoder.default(self, o) - - """ - raise TypeError(repr(o) + " is not JSON serializable") - - def encode(self, o): - """Return a JSON string representation of a Python data structure. - - >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) - '{"foo": ["bar", "baz"]}' - - """ - # This is for extremely simple cases and benchmarks. - if isinstance(o, basestring): - if isinstance(o, str): - _encoding = self.encoding - if (_encoding is not None - and not (_encoding == 'utf-8')): - o = o.decode(_encoding) - if self.ensure_ascii: - return encode_basestring_ascii(o) - else: - return encode_basestring(o) - # This doesn't pass the iterator directly to ''.join() because the - # exceptions aren't as detailed. The list call should be roughly - # equivalent to the PySequence_Fast that ''.join() would do. - chunks = self.iterencode(o, _one_shot=True) - if not isinstance(chunks, (list, tuple)): - chunks = list(chunks) - return ''.join(chunks) - - def iterencode(self, o, _one_shot=False): - """Encode the given object and yield each string - representation as available. - - For example:: - - for chunk in JSONEncoder().iterencode(bigobject): - mysocket.write(chunk) - - """ - if self.check_circular: - markers = {} - else: - markers = None - if self.ensure_ascii: - _encoder = encode_basestring_ascii - else: - _encoder = encode_basestring - if self.encoding != 'utf-8': - def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): - if isinstance(o, str): - o = o.decode(_encoding) - return _orig_encoder(o) - - def floatstr(o, allow_nan=self.allow_nan, _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY): - # Check for specials. Note that this type of test is processor- and/or - # platform-specific, so do tests which don't depend on the internals. - - if o != o: - text = 'NaN' - elif o == _inf: - text = 'Infinity' - elif o == _neginf: - text = '-Infinity' - else: - return _repr(o) - - if not allow_nan: - raise ValueError( - "Out of range float values are not JSON compliant: " + - repr(o)) - - return text - - - if _one_shot and c_make_encoder is not None and not self.indent and not self.sort_keys: - _iterencode = c_make_encoder( - markers, self.default, _encoder, self.indent, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, self.allow_nan) - else: - _iterencode = _make_iterencode( - markers, self.default, _encoder, self.indent, floatstr, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, _one_shot) - return _iterencode(o, 0) - -def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, - ## HACK: hand-optimized bytecode; turn globals into locals - False=False, - True=True, - ValueError=ValueError, - basestring=basestring, - dict=dict, - float=float, - id=id, - int=int, - isinstance=isinstance, - list=list, - long=long, - str=str, - tuple=tuple, - ): - - def _iterencode_list(lst, _current_indent_level): - if not lst: - yield '[]' - return - if markers is not None: - markerid = id(lst) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = lst - buf = '[' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) - separator = _item_separator + newline_indent - buf += newline_indent - else: - newline_indent = None - separator = _item_separator - first = True - for value in lst: - if first: - first = False - else: - buf = separator - if isinstance(value, basestring): - yield buf + _encoder(value) - elif value is None: - yield buf + 'null' - elif value is True: - yield buf + 'true' - elif value is False: - yield buf + 'false' - elif isinstance(value, (int, long)): - yield buf + str(value) - elif isinstance(value, float): - yield buf + _floatstr(value) - else: - yield buf - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) - yield ']' - if markers is not None: - del markers[markerid] - - def _iterencode_dict(dct, _current_indent_level): - if not dct: - yield '{}' - return - if markers is not None: - markerid = id(dct) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = dct - yield '{' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) - item_separator = _item_separator + newline_indent - yield newline_indent - else: - newline_indent = None - item_separator = _item_separator - first = True - if _sort_keys: - items = dct.items() - items.sort(key=lambda kv: kv[0]) - else: - items = dct.iteritems() - for key, value in items: - if isinstance(key, basestring): - pass - # JavaScript is weakly typed for these, so it makes sense to - # also allow them. Many encoders seem to do something like this. - elif isinstance(key, float): - key = _floatstr(key) - elif key is True: - key = 'true' - elif key is False: - key = 'false' - elif key is None: - key = 'null' - elif isinstance(key, (int, long)): - key = str(key) - elif _skipkeys: - continue - else: - raise TypeError("key " + repr(key) + " is not a string") - if first: - first = False - else: - yield item_separator - yield _encoder(key) - yield _key_separator - if isinstance(value, basestring): - yield _encoder(value) - elif value is None: - yield 'null' - elif value is True: - yield 'true' - elif value is False: - yield 'false' - elif isinstance(value, (int, long)): - yield str(value) - elif isinstance(value, float): - yield _floatstr(value) - else: - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) - yield '}' - if markers is not None: - del markers[markerid] - - def _iterencode(o, _current_indent_level): - if isinstance(o, basestring): - yield _encoder(o) - elif o is None: - yield 'null' - elif o is True: - yield 'true' - elif o is False: - yield 'false' - elif isinstance(o, (int, long)): - yield str(o) - elif isinstance(o, float): - yield _floatstr(o) - elif isinstance(o, (list, tuple)): - for chunk in _iterencode_list(o, _current_indent_level): - yield chunk - elif isinstance(o, dict): - for chunk in _iterencode_dict(o, _current_indent_level): - yield chunk - else: - if markers is not None: - markerid = id(o) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = o - o = _default(o) - for chunk in _iterencode(o, _current_indent_level): - yield chunk - if markers is not None: - del markers[markerid] - - return _iterencode diff --git a/test/simplejson/scanner.py b/test/simplejson/scanner.py deleted file mode 100644 index adbc6ec979..0000000000 --- a/test/simplejson/scanner.py +++ /dev/null @@ -1,65 +0,0 @@ -"""JSON token scanner -""" -import re -try: - from simplejson._speedups import make_scanner as c_make_scanner -except ImportError: - c_make_scanner = None - -__all__ = ['make_scanner'] - -NUMBER_RE = re.compile( - r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', - (re.VERBOSE | re.MULTILINE | re.DOTALL)) - -def py_make_scanner(context): - parse_object = context.parse_object - parse_array = context.parse_array - parse_string = context.parse_string - match_number = NUMBER_RE.match - encoding = context.encoding - strict = context.strict - parse_float = context.parse_float - parse_int = context.parse_int - parse_constant = context.parse_constant - object_hook = context.object_hook - - def _scan_once(string, idx): - try: - nextchar = string[idx] - except IndexError: - raise StopIteration - - if nextchar == '"': - return parse_string(string, idx + 1, encoding, strict) - elif nextchar == '{': - return parse_object((string, idx + 1), encoding, strict, _scan_once, object_hook) - elif nextchar == '[': - return parse_array((string, idx + 1), _scan_once) - elif nextchar == 'n' and string[idx:idx + 4] == 'null': - return None, idx + 4 - elif nextchar == 't' and string[idx:idx + 4] == 'true': - return True, idx + 4 - elif nextchar == 'f' and string[idx:idx + 5] == 'false': - return False, idx + 5 - - m = match_number(string, idx) - if m is not None: - integer, frac, exp = m.groups() - if frac or exp: - res = parse_float(integer + (frac or '') + (exp or '')) - else: - res = parse_int(integer) - return res, m.end() - elif nextchar == 'N' and string[idx:idx + 3] == 'NaN': - return parse_constant('NaN'), idx + 3 - elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity': - return parse_constant('Infinity'), idx + 8 - elif nextchar == '-' and string[idx:idx + 9] == '-Infinity': - return parse_constant('-Infinity'), idx + 9 - else: - raise StopIteration - - return _scan_once - -make_scanner = c_make_scanner or py_make_scanner diff --git a/test/simplejson/tool.py b/test/simplejson/tool.py deleted file mode 100644 index 90443317b2..0000000000 --- a/test/simplejson/tool.py +++ /dev/null @@ -1,37 +0,0 @@ -r"""Command-line tool to validate and pretty-print JSON - -Usage:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) - -""" -import sys -import simplejson - -def main(): - if len(sys.argv) == 1: - infile = sys.stdin - outfile = sys.stdout - elif len(sys.argv) == 2: - infile = open(sys.argv[1], 'rb') - outfile = sys.stdout - elif len(sys.argv) == 3: - infile = open(sys.argv[1], 'rb') - outfile = open(sys.argv[2], 'wb') - else: - raise SystemExit(sys.argv[0] + " [infile [outfile]]") - try: - obj = simplejson.load(infile) - except ValueError, e: - raise SystemExit(e) - simplejson.dump(obj, outfile, sort_keys=True, indent=4) - outfile.write('\n') - - -if __name__ == '__main__': - main() diff --git a/versions.properties b/versions.properties index ae903bfe6e..26e8324c44 100644 --- a/versions.properties +++ b/versions.properties @@ -16,9 +16,9 @@ scala.binary.version=2.12 # external modules shipped with distribution, as specified by scala-library-all's pom scala-xml.version.number=1.0.6 -scala-parser-combinators.version.number=1.0.4 -scala-swing.version.number=2.0.0-M2 -scala-swing.version.osgi=2.0.0.M2 +scala-parser-combinators.version.number=1.0.5 +scala-swing.version.number=2.0.0 +scala-swing.version.osgi=2.0.0 jline.version=2.14.3 # this one is shaded and embedded in scala-compiler.jar scala-asm.version=5.1.0-scala-1 |