diff options
-rw-r--r-- | README.md | 22 | ||||
-rw-r--r-- | spec/04-basic-declarations-and-definitions.md | 9 | ||||
-rw-r--r-- | spec/06-expressions.md | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 18 | ||||
-rw-r--r-- | src/library/scala/collection/mutable/HashMap.scala | 12 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeInfo.scala | 1 | ||||
-rw-r--r-- | test/files/pos/t4237.scala | 15 | ||||
-rw-r--r-- | test/files/run/number-parsing.scala | 4 | ||||
-rw-r--r-- | test/files/run/sd329.scala | 76 | ||||
-rw-r--r-- | test/junit/scala/collection/mutable/HashMapTest.scala | 38 |
10 files changed, 176 insertions, 23 deletions
@@ -104,10 +104,13 @@ Core commands: - `partest` runs partest tests (accepts options, try `partest --help`) - `publishLocal` publishes a distribution locally (can be used as `scalaVersion` in other sbt projects) - - Optionally `set baseVersionSuffix := "abcd123-SNAPSHOT"` + - Optionally `set baseVersionSuffix := "-bin-abcd123-SNAPSHOT"` where `abcd123` is the git hash of the revision being published. You can also - use something custom like `"mypatch"`. This changes the version number from - `2.12.0-SNAPSHOT` to something more stable (`2.12.0-abcd123-SNAPSHOT`). + use something custom like `"-bin-mypatch"`. This changes the version number from + `2.12.2-SNAPSHOT` to something more stable (`2.12.2-bin-abcd123-SNAPSHOT`). + - Note that the `-bin` string marks the version binary compatible. Using it in + sbt will cause the `scalaBinaryVersion` to be `2.12`. If the version is not + binary compatible, we recommend using `-pre`, e.g., `2.13.0-pre-abcd123-SNAPSHOT`. - Optionally `set publishArtifact in (Compile, packageDoc) in ThisBuild := false` to skip generating / publishing API docs (speeds up the process). @@ -199,8 +202,9 @@ CI performs a full bootstrap. The first task, `validate-publish-core`, publishes a build of your commit to the temporary repository https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots. Note that this build is not yet bootstrapped, its bytecode is built using the -current `starr`. The version number is `2.12.0-abcd123-SNAPSHOT` where `abcd123` -is the commit hash. +current `starr`. The version number is `2.12.2-bin-abcd123-SNAPSHOT` where `abcd123` +is the commit hash. For binary incompatible builds, the version number is +`2.13.0-pre-abcd123-SNAPSHOT`. You can use Scala builds in the validation repository locally by adding a resolver and specifying the corresponding `scalaVersion`: @@ -208,7 +212,7 @@ and specifying the corresponding `scalaVersion`: ``` $ sbt > set resolvers += "pr" at "https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots/" -> set scalaVersion := "2.12.0-abcd123-SNAPSHOT" +> set scalaVersion := "2.12.2-bin-abcd123-SNAPSHOT" > console ``` @@ -228,10 +232,8 @@ The CI also publishes nightly API docs: - [2.11.x](http://www.scala-lang.org/files/archive/nightly/2.11.x/api/?C=M;O=D) - [symlink to the latest](http://www.scala-lang.org/files/archive/nightly/2.11.x/api/2.11.x/) -Note that we currently don't publish nightly (or SNAPSHOT) builds in maven or ivy -format to any repository. You can track progress on this front at -[scala-jenkins-infra#133](https://github.com/scala/scala-jenkins-infra/issues/133) -and [scala-dev#68](https://github.com/scala/scala-dev/issues/68). +Using a nightly build in sbt is explained in +[this answer on Stack Overflow](http://stackoverflow.com/questions/40622878) ## Scala CI Internals diff --git a/spec/04-basic-declarations-and-definitions.md b/spec/04-basic-declarations-and-definitions.md index 53b34dedc5..c4d3425fff 100644 --- a/spec/04-basic-declarations-and-definitions.md +++ b/spec/04-basic-declarations-and-definitions.md @@ -669,6 +669,15 @@ def f(a: Int = 0)(b: Int = a + 1) = b // OK f(10)() // returns 11 (not 1) ``` +If an [implicit argument](07-implicits.html#implicit-parameters) +is not found by implicit search, it may be supplied using a default argument. + +```scala +implicit val i: Int = 2 +def f(implicit x: Int, s: String = "hi") = s * x +f // "hihi" +``` + ### By-Name Parameters ```ebnf diff --git a/spec/06-expressions.md b/spec/06-expressions.md index 48cff1725a..581170c5f9 100644 --- a/spec/06-expressions.md +++ b/spec/06-expressions.md @@ -320,7 +320,7 @@ would not typecheck. ### Named and Default Arguments -If an application might uses named arguments $p = e$ or default +If an application is to use named arguments $p = e$ or default arguments, the following conditions must hold. - For every named argument $p_i = e_i$ which appears left of a positional argument @@ -330,7 +330,7 @@ arguments, the following conditions must hold. argument defines a parameter which is already specified by a positional argument. - Every formal parameter $p_j:T_j$ which is not specified by either a positional - or a named argument has a default argument. + or named argument has a default argument. If the application uses named or default arguments the following transformation is applied to convert it into diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 76d042ce3b..37dea477c6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1264,14 +1264,22 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { def genEqEqPrimitive(l: Tree, r: Tree, success: asm.Label, failure: asm.Label, targetIfNoJump: asm.Label, pos: Position) { /* True if the equality comparison is between values that require the use of the rich equality - * comparator (scala.runtime.Comparator.equals). This is the case when either side of the + * comparator (scala.runtime.BoxesRunTime.equals). This is the case when either side of the * comparison might have a run-time type subtype of java.lang.Number or java.lang.Character. - * When it is statically known that both sides are equal and subtypes of Number of Character, - * not using the rich equality is possible (their own equals method will do ok.) + * + * When it is statically known that both sides are equal and subtypes of Number or Character, + * not using the rich equality is possible (their own equals method will do ok), except for + * java.lang.Float and java.lang.Double: their `equals` have different behavior around `NaN` + * and `-0.0`, see Javadoc (scala-dev#329). */ val mustUseAnyComparator: Boolean = { - val areSameFinals = l.tpe.isFinalType && r.tpe.isFinalType && (l.tpe =:= r.tpe) - !areSameFinals && platform.isMaybeBoxed(l.tpe.typeSymbol) && platform.isMaybeBoxed(r.tpe.typeSymbol) + platform.isMaybeBoxed(l.tpe.typeSymbol) && platform.isMaybeBoxed(r.tpe.typeSymbol) && { + val areSameFinals = l.tpe.isFinalType && r.tpe.isFinalType && (l.tpe =:= r.tpe) && { + val sym = l.tpe.typeSymbol + sym != BoxedFloatClass && sym != BoxedDoubleClass + } + !areSameFinals + } } if (mustUseAnyComparator) { diff --git a/src/library/scala/collection/mutable/HashMap.scala b/src/library/scala/collection/mutable/HashMap.scala index 11ff1f0893..de61ebb796 100644 --- a/src/library/scala/collection/mutable/HashMap.scala +++ b/src/library/scala/collection/mutable/HashMap.scala @@ -73,10 +73,18 @@ extends AbstractMap[A, B] } override def getOrElseUpdate(key: A, defaultValue: => B): B = { - val i = index(elemHashCode(key)) + val hash = elemHashCode(key) + val i = index(hash) val entry = findEntry(key, i) if (entry != null) entry.value - else addEntry(createNewEntry(key, defaultValue), i) + else { + val table0 = table + val default = defaultValue + // Avoid recomputing index if the `defaultValue()` hasn't triggered + // a table resize. + val newEntryIndex = if (table0 eq table) i else index(hash) + addEntry(createNewEntry(key, default), newEntryIndex) + } } /* inlined HashTable.findEntry0 to preserve its visibility */ diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 1aef30819a..933afbea2b 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -274,6 +274,7 @@ abstract class TreeInfo { def mayBeVarGetter(sym: Symbol): Boolean = sym.info match { case NullaryMethodType(_) => sym.owner.isClass && !sym.isStable case PolyType(_, NullaryMethodType(_)) => sym.owner.isClass && !sym.isStable + case PolyType(_, mt @ MethodType(_, _))=> mt.isImplicit && sym.owner.isClass && !sym.isStable case mt @ MethodType(_, _) => mt.isImplicit && sym.owner.isClass && !sym.isStable case _ => false } diff --git a/test/files/pos/t4237.scala b/test/files/pos/t4237.scala index fcf6eb8bf1..3f605607b2 100644 --- a/test/files/pos/t4237.scala +++ b/test/files/pos/t4237.scala @@ -2,5 +2,16 @@ class A { (new { def field = 0; def field_=(i: Int) = () }).field = 5 // compiles as expected (new { def field(implicit i: Int) = 0; def field_=(i: Int) = () }).field = 5 // compiles even with implicit params on getter (new { def field = 0; def field_=[T](i: Int) = () }).field = 5 // compiles with type param on setter - (new { def field[T] = 0; def field_=(i: Int) = () }).field = 5 // DOESN'T COMPILE -}
\ No newline at end of file + (new { def field[T] = 0; def field_=(i: Int) = () }).field = 5 // DIDN'T COMPILE + + class Imp + implicit val imp: Imp = new Imp + implicit val implicitList: List[Int] = null + + // compiles even with implicit params on setter + (new { def field(implicit i: Int) = 0; def field_=(i: Int)(implicit j: Imp) = () }).field = 5 + (new { def field(implicit i: Int) = 0; def field_=[T <: Imp](i: Int)(implicit j: T) = () }).field = 5 + // was reassignment to val + (new { def field[T](implicit ts: List[T]) = 0; def field_=[T](i: Int)(implicit ts: List[T]) = () }).field = 5 + (new { def field[T](implicit ts: List[T]) = 0; def field_=[T](i: T)(implicit ts: List[T]) = () }).field = 5 +} diff --git a/test/files/run/number-parsing.scala b/test/files/run/number-parsing.scala index ad1481063e..5627ee9006 100644 --- a/test/files/run/number-parsing.scala +++ b/test/files/run/number-parsing.scala @@ -3,8 +3,8 @@ object Test { val MinusZero = Float.box(-0.0f) val PlusZero = Float.box(0.0f) - assert(PlusZero match { case MinusZero => false ; case _ => true }) - assert(MinusZero match { case PlusZero => false ; case _ => true }) + assert(PlusZero match { case MinusZero => true ; case _ => false }) + assert(MinusZero match { case PlusZero => true ; case _ => false }) assert((MinusZero: scala.Float) == (PlusZero: scala.Float)) assert(!(MinusZero equals PlusZero)) diff --git a/test/files/run/sd329.scala b/test/files/run/sd329.scala new file mode 100644 index 0000000000..c934e2c986 --- /dev/null +++ b/test/files/run/sd329.scala @@ -0,0 +1,76 @@ +object Test extends App { + def d1: Double = 0.0 + def d2: Double = -0.0 + def d3: Double = Double.NaN + def d4: Double = Double.NaN + assert(d1 == d2) + assert(d3 != d4) + + def d1B: java.lang.Double = d1 + def d2B: java.lang.Double = d2 + def d3B: java.lang.Double = d3 + def d4B: java.lang.Double = d4 + assert(d1B == d2B) + assert(d1 == d1B) + assert(d1B == d1) + assert(d3B != d4B) + assert(d3 != d4B) + assert(d3B != d4) + + assert(!d1B.equals(d2B)) // ! see javadoc + assert( d3B.equals(d4B)) // ! see javadoc + + def d1A: Any = d1 + def d2A: Any = d2 + def d3A: Any = d3 + def d4A: Any = d4 + assert(d1A == d2A) + assert(d1 == d1A) + assert(d1A == d1) + assert(d1B == d1A) + assert(d1A == d1B) + + assert(d3A != d4A) + assert(d3 != d4A) + assert(d3A != d4) + assert(d3B != d4A) + assert(d3A != d4B) + + + def f1: Float = 0.0f + def f2: Float = -0.0f + def f3: Float = Float.NaN + def f4: Float = Float.NaN + assert(f1 == f2) + assert(f3 != f4) + + def f1B: java.lang.Float = f1 + def f2B: java.lang.Float = f2 + def f3B: java.lang.Float = f3 + def f4B: java.lang.Float = f4 + assert(f1B == f2B) + assert(f1 == f1B) + assert(f1B == f1) + assert(f3B != f4B) + assert(f3 != f4B) + assert(f3B != f4) + + assert(!f1B.equals(f2B)) // ! see javadoc + assert( f3B.equals(f4B)) // ! see javadoc + + def f1A: Any = f1 + def f2A: Any = f2 + def f3A: Any = f3 + def f4A: Any = f4 + assert(f1A == f2A) + assert(f1 == f1A) + assert(f1A == f1) + assert(f1B == f1A) + assert(f1A == f1B) + + assert(f3A != f4A) + assert(f3 != f4A) + assert(f3A != f4) + assert(f3B != f4A) + assert(f3A != f4B) +} diff --git a/test/junit/scala/collection/mutable/HashMapTest.scala b/test/junit/scala/collection/mutable/HashMapTest.scala new file mode 100644 index 0000000000..cc1979a920 --- /dev/null +++ b/test/junit/scala/collection/mutable/HashMapTest.scala @@ -0,0 +1,38 @@ +package scala.collection +package mutable + +import org.junit.Assert._ +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(classOf[JUnit4]) +class HashMapTest { + + @Test + def getOrElseUpdate_mutationInCallback() { + val hm = new mutable.HashMap[String, String]() + // add enough elements to resize the hash table in the callback + def add() = 1 to 100000 foreach (i => hm(i.toString) = "callback") + hm.getOrElseUpdate("0", { + add() + "" + }) + assertEquals(Some(""), hm.get("0")) + } + + @Test + def getOrElseUpdate_evalOnce(): Unit = { + var i = 0 + val hm = new mutable.HashMap[Int, Int]() + hm.getOrElseUpdate(0, {i += 1; i}) + assertEquals(1, hm(0)) + } + + @Test + def getOrElseUpdate_noEval(): Unit = { + val hm = new mutable.HashMap[Int, Int]() + hm.put(0, 0) + hm.getOrElseUpdate(0, throw new AssertionError()) + } +} |