Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

SI-7335 Mandate that parents of Predef must be defined in Predef.scala

This avoids thorny issues of cyclic references and/or missing symbol errors
due to the way Predef is completed earlier than user classes, and due to the
addition of `import Predef._` to LowPriorityImplicits.scala. More details in
Lukas's comments in [2].

How did we bootstrap originally? Manually ordering source files,
either in the Ant Build [1], or later in Global [2]. But neither mechanism
remains in place (due, I suppose, to the difficulty in defending them
with a test case.) The reordering in Global was removed in [3].

After the change, we can compile the standard library without the
results of a prior compilation run on the classpath.

    rm -rf target/locker/library/classes/scala && export LIB=build/pack/lib; java -Xmx1G -cp $LIB/scala-library.jar:$LIB/scala-reflect.jar:$LIB/scala-compiler.jar:$LIB/forkjoin.jar scala.tools.nsc.Main @args.txt
    src/library/scala/SerialVersionUID.scala:15: warning: Implementation restriction: subclassing Classfile does not
    make your annotation visible at runtime.  If that is what
    you want, you must write the annotation class in Java.
    class SerialVersionUID(value: Long) extends scala.annotation.ClassfileAnnotation
          ^
    warning: there were 75 deprecation warning(s); re-run with -deprecation for details
    warning: there were 1 unchecked warning(s); re-run with -unchecked for details
    warning: there were 5 feature warning(s); re-run with -feature for details
    four warnings found

 Where @args.txt contains:

     -classpath
     lib/forkjoin.jar:target/locker/library/classes
     -sourcepath
     src/library
     -d
     target/locker/library/classes
     src/library/scala/Function3.scala
     src/library/scala/Console.scala
     <more of src/library/**, unsorted>

This change will break scala-virtualized, which will need to move
the contents of StandardEmbeddings.scala into Predef.scala.

[1] c5441dc
[2] e72f0c7
[3] #968
  • Loading branch information...
commit d43f5ce5aa10e39ad05a385c31fc7178eba997c1 1 parent c57c4f8
@retronym retronym authored
View
9 src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1856,6 +1856,9 @@ trait Typers extends Adaptations with Tags {
}
val impl2 = finishMethodSynthesis(impl1, clazz, context)
+ if (mdef.symbol == PredefModule)
+ ensurePredefParentsAreInSameSourceFile(impl2)
+
// SI-5954. On second compile of a companion class contained in a package object we end up
// with some confusion of names which leads to having two symbols with the same name in the
// same owner. Until that can be straightened out we will warn on companion objects in package
@@ -1884,6 +1887,12 @@ trait Typers extends Adaptations with Tags {
treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType
}
+
+ private def ensurePredefParentsAreInSameSourceFile(template: Template) = {
+ val parentSyms = template.parents map (_.symbol) filterNot (_ == AnyRefClass)
+ if (parentSyms exists (_.associatedFile != PredefModule.associatedFile))
+ unit.error(template.pos, s"All parents of Predef must be defined in ${PredefModule.associatedFile}.")
+ }
/** In order to override this in the TreeCheckers Typer so synthetics aren't re-added
* all the time, it is exposed here the module/class typing methods go through it.
* ...but it turns out it's also the ideal spot for namer/typer coordination for
View
95 src/library/scala/LowPriorityImplicits.scala
@@ -1,95 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala
-
-import scala.collection.{ mutable, immutable, generic }
-import mutable.WrappedArray
-import immutable.WrappedString
-import generic.CanBuildFrom
-import scala.language.implicitConversions
-
-/** The `LowPriorityImplicits` class provides implicit values that
- * are valid in all Scala compilation units without explicit qualification,
- * but that are partially overridden by higher-priority conversions in object
- * `Predef`.
- *
- * @author Martin Odersky
- * @since 2.8
- */
-private[scala] abstract class LowPriorityImplicits {
- /** We prefer the java.lang.* boxed types to these wrappers in
- * any potential conflicts. Conflicts do exist because the wrappers
- * need to implement ScalaNumber in order to have a symmetric equals
- * method, but that implies implementing java.lang.Number as well.
- *
- * Note - these are inlined because they are value classes, but
- * the call to xxxWrapper is not eliminated even though it does nothing.
- * Even inlined, every call site does a no-op retrieval of Predef's MODULE$
- * because maybe loading Predef has side effects!
- */
- @inline implicit def byteWrapper(x: Byte) = new runtime.RichByte(x)
- @inline implicit def shortWrapper(x: Short) = new runtime.RichShort(x)
- @inline implicit def intWrapper(x: Int) = new runtime.RichInt(x)
- @inline implicit def charWrapper(c: Char) = new runtime.RichChar(c)
- @inline implicit def longWrapper(x: Long) = new runtime.RichLong(x)
- @inline implicit def floatWrapper(x: Float) = new runtime.RichFloat(x)
- @inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x)
- @inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x)
-
- // These eight implicits exist solely to exclude Null from the domain of
- // the boxed types, so that e.g. "var x: Int = null" is a compile time
- // error rather than a delayed null pointer exception by way of the
- // conversion from java.lang.Integer. If defined in the same file as
- // Integer2int, they would have higher priority because Null is a subtype
- // of Integer. We balance that out and create conflict by moving the
- // definition into the superclass.
- //
- // Caution: do not adjust tightrope tension without safety goggles in place.
- implicit def Byte2byteNullConflict(x: Null): Byte = sys.error("value error")
- implicit def Short2shortNullConflict(x: Null): Short = sys.error("value error")
- implicit def Character2charNullConflict(x: Null): Char = sys.error("value error")
- implicit def Integer2intNullConflict(x: Null): Int = sys.error("value error")
- implicit def Long2longNullConflict(x: Null): Long = sys.error("value error")
- implicit def Float2floatNullConflict(x: Null): Float = sys.error("value error")
- implicit def Double2doubleNullConflict(x: Null): Double = sys.error("value error")
- implicit def Boolean2booleanNullConflict(x: Null): Boolean = sys.error("value error")
-
- implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] =
- if (xs eq null) null
- else WrappedArray.make(xs)
-
- // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef]
- // is as good as another for all T <: AnyRef. Instead of creating 100,000,000
- // unique ones by way of this implicit, let's share one.
- implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = {
- if (xs eq null) null
- else if (xs.length == 0) WrappedArray.empty[T]
- else new WrappedArray.ofRef[T](xs)
- }
-
- implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = if (xs ne null) new WrappedArray.ofInt(xs) else null
- implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = if (xs ne null) new WrappedArray.ofDouble(xs) else null
- implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = if (xs ne null) new WrappedArray.ofLong(xs) else null
- implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = if (xs ne null) new WrappedArray.ofFloat(xs) else null
- implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = if (xs ne null) new WrappedArray.ofChar(xs) else null
- implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = if (xs ne null) new WrappedArray.ofByte(xs) else null
- implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = if (xs ne null) new WrappedArray.ofShort(xs) else null
- implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = if (xs ne null) new WrappedArray.ofBoolean(xs) else null
- implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = if (xs ne null) new WrappedArray.ofUnit(xs) else null
-
- implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null
- implicit def unwrapString(ws: WrappedString): String = if (ws ne null) ws.self else null
-
- implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] =
- new CanBuildFrom[String, T, immutable.IndexedSeq[T]] {
- def apply(from: String) = immutable.IndexedSeq.newBuilder[T]
- def apply() = immutable.IndexedSeq.newBuilder[T]
- }
-}
-
View
86 src/library/scala/Predef.scala
@@ -446,3 +446,89 @@ private[scala] trait DeprecatedPredef {
@deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readf2(format: String) = ReadStdin.readf2(format)
@deprecated("Use the method in `scala.io.ReadStdin`", "2.11.0") def readf3(format: String) = ReadStdin.readf3(format)
}
+
+/** The `LowPriorityImplicits` class provides implicit values that
+* are valid in all Scala compilation units without explicit qualification,
+* but that are partially overridden by higher-priority conversions in object
+* `Predef`.
+*
+* @author Martin Odersky
+* @since 2.8
+*/
+// SI-7335 Parents of Predef are defined in the same compilation unit to avoid
+// cyclic reference errors compiling the standard library *without* a previously
+// compiled copy on the classpath.
+private[scala] abstract class LowPriorityImplicits {
+ import mutable.WrappedArray
+ import immutable.WrappedString
+
+ /** We prefer the java.lang.* boxed types to these wrappers in
+ * any potential conflicts. Conflicts do exist because the wrappers
+ * need to implement ScalaNumber in order to have a symmetric equals
+ * method, but that implies implementing java.lang.Number as well.
+ *
+ * Note - these are inlined because they are value classes, but
+ * the call to xxxWrapper is not eliminated even though it does nothing.
+ * Even inlined, every call site does a no-op retrieval of Predef's MODULE$
+ * because maybe loading Predef has side effects!
+ */
+ @inline implicit def byteWrapper(x: Byte) = new runtime.RichByte(x)
+ @inline implicit def shortWrapper(x: Short) = new runtime.RichShort(x)
+ @inline implicit def intWrapper(x: Int) = new runtime.RichInt(x)
+ @inline implicit def charWrapper(c: Char) = new runtime.RichChar(c)
+ @inline implicit def longWrapper(x: Long) = new runtime.RichLong(x)
+ @inline implicit def floatWrapper(x: Float) = new runtime.RichFloat(x)
+ @inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x)
+ @inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x)
+
+ // These eight implicits exist solely to exclude Null from the domain of
+ // the boxed types, so that e.g. "var x: Int = null" is a compile time
+ // error rather than a delayed null pointer exception by way of the
+ // conversion from java.lang.Integer. If defined in the same file as
+ // Integer2int, they would have higher priority because Null is a subtype
+ // of Integer. We balance that out and create conflict by moving the
+ // definition into the superclass.
+ //
+ // Caution: do not adjust tightrope tension without safety goggles in place.
+ implicit def Byte2byteNullConflict(x: Null): Byte = sys.error("value error")
+ implicit def Short2shortNullConflict(x: Null): Short = sys.error("value error")
+ implicit def Character2charNullConflict(x: Null): Char = sys.error("value error")
+ implicit def Integer2intNullConflict(x: Null): Int = sys.error("value error")
+ implicit def Long2longNullConflict(x: Null): Long = sys.error("value error")
+ implicit def Float2floatNullConflict(x: Null): Float = sys.error("value error")
+ implicit def Double2doubleNullConflict(x: Null): Double = sys.error("value error")
+ implicit def Boolean2booleanNullConflict(x: Null): Boolean = sys.error("value error")
+
+ implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] =
+ if (xs eq null) null
+ else WrappedArray.make(xs)
+
+ // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef]
+ // is as good as another for all T <: AnyRef. Instead of creating 100,000,000
+ // unique ones by way of this implicit, let's share one.
+ implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = {
+ if (xs eq null) null
+ else if (xs.length == 0) WrappedArray.empty[T]
+ else new WrappedArray.ofRef[T](xs)
+ }
+
+ implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = if (xs ne null) new WrappedArray.ofInt(xs) else null
+ implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = if (xs ne null) new WrappedArray.ofDouble(xs) else null
+ implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = if (xs ne null) new WrappedArray.ofLong(xs) else null
+ implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = if (xs ne null) new WrappedArray.ofFloat(xs) else null
+ implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = if (xs ne null) new WrappedArray.ofChar(xs) else null
+ implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = if (xs ne null) new WrappedArray.ofByte(xs) else null
+ implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = if (xs ne null) new WrappedArray.ofShort(xs) else null
+ implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = if (xs ne null) new WrappedArray.ofBoolean(xs) else null
+ implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = if (xs ne null) new WrappedArray.ofUnit(xs) else null
+
+ implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null
+ implicit def unwrapString(ws: WrappedString): String = if (ws ne null) ws.self else null
+
+ implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] =
+ new CanBuildFrom[String, T, immutable.IndexedSeq[T]] {
+ def apply(from: String) = immutable.IndexedSeq.newBuilder[T]
+ def apply() = immutable.IndexedSeq.newBuilder[T]
+ }
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.