summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--build.sbt4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala3
-rw-r--r--src/library/scala/collection/GenTraversableOnce.scala6
-rw-r--r--src/library/scala/collection/IndexedSeqLike.scala2
-rw-r--r--src/library/scala/collection/mutable/Builder.scala23
-rw-r--r--src/library/scala/reflect/ClassTag.scala15
-rw-r--r--src/reflect/scala/reflect/internal/Variances.scala20
-rw-r--r--test/files/neg/t8079a.check4
-rw-r--r--test/files/neg/t8079a.scala4
-rw-r--r--test/files/neg/variances.check2
-rw-r--r--test/files/pos/fields_widen_trait_var.scala4
-rw-r--r--test/files/pos/t8079b.scala7
-rw-r--r--test/junit/scala/runtime/LambdaDeserializerTest.java1
-rw-r--r--test/junit/scala/tools/testing/ClearAfterClass.java1
-rw-r--r--test/pending/neg/t8079d.check4
-rw-r--r--test/pending/neg/t8079d.scala4
-rw-r--r--test/pending/pos/t8079c.scala7
18 files changed, 75 insertions, 38 deletions
diff --git a/README.md b/README.md
index ed42eadaaa..8d84daf0e5 100644
--- a/README.md
+++ b/README.md
@@ -115,7 +115,7 @@ 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 VersionUtil.baseVersionSuffix in Global := "abcd123-SNAPSHOT"`
+ - Optionally `set baseVersionSuffix := "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`).
diff --git a/build.sbt b/build.sbt
index 76ffe52728..4a8f349a59 100644
--- a/build.sbt
+++ b/build.sbt
@@ -133,7 +133,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
// we always assume that Java classes are standalone and do not have any dependency
// on Scala classes
compileOrder := CompileOrder.JavaThenScala,
- javacOptions in Compile ++= Seq("-g", "-source", "1.8", "-target", "1.8"),
+ javacOptions in Compile ++= Seq("-g", "-source", "1.8", "-target", "1.8", "-Xlint:unchecked"),
// we don't want any unmanaged jars; as a reminder: unmanaged jar is a jar stored
// directly on the file system and it's not resolved through Ivy
// Ant's build stored unmanaged jars in `lib/` directory
@@ -556,7 +556,7 @@ lazy val junit = project.in(file("test") / "junit")
.settings(disablePublishing: _*)
.settings(
fork in Test := true,
- javaOptions in Test += "-Xss5M",
+ javaOptions in Test += "-Xss1M",
libraryDependencies ++= Seq(junitDep, junitInterfaceDep, jolDep),
testOptions += Tests.Argument(TestFrameworks.JUnit, "-a", "-v"),
testFrameworks -= new TestFramework("org.scalacheck.ScalaCheckFramework"),
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 3d2b689e4c..0cd547c1eb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -976,7 +976,8 @@ trait Namers extends MethodSynthesis {
!tpe.typeSymbolDirect.isModuleClass // Infer Foo.type instead of "object Foo"
&& (tpe.widen <:< pt) // Don't widen our way out of conforming to pt
&& ( sym.isVariable
- || sym.isMethod && !sym.hasAccessorFlag
+ || sym.hasFlag(ACCESSOR) && !sym.hasFlag(STABLE)
+ || sym.isMethod && !sym.hasFlag(ACCESSOR)
|| isHidden(tpe)
)
)
diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala
index 4af2ca23be..d3096a872c 100644
--- a/src/library/scala/collection/GenTraversableOnce.scala
+++ b/src/library/scala/collection/GenTraversableOnce.scala
@@ -96,6 +96,12 @@ trait GenTraversableOnce[+A] extends Any {
*/
def size: Int
+ /** The size of this $coll if it is can be cheaply computed
+ *
+ * @return the number of elements in this $coll, or -1 if the size cannot be determined cheaply
+ */
+ protected[collection] def sizeHintIfCheap: Int = -1
+
/** Tests whether the $coll is empty.
*
* Note: Implementations in subclasses that are not repeatedly traversable must take
diff --git a/src/library/scala/collection/IndexedSeqLike.scala b/src/library/scala/collection/IndexedSeqLike.scala
index f4bf58ffe3..f0cede224d 100644
--- a/src/library/scala/collection/IndexedSeqLike.scala
+++ b/src/library/scala/collection/IndexedSeqLike.scala
@@ -92,4 +92,6 @@ trait IndexedSeqLike[+A, +Repr] extends Any with SeqLike[A, Repr] {
copyToBuffer(result)
result
}
+
+ override protected[collection] def sizeHintIfCheap: Int = size
}
diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala
index 8d6a0ec69d..528f78bd98 100644
--- a/src/library/scala/collection/mutable/Builder.scala
+++ b/src/library/scala/collection/mutable/Builder.scala
@@ -65,18 +65,18 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
/** Gives a hint that one expects the `result` of this builder
* to have the same size as the given collection, plus some delta. This will
* provide a hint only if the collection is known to have a cheap
- * `size` method. Currently this is assumed to be the case if and only if
- * the collection is of type `IndexedSeqLike`.
- * Some builder classes
- * will optimize their representation based on the hint. However,
+ * `size` method, which is determined by calling `sizeHint`.
+ *
+ * Some builder classes will optimize their representation based on the hint. However,
* builder implementations are still required to work correctly even if the hint is
* wrong, i.e. a different number of elements is added.
*
* @param coll the collection which serves as a hint for the result's size.
*/
def sizeHint(coll: TraversableLike[_, _]) {
- if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) {
- sizeHint(coll.size)
+ coll.sizeHintIfCheap match {
+ case -1 =>
+ case n => sizeHint(n)
}
}
@@ -94,8 +94,9 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
* @param delta a correction to add to the `coll.size` to produce the size hint.
*/
def sizeHint(coll: TraversableLike[_, _], delta: Int) {
- if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) {
- sizeHint(coll.size + delta)
+ coll.sizeHintIfCheap match {
+ case -1 =>
+ case n => sizeHint(n + delta)
}
}
@@ -112,8 +113,10 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
* than collection's size are reduced.
*/
def sizeHintBounded(size: Int, boundingColl: TraversableLike[_, _]) {
- if (boundingColl.isInstanceOf[collection.IndexedSeqLike[_,_]])
- sizeHint(size min boundingColl.size)
+ boundingColl.sizeHintIfCheap match {
+ case -1 =>
+ case n => sizeHint(size min n)
+ }
}
/** Creates a new builder by applying a transformation function to
diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala
index 3a300e0593..eb3aeeecfc 100644
--- a/src/library/scala/reflect/ClassTag.scala
+++ b/src/library/scala/reflect/ClassTag.scala
@@ -83,21 +83,6 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial
) Some(x.asInstanceOf[T])
else None
- // TODO: deprecate overloads in 2.12.0, remove in 2.13.0
- def unapply(x: Byte) : Option[T] = unapplyImpl(x, classOf[Byte])
- def unapply(x: Short) : Option[T] = unapplyImpl(x, classOf[Short])
- def unapply(x: Char) : Option[T] = unapplyImpl(x, classOf[Char])
- def unapply(x: Int) : Option[T] = unapplyImpl(x, classOf[Int])
- def unapply(x: Long) : Option[T] = unapplyImpl(x, classOf[Long])
- def unapply(x: Float) : Option[T] = unapplyImpl(x, classOf[Float])
- def unapply(x: Double) : Option[T] = unapplyImpl(x, classOf[Double])
- def unapply(x: Boolean) : Option[T] = unapplyImpl(x, classOf[Boolean])
- def unapply(x: Unit) : Option[T] = unapplyImpl(x, classOf[Unit])
-
- private[this] def unapplyImpl(x: Any, primitiveCls: java.lang.Class[_]): Option[T] =
- if (runtimeClass.isInstance(x) || runtimeClass.isAssignableFrom(primitiveCls)) Some(x.asInstanceOf[T])
- else None
-
// case class accessories
override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]]
override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass
diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala
index bc8a5de119..98b4e881af 100644
--- a/src/reflect/scala/reflect/internal/Variances.scala
+++ b/src/reflect/scala/reflect/internal/Variances.scala
@@ -50,11 +50,9 @@ trait Variances {
sym.isParameter
&& !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem && tvar.owner == sym.owner)
)
- // return Bivariant if `sym` is local to a term
- // or is private[this] or protected[this]
- def isLocalOnly(sym: Symbol) = !sym.owner.isClass || (
- sym.isTerm // ?? shouldn't this be sym.owner.isTerm according to the comments above?
- && (sym.isLocalToThis || sym.isSuperAccessor) // super accessors are implicitly local #4345
+ // Is `sym` is local to a term or is private[this] or protected[this]?
+ def isExemptFromVariance(sym: Symbol): Boolean = !sym.owner.isClass || (
+ (sym.isLocalToThis || sym.isSuperAccessor) // super accessors are implicitly local #4345
&& !escapedLocals(sym)
)
@@ -66,7 +64,7 @@ trait Variances {
* Initially the state is covariant, but it might change along the search.
*
* A local alias type is treated as Bivariant;
- * this is OK because we always expand aliases for variance checking.
+ * this is OK because such aliases are expanded for variance checking.
* However, for an alias which might be externally visible, we must assume Invariant,
* because there may be references to the type parameter that are not checked,
* leading to unsoundness (see SI-6566).
@@ -74,7 +72,7 @@ trait Variances {
def relativeVariance(tvar: Symbol): Variance = {
def nextVariance(sym: Symbol, v: Variance): Variance = (
if (shouldFlip(sym, tvar)) v.flip
- else if (isLocalOnly(sym)) Bivariant
+ else if (isExemptFromVariance(sym)) Bivariant
else if (sym.isAliasType) (
// Unsound pre-2.11 behavior preserved under -Xsource:2.10
if (settings.isScala211 || sym.isOverridingSymbol) Invariant
@@ -126,7 +124,7 @@ trait Variances {
tp match {
case _ if isUncheckedVariance(tp) =>
case _ if resultTypeOnly(tp) => this(tp.resultType)
- case TypeRef(_, sym, _) if sym.isAliasType => this(tp.normalize)
+ case TypeRef(_, sym, _) if shouldDealias(sym) => this(tp.normalize)
case TypeRef(_, sym, _) if !sym.variance.isInvariant => checkVarianceOfSymbol(sym) ; mapOver(tp)
case RefinedType(_, _) => withinRefinement(mapOver(tp))
case ClassInfoType(parents, _, _) => parents foreach this
@@ -138,6 +136,12 @@ trait Variances {
// than the result of the pattern match above, which normalizes types.
tp
}
+ private def shouldDealias(sym: Symbol): Boolean = {
+ // The RHS of (private|protected)[this] type aliases are excluded from variance checks. This is
+ // implemented in relativeVariance.
+ // As such, we need to expand references to them to retain soundness. Example: neg/t8079a.scala
+ sym.isAliasType && isExemptFromVariance(sym)
+ }
def validateDefinition(base: Symbol) {
val saved = this.base
this.base = base
diff --git a/test/files/neg/t8079a.check b/test/files/neg/t8079a.check
new file mode 100644
index 0000000000..6bbe78afa6
--- /dev/null
+++ b/test/files/neg/t8079a.check
@@ -0,0 +1,4 @@
+t8079a.scala:3: error: contravariant type I occurs in covariant position in type C.this.X of value b
+ def f2(b: X): Unit
+ ^
+one error found
diff --git a/test/files/neg/t8079a.scala b/test/files/neg/t8079a.scala
new file mode 100644
index 0000000000..4997ea282e
--- /dev/null
+++ b/test/files/neg/t8079a.scala
@@ -0,0 +1,4 @@
+trait C[-I] {
+ private[this] type X = C[I]
+ def f2(b: X): Unit
+}
diff --git a/test/files/neg/variances.check b/test/files/neg/variances.check
index cb1a60a632..3c1545a375 100644
--- a/test/files/neg/variances.check
+++ b/test/files/neg/variances.check
@@ -19,7 +19,7 @@ variances.scala:74: error: covariant type A occurs in contravariant position in
variances.scala:89: error: covariant type T occurs in invariant position in type T of type A
type A = T
^
-variances.scala:90: error: covariant type T occurs in contravariant position in type => test.TestAlias.B[C.this.A] of method foo
+variances.scala:90: error: covariant type A occurs in contravariant position in type => test.TestAlias.B[C.this.A] of method foo
def foo: B[A]
^
8 errors found
diff --git a/test/files/pos/fields_widen_trait_var.scala b/test/files/pos/fields_widen_trait_var.scala
new file mode 100644
index 0000000000..0ea9d9629a
--- /dev/null
+++ b/test/files/pos/fields_widen_trait_var.scala
@@ -0,0 +1,4 @@
+// check that the `var x` below is assigned the type `Int`, and not `Constant(0)`,
+// and that we can assign to it (if it gets a constant type, the `x` in `x = 42`
+// is constant-folded to `0` and we can't find a setter..
+trait C { protected final var x = 0; x = 42 }
diff --git a/test/files/pos/t8079b.scala b/test/files/pos/t8079b.scala
new file mode 100644
index 0000000000..f3b7b78077
--- /dev/null
+++ b/test/files/pos/t8079b.scala
@@ -0,0 +1,7 @@
+trait F1[/* - */T, /* + */ R]
+
+object Test {
+ import scala.annotation.unchecked._
+ type VariantF1[-T, +R] = F1[T @uncheckedVariance, R @uncheckedVariance]
+ trait C[+T] { def foo: VariantF1[Any, T] }
+}
diff --git a/test/junit/scala/runtime/LambdaDeserializerTest.java b/test/junit/scala/runtime/LambdaDeserializerTest.java
index 3ed1ae1365..4e9c5c8954 100644
--- a/test/junit/scala/runtime/LambdaDeserializerTest.java
+++ b/test/junit/scala/runtime/LambdaDeserializerTest.java
@@ -136,6 +136,7 @@ public final class LambdaDeserializerTest {
}
}
+ @SuppressWarnings("unchecked")
private <A> A deserizalizeLambdaCreatingAllowedMap(A f1, HashMap<String, MethodHandle> cache, MethodHandles.Lookup lookup) {
SerializedLambda serialized = writeReplace(f1);
HashMap<String, MethodHandle> allowed = createAllowedMap(lookup, serialized);
diff --git a/test/junit/scala/tools/testing/ClearAfterClass.java b/test/junit/scala/tools/testing/ClearAfterClass.java
index 95e170ec13..7f87f9a4d7 100644
--- a/test/junit/scala/tools/testing/ClearAfterClass.java
+++ b/test/junit/scala/tools/testing/ClearAfterClass.java
@@ -45,6 +45,7 @@ public class ClearAfterClass {
}
}
+ @SuppressWarnings("unchecked")
public <T> T cached(String key, scala.Function0<T> t) {
Map<String, Object> perClassCache = cache.get(getClass());
return (T) perClassCache.computeIfAbsent(key, s -> t.apply());
diff --git a/test/pending/neg/t8079d.check b/test/pending/neg/t8079d.check
new file mode 100644
index 0000000000..f63f4902f8
--- /dev/null
+++ b/test/pending/neg/t8079d.check
@@ -0,0 +1,4 @@
+t8079d.scala:3: error: contravariant type I occurs in covariant position in type C.this.X of value b
+ def f2(b: X): Unit
+ ^
+one error found
diff --git a/test/pending/neg/t8079d.scala b/test/pending/neg/t8079d.scala
new file mode 100644
index 0000000000..ad420b99e3
--- /dev/null
+++ b/test/pending/neg/t8079d.scala
@@ -0,0 +1,4 @@
+trait C[-I] {
+ protected[this] type X = C[I]
+ def f2(b: X): Unit
+}
diff --git a/test/pending/pos/t8079c.scala b/test/pending/pos/t8079c.scala
new file mode 100644
index 0000000000..ae7f37e2bf
--- /dev/null
+++ b/test/pending/pos/t8079c.scala
@@ -0,0 +1,7 @@
+trait F1[/* - */T, /* + */ R]
+
+object Test {
+ import scala.annotation.unchecked._
+ private[this] type VariantF1[-T, +R] = F1[T @uncheckedVariance, R @uncheckedVariance]
+ trait C[+T] { def foo: VariantF1[Any, T] }
+}