diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-04-15 18:58:34 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-04-15 18:58:34 -0700 |
commit | 835fbfb152f8f806639473a96883e002bd8706c4 (patch) | |
tree | e18fa104f0190648b09a9c3ed526a196fd64157d /src | |
parent | 432faaada5bd7f2b622092570ab9f65f7053cf51 (diff) | |
parent | 66904556ef34dc81cbb7c09257b013b3ddb76f78 (diff) | |
download | scala-835fbfb152f8f806639473a96883e002bd8706c4.tar.gz scala-835fbfb152f8f806639473a96883e002bd8706c4.tar.bz2 scala-835fbfb152f8f806639473a96883e002bd8706c4.zip |
Merge pull request #2368 from retronym/ticket/7335
SI-7335 Simpler bootstrapping the standard library
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 5 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 9 | ||||
-rw-r--r-- | src/library/scala/LowPriorityImplicits.scala | 95 | ||||
-rw-r--r-- | src/library/scala/Predef.scala | 85 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Symbols.scala | 20 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeInfo.scala | 23 |
7 files changed, 118 insertions, 127 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 6a0f4407fc..0731d78a9b 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -87,12 +87,4 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo { case DocDef(_, definition) => isPureDef(definition) case _ => super.isPureDef(tree) } - - /** Does list of trees start with a definition of - * a class of module with given name (ignoring imports) - */ - override def firstDefinesClassOrObject(trees: List[Tree], name: Name): Boolean = trees match { - case ClassDef(_, `name`, _, _) :: Nil => true - case _ => super.firstDefinesClassOrObject(trees, name) - } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index e89a860e0f..f135f7f6ae 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -81,7 +81,10 @@ trait Contexts { self: Analyzer => if (settings.noimports) Nil else if (unit.isJava) RootImports.javaList - else if (settings.nopredef || treeInfo.noPredefImportForUnit(unit.body)) RootImports.javaAndScalaList + else if (settings.nopredef || treeInfo.noPredefImportForUnit(unit.body)) { + debuglog("Omitted import of Predef._ for " + unit) + RootImports.javaAndScalaList + } else RootImports.completeList } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ece6da2358..a75061c492 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/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 diff --git a/src/library/scala/LowPriorityImplicits.scala b/src/library/scala/LowPriorityImplicits.scala deleted file mode 100644 index 535f1ac699..0000000000 --- a/src/library/scala/LowPriorityImplicits.scala +++ /dev/null @@ -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] - } -} - diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 9a468489a2..569157de20 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -446,3 +446,88 @@ 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 template 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] + } +} diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 76ed9b8af7..a87d002f25 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -887,9 +887,23 @@ trait Symbols extends api.Symbols { self: SymbolTable => supersym == NoSymbol || supersym.isIncompleteIn(base) } - // Does not always work if the rawInfo is a SourcefileLoader, see comment - // in "def coreClassesFirst" in Global. - def exists = !isTopLevel || { rawInfo.load(this); rawInfo != NoType } + def exists: Boolean = !isTopLevel || { + val isSourceLoader = rawInfo match { + case sl: SymLoader => sl.fromSource + case _ => false + } + def warnIfSourceLoader() { + if (isSourceLoader) + // Predef is completed early due to its autoimport; we used to get here when type checking its + // parent LowPriorityImplicits. See comment in c5441dc for more elaboration. + // Since the fix for SI-7335 Predef parents must be defined in Predef.scala, and we should not + // get here anymore. + devWarning(s"calling Symbol#exists with sourcefile based symbol loader may give incorrect results."); + } + + rawInfo load this + rawInfo != NoType || { warnIfSourceLoader(); false } + } final def isInitialized: Boolean = validTo != NoPeriod diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index b1f58814c7..3296353b6b 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -663,20 +663,9 @@ abstract class TreeInfo { unapply(dissectApplied(tree)) } - /** Does list of trees start with a definition of - * a class of module with given name (ignoring imports) - */ - def firstDefinesClassOrObject(trees: List[Tree], name: Name): Boolean = trees match { - case Import(_, _) :: xs => firstDefinesClassOrObject(xs, name) - case Annotated(_, tree1) :: Nil => firstDefinesClassOrObject(List(tree1), name) - case ModuleDef(_, `name`, _) :: Nil => true - case ClassDef(_, `name`, _, _) :: Nil => true - case _ => false - } - - /** Is this file the body of a compilation unit which should not - * have Predef imported? + * have Predef imported? This is the case iff the first import in the + * unit explicitly refers to Predef. */ def noPredefImportForUnit(body: Tree) = { // Top-level definition whose leading imports include Predef. @@ -685,13 +674,7 @@ abstract class TreeInfo { case Import(expr, _) => isReferenceToPredef(expr) case _ => false } - // Compilation unit is class or object 'name' in package 'scala' - def isUnitInScala(tree: Tree, name: Name) = tree match { - case PackageDef(Ident(nme.scala_), defs) => firstDefinesClassOrObject(defs, name) - case _ => false - } - - isUnitInScala(body, nme.Predef) || isLeadingPredefImport(body) + isLeadingPredefImport(body) } def isAbsTypeDef(tree: Tree) = tree match { |