summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build/maven/maven-deploy.xml21
-rw-r--r--src/build/pack.xml26
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala852
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala225
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala3
-rw-r--r--src/reflect/scala/reflect/api/Trees.scala28
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala2
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala74
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala48
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala10
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala13
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala51
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala173
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala67
-rw-r--r--src/reflect/scala/reflect/internal/Variances.scala3
-rw-r--r--src/reflect/scala/reflect/internal/pickling/Translations.scala128
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala514
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala25
-rw-r--r--src/reflect/scala/reflect/internal/tpe/GlbLubs.scala7
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeComparers.scala64
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala43
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeMaps.scala7
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/Gil.scala25
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala52
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala72
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala496
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala5
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala91
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolTable.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala53
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala129
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala85
-rw-r--r--src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala28
-rw-r--r--src/reflect/scala/reflect/runtime/TwoWayCaches.scala68
44 files changed, 2053 insertions, 1507 deletions
diff --git a/src/build/maven/maven-deploy.xml b/src/build/maven/maven-deploy.xml
index 946b712b6c..fbd6d4cd51 100644
--- a/src/build/maven/maven-deploy.xml
+++ b/src/build/maven/maven-deploy.xml
@@ -74,12 +74,21 @@
<artifact:attach type="jar" file="${path}-docs.jar" classifier="javadoc" />
</artifact:deploy>
</then><else>
- <artifact:install file="${path}.jar">
- <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" />
- <artifact:pom refid="@{name}.pom" />
- <artifact:attach type="jar" file="${path}-src.jar" classifier="sources" />
- <artifact:attach type="jar" file="${path}-docs.jar" classifier="javadoc" />
- </artifact:install>
+ <if><isset property="docs.skip"/><then>
+ <artifact:install file="${path}.jar">
+ <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" />
+ <artifact:pom refid="@{name}.pom" />
+ <artifact:attach type="jar" file="${path}-src.jar" classifier="sources" />
+ </artifact:install>
+ </then>
+ <else>
+ <artifact:install file="${path}.jar">
+ <artifact:localRepository path="${local.repository}" id="${repository.credentials.id}" />
+ <artifact:pom refid="@{name}.pom" />
+ <artifact:attach type="jar" file="${path}-src.jar" classifier="sources" />
+ </artifact:install>
+ </else>
+ </if>
</else></if>
</then><else>
<local name="repo"/>
diff --git a/src/build/pack.xml b/src/build/pack.xml
index ed628726fb..4c5ba228fc 100644
--- a/src/build/pack.xml
+++ b/src/build/pack.xml
@@ -56,7 +56,7 @@ MAIN DISTRIBUTION PACKAGING
<checksum file="${dists.dir}/archives/${dist.name}.zip" fileext=".md5"/>
</target>
- <target name="pack-devel-docs.tar" depends="pack-archives.zip">
+ <target name="pack-devel-docs.tar" depends="pack-archives.zip" unless="docs.skip">
<tar destfile="${dists.dir}/archives/${dist.name}-devel-docs.tar"
compression="none" longfile="gnu">
<tarfileset dir="${dist.dir}/doc/scala-devel-docs" prefix="${dist.name}-devel-docs"/>
@@ -119,11 +119,11 @@ MAIN DISTRIBUTION PACKAGING
`resource` is relative to directory of `link` -->
<symlink link="${dists.dir}/archives/scala-latest-sources.tgz"
resource="scala-${version.number}-sources.tgz"
- overwrite="yes"/>
+ overwrite="true"/>
</target>
<target name="pack-archives.latest.win" depends="pack-archives.src" if="os.win">
- <copy tofile="${dists.dir}/archives/scala-latest-sources.tgz">
+ <copy tofile="${dists.dir}/archives/scala-latest-sources.tgz" overwrite="true">
<fileset dir="${dists.dir}/archives">
<include name="scala-${version.number}-sources.tgz"/>
</fileset>
@@ -141,7 +141,7 @@ MAIN DISTRIBUTION PACKAGING
<attribute name="mvn.artifact.name"/>
<sequential>
<mkdir dir="${dists.dir}/maven/${version.number}/@{mvn.artifact.name}"/>
- <copy todir="${dists.dir}/maven/${version.number}/@{mvn.artifact.name}">
+ <copy verbose="true" overwrite="true" todir="${dists.dir}/maven/${version.number}/@{mvn.artifact.name}">
<fileset dir="${dist.dir}/lib/">
<filename name="@{mvn.artifact.name}.jar"/>
</fileset>
@@ -167,7 +167,7 @@ MAIN DISTRIBUTION PACKAGING
<attribute name="mvn.artifact.name"/>
<sequential>
<mkdir dir="${dists.dir}/maven/${version.number}/plugins/@{mvn.artifact.name}"/>
- <copy todir="${dists.dir}/maven/${version.number}/plugins/@{mvn.artifact.name}">
+ <copy todir="${dists.dir}/maven/${version.number}/plugins/@{mvn.artifact.name}" overwrite="true">
<fileset dir="${dist.dir}/misc/scala-devel/plugins/">
<filename name="@{mvn.artifact.name}.jar"/>
</fileset>
@@ -189,7 +189,7 @@ MAIN DISTRIBUTION PACKAGING
</jar>
</target>
- <target name="pack-maven.docs" depends="pack-maven.libs, pack-maven.plugins">
+ <target name="pack-maven.docs" depends="pack-maven.libs, pack-maven.plugins" unless="docs.skip">
<jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"
basedir="${build-docs.dir}/library">
<include name="**/*"/>
@@ -209,30 +209,30 @@ MAIN DISTRIBUTION PACKAGING
<!-- TODO - Scala swing and actors should maybe have thier own jar, but creating it is SLOW. -->
<copy tofile="${dists.dir}/maven/${version.number}/scala-swing/scala-swing-docs.jar"
- file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"/>
+ file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar" overwrite="true"/>
<copy tofile="${dists.dir}/maven/${version.number}/scala-actors/scala-actors-docs.jar"
- file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"/>
+ file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar" overwrite="true"/>
<copy tofile="${dists.dir}/maven/${version.number}/scala-reflect/scala-reflect-docs.jar"
- file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"/>
+ file="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar" overwrite="true"/>
</target>
<target name="pack-maven.latest.unix" depends="pack-maven.docs" unless="os.win">
<symlink link="${dists.dir}/maven/latest"
resource="${version.number}"
- overwrite="yes"/>
+ overwrite="true"/>
</target>
<target name="pack-maven.latest.win" depends="pack-maven.docs" if="os.win">
- <copy todir="${dists.dir}/maven/latest">
+ <copy todir="${dists.dir}/maven/latest" overwrite="true">
<fileset dir="${dists.dir}/maven/${version.number}"/>
</copy>
</target>
<target name="pack-maven.scripts" depends="pack-maven.latest.unix,pack-maven.latest.win,pack-maven.srcs">
<copy todir="${dists.dir}/maven/${version.number}"
- file="${lib-ant.dir}/ant-contrib.jar"/>
+ file="${lib-ant.dir}/ant-contrib.jar" overwrite="true"/>
<copy todir="${dists.dir}/maven/${version.number}"
- file="${lib-ant.dir}/maven-ant-tasks-2.1.1.jar"/>
+ file="${lib-ant.dir}/maven-ant-tasks-2.1.1.jar" overwrite="true"/>
<copy tofile="${dists.dir}/maven/${version.number}/build.xml"
file="${src.dir}/build/maven/maven-deploy.xml"/>
<!-- export properties for use when deploying -->
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 1f80aa4b6f..01d5791f60 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -176,8 +176,8 @@ trait ScalaSettings extends AbsScalaSettings
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "")
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
- val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").
- withDeprecationMessage("This flag is scheduled for removal in 2.12. If you have a case where you need this flag then please report a bug.")
+ val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
+ val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
val Yinvalidate = StringSetting ("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "")
val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes")
val YdisableUnreachablePrevention = BooleanSetting("-Ydisable-unreachable-prevention", "Disable the prevention of unreachable blocks in code generation.")
@@ -185,6 +185,8 @@ trait ScalaSettings extends AbsScalaSettings
val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
+ private def removalIn212 = "This flag is scheduled for removal in 2.12. If you have a case where you need this flag then please report a bug."
+
/** Area-specific debug output.
*/
val Ydocdebug = BooleanSetting("-Ydoc-debug", "Trace all scaladoc activity.")
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 9ac1ce1b9c..ce3e7b1bb5 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -11,6 +11,7 @@ import java.lang.Float.floatToIntBits
import java.lang.Double.doubleToLongBits
import scala.io.Codec
import scala.reflect.internal.pickling.{ PickleBuffer, PickleFormat }
+import scala.reflect.internal.util.shortClassOfInstance
import scala.collection.mutable.LinkedHashMap
import PickleFormat._
import Flags._
@@ -80,7 +81,7 @@ abstract class Pickler extends SubComponent {
private var entries = new Array[AnyRef](256)
private var ep = 0
private val index = new LinkedHashMap[AnyRef, Int]
- private lazy val nonClassRoot = findOrElse(root.ownersIterator)(!_.isClass)(NoSymbol)
+ private lazy val nonClassRoot = findSymbol(root.ownersIterator)(!_.isClass)
private def isRootSym(sym: Symbol) =
sym.name.toTermName == rootName && sym.owner == rootOwner
@@ -106,13 +107,14 @@ abstract class Pickler extends SubComponent {
* anyway? This is the case if symbol is a refinement class,
* an existentially bound variable, or a higher-order type parameter.
*/
- private def isLocal(sym: Symbol): Boolean =
- !sym.isPackageClass && sym != NoSymbol &&
- (isRootSym(sym) ||
- sym.isRefinementClass ||
- sym.isAbstractType && sym.hasFlag(EXISTENTIAL) || // existential param
- sym.isParameter ||
- isLocal(sym.owner))
+ private def isLocal(sym: Symbol): Boolean = (sym != NoSymbol) && !sym.isPackageClass && (
+ isRootSym(sym)
+ || sym.isRefinementClass
+ || sym.isAbstractType && sym.hasFlag(EXISTENTIAL) // existential param
+ || sym.isParameter
+ || isLocal(sym.owner)
+ )
+ private def isExternalSymbol(sym: Symbol): Boolean = (sym != NoSymbol) && !isLocal(sym)
// Phase 1 methods: Populate entries/index ------------------------------------
@@ -135,13 +137,18 @@ abstract class Pickler extends SubComponent {
true
}
+ private def deskolemizeTypeSymbols(ref: AnyRef): AnyRef = ref match {
+ case sym: Symbol => deskolemize(sym)
+ case _ => ref
+ }
+
/** If the symbol is a type skolem, deskolemize and log it.
* If we fail to deskolemize, in a method like
* trait Trait[+A] { def f[CC[X]] : CC[A] }
* the applied type CC[A] will hold a different CC symbol
* than the type-constructor type-parameter CC.
*/
- private def deskolemize(sym: Symbol) = {
+ private def deskolemize(sym: Symbol): Symbol = {
if (sym.isTypeSkolem) {
val sym1 = sym.deSkolemize
log({
@@ -169,7 +176,7 @@ abstract class Pickler extends SubComponent {
putSymbol(sym.owner)
putSymbol(sym.privateWithin)
putType(sym.info)
- if (sym.thisSym.tpeHK != sym.tpeHK)
+ if (sym.hasSelfType)
putType(sym.typeOfThis)
putSymbol(sym.alias)
if (!sym.children.isEmpty) {
@@ -202,252 +209,65 @@ abstract class Pickler extends SubComponent {
case ThisType(sym) =>
putSymbol(sym)
case SingleType(pre, sym) =>
- putType(pre); putSymbol(sym)
+ putType(pre)
+ putSymbol(sym)
case SuperType(thistpe, supertpe) =>
putType(thistpe)
putType(supertpe)
case ConstantType(value) =>
putConstant(value)
case TypeRef(pre, sym, args) =>
-// if (sym.isAbstractType && (sym hasFlag EXISTENTIAL))
-// if (!(boundSyms contains sym))
-// println("unbound existential: "+sym+sym.locationString)
- putType(pre); putSymbol(sym); putTypes(args)
+ putType(pre)
+ putSymbol(sym)
+ putTypes(args)
case TypeBounds(lo, hi) =>
- putType(lo); putType(hi)
- case RefinedType(parents, decls) =>
- val rclazz = tp.typeSymbol
- for (m <- decls.iterator)
- if (m.owner != rclazz) abort("bad refinement member "+m+" of "+tp+", owner = "+m.owner)
- putSymbol(rclazz); putTypes(parents); putSymbols(decls.toList)
- case ClassInfoType(parents, decls, clazz) =>
- putSymbol(clazz); putTypes(parents); putSymbols(decls.toList)
+ putType(lo)
+ putType(hi)
+ case tp: CompoundType =>
+ putSymbol(tp.typeSymbol)
+ putTypes(tp.parents)
+ putSymbols(tp.decls.toList)
case MethodType(params, restpe) =>
- putType(restpe); putSymbols(params)
+ putType(restpe)
+ putSymbols(params)
case NullaryMethodType(restpe) =>
putType(restpe)
case PolyType(tparams, restpe) =>
- /* no longer needed since all params are now local
- tparams foreach { tparam =>
- if (!isLocal(tparam)) locals += tparam // similar to existential types, these tparams are local
- }
- */
- putType(restpe); putSymbols(tparams)
+ putType(restpe)
+ putSymbols(tparams)
case ExistentialType(tparams, restpe) =>
-// val savedBoundSyms = boundSyms // boundSyms are known to be local based on the EXISTENTIAL flag (see isLocal)
-// boundSyms = tparams ::: boundSyms
-// try {
- putType(restpe)
- // } finally {
-// boundSyms = savedBoundSyms
-// }
+ putType(restpe)
putSymbols(tparams)
- case AnnotatedType(annotations, underlying, selfsym) =>
+ case AnnotatedType(_, underlying, selfsym) =>
putType(underlying)
if (settings.selfInAnnots) putSymbol(selfsym)
- putAnnotations(annotations filter (_.isStatic))
+ tp.staticAnnotations foreach putAnnotation
case _ =>
throw new FatalError("bad type: " + tp + "(" + tp.getClass + ")")
}
}
private def putTypes(tps: List[Type]) { tps foreach putType }
- private def putTree(tree: Tree): Unit = if (putEntry(tree)) {
- if (tree != EmptyTree)
- putType(tree.tpe)
- if (tree.hasSymbolField)
- putSymbol(tree.symbol)
-
- tree match {
- case EmptyTree =>
-
- case tree@PackageDef(pid, stats) =>
- putTree(pid)
- putTrees(stats)
-
- case ClassDef(mods, name, tparams, impl) =>
- putMods(mods)
- putEntry(name)
- putTree(impl)
- putTrees(tparams)
-
- case ModuleDef(mods, name, impl) =>
- putMods(mods)
- putEntry(name)
- putTree(impl)
-
- case ValDef(mods, name, tpt, rhs) =>
- putMods(mods)
- putEntry(name)
- putTree(tpt)
- putTree(rhs)
-
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- putMods(mods)
- putEntry(name)
- putTrees(tparams)
- putTreess(vparamss)
- putTree(tpt)
- putTree(rhs)
-
- case TypeDef(mods, name, tparams, rhs) =>
- putMods(mods)
- putEntry(name)
- putTree(rhs)
- putTrees(tparams)
-
- case LabelDef(name, params, rhs) =>
- putEntry(name)
- putTree(rhs)
- putTrees(params)
-
- case Import(expr, selectors) =>
- putTree(expr)
- for (ImportSelector(from, _, to, _) <- selectors) {
- putEntry(from)
- putEntry(to)
- }
-/*
- case DocDef(comment, definition) => should not be needed
- putConstant(Constant(comment))
- putTree(definition)
-*/
- case Template(parents, self, body) =>
- putTrees(parents)
- putTree(self)
- putTrees(body)
-
- case Block(stats, expr) =>
- putTree(expr)
- putTrees(stats)
-
- case CaseDef(pat, guard, body) =>
- putTree(pat)
- putTree(guard)
- putTree(body)
-
- case Alternative(trees) =>
- putTrees(trees)
-
- case Star(elem) =>
- putTree(elem)
-
- case Bind(name, body) =>
- putEntry(name)
- putTree(body)
-
- case UnApply(fun: Tree, args) =>
- putTree(fun)
- putTrees(args)
-
- case ArrayValue(elemtpt, trees) =>
- putTree(elemtpt)
- putTrees(trees)
-
-
- case Function(vparams, body) =>
- putTree(body)
- putTrees(vparams)
-
- case Assign(lhs, rhs) =>
- putTree(lhs)
- putTree(rhs)
-
- case If(cond, thenp, elsep) =>
- putTree(cond)
- putTree(thenp)
- putTree(elsep)
-
- case Match(selector, cases) =>
- putTree(selector)
- putTrees(cases)
-
- case Return(expr) =>
- putTree(expr)
-
- case Try(block, catches, finalizer) =>
- putTree(block)
- putTree(finalizer)
- putTrees(catches)
-
- case Throw(expr) =>
- putTree(expr)
-
- case New(tpt) =>
- putTree(tpt)
-
- case Typed(expr, tpt) =>
- putTree(expr)
- putTree(tpt)
-
- case TypeApply(fun, args) =>
- putTree(fun)
- putTrees(args)
-
- case Apply(fun, args) =>
- putTree(fun)
- putTrees(args)
-
- case ApplyDynamic(qual, args) =>
- putTree(qual)
- putTrees(args)
-
- case Super(qual, mix) =>
- putTree(qual)
- putEntry(mix:Name)
-
- case This(qual) =>
- putEntry(qual)
-
- case Select(qualifier, selector) =>
- putTree(qualifier)
- putEntry(selector)
-
- case Ident(name) =>
- putEntry(name)
-
- case Literal(value) =>
- putEntry(value)
-
- case TypeTree() =>
-
- case Annotated(annot, arg) =>
- putTree(annot)
- putTree(arg)
-
- case SingletonTypeTree(ref) =>
- putTree(ref)
-
- case SelectFromTypeTree(qualifier, selector) =>
- putTree(qualifier)
- putEntry(selector)
-
- case CompoundTypeTree(templ: Template) =>
- putTree(templ)
-
- case AppliedTypeTree(tpt, args) =>
- putTree(tpt)
- putTrees(args)
-
- case TypeBoundsTree(lo, hi) =>
- putTree(lo)
- putTree(hi)
-
- case ExistentialTypeTree(tpt, whereClauses) =>
- putTree(tpt)
- putTrees(whereClauses)
+ private object putTreeTraverser extends Traverser {
+ // Only used when pickling trees, i.e. in an argument of some Annotation
+ // annotations in Modifiers are removed by the typechecker
+ override def traverseModifiers(mods: Modifiers): Unit = if (putEntry(mods)) putEntry(mods.privateWithin)
+ override def traverseName(name: Name): Unit = putEntry(name)
+ override def traverseConstant(const: Constant): Unit = putEntry(const)
+ override def traverse(tree: Tree): Unit = putTree(tree)
+
+ def put(tree: Tree): Unit = {
+ if (tree.canHaveAttrs)
+ putType(tree.tpe)
+ if (tree.hasSymbolField)
+ putSymbol(tree.symbol)
+
+ super.traverse(tree)
}
}
-
- private def putTrees(trees: List[Tree]) = trees foreach putTree
- private def putTreess(treess: List[List[Tree]]) = treess foreach putTrees
-
- /** only used when pickling trees, i.e. in an
- * argument of some Annotation */
- private def putMods(mods: Modifiers) = if (putEntry(mods)) {
- // annotations in Modifiers are removed by the typechecker
- val Modifiers(_, privateWithin, Nil) = mods
- putEntry(privateWithin)
+ private def putTree(tree: Tree) {
+ if (putEntry(tree))
+ putTreeTraverser put tree
}
/** Store a constant in map index, along with anything it references.
@@ -461,7 +281,7 @@ abstract class Pickler extends SubComponent {
}
private def putChildren(sym: Symbol, children: List[Symbol]) {
- assert(putEntry((sym, children)))
+ putEntry(sym -> children)
children foreach putSymbol
}
@@ -469,14 +289,10 @@ abstract class Pickler extends SubComponent {
private def putAnnotation(sym: Symbol, annot: AnnotationInfo) {
// if an annotation with the same arguments is applied to the
// same symbol multiple times, it's only pickled once.
- if (putEntry((sym, annot)))
+ if (putEntry(sym -> annot))
putAnnotationBody(annot)
}
- /** used in AnnotatedType only, i.e. annotations on types */
- private def putAnnotations(annots: List[AnnotationInfo]) {
- annots foreach putAnnotation
- }
private def putAnnotation(annot: AnnotationInfo) {
if (putEntry(annot))
putAnnotationBody(annot)
@@ -510,14 +326,11 @@ abstract class Pickler extends SubComponent {
/** Write a reference to object, i.e., the object's number in the map index.
*/
- private def writeRef(ref0: AnyRef) {
- val ref = ref0 match {
- case sym: Symbol => deskolemize(sym)
- case _ => ref0
- }
- writeNat(index(ref))
+ private def writeRef(ref: AnyRef) {
+ writeNat(index(deskolemizeTypeSymbols(ref)))
}
- private def writeRefs(refs: List[AnyRef]) { refs foreach writeRef }
+ private def writeRefs(refs: List[AnyRef]): Unit = refs foreach writeRef
+
private def writeRefsWithLength(refs: List[AnyRef]) {
writeNat(refs.length)
writeRefs(refs)
@@ -567,446 +380,137 @@ abstract class Pickler extends SubComponent {
}
}
- /** Write an entry */
- private def writeEntry(entry: AnyRef) {
- def writeBody(entry: AnyRef): Int = entry match {
- case name: Name =>
- writeName(name)
- if (name.isTermName) TERMname else TYPEname
- case NoSymbol =>
- NONEsym
- case sym: Symbol if !isLocal(sym) =>
- val tag =
- if (sym.isModuleClass) {
- writeRef(sym.name.toTermName); EXTMODCLASSref
- } else {
- writeRef(sym.name); EXTref
- }
- if (!sym.owner.isRoot) writeRef(sym.owner)
- tag
- case sym: ClassSymbol =>
- writeSymInfo(sym)
- if (sym.thisSym.tpe_* != sym.tpe_*) writeRef(sym.typeOfThis)
- CLASSsym
- case sym: TypeSymbol =>
- writeSymInfo(sym)
- if (sym.isAbstractType) TYPEsym else ALIASsym
- case sym: TermSymbol =>
- writeSymInfo(sym)
- if (sym.alias != NoSymbol) writeRef(sym.alias)
- if (sym.isModule) MODULEsym else VALsym
- case NoType =>
- NOtpe
- case NoPrefix =>
- NOPREFIXtpe
- case ThisType(sym) =>
- writeRef(sym); THIStpe
- case SingleType(pre, sym) =>
- writeRef(pre); writeRef(sym); SINGLEtpe
- case SuperType(thistpe, supertpe) =>
- writeRef(thistpe); writeRef(supertpe); SUPERtpe
- case ConstantType(value) =>
- writeRef(value); CONSTANTtpe
- case TypeRef(pre, sym, args) =>
- writeRef(pre); writeRef(sym); writeRefs(args); TYPEREFtpe
- case TypeBounds(lo, hi) =>
- writeRef(lo); writeRef(hi); TYPEBOUNDStpe
- case tp @ RefinedType(parents, decls) =>
- writeRef(tp.typeSymbol); writeRefs(parents); REFINEDtpe
- case ClassInfoType(parents, decls, clazz) =>
- writeRef(clazz); writeRefs(parents); CLASSINFOtpe
- case mt @ MethodType(formals, restpe) =>
- writeRef(restpe); writeRefs(formals) ; METHODtpe
- case mt @ NullaryMethodType(restpe) =>
- // reuse POLYtpe since those can never have an empty list of tparams.
- // TODO: is there any way this can come back and bite us in the bottom?
- // ugliness and thrift aside, this should make this somewhat more backward compatible
- // (I'm not sure how old scalac's would deal with nested PolyTypes, as these used to be folded into one)
- writeRef(restpe); writeRefs(Nil); POLYtpe
- case PolyType(tparams, restpe) => // invar: tparams nonEmpty
- writeRef(restpe); writeRefs(tparams); POLYtpe
- case ExistentialType(tparams, restpe) =>
- writeRef(restpe); writeRefs(tparams); EXISTENTIALtpe
- case c @ Constant(_) =>
- if (c.tag == BooleanTag) writeLong(if (c.booleanValue) 1 else 0)
- else if (ByteTag <= c.tag && c.tag <= LongTag) writeLong(c.longValue)
- else if (c.tag == FloatTag) writeLong(floatToIntBits(c.floatValue).toLong)
- else if (c.tag == DoubleTag) writeLong(doubleToLongBits(c.doubleValue))
- else if (c.tag == StringTag) writeRef(newTermName(c.stringValue))
- else if (c.tag == ClazzTag) writeRef(c.typeValue)
- else if (c.tag == EnumTag) writeRef(c.symbolValue)
- LITERAL + c.tag // also treats UnitTag, NullTag; no value required
- case AnnotatedType(annotations, tp, selfsym) =>
- annotations filter (_.isStatic) match {
- case Nil => writeBody(tp) // write the underlying type if there are no annotations
- case staticAnnots =>
- if (settings.selfInAnnots && selfsym != NoSymbol)
- writeRef(selfsym)
- writeRef(tp)
- writeRefs(staticAnnots)
- ANNOTATEDtpe
- }
- // annotations attached to a symbol (i.e. annots on terms)
- case (target: Symbol, annot@AnnotationInfo(_, _, _)) =>
- writeRef(target)
- writeAnnotation(annot)
- SYMANNOT
-
- case ArrayAnnotArg(args) =>
- args foreach writeClassfileAnnotArg
- ANNOTARGARRAY
-
- case (target: Symbol, children: List[_]) =>
- writeRef(target)
- writeRefs(children.asInstanceOf[List[Symbol]])
- CHILDREN
-
- case EmptyTree =>
- writeNat(EMPTYtree)
- TREE
-
- case tree@PackageDef(pid, stats) =>
- writeNat(PACKAGEtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(tree.mods)
- writeRef(pid)
- writeRefs(stats)
- TREE
-
- case tree@ClassDef(mods, name, tparams, impl) =>
- writeNat(CLASStree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(mods)
- writeRef(name)
- writeRef(impl)
- writeRefs(tparams)
- TREE
-
- case tree@ModuleDef(mods, name, impl) =>
- writeNat(MODULEtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(mods)
- writeRef(name)
- writeRef(impl)
- TREE
-
- case tree@ValDef(mods, name, tpt, rhs) =>
- writeNat(VALDEFtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(mods)
- writeRef(name)
- writeRef(tpt)
- writeRef(rhs)
- TREE
-
- case tree@DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- writeNat(DEFDEFtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(mods)
- writeRef(name)
- writeRefsWithLength(tparams)
- writeNat(vparamss.length)
- vparamss foreach writeRefsWithLength
- writeRef(tpt)
- writeRef(rhs)
- TREE
-
- case tree@TypeDef(mods, name, tparams, rhs) =>
- writeNat(TYPEDEFtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(mods)
- writeRef(name)
- writeRef(rhs)
- writeRefs(tparams)
- TREE
-
- case tree@LabelDef(name, params, rhs) =>
- writeNat(LABELtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(name)
- writeRef(rhs)
- writeRefs(params)
- TREE
-
- case tree@Import(expr, selectors) =>
- writeNat(IMPORTtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(expr)
- for (ImportSelector(from, _, to, _) <- selectors) {
- writeRef(from)
- writeRef(to)
- }
- TREE
-
- case tree@DocDef(comment, definition) =>
- writeNat(DOCDEFtree)
- writeRef(tree.tpe)
- writeRef(Constant(comment))
- writeRef(definition)
- TREE
-
- case tree@Template(parents, self, body) =>
- writeNat(TEMPLATEtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRefsWithLength(parents)
- writeRef(self)
- writeRefs(body)
- TREE
-
- case tree@Block(stats, expr) =>
- writeNat(BLOCKtree)
- writeRef(tree.tpe)
- writeRef(expr)
- writeRefs(stats)
- TREE
-
- case tree@CaseDef(pat, guard, body) =>
- writeNat(CASEtree)
- writeRef(tree.tpe)
- writeRef(pat)
- writeRef(guard)
- writeRef(body)
- TREE
-
- case tree@Alternative(trees) =>
- writeNat(ALTERNATIVEtree)
- writeRef(tree.tpe)
- writeRefs(trees)
- TREE
-
- case tree@Star(elem) =>
- writeNat(STARtree)
- writeRef(tree.tpe)
- writeRef(elem)
- TREE
-
- case tree@Bind(name, body) =>
- writeNat(BINDtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(name)
- writeRef(body)
- TREE
-
- case tree@UnApply(fun: Tree, args) =>
- writeNat(UNAPPLYtree)
- writeRef(tree.tpe)
- writeRef(fun)
- writeRefs(args)
- TREE
-
- case tree@ArrayValue(elemtpt, trees) =>
- writeNat(ARRAYVALUEtree)
- writeRef(tree.tpe)
- writeRef(elemtpt)
- writeRefs(trees)
- TREE
-
- case tree@Function(vparams, body) =>
- writeNat(FUNCTIONtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(body)
- writeRefs(vparams)
- TREE
-
- case tree@Assign(lhs, rhs) =>
- writeNat(ASSIGNtree)
- writeRef(tree.tpe)
- writeRef(lhs)
- writeRef(rhs)
- TREE
-
- case tree@If(cond, thenp, elsep) =>
- writeNat(IFtree)
- writeRef(tree.tpe)
- writeRef(cond)
- writeRef(thenp)
- writeRef(elsep)
- TREE
-
- case tree@Match(selector, cases) =>
- writeNat(MATCHtree)
- writeRef(tree.tpe)
- writeRef(selector)
- writeRefs(cases)
- TREE
-
- case tree@Return(expr) =>
- writeNat(RETURNtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(expr)
- TREE
-
- case tree@Try(block, catches, finalizer) =>
- writeNat(TREtree)
- writeRef(tree.tpe)
- writeRef(block)
- writeRef(finalizer)
- writeRefs(catches)
- TREE
-
- case tree@Throw(expr) =>
- writeNat(THROWtree)
- writeRef(tree.tpe)
- writeRef(expr)
- TREE
-
- case tree@New(tpt) =>
- writeNat(NEWtree)
- writeRef(tree.tpe)
- writeRef(tpt)
- TREE
-
- case tree@Typed(expr, tpt) =>
- writeNat(TYPEDtree)
- writeRef(tree.tpe)
- writeRef(expr)
- writeRef(tpt)
- TREE
-
- case tree@TypeApply(fun, args) =>
- writeNat(TYPEAPPLYtree)
- writeRef(tree.tpe)
- writeRef(fun)
- writeRefs(args)
- TREE
-
- case tree@Apply(fun, args) =>
- writeNat(APPLYtree)
- writeRef(tree.tpe)
- writeRef(fun)
- writeRefs(args)
- TREE
-
- case tree@ApplyDynamic(qual, args) =>
- writeNat(APPLYDYNAMICtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(qual)
- writeRefs(args)
- TREE
-
- case tree@Super(qual, mix) =>
- writeNat(SUPERtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(qual)
- writeRef(mix)
- TREE
-
- case tree@This(qual) =>
- writeNat(THIStree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(qual)
- TREE
-
- case tree@Select(qualifier, selector) =>
- writeNat(SELECTtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(qualifier)
- writeRef(selector)
- TREE
-
- case tree@Ident(name) =>
- writeNat(IDENTtree)
- writeRef(tree.tpe)
- writeRef(tree.symbol)
- writeRef(name)
- TREE
-
- case tree@Literal(value) =>
- writeNat(LITERALtree)
- writeRef(tree.tpe)
- writeRef(value)
- TREE
-
- case tree@TypeTree() =>
- writeNat(TYPEtree)
- writeRef(tree.tpe)
- TREE
-
- case tree@Annotated(annot, arg) =>
- writeNat(ANNOTATEDtree)
- writeRef(tree.tpe)
- writeRef(annot)
- writeRef(arg)
- TREE
-
- case tree@SingletonTypeTree(ref) =>
- writeNat(SINGLETONTYPEtree)
+ private object writeTreeBodyTraverser extends Traverser {
+ private var refs = false
+ @inline private def asRefs[T](body: => T): T = {
+ val saved = refs
+ refs = true
+ try body finally refs = saved
+ }
+ override def traverseModifiers(mods: Modifiers): Unit = if (refs) writeRef(mods) else super.traverseModifiers(mods)
+ override def traverseName(name: Name): Unit = writeRef(name)
+ override def traverseConstant(const: Constant): Unit = writeRef(const)
+ override def traverseParams(params: List[Tree]): Unit = writeRefsWithLength(params)
+ override def traverseParamss(vparamss: List[List[Tree]]): Unit = {
+ writeNat(vparamss.length)
+ super.traverseParamss(vparamss)
+ }
+ override def traverse(tree: Tree): Unit = {
+ if (refs)
+ writeRef(tree)
+ else {
writeRef(tree.tpe)
- writeRef(ref)
- TREE
+ if (tree.hasSymbolField)
+ writeRef(tree.symbol)
- case tree@SelectFromTypeTree(qualifier, selector) =>
- writeNat(SELECTFROMTYPEtree)
- writeRef(tree.tpe)
- writeRef(qualifier)
- writeRef(selector)
- TREE
+ asRefs(super.traverse(tree))
+ }
+ }
+ }
- case tree@CompoundTypeTree(templ: Template) =>
- writeNat(COMPOUNDTYPEtree)
- writeRef(tree.tpe)
- writeRef(templ)
- TREE
+ /** Write an entry */
+ private def writeEntry(entry: AnyRef) {
+ def writeLocalSymbolBody(sym: Symbol) {
+ writeSymInfo(sym)
+ sym match {
+ case _: ClassSymbol if sym.hasSelfType => writeRef(sym.typeOfThis)
+ case _: TermSymbol if sym.alias.exists => writeRef(sym.alias)
+ case _ =>
+ }
+ }
+ def writeExtSymbolBody(sym: Symbol) {
+ val name = if (sym.isModuleClass) sym.name.toTermName else sym.name
+ writeRef(name)
+ if (!sym.owner.isRoot)
+ writeRef(sym.owner)
+ }
+ def writeSymbolBody(sym: Symbol) {
+ if (sym ne NoSymbol) {
+ if (isLocal(sym))
+ writeLocalSymbolBody(sym)
+ else
+ writeExtSymbolBody(sym)
+ }
+ }
- case tree@AppliedTypeTree(tpt, args) =>
- writeNat(APPLIEDTYPEtree)
- writeRef(tree.tpe)
- writeRef(tpt)
- writeRefs(args)
- TREE
+ // NullaryMethodType reuses POLYtpe since those can never have an empty list of tparams.
+ // TODO: is there any way this can come back and bite us in the bottom?
+ // ugliness and thrift aside, this should make this somewhat more backward compatible
+ // (I'm not sure how old scalac's would deal with nested PolyTypes, as these used to be folded into one)
+ def writeTypeBody(tpe: Type): Unit = tpe match {
+ case NoType | NoPrefix =>
+ case ThisType(sym) => writeRef(sym)
+ case SingleType(pre, sym) => writeRef(pre) ; writeRef(sym)
+ case SuperType(thistpe, supertpe) => writeRef(thistpe) ; writeRef(supertpe)
+ case ConstantType(value) => writeRef(value)
+ case TypeBounds(lo, hi) => writeRef(lo) ; writeRef(hi)
+ case TypeRef(pre, sym, args) => writeRef(pre) ; writeRef(sym); writeRefs(args)
+ case MethodType(formals, restpe) => writeRef(restpe) ; writeRefs(formals)
+ case NullaryMethodType(restpe) => writeRef(restpe); writeRefs(Nil)
+ case PolyType(tparams, restpe) => writeRef(restpe); writeRefs(tparams)
+ case ExistentialType(tparams, restpe) => writeRef(restpe); writeRefs(tparams)
+ case StaticallyAnnotatedType(annots, tp) => writeRef(tp) ; writeRefs(annots)
+ case AnnotatedType(_, tp, _) => writeTypeBody(tp) // write the underlying type if there are no static annotations
+ case CompoundType(parents, _, clazz) => writeRef(clazz); writeRefs(parents)
+ }
- case tree@TypeBoundsTree(lo, hi) =>
- writeNat(TYPEBOUNDStree)
- writeRef(tree.tpe)
- writeRef(lo)
- writeRef(hi)
- TREE
+ def writeTreeBody(tree: Tree) {
+ writeNat(picklerSubTag(tree))
+ if (!tree.isEmpty)
+ writeTreeBodyTraverser traverse tree
+ }
- case tree@ExistentialTypeTree(tpt, whereClauses) =>
- writeNat(EXISTENTIALTYPEtree)
- writeRef(tree.tpe)
- writeRef(tpt)
- writeRefs(whereClauses)
- TREE
+ def writeConstant(c: Constant): Unit = c.tag match {
+ case BooleanTag => writeLong(if (c.booleanValue) 1 else 0)
+ case FloatTag => writeLong(floatToIntBits(c.floatValue).toLong)
+ case DoubleTag => writeLong(doubleToLongBits(c.doubleValue))
+ case StringTag => writeRef(newTermName(c.stringValue))
+ case ClazzTag => writeRef(c.typeValue)
+ case EnumTag => writeRef(c.symbolValue)
+ case tag => if (ByteTag <= tag && tag <= LongTag) writeLong(c.longValue)
+ }
- case Modifiers(flags, privateWithin, _) =>
- val pflags = rawToPickledFlags(flags)
- writeNat((pflags >> 32).toInt)
- writeNat((pflags & 0xFFFFFFFF).toInt)
- writeRef(privateWithin)
- MODIFIERS
+ def writeModifiers(mods: Modifiers) {
+ val pflags = rawToPickledFlags(mods.flags)
+ writeNat((pflags >> 32).toInt)
+ writeNat((pflags & 0xFFFFFFFF).toInt)
+ writeRef(mods.privateWithin)
+ }
- // annotations on types (not linked to a symbol)
- case annot@AnnotationInfo(_, _, _) =>
- writeAnnotation(annot)
- ANNOTINFO
+ def writeSymbolTuple(target: Symbol, other: Any) {
+ writeRef(target)
+ other match {
+ case annot: AnnotationInfo => writeAnnotation(annot)
+ case children: List[Symbol @unchecked] => writeRefs(children)
+ case _ =>
+ }
+ }
- case _ =>
- throw new FatalError("bad entry: " + entry + " " + entry.getClass)
+ def writeBody(entry: AnyRef): Unit = entry match {
+ case tree: Tree => writeTreeBody(tree)
+ case sym: Symbol => writeSymbolBody(sym)
+ case tpe: Type => writeTypeBody(tpe)
+ case name: Name => writeName(name)
+ case const: Constant => writeConstant(const)
+ case mods: Modifiers => writeModifiers(mods)
+ case annot: AnnotationInfo => writeAnnotation(annot)
+ case (target: Symbol, other) => writeSymbolTuple(target, other)
+ case ArrayAnnotArg(args) => args foreach writeClassfileAnnotArg
+ case _ => devWarning(s"Unexpected entry to pickler ${shortClassOfInstance(entry)} $entry")
}
// begin writeEntry
- val startpos = writeIndex
- // reserve some space so that the patchNat's most likely won't need to shift
- writeByte(0); writeByte(0)
- patchNat(startpos, writeBody(entry))
- patchNat(startpos + 1, writeIndex - (startpos + 2))
+ // The picklerTag method can't determine if it's an external symbol reference
+ val tag = entry match {
+ case sym: Symbol if isExternalSymbol(sym) => if (sym.isModuleClass) EXTMODCLASSref else EXTref
+ case _ => picklerTag(entry)
+ }
+ writeNat(tag)
+ writeByte(0) // reserve a place to record the number of bytes written
+ val start = writeIndex
+ writeBody(entry)
+ val length = writeIndex - start
+ patchNat(start - 1, length) // patch bytes written over the placeholder
}
/** Write byte array */
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index d97f62d5d6..ccf2266540 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -85,9 +85,6 @@ abstract class UnCurry extends InfoTransform
transformFunction(result)
}
- private lazy val serialVersionUIDAnnotation =
- AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List())
-
// I don't have a clue why I'm catching TypeErrors here, but it's better
// than spewing stack traces at end users for internal errors. Examples
// which hit at this point should not be hard to come by, but the immediate
@@ -220,7 +217,7 @@ abstract class UnCurry extends InfoTransform
case fun1 if fun1 ne fun => fun1
case _ =>
val parents = addSerializable(abstractFunctionForFunctionType(fun.tpe))
- val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation
+ val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation SerialVersionUIDAnnotation
anonClass setInfo ClassInfoType(parents, newScope, anonClass)
val targs = fun.tpe.typeArgs
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index b30ae917d9..c19d861d23 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -579,10 +579,10 @@ trait Implicits {
private def typedImplicit1(info: ImplicitInfo, isLocal: Boolean): SearchResult = {
if (Statistics.canEnable) Statistics.incCounter(matchingImplicits)
- val itree = atPos(pos.focus) {
- // workaround for deficient context provided by ModelFactoryImplicitSupport#makeImplicitConstraints
- val isScalaDoc = context.tree == EmptyTree
+ // workaround for deficient context provided by ModelFactoryImplicitSupport#makeImplicitConstraints
+ val isScalaDoc = context.tree == EmptyTree
+ val itree = atPos(pos.focus) {
if (isLocal && !isScalaDoc) {
// SI-4270 SI-5376 Always use an unattributed Ident for implicits in the local scope,
// rather than an attributed Select, to detect shadowing.
@@ -605,7 +605,23 @@ trait Implicits {
atPos(itree.pos)(Apply(itree, List(Ident("<argument>") setType approximate(arg1)))),
EXPRmode,
approximate(arg2)
- )
+ ) match {
+ // try to infer implicit parameters immediately in order to:
+ // 1) guide type inference for implicit views
+ // 2) discard ineligible views right away instead of risking spurious ambiguous implicits
+ //
+ // this is an improvement of the state of the art that brings consistency to implicit resolution rules
+ // (and also helps fundep materialization to be applicable to implicit views)
+ //
+ // there's one caveat though. we need to turn this behavior off for scaladoc
+ // because scaladoc usually doesn't know the entire story
+ // and is just interested in views that are potentially applicable
+ // for instance, if we have `class C[T]` and `implicit def conv[T: Numeric](c: C[T]) = ???`
+ // then Scaladoc will give us something of type `C[T]`, and it would like to know
+ // that `conv` is potentially available under such and such conditions
+ case tree if isImplicitMethodType(tree.tpe) && !isScalaDoc => applyImplicitArgs(tree)
+ case tree => tree
+ }
case _ => fallback
}
context.firstError match { // using match rather than foreach to avoid non local return.
@@ -617,7 +633,7 @@ trait Implicits {
if (Statistics.canEnable) Statistics.incCounter(typedImplicits)
- val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun }
+ val itree2 = if (isView) treeInfo.dissectApplied(itree1).callee
else adapt(itree1, EXPRmode, wildPt)
typingStack.showAdapt(itree, itree2, pt, context)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index ccf4a5e46f..dd0923a696 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -913,7 +913,11 @@ trait Infer extends Checkable {
val targs = exprTypeArgs(tvars, tparams, treeTp, pt, useWeaklyCompatible)
def infer_s = map3(tparams, tvars, targs)((tparam, tvar, targ) => s"$tparam=$tvar/$targ") mkString ","
printTyping(tree, s"infer expr instance from pt=$pt, $infer_s")
- def targsStrict = if (targs eq null) null else targs mapConserve dropByName
+
+ // SI-7899 infering by-name types is unsound. The correct behaviour is conditional because the hole is
+ // exploited in Scalaz (Free.scala), as seen in: run/t7899-regression.
+ def dropByNameIfStrict(tp: Type): Type = if (settings.inferByName) tp else dropByName(tp)
+ def targsStrict = if (targs eq null) null else targs mapConserve dropByNameIfStrict
if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226
substExpr(tree, tparams, targsStrict, pt)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 599969598e..e3d7bfd4f8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -425,11 +425,10 @@ trait Namers extends MethodSynthesis {
sym
}
- /** Enter a module symbol. The tree parameter can be either
- * a module definition or a class definition.
+ /** Enter a module symbol.
*/
def enterModuleSymbol(tree : ModuleDef): Symbol = {
- var m: Symbol = context.scope lookupAll tree.name find (_.isModule) getOrElse NoSymbol
+ var m: Symbol = context.scope lookupModule tree.name
val moduleFlags = tree.mods.flags | MODULE
if (m.isModule && !m.isPackage && inCurrentScope(m) && (currentRun.canRedefine(m) || m.isSynthetic)) {
updatePosFlags(m, tree.pos, moduleFlags)
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index a9a7f6a954..36f889f8a4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1414,7 +1414,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
private def checkTypeRef(tp: Type, tree: Tree, skipBounds: Boolean) = tp match {
case TypeRef(pre, sym, args) =>
- checkDeprecated(sym, tree.pos)
+ tree match {
+ case tt: TypeTree if tt.original == null => // SI-7783 don't warn about inferred types
+ case _ =>
+ checkDeprecated(sym, tree.pos)
+ }
if(sym.isJavaDefined)
sym.typeParams foreach (_.cookJavaRawInfo())
if (!tp.isHigherKinded && !skipBounds)
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 1b726c37b9..fd8f9bebba 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -283,6 +283,9 @@ abstract class TreeCheckers extends Analyzer {
}
private def traverseInternal(tree: Tree) {
+ if (!tree.canHaveAttrs)
+ return
+
checkSymbolRefsRespectScope(enclosingMemberDefs takeWhile (md => !md.symbol.hasPackageFlag), tree)
checkReturnReferencesDirectlyEnclosingDef(tree)
@@ -329,10 +332,9 @@ abstract class TreeCheckers extends Analyzer {
return
case _ =>
}
-
- if (tree.canHaveAttrs && tree.pos == NoPosition)
+ if (tree.pos == NoPosition)
noPos(tree)
- else if (tree.tpe == null && phase.id > currentRun.typerPhase.id)
+ else if (tree.tpe == null && isPastTyper)
noType(tree)
else if (tree.isDef) {
checkSym(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 3cd937313f..c385e7533a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -13,7 +13,7 @@ package scala
package tools.nsc
package typechecker
-import scala.collection.mutable
+import scala.collection.{ mutable, immutable }
import scala.reflect.internal.util.{ BatchSourceFile, Statistics, shortClassOfInstance }
import mutable.ListBuffer
import symtab.Flags._
@@ -2503,7 +2503,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
assert(pt.typeSymbol == PartialFunctionClass, s"PartialFunction synthesis for match in $tree requires PartialFunction expected type, but got $pt.")
val targs = pt.dealiasWiden.typeArgs
- // if targs.head isn't fully defined, we can translate --> error
+ // if targs.head isn't fully defined, we can't translate --> error
targs match {
case argTp :: _ if isFullyDefined(argTp) => // ok
case _ => // uh-oh
@@ -2517,9 +2517,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// targs must conform to Any for us to synthesize an applyOrElse (fallback to apply otherwise -- typically for @cps annotated targs)
val targsValidParams = targs forall (_ <:< AnyTpe)
- val anonClass = (context.owner
- newAnonymousFunctionClass tree.pos
- addAnnotation AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List()))
+ val anonClass = context.owner newAnonymousFunctionClass tree.pos addAnnotation SerialVersionUIDAnnotation
import CODE._
@@ -2712,17 +2710,197 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
}
+ /** Synthesize and type check the implementation of a type with a Single Abstract Method
+ *
+ * `{ (p1: T1, ..., pN: TN) => body } : S`
+ *
+ * expands to (where `S` is the expected type that defines a single abstract method named `apply`)
+ *
+ * `{
+ * def apply$body(p1: T1, ..., pN: TN): T = body
+ * new S {
+ * def apply(p1: T1, ..., pN: TN): T = apply$body(p1,..., pN)
+ * }
+ * }`
+ *
+ * If 'T' is not fully defined, it is inferred by type checking
+ * `apply$body` without a result type before type checking the block.
+ * The method's inferred result type is used instead of T`. [See test/files/pos/sammy_poly.scala]
+ *
+ * The `apply` method is identified by the argument `sam`; `S` corresponds to the argument `samClassTp`,
+ * and `resPt` is derived from `samClassTp` -- it may be fully defined, or not...
+ *
+ * The function's body is put in a method outside of the class definition to enforce scoping.
+ * S's members should not be in scope in `body`.
+ *
+ * The restriction on implicit arguments (neither S's constructor, nor sam may take an implicit argument list),
+ * is largely to keep the implementation of type inference (the computation of `samClassTpFullyDefined`) simple.
+ *
+ * NOTE: it would be nicer to not have to type check `apply$body` separately when `T` is not fully defined.
+ * However T must be fully defined before we type the instantiation, as it'll end up as a parent type,
+ * which must be fully defined. Would be nice to have some kind of mechanism to insert type vars in a block of code,
+ * and have the instantiation of the first occurrence propagate to the rest of the block.
+ */
+ def synthesizeSAMFunction(sam: Symbol, fun: Function, resPt: Type, samClassTp: Type, mode: Mode): Tree = {
+ // assert(fun.vparams forall (vp => isFullyDefined(vp.tpt.tpe))) -- by construction, as we take them from sam's info
+ val sampos = fun.pos
+
+ // if the expected sam type is fully defined, use it for the method's result type
+ // otherwise, NoType, so that type inference will determine the method's result type
+ // resPt is syntactically contained in samClassTp, so if the latter is fully defined, so is the former
+ // ultimately, we want to fully define samClassTp as it is used as the superclass of our anonymous class
+ val samDefTp = if (isFullyDefined(resPt)) resPt else NoType
+ val bodyName = newTermName(sam.name + "$body")
+
+ // `def '${sam.name}\$body'($p1: $T1, ..., $pN: $TN): $resPt = $body`
+ val samBodyDef =
+ DefDef(NoMods,
+ bodyName,
+ Nil,
+ List(fun.vparams.map(_.duplicate)), // must duplicate as we're also using them for `samDef`
+ TypeTree(samDefTp) setPos sampos.focus,
+ fun.body)
+
+ // If we need to enter the sym for the body def before type checking the block,
+ // we'll create a nested context, as explained below.
+ var nestedTyper = this
+
+ // Type check body def before classdef to fully determine samClassTp (if necessary).
+ // As `samClassTp` determines a parent type for the class,
+ // we can't type check `block` in one go unless `samClassTp` is fully defined.
+ val samClassTpFullyDefined =
+ if (isFullyDefined(samClassTp)) samClassTp
+ else try {
+ // This creates a symbol for samBodyDef with a type completer that'll be triggered immediately below.
+ // The symbol is entered in the same scope used for the block below, and won't thus be reentered later.
+ // It has to be a new scope, though, or we'll "get ambiguous reference to overloaded definition" [pos/sammy_twice.scala]
+ // makeSilent: [pos/nonlocal-unchecked.scala -- when translation all functions to sams]
+ val nestedCtx = enterSym(context.makeNewScope(context.tree, context.owner).makeSilent(), samBodyDef)
+ nestedTyper = newTyper(nestedCtx)
+
+ // NOTE: this `samBodyDef.symbol.info` runs the type completer set up by the enterSym above
+ val actualSamType = samBodyDef.symbol.info
+
+ // we're trying to fully define the type arguments for this type constructor
+ val samTyCon = samClassTp.typeSymbol.typeConstructor
+
+ // the unknowns
+ val tparams = samClassTp.typeSymbol.typeParams
+ // ... as typevars
+ val tvars = tparams map freshVar
+
+ // 1. Recover partial information:
+ // - derive a type from samClassTp that has the corresponding tparams for type arguments that aren't fully defined
+ // - constrain typevars to be equal to type args that are fully defined
+ val samClassTpMoreDefined = appliedType(samTyCon,
+ (samClassTp.typeArgs, tparams, tvars).zipped map {
+ case (a, _, tv) if isFullyDefined(a) => tv =:= a; a
+ case (_, p, _) => p.typeConstructor
+ })
+
+ // the method type we're expecting the synthesized sam to have, based on the expected sam type,
+ // where fully defined type args to samClassTp have been preserved,
+ // with the unknown args replaced by their corresponding type param
+ val expectedSamType = samClassTpMoreDefined.memberInfo(sam)
+
+ // 2. make sure the body def's actual type (formals and result) conforms to
+ // sam's expected type (in terms of the typevars that represent the sam's class's type params)
+ actualSamType <:< expectedSamType.substituteTypes(tparams, tvars)
+
+ // solve constraints tracked by tvars
+ val targs = solvedTypes(tvars, tparams, tparams map varianceInType(sam.info), upper = false, lubDepth(sam.info :: Nil))
+
+ debuglog(s"sam infer: $samClassTp --> ${appliedType(samTyCon, targs)} by $actualSamType <:< $expectedSamType --> $targs for $tparams")
+
+ // a fully defined samClassTp
+ appliedType(samTyCon, targs)
+ } catch {
+ case _: NoInstance | _: TypeError =>
+ devWarning(sampos, s"Could not define type $samClassTp using ${samBodyDef.symbol.rawInfo} <:< ${samClassTp memberInfo sam} (for $sam)")
+ samClassTp
+ }
+
+ // `final override def ${sam.name}($p1: $T1, ..., $pN: $TN): $resPt = ${sam.name}\$body'($p1, ..., $pN)`
+ val samDef =
+ DefDef(Modifiers(FINAL | OVERRIDE | SYNTHETIC),
+ sam.name.toTermName,
+ Nil,
+ List(fun.vparams),
+ TypeTree(samBodyDef.tpt.tpe) setPos sampos.focus,
+ Apply(Ident(bodyName), fun.vparams map (p => Ident(p.name)))
+ )
+
+ val serializableParentAddendum =
+ if (typeIsSubTypeOfSerializable(samClassTp)) Nil
+ else List(TypeTree(SerializableTpe))
+
+ val classDef =
+ ClassDef(Modifiers(FINAL), tpnme.ANON_FUN_NAME, tparams = Nil,
+ gen.mkTemplate(
+ parents = TypeTree(samClassTpFullyDefined) :: serializableParentAddendum,
+ self = emptyValDef,
+ constrMods = NoMods,
+ vparamss = ListOfNil,
+ body = List(samDef),
+ superPos = sampos.focus
+ )
+ )
+
+ // type checking the whole block, so that everything is packaged together nicely
+ // and we don't have to create any symbols by hand
+ val block =
+ nestedTyper.typedPos(sampos, mode, samClassTpFullyDefined) {
+ Block(
+ samBodyDef,
+ classDef,
+ Apply(Select(New(Ident(tpnme.ANON_FUN_NAME)), nme.CONSTRUCTOR), Nil)
+ )
+ }
+
+ classDef.symbol addAnnotation SerialVersionUIDAnnotation
+ block
+ }
+
+ /** Type check a function literal.
+ *
+ * Based on the expected type pt, potentially synthesize an instance of
+ * - PartialFunction,
+ * - a type with a Single Abstract Method (under -Xexperimental for now).
+ */
private def typedFunction(fun: Function, mode: Mode, pt: Type): Tree = {
val numVparams = fun.vparams.length
- if (numVparams > definitions.MaxFunctionArity)
- return MaxFunctionArityError(fun)
+ val FunctionSymbol =
+ if (numVparams > definitions.MaxFunctionArity) NoSymbol
+ else FunctionClass(numVparams)
- val FunctionSymbol = FunctionClass(numVparams)
- val (argpts, respt) = pt baseType FunctionSymbol match {
- case TypeRef(_, FunctionSymbol, args :+ res) => (args, res)
- case _ => (fun.vparams map (_ => if (pt == ErrorType) ErrorType else NoType), WildcardType)
- }
- if (argpts.lengthCompare(numVparams) != 0)
+ /* The Single Abstract Member of pt, unless pt is the built-in function type of the expected arity,
+ * as `(a => a): Int => Int` should not (yet) get the sam treatment.
+ */
+ val sam =
+ if (!settings.Xexperimental || pt.typeSymbol == FunctionSymbol) NoSymbol
+ else samOf(pt)
+
+ /* The SAM case comes first so that this works:
+ * abstract class MyFun extends (Int => Int)
+ * (a => a): MyFun
+ *
+ * Note that the arity of the sam must correspond to the arity of the function.
+ */
+ val samViable = sam.exists && sameLength(sam.info.params, fun.vparams)
+ val (argpts, respt) =
+ if (samViable) {
+ val samInfo = pt memberInfo sam
+ (samInfo.paramTypes, samInfo.resultType)
+ } else {
+ pt baseType FunctionSymbol match {
+ case TypeRef(_, FunctionSymbol, args :+ res) => (args, res)
+ case _ => (fun.vparams map (_ => if (pt == ErrorType) ErrorType else NoType), WildcardType)
+ }
+ }
+
+ if (!FunctionSymbol.exists)
+ MaxFunctionArityError(fun)
+ else if (argpts.lengthCompare(numVparams) != 0)
WrongNumberOfParametersError(fun, argpts)
else {
foreach2(fun.vparams, argpts) { (vparam, argpt) =>
@@ -2733,7 +2911,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
fun match {
case etaExpansion(vparams, fn, args) =>
silent(_.typed(fn, mode.forFunMode, pt)) filter (_ => context.undetparams.isEmpty) map { fn1 =>
- // if context,undetparams is not empty, the function was polymorphic,
+ // if context.undetparams is not empty, the function was polymorphic,
// so we need the missing arguments to infer its type. See #871
//println("typing eta "+fun+":"+fn1.tpe+"/"+context.undetparams)
val ftpe = normalize(fn1.tpe) baseType FunctionClass(numVparams)
@@ -2761,6 +2939,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (p.tpt.tpe == null) p.tpt setType outerTyper.typedType(p.tpt).tpe
outerTyper.synthesizePartialFunction(p.name, p.pos, fun.body, mode, pt)
+
+ // Use synthesizeSAMFunction to expand `(p1: T1, ..., pN: TN) => body`
+ // to an instance of the corresponding anonymous subclass of `pt`.
+ case _ if samViable =>
+ newTyper(context.outer).synthesizeSAMFunction(sam, fun, respt, pt, mode)
+
+ // regular Function
case _ =>
val vparamSyms = fun.vparams map { vparam =>
enterSym(context, vparam)
@@ -3404,7 +3589,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else {
val annScope = annType.decls
.filter(sym => sym.isMethod && !sym.isConstructor && sym.isJavaDefined)
- val names = new scala.collection.mutable.HashSet[Symbol]
+ val names = mutable.Set[Symbol]()
names ++= (if (isJava) annScope.iterator
else typedFun.tpe.params.iterator)
@@ -3417,7 +3602,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val nvPairs = args map {
case arg @ AssignOrNamedArg(Ident(name), rhs) =>
val sym = if (isJava) annScope.lookup(name)
- else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol)
+ else findSymbol(typedFun.tpe.params)(_.name == name)
if (sym == NoSymbol) {
reportAnnotationError(UnknownAnnotationNameError(arg, name))
(nme.ERROR, None)
@@ -3544,8 +3729,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
while (o != owner && o != NoSymbol && !o.hasPackageFlag) o = o.owner
o == owner && !isVisibleParameter(sym)
}
- var localSyms = scala.collection.immutable.Set[Symbol]()
- var boundSyms = scala.collection.immutable.Set[Symbol]()
+ var localSyms = immutable.Set[Symbol]()
+ var boundSyms = immutable.Set[Symbol]()
def isLocal(sym: Symbol): Boolean =
if (sym == NoSymbol || sym.isRefinementClass || sym.isLocalDummy) false
else if (owner == NoSymbol) tree exists (defines(_, sym))
@@ -4125,7 +4310,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
NotAMemberError(tpt, TypeTree(tp), nme.CONSTRUCTOR)
setError(tpt)
}
- else if (!( tp == sym.thisSym.tpe_* // when there's no explicit self type -- with (#3612) or without self variable
+ else if (!( tp == sym.typeOfThis // when there's no explicit self type -- with (#3612) or without self variable
// sym.thisSym.tpe == tp.typeOfThis (except for objects)
|| narrowRhs(tp) <:< tp.typeOfThis
|| phase.erasedTypes
@@ -4561,7 +4746,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def sym = tree1.symbol
if (tree.isInstanceOf[PostfixSelect])
checkFeature(tree.pos, PostfixOpsFeature, name.decode)
- if (sym != null && sym.isOnlyRefinementMember)
+ if (sym != null && sym.isOnlyRefinementMember && !sym.isMacro)
checkFeature(tree1.pos, ReflectiveCallsFeature, sym.toString)
qualStableOrError.symbol match {
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 9e5a97270d..e94b7725cd 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -340,7 +340,8 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
lazy val exporter = importer.reverse
}
- def apply[T](f: CompilerApi => T): T = {
+ private val toolBoxLock = new Object
+ def apply[T](f: CompilerApi => T): T = toolBoxLock.synchronized {
try f(api)
catch { case ex: FatalError => throw ToolBoxError(s"fatal compiler error", ex) }
finally api.compiler.cleanupCaches()
diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala
index fa7d41f0fc..241747e6d8 100644
--- a/src/reflect/scala/reflect/api/Trees.scala
+++ b/src/reflect/scala/reflect/api/Trees.scala
@@ -2544,18 +2544,32 @@ trait Trees { self: Universe =>
class Traverser {
protected[scala] var currentOwner: Symbol = rootMirror.RootClass
+ /** Traverse something which Trees contain, but which isn't a Tree itself. */
+ def traverseName(name: Name): Unit = ()
+ def traverseConstant(c: Constant): Unit = ()
+ def traverseImportSelector(sel: ImportSelector): Unit = ()
+ def traverseModifiers(mods: Modifiers): Unit = traverseAnnotations(mods.annotations)
+
/** Traverses a single tree. */
- def traverse(tree: Tree): Unit = itraverse(this, tree)
+ def traverse(tree: Tree): Unit = itraverse(this, tree)
+ def traversePattern(pat: Tree): Unit = traverse(pat)
+ def traverseGuard(guard: Tree): Unit = traverse(guard)
+ def traverseTypeAscription(tpt: Tree): Unit = traverse(tpt)
+ // Special handling of noSelfType necessary for backward compat: existing
+ // traversers break down when they see the unexpected tree.
+ def traverseSelfType(self: ValDef): Unit = if (self ne noSelfType) traverse(self)
/** Traverses a list of trees. */
- def traverseTrees(trees: List[Tree]) {
- trees foreach traverse
- }
+ def traverseTrees(trees: List[Tree]): Unit = trees foreach traverse
+ def traverseTypeArgs(args: List[Tree]): Unit = traverseTrees(args)
+ def traverseParents(parents: List[Tree]): Unit = traverseTrees(parents)
+ def traverseCases(cases: List[CaseDef]): Unit = traverseTrees(cases)
+ def traverseAnnotations(annots: List[Tree]): Unit = traverseTrees(annots)
/** Traverses a list of lists of trees. */
- def traverseTreess(treess: List[List[Tree]]) {
- treess foreach traverseTrees
- }
+ def traverseTreess(treess: List[List[Tree]]): Unit = treess foreach traverseTrees
+ def traverseParams(params: List[Tree]): Unit = traverseTrees(params)
+ def traverseParamss(vparamss: List[List[Tree]]): Unit = vparamss foreach traverseParams
/** Traverses a list of trees with a given owner symbol. */
def traverseStats(stats: List[Tree], exprOwner: Symbol) {
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 215ab6abd6..f45fa40f89 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -27,6 +27,8 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
def filterAnnotations(p: AnnotationInfo => Boolean): Self // Retain only annotations meeting the condition.
def withoutAnnotations: Self // Remove all annotations from this type.
+ def staticAnnotations = annotations filter (_.isStatic)
+
/** Symbols of any @throws annotations on this symbol.
*/
def throwsAnnotations(): List[Symbol] = annotations collect {
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
index 05aaa462c4..19c67879f5 100644
--- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -38,7 +38,7 @@ trait BaseTypeSeqs {
* This is necessary because when run from reflection every base type sequence needs to have a
* SynchronizedBaseTypeSeq as mixin.
*/
- class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
+ class BaseTypeSeq protected[reflect] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
self =>
if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqCount)
if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 4d8ae73bcc..7b88514429 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -289,12 +289,6 @@ trait Definitions extends api.StandardDefinitions {
lazy val ConstantFalse = ConstantType(Constant(false))
lazy val ConstantNull = ConstantType(Constant(null))
- // Note: this is not the type alias AnyRef, it's a companion-like
- // object used by the @specialize annotation.
- lazy val AnyRefModule = getMemberModule(ScalaPackageClass, nme.AnyRef)
- @deprecated("Use AnyRefModule", "2.10.0")
- def Predef_AnyRef = AnyRefModule
-
lazy val AnyValClass: ClassSymbol = (ScalaPackageClass.info member tpnme.AnyVal orElse {
val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, AnyTpe :: Nil, ABSTRACT)
val av_constr = anyval.newClassConstructor(NoPosition)
@@ -799,6 +793,44 @@ trait Definitions extends api.StandardDefinitions {
(sym eq PartialFunctionClass) || (sym eq AbstractPartialFunctionClass)
}
+ /** The single abstract method declared by type `tp` (or `NoSymbol` if it cannot be found).
+ *
+ * The method must be monomorphic and have exactly one parameter list.
+ * The class defining the method is a supertype of `tp` that
+ * has a public no-arg primary constructor.
+ */
+ def samOf(tp: Type): Symbol = {
+ // if tp has a constructor, it must be public and must not take any arguments
+ // (not even an implicit argument list -- to keep it simple for now)
+ val tpSym = tp.typeSymbol
+ val ctor = tpSym.primaryConstructor
+ val ctorOk = !ctor.exists || (!ctor.isOverloaded && ctor.isPublic && ctor.info.params.isEmpty && ctor.info.paramSectionCount <= 1)
+
+ if (tpSym.exists && ctorOk) {
+ // find the single abstract member, if there is one
+ // don't go out requiring DEFERRED members, as you will get them even if there's a concrete override:
+ // scala> abstract class X { def m: Int }
+ // scala> class Y extends X { def m: Int = 1}
+ // scala> typeOf[Y].deferredMembers
+ // Scopes(method m, method getClass)
+ //
+ // scala> typeOf[Y].members.filter(_.isDeferred)
+ // Scopes()
+ // must filter out "universal" members (getClass is deferred for some reason)
+ val deferredMembers = (
+ tp membersBasedOnFlags (excludedFlags = BridgeAndPrivateFlags, requiredFlags = METHOD)
+ filter (mem => mem.isDeferredNotDefault && !isUniversalMember(mem)) // TODO: test
+ )
+
+ // if there is only one, it's monomorphic and has a single argument list
+ if (deferredMembers.size == 1 &&
+ deferredMembers.head.typeParams.isEmpty &&
+ deferredMembers.head.info.paramSectionCount == 1)
+ deferredMembers.head
+ else NoSymbol
+ } else NoSymbol
+ }
+
def arrayType(arg: Type) = appliedType(ArrayClass, arg)
def byNameType(arg: Type) = appliedType(ByNameParamClass, arg)
def iteratorOfType(tp: Type) = appliedType(IteratorClass, tp)
@@ -1089,6 +1121,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val ScalaInlineClass = requiredClass[scala.inline]
lazy val ScalaNoInlineClass = requiredClass[scala.noinline]
lazy val SerialVersionUIDAttr = requiredClass[scala.SerialVersionUID]
+ lazy val SerialVersionUIDAnnotation = AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List())
lazy val SpecializedClass = requiredClass[scala.specialized]
lazy val ThrowsClass = requiredClass[scala.throws[_]]
lazy val TransientAttr = requiredClass[scala.transient]
@@ -1141,14 +1174,21 @@ trait Definitions extends api.StandardDefinitions {
}
lazy val AnnotationDefaultAttr: ClassSymbol = {
- val attr = enterNewClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.tpe))
- // This attribute needs a constructor so that modifiers in parsed Java code make sense
- attr.info.decls enter attr.newClassConstructor(NoPosition)
- attr
+ val sym = RuntimePackageClass.newClassSymbol(tpnme.AnnotationDefaultATTR, NoPosition, 0L)
+ sym setInfo ClassInfoType(List(AnnotationClass.tpe), newScope, sym)
+ RuntimePackageClass.info.decls.toList.filter(_.name == sym.name) match {
+ case existing :: _ =>
+ existing.asInstanceOf[ClassSymbol]
+ case _ =>
+ RuntimePackageClass.info.decls enter sym
+ // This attribute needs a constructor so that modifiers in parsed Java code make sense
+ sym.info.decls enter sym.newClassConstructor(NoPosition)
+ sym
+ }
}
- private def fatalMissingSymbol(owner: Symbol, name: Name, what: String = "member") = {
- throw new FatalError(owner + " does not have a " + what + " " + name)
+ private def fatalMissingSymbol(owner: Symbol, name: Name, what: String = "member", addendum: String = "") = {
+ throw new FatalError(owner + " does not have a " + what + " " + name + addendum)
}
def getLanguageFeature(name: String, owner: Symbol = languageFeatureModule): Symbol = getMember(owner, newTypeName(name))
@@ -1183,7 +1223,8 @@ trait Definitions extends api.StandardDefinitions {
def getMemberModule(owner: Symbol, name: Name): ModuleSymbol = {
getMember(owner, name.toTermName) match {
case x: ModuleSymbol => x
- case _ => fatalMissingSymbol(owner, name, "member object")
+ case NoSymbol => fatalMissingSymbol(owner, name, "member object")
+ case other => fatalMissingSymbol(owner, name, "member object", addendum = s". A symbol ${other} of kind ${other.accurateKindString} already exists.")
}
}
def getTypeMember(owner: Symbol, name: Name): TypeSymbol = {
@@ -1349,10 +1390,13 @@ trait Definitions extends api.StandardDefinitions {
else flatNameString(etp.typeSymbol, '.')
}
+ // documented in JavaUniverse.init
def init() {
if (isInitialized) return
- // force initialization of every symbol that is synthesized or hijacked by the compiler
- val _ = symbolsNotPresentInBytecode
+ ObjectClass.initialize
+ ScalaPackageClass.initialize
+ val forced1 = symbolsNotPresentInBytecode
+ val forced2 = NoSymbol
isInitialized = true
} //init
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index 6ed9de8e20..e122fa498b 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -250,6 +250,19 @@ trait Mirrors extends api.Mirrors {
RootClass.info.decls enter EmptyPackage
RootClass.info.decls enter RootPackage
+ if (rootOwner != NoSymbol) {
+ // synthetic core classes are only present in root mirrors
+ // because Definitions.scala, which initializes and enters them, only affects rootMirror
+ // therefore we need to enter them manually for non-root mirrors
+ definitions.syntheticCoreClasses foreach (theirSym => {
+ val theirOwner = theirSym.owner
+ assert(theirOwner.isPackageClass, s"theirSym = $theirSym, theirOwner = $theirOwner")
+ val ourOwner = staticPackage(theirOwner.fullName).moduleClass
+ val ourSym = theirSym // just copy the symbol into our branch of the symbol table
+ ourOwner.info.decls enterIfNew ourSym
+ })
+ }
+
initialized = true
}
}
@@ -274,34 +287,45 @@ trait Mirrors extends api.Mirrors {
def mirror = thisMirror.asInstanceOf[Mirror]
}
- // This is the package _root_. The actual root cannot be referenced at
- // the source level, but _root_ is essentially a function => <root>.
- final object RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol {
+ class RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol {
this setInfo NullaryMethodType(RootClass.tpe)
RootClass.sourceModule = this
override def isRootPackage = true
}
+
+ // This is the package _root_. The actual root cannot be referenced at
+ // the source level, but _root_ is essentially a function => <root>.
+ lazy val RootPackage = new RootPackage
+
+ class RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol {
+ this setInfo rootLoader
+
+ override def isRoot = true
+ override def isEffectiveRoot = true
+ override def isNestedClass = false
+ }
+
// This is <root>, the actual root of everything except the package _root_.
// <root> and _root_ (RootPackage and RootClass) should be the only "well known"
// symbols owned by NoSymbol. All owner chains should go through RootClass,
// although it is probable that some symbols are created as direct children
// of NoSymbol to ensure they will not be stumbled upon. (We should designate
// a better encapsulated place for that.)
- final object RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol {
- this setInfo rootLoader
+ lazy val RootClass = new RootClass
- override def isRoot = true
- override def isEffectiveRoot = true
- override def isNestedClass = false
- }
- // The empty package, which holds all top level types without given packages.
- final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ class EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEmptyPackage = true
}
- final object EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+
+ // The empty package, which holds all top level types without given packages.
+ lazy val EmptyPackage = new EmptyPackage
+
+ class EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
override def isEffectiveRoot = true
override def isEmptyPackageClass = true
}
+
+ lazy val EmptyPackageClass = new EmptyPackageClass
}
}
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index 485d4d5ddd..b7a1681838 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -139,6 +139,12 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
enter(sym)
}
+ def enterIfNew[T <: Symbol](sym: T): T = {
+ val existing = lookupEntry(sym.name)
+ if (existing == null) enter(sym)
+ else existing.sym.asInstanceOf[T]
+ }
+
private def createHash() {
hashtable = new Array[ScopeEntry](HASHSIZE)
enterAllInHash(elems)
@@ -221,8 +227,8 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
/** Lookup a module or a class, filtering out matching names in scope
* which do not match that requirement.
*/
- def lookupModule(name: Name): Symbol = lookupAll(name.toTermName) find (_.isModule) getOrElse NoSymbol
- def lookupClass(name: Name): Symbol = lookupAll(name.toTypeName) find (_.isClass) getOrElse NoSymbol
+ def lookupModule(name: Name): Symbol = findSymbol(lookupAll(name.toTermName))(_.isModule)
+ def lookupClass(name: Name): Symbol = findSymbol(lookupAll(name.toTypeName))(_.isClass)
/** True if the name exists in this scope, false otherwise. */
def containsName(name: Name) = lookupEntry(name) != null
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 8a0e1e4768..9f56e78059 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -274,6 +274,8 @@ trait StdNames {
final val SourceFileATTR: NameType = "SourceFile"
final val SyntheticATTR: NameType = "Synthetic"
+ final val scala_ : NameType = "scala"
+
def dropSingletonName(name: Name): TypeName = (name dropRight SINGLETON_SUFFIX.length).toTypeName
def singletonName(name: Name): TypeName = (name append SINGLETON_SUFFIX).toTypeName
def implClassName(name: Name): TypeName = (name append IMPL_CLASS_SUFFIX).toTypeName
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
index 8f954e4095..8386d02b7c 100644
--- a/src/reflect/scala/reflect/internal/SymbolTable.scala
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -41,6 +41,7 @@ abstract class SymbolTable extends macros.Universe
with StdCreators
with BuildUtils
with PrivateWithin
+ with pickling.Translations
{
val gen = new TreeGen { val global: SymbolTable.this.type = SymbolTable.this }
@@ -124,6 +125,10 @@ abstract class SymbolTable extends macros.Universe
result
}
+ @inline final def findSymbol(xs: TraversableOnce[Symbol])(p: Symbol => Boolean): Symbol = {
+ xs find p getOrElse NoSymbol
+ }
+
// For too long have we suffered in order to sort NAMES.
// I'm pretty sure there's a reasonable default for that.
// Notice challenge created by Ordering's invariance.
@@ -237,12 +242,20 @@ abstract class SymbolTable extends macros.Universe
finally popPhase(saved)
}
+ def slowButSafeEnteringPhase[T](ph: Phase)(op: => T): T = {
+ if (isCompilerUniverse) enteringPhase(ph)(op)
+ else op
+ }
+
@inline final def exitingPhase[T](ph: Phase)(op: => T): T = enteringPhase(ph.next)(op)
@inline final def enteringPrevPhase[T](op: => T): T = enteringPhase(phase.prev)(op)
@inline final def enteringPhaseNotLaterThan[T](target: Phase)(op: => T): T =
if (isAtPhaseAfter(target)) enteringPhase(target)(op) else op
+ def slowButSafeEnteringPhaseNotLaterThan[T](target: Phase)(op: => T): T =
+ if (isCompilerUniverse) enteringPhaseNotLaterThan(target)(op) else op
+
final def isValid(period: Period): Boolean =
period != 0 && runId(period) == currentRunId && {
val pid = phaseId(period)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index efdc8f7435..ba785c14bd 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -30,13 +30,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
//protected var lockedSyms = scala.collection.immutable.Set[Symbol]()
/** Used to keep track of the recursion depth on locked symbols */
- private var recursionTable = immutable.Map.empty[Symbol, Int]
+ private var _recursionTable = immutable.Map.empty[Symbol, Int]
+ def recursionTable = _recursionTable
+ def recursionTable_=(value: immutable.Map[Symbol, Int]) = _recursionTable = value
- private var nextexid = 0
- protected def freshExistentialName(suffix: String) = {
- nextexid += 1
- newTypeName("_" + nextexid + suffix)
- }
+ private var existentialIds = 0
+ protected def nextExistentialId() = { existentialIds += 1; existentialIds }
+ protected def freshExistentialName(suffix: String) = newTypeName("_" + nextExistentialId() + suffix)
// Set the fields which point companions at one another. Returns the module.
def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = {
@@ -110,10 +110,14 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
children
}
+ def selfType = {
+ if (!isCompilerUniverse && needsInitialize(isFlagRelated = false, mask = 0)) initialize
+ typeOfThis
+ }
+
def baseClasses = info.baseClasses
def module = sourceModule
def thisPrefix: Type = thisType
- def selfType: Type = typeOfThis
def typeSignature: Type = { fullyInitializeSymbol(this); info }
def typeSignatureIn(site: Type): Type = { fullyInitializeSymbol(this); site memberInfo this }
@@ -127,6 +131,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def setter: Symbol = setter(owner)
}
+ private[reflect] case class SymbolKind(accurate: String, sanitized: String, abbreviation: String)
+
/** The class for all symbols */
abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name)
extends SymbolContextApiImpl
@@ -800,7 +806,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*
* Stability and volatility are checked separately to allow volatile paths in patterns that amount to equality checks. SI-6815
*/
- final def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag)
+ def isStable = isTerm && !isMutable && !(hasFlag(BYNAMEPARAM)) && (!isMethod || hasStableFlag)
final def hasVolatileType = tpe.isVolatile && !hasAnnotation(uncheckedStableClass)
/** Does this symbol denote the primary constructor of its enclosing class? */
@@ -949,6 +955,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def isInitialized: Boolean =
validTo != NoPeriod
+ /** Some completers call sym.setInfo when still in-flight and then proceed with initialization (e.g. see LazyPackageType)
+ * setInfo sets _validTo to current period, which means that after a call to setInfo isInitialized will start returning true.
+ * Unfortunately, this doesn't mean that info becomes ready to be used, because subsequent initialization might change the info.
+ * Therefore we need this method to distinguish between initialized and really initialized symbol states.
+ */
+ final def isFullyInitialized: Boolean = _validTo != NoPeriod && (flags & LOCKED) == 0
+
/** Can this symbol be loaded by a reflective mirror?
*
* Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs.
@@ -1563,6 +1576,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* assumption: if a type starts out as monomorphic, it will not acquire
* type parameters later.
*/
+ // NOTE: overridden in SynchronizedSymbols with the code copy/pasted
+ // don't forget to modify the code over there if you modify this method
def unsafeTypeParams: List[Symbol] =
if (isMonomorphicType) Nil
else enteringPhase(unsafeTypeParamPhase)(rawInfo.typeParams)
@@ -1571,6 +1586,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* assumption: if a type starts out as monomorphic, it will not acquire
* type parameters later.
*/
+ // NOTE: overridden in SynchronizedSymbols with the code copy/pasted
+ // don't forget to modify the code over there if you modify this method
def typeParams: List[Symbol] =
if (isMonomorphicType) Nil
else {
@@ -1859,6 +1876,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
*/
def thisSym: Symbol = this
+ def hasSelfType = thisSym.tpeHK != this.tpeHK
+
/** The type of `this` in a class, or else the type of the symbol itself. */
def typeOfThis = thisSym.tpe_*
@@ -2391,7 +2410,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else if (isTerm && (!isParameter || isParamAccessor)) "val"
else ""
- private case class SymbolKind(accurate: String, sanitized: String, abbreviation: String)
private def symbolKind: SymbolKind = {
var kind =
if (isTermMacro) ("term macro", "macro method", "MACM")
@@ -3122,8 +3140,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def thisType: Type = {
val period = thisTypePeriod
if (period != currentPeriod) {
- thisTypePeriod = currentPeriod
if (!isValid(period)) thisTypeCache = ThisType(this)
+ thisTypePeriod = currentPeriod
}
thisTypeCache
}
@@ -3211,9 +3229,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def typeOfThis = {
val period = typeOfThisPeriod
if (period != currentPeriod) {
- typeOfThisPeriod = currentPeriod
if (!isValid(period))
typeOfThisCache = singleType(owner.thisType, sourceModule)
+ typeOfThisPeriod = currentPeriod
}
typeOfThisCache
}
@@ -3224,9 +3242,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// Skip a package object class, because the members are also in
// the package and we wish to avoid spurious ambiguities as in pos/t3999.
if (!isPackageObjectClass) {
+ implicitMembersCacheValue = tp.implicitMembers
implicitMembersCacheKey1 = tp
implicitMembersCacheKey2 = tp.decls.elems
- implicitMembersCacheValue = tp.implicitMembers
}
}
implicitMembersCacheValue
@@ -3334,10 +3352,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def name = nme.NO_NAME
override def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n)
- synchronized {
- setInfo(NoType)
- privateWithin = this
- }
+ // Syncnote: no need to synchronize this, because NoSymbol's initialization is triggered by JavaUniverse.init
+ // which is called in universe's constructor - something that's inherently single-threaded
+ setInfo(NoType)
+ privateWithin = this
+
override def info_=(info: Type) = {
infos = TypeHistory(1, NoType, null)
unlock()
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 54a1913b96..9adddeed50 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -8,10 +8,12 @@ package reflect
package internal
import Flags._
-import scala.collection.mutable.{ListBuffer, LinkedHashSet}
+import pickling.PickleFormat._
+import scala.collection.{ mutable, immutable }
import util.Statistics
-trait Trees extends api.Trees { self: SymbolTable =>
+trait Trees extends api.Trees {
+ self: SymbolTable =>
private[scala] var nodeCount = 0
@@ -160,7 +162,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def freeTypes: List[FreeTypeSymbol] = freeSyms[FreeTypeSymbol](_.isFreeType, _.typeSymbol)
private def freeSyms[S <: Symbol](isFree: Symbol => Boolean, symOfType: Type => Symbol): List[S] = {
- val s = scala.collection.mutable.LinkedHashSet[S]()
+ val s = mutable.LinkedHashSet[S]()
def addIfFree(sym: Symbol): Unit = if (sym != null && isFree(sym)) s += sym.asInstanceOf[S]
for (t <- this) {
addIfFree(t.symbol)
@@ -1019,18 +1021,22 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
trait CannotHaveAttrs extends Tree {
- override def canHaveAttrs = false
-
- private def requireLegal(value: Any, allowed: Any, what: String) =
- require(value == allowed, s"can't set $what for $self to value other than $allowed")
-
super.setPos(NoPosition)
+ super.setType(NoType)
+
+ override def canHaveAttrs = false
override def setPos(pos: Position) = { requireLegal(pos, NoPosition, "pos"); this }
override def pos_=(pos: Position) = setPos(pos)
-
- super.setType(NoType)
override def setType(t: Type) = { requireLegal(t, NoType, "tpe"); this }
override def tpe_=(t: Type) = setType(t)
+
+ private def requireLegal(value: Any, allowed: Any, what: String) = (
+ if (value != allowed) {
+ log(s"can't set $what for $self to value other than $allowed")
+ if (settings.debug && settings.developer)
+ (new Throwable).printStackTrace
+ }
+ )
}
case object EmptyTree extends TermTree with CannotHaveAttrs { override def isEmpty = true; val asList = List(this) }
@@ -1159,113 +1165,136 @@ trait Trees extends api.Trees { self: SymbolTable =>
override protected def itraverse(traverser: Traverser, tree: Tree): Unit = {
import traverser._
- tree match {
- case EmptyTree =>
- ;
- case PackageDef(pid, stats) =>
- traverse(pid)
- atOwner(mclass(tree.symbol)) {
- traverseTrees(stats)
- }
- case ClassDef(mods, name, tparams, impl) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverseTrees(tparams); traverse(impl)
- }
- case ModuleDef(mods, name, impl) =>
- atOwner(mclass(tree.symbol)) {
- traverseTrees(mods.annotations); traverse(impl)
- }
- case ValDef(mods, name, tpt, rhs) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverse(tpt); traverse(rhs)
- }
- case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverseTrees(tparams); traverseTreess(vparamss); traverse(tpt); traverse(rhs)
- }
- case TypeDef(mods, name, tparams, rhs) =>
- atOwner(tree.symbol) {
- traverseTrees(mods.annotations); traverseTrees(tparams); traverse(rhs)
- }
+
+ def traverseMemberDef(md: MemberDef, owner: Symbol): Unit = atOwner(owner) {
+ traverseModifiers(md.mods)
+ traverseName(md.name)
+ md match {
+ case ClassDef(_, _, tparams, impl) => traverseParams(tparams) ; traverse(impl)
+ case ModuleDef(_, _, impl) => traverse(impl)
+ case ValDef(_, _, tpt, rhs) => traverseTypeAscription(tpt) ; traverse(rhs)
+ case TypeDef(_, _, tparams, rhs) => traverseParams(tparams) ; traverse(rhs)
+ case DefDef(_, _, tparams, vparamss, tpt, rhs) =>
+ traverseParams(tparams)
+ traverseParamss(vparamss)
+ traverseTypeAscription(tpt)
+ traverse(rhs)
+ }
+ }
+ def traverseComponents(): Unit = tree match {
case LabelDef(name, params, rhs) =>
- traverseTrees(params); traverse(rhs)
+ traverseName(name)
+ traverseParams(params)
+ traverse(rhs)
case Import(expr, selectors) =>
traverse(expr)
+ selectors foreach traverseImportSelector
case Annotated(annot, arg) =>
- traverse(annot); traverse(arg)
+ traverse(annot)
+ traverse(arg)
case Template(parents, self, body) =>
- traverseTrees(parents)
- if (self ne noSelfType) traverse(self)
+ traverseParents(parents)
+ traverseSelfType(self)
traverseStats(body, tree.symbol)
case Block(stats, expr) =>
- traverseTrees(stats); traverse(expr)
+ traverseTrees(stats)
+ traverse(expr)
case CaseDef(pat, guard, body) =>
- traverse(pat); traverse(guard); traverse(body)
+ traversePattern(pat)
+ traverseGuard(guard)
+ traverse(body)
case Alternative(trees) =>
traverseTrees(trees)
case Star(elem) =>
traverse(elem)
case Bind(name, body) =>
+ traverseName(name)
traverse(body)
case UnApply(fun, args) =>
- traverse(fun); traverseTrees(args)
+ traverse(fun)
+ traverseTrees(args)
case ArrayValue(elemtpt, trees) =>
- traverse(elemtpt); traverseTrees(trees)
- case Function(vparams, body) =>
- atOwner(tree.symbol) {
- traverseTrees(vparams); traverse(body)
- }
+ traverse(elemtpt)
+ traverseTrees(trees)
case Assign(lhs, rhs) =>
- traverse(lhs); traverse(rhs)
+ traverse(lhs)
+ traverse(rhs)
case AssignOrNamedArg(lhs, rhs) =>
- traverse(lhs); traverse(rhs)
+ traverse(lhs)
+ traverse(rhs)
case If(cond, thenp, elsep) =>
- traverse(cond); traverse(thenp); traverse(elsep)
+ traverse(cond)
+ traverse(thenp)
+ traverse(elsep)
case Match(selector, cases) =>
- traverse(selector); traverseTrees(cases)
+ traverse(selector)
+ traverseCases(cases)
case Return(expr) =>
traverse(expr)
case Try(block, catches, finalizer) =>
- traverse(block); traverseTrees(catches); traverse(finalizer)
+ traverse(block)
+ traverseCases(catches)
+ traverse(finalizer)
case Throw(expr) =>
traverse(expr)
case New(tpt) =>
traverse(tpt)
case Typed(expr, tpt) =>
- traverse(expr); traverse(tpt)
+ traverse(expr)
+ traverseTypeAscription(tpt)
case TypeApply(fun, args) =>
- traverse(fun); traverseTrees(args)
+ traverse(fun)
+ traverseTypeArgs(args)
case Apply(fun, args) =>
- traverse(fun); traverseTrees(args)
+ traverse(fun)
+ traverseTrees(args)
case ApplyDynamic(qual, args) =>
- traverse(qual); traverseTrees(args)
- case Super(qual, _) =>
traverse(qual)
- case This(_) =>
- ;
+ traverseTrees(args)
+ case Super(qual, mix) =>
+ traverse(qual)
+ traverseName(mix)
+ case This(qual) =>
+ traverseName(qual)
case Select(qualifier, selector) =>
traverse(qualifier)
- case Ident(_) =>
- ;
+ traverseName(selector)
+ case Ident(name) =>
+ traverseName(name)
case ReferenceToBoxed(idt) =>
traverse(idt)
- case Literal(_) =>
- ;
+ case Literal(const) =>
+ traverseConstant(const)
case TypeTree() =>
;
case SingletonTypeTree(ref) =>
traverse(ref)
case SelectFromTypeTree(qualifier, selector) =>
traverse(qualifier)
+ traverseName(selector)
case CompoundTypeTree(templ) =>
traverse(templ)
case AppliedTypeTree(tpt, args) =>
- traverse(tpt); traverseTrees(args)
+ traverse(tpt)
+ traverseTypeArgs(args)
case TypeBoundsTree(lo, hi) =>
- traverse(lo); traverse(hi)
+ traverse(lo)
+ traverse(hi)
case ExistentialTypeTree(tpt, whereClauses) =>
- traverse(tpt); traverseTrees(whereClauses)
- case _ => xtraverse(traverser, tree)
+ traverse(tpt)
+ traverseTrees(whereClauses)
+ case _ =>
+ xtraverse(traverser, tree)
+ }
+
+ if (tree.canHaveAttrs) {
+ tree match {
+ case PackageDef(pid, stats) => traverse(pid) ; traverseStats(stats, mclass(tree.symbol))
+ case md: ModuleDef => traverseMemberDef(md, mclass(tree.symbol))
+ case md: MemberDef => traverseMemberDef(md, tree.symbol)
+ case Function(vparams, body) => atOwner(tree.symbol) { traverseParams(vparams) ; traverse(body) }
+ case _ => traverseComponents()
+ }
}
}
@@ -1563,7 +1592,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
class FilterTreeTraverser(p: Tree => Boolean) extends Traverser {
- val hits = new ListBuffer[Tree]
+ val hits = mutable.ListBuffer[Tree]()
override def traverse(t: Tree) {
if (p(t)) hits += t
super.traverse(t)
@@ -1571,7 +1600,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
class CollectTreeTraverser[T](pf: PartialFunction[Tree, T]) extends Traverser {
- val results = new ListBuffer[T]
+ val results = mutable.ListBuffer[T]()
override def traverse(t: Tree) {
if (pf.isDefinedAt(t)) results += pf(t)
super.traverse(t)
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 85dfa037ec..204a2e7088 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -115,14 +115,17 @@ trait Types
/** The current skolemization level, needed for the algorithms
* in isSameType, isSubType that do constraint solving under a prefix.
*/
- var skolemizationLevel = 0
+ private var _skolemizationLevel = 0
+ def skolemizationLevel = _skolemizationLevel
+ def skolemizationLevel_=(value: Int) = _skolemizationLevel = value
/** A map from lists to compound types that have the given list as parents.
* This is used to avoid duplication in the computation of base type sequences and baseClasses.
* It makes use of the fact that these two operations depend only on the parents,
* not on the refinement.
*/
- val intersectionWitness = perRunCaches.newWeakMap[List[Type], WeakReference[Type]]()
+ private val _intersectionWitness = perRunCaches.newWeakMap[List[Type], WeakReference[Type]]()
+ def intersectionWitness = _intersectionWitness
/** A proxy for a type (identified by field `underlying`) that forwards most
* operations to it (for exceptions, see WrappingProxy, which forwards even more operations).
@@ -974,6 +977,18 @@ trait Types
else (baseClasses.head.newOverloaded(this, alts))
}
+ /** Find all members meeting the flag requirements.
+ *
+ * If you require a DEFERRED member, you will get it if it exists -- even if there's an overriding concrete member.
+ * If you exclude DEFERRED members, or don't specify any requirements,
+ * you won't get deferred members (whether they have an overriding concrete member or not)
+ *
+ * Thus, findMember requiring DEFERRED flags yields deferred members,
+ * while `findMember(excludedFlags = 0, requiredFlags = 0).filter(_.isDeferred)` may not (if there's a corresponding concrete member)
+ *
+ * Requirements take precedence over exclusions, so requiring and excluding DEFERRED will yield a DEFERRED member (if there is one).
+ *
+ */
def findMembers(excludedFlags: Long, requiredFlags: Long): Scope = {
def findMembersInternal: Scope = {
var members: Scope = null
@@ -983,10 +998,10 @@ trait Types
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var required = requiredFlags
var excluded = excludedFlags | DEFERRED
- var continue = true
+ var retryForDeferred = true
var self: Type = null
- while (continue) {
- continue = false
+ while (retryForDeferred) {
+ retryForDeferred = false
val bcs0 = baseClasses
var bcs = bcs0
while (!bcs.isEmpty) {
@@ -1018,7 +1033,7 @@ trait Types
}
if (others eq null) members enter sym
} else if (excl == DEFERRED) {
- continue = true
+ retryForDeferred = (excludedFlags & DEFERRED) == 0
}
}
entry = entry.next
@@ -1028,7 +1043,7 @@ trait Types
} // while (!bcs.isEmpty)
required |= DEFERRED
excluded &= ~(DEFERRED.toLong)
- } // while (continue)
+ } // while (retryForDeferred)
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
if (members eq null) EmptyScope else members
}
@@ -1471,6 +1486,14 @@ trait Types
}
}
+ object CompoundType {
+ def unapply(tp: Type): Option[(List[Type], Scope, Symbol)] = tp match {
+ case ClassInfoType(parents, decls, clazz) => Some((parents, decls, clazz))
+ case RefinedType(parents, decls) => Some((parents, decls, tp.typeSymbol))
+ case _ => None
+ }
+ }
+
/** A common base class for intersection types and class types
*/
abstract class CompoundType extends Type {
@@ -1954,12 +1977,12 @@ trait Types
def apply(value: Constant) = unique(new UniqueConstantType(value))
}
- /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected
- * with synchronized, because they are accessed only from isVolatile, which is called only from
- * Typer.
- */
- private var volatileRecursions: Int = 0
- private val pendingVolatiles = new mutable.HashSet[Symbol]
+ private var _volatileRecursions: Int = 0
+ def volatileRecursions = _volatileRecursions
+ def volatileRecursions_=(value: Int) = _volatileRecursions = value
+
+ private val _pendingVolatiles = new mutable.HashSet[Symbol]
+ def pendingVolatiles = _pendingVolatiles
class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) {
require(args0.nonEmpty, this)
@@ -3293,6 +3316,13 @@ trait Types
object AnnotatedType extends AnnotatedTypeExtractor
+ object StaticallyAnnotatedType {
+ def unapply(tp: Type): Option[(List[AnnotationInfo], Type)] = tp.staticAnnotations match {
+ case Nil => None
+ case annots => Some((annots, tp.withoutAnnotations))
+ }
+ }
+
/** A class representing types with a name. When an application uses
* named arguments, the named argument types for calling isApplicable
* are represented as NamedType.
@@ -3920,9 +3950,12 @@ trait Types
*/
final def hasLength(xs: List[_], len: Int) = xs.lengthCompare(len) == 0
- private var basetypeRecursions: Int = 0
- private val pendingBaseTypes = new mutable.HashSet[Type]
+ private var _basetypeRecursions: Int = 0
+ def basetypeRecursions = _basetypeRecursions
+ def basetypeRecursions_=(value: Int) = _basetypeRecursions = value
+ private val _pendingBaseTypes = new mutable.HashSet[Type]
+ def pendingBaseTypes = _pendingBaseTypes
/** Does this type have a prefix that begins with a type variable,
* or is it a refinement type? For type prefixes that fulfil this condition,
@@ -4422,7 +4455,9 @@ trait Types
}
/** The current indentation string for traces */
- protected[internal] var indent: String = ""
+ private var _indent: String = ""
+ protected def indent = _indent
+ protected def indent_=(value: String) = _indent = value
/** Perform operation `p` on arguments `tp1`, `arg2` and print trace of computation. */
protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala
index bf00a7ac87..5280467055 100644
--- a/src/reflect/scala/reflect/internal/Variances.scala
+++ b/src/reflect/scala/reflect/internal/Variances.scala
@@ -142,7 +142,8 @@ trait Variances {
// No variance check for object-private/protected methods/values.
// Or constructors, or case class factory or extractor.
def skip = (
- sym.hasLocalFlag
+ sym == NoSymbol
+ || sym.hasLocalFlag
|| sym.owner.isConstructor
|| sym.owner.isCaseApplyOrUnapply
)
diff --git a/src/reflect/scala/reflect/internal/pickling/Translations.scala b/src/reflect/scala/reflect/internal/pickling/Translations.scala
new file mode 100644
index 0000000000..e56cf796cb
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/pickling/Translations.scala
@@ -0,0 +1,128 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala
+package reflect
+package internal
+package pickling
+
+import PickleFormat._
+import util.shortClassOfInstance
+
+trait Translations {
+ self: SymbolTable =>
+
+ def isTreeSymbolPickled(code: Int): Boolean = (code: @annotation.switch) match {
+ case PACKAGEtree | CLASStree | MODULEtree | VALDEFtree | DEFDEFtree | TYPEDEFtree | LABELtree => true
+ case IMPORTtree | TEMPLATEtree | BINDtree | FUNCTIONtree | RETURNtree => true
+ case APPLYDYNAMICtree | SUPERtree | THIStree | SELECTtree | IDENTtree => true
+ case _ => false
+ }
+ /** This method should be equivalent to tree.hasSymbolField, but that method
+ * doesn't do us any good when we're unpickling because we need to know based
+ * on the Int tag - the tree doesn't exist yet. Thus, this method is documentation only.
+ */
+ def isTreeSymbolPickled(tree: Tree): Boolean = isTreeSymbolPickled(picklerSubTag(tree))
+
+ // The ad hoc pattern matching of tuples out of AnyRefs is a
+ // truly terrible idea. It reaches the height of its powers in
+ // combination with scala's insistence on helpfully tupling
+ // multiple arguments passed to a single-arg AnyRef.
+ def picklerTag(ref: AnyRef): Int = ref match {
+ case tp: Type => picklerTag(tp)
+ case sym: Symbol => picklerTag(sym)
+ case const: Constant => LITERAL + const.tag
+ case _: Tree => TREE // its sub tag more precisely identifies it
+ case _: TermName => TERMname
+ case _: TypeName => TYPEname
+ case _: ArrayAnnotArg => ANNOTARGARRAY // an array of annotation arguments
+ case _: AnnotationInfo => ANNOTINFO // annotations on types (not linked to a symbol)
+ case (_: Symbol, _: AnnotationInfo) => SYMANNOT // symbol annotations, i.e. on terms
+ case (_: Symbol, _: List[_]) => CHILDREN // the direct subclasses of a sealed symbol
+ case _: Modifiers => MODIFIERS
+ case _ => sys.error(s"unpicklable entry ${shortClassOfInstance(ref)} $ref")
+ }
+
+ /** Local symbols only. The assessment of locality depends
+ * on convoluted conditions which depends in part on the root
+ * symbol being pickled, so it cannot be reproduced here.
+ * The pickler tags at stake are EXTMODCLASSref and EXTref.
+ * Those tags are never produced here - such symbols must be
+ * excluded prior to calling this method.
+ */
+ def picklerTag(sym: Symbol): Int = sym match {
+ case NoSymbol => NONEsym
+ case _: ClassSymbol => CLASSsym
+ case _: TypeSymbol if sym.isAbstractType => TYPEsym
+ case _: TypeSymbol => ALIASsym
+ case _: TermSymbol if sym.isModule => MODULEsym
+ case _: TermSymbol => VALsym
+ }
+
+ def picklerTag(tpe: Type): Int = tpe match {
+ case NoType => NOtpe
+ case NoPrefix => NOPREFIXtpe
+ case _: ThisType => THIStpe
+ case _: SingleType => SINGLEtpe
+ case _: SuperType => SUPERtpe
+ case _: ConstantType => CONSTANTtpe
+ case _: TypeBounds => TYPEBOUNDStpe
+ case _: TypeRef => TYPEREFtpe
+ case _: RefinedType => REFINEDtpe
+ case _: ClassInfoType => CLASSINFOtpe
+ case _: MethodType => METHODtpe
+ case _: PolyType => POLYtpe
+ case _: NullaryMethodType => POLYtpe // bad juju, distinct ints are not at a premium!
+ case _: ExistentialType => EXISTENTIALtpe
+ case _: AnnotatedType => ANNOTATEDtpe
+ }
+
+ def picklerSubTag(tree: Tree): Int = tree match {
+ case EmptyTree => EMPTYtree
+ case _: PackageDef => PACKAGEtree
+ case _: ClassDef => CLASStree
+ case _: ModuleDef => MODULEtree
+ case _: ValDef => VALDEFtree
+ case _: DefDef => DEFDEFtree
+ case _: TypeDef => TYPEDEFtree
+ case _: LabelDef => LABELtree
+ case _: Import => IMPORTtree
+ // case _: DocDef => DOCDEFtree
+ case _: Template => TEMPLATEtree
+ case _: Block => BLOCKtree
+ case _: CaseDef => CASEtree
+ case _: Alternative => ALTERNATIVEtree
+ case _: Star => STARtree
+ case _: Bind => BINDtree
+ case _: UnApply => UNAPPLYtree
+ case _: ArrayValue => ARRAYVALUEtree
+ case _: Function => FUNCTIONtree
+ case _: Assign => ASSIGNtree
+ case _: If => IFtree
+ case _: Match => MATCHtree
+ case _: Return => RETURNtree
+ case _: Try => TREtree // TREtree?
+ case _: Throw => THROWtree
+ case _: New => NEWtree
+ case _: Typed => TYPEDtree
+ case _: TypeApply => TYPEAPPLYtree
+ case _: Apply => APPLYtree
+ case _: ApplyDynamic => APPLYDYNAMICtree
+ case _: Super => SUPERtree
+ case _: This => THIStree
+ case _: Select => SELECTtree
+ case _: Ident => IDENTtree
+ case _: Literal => LITERALtree
+ case _: TypeTree => TYPEtree
+ case _: Annotated => ANNOTATEDtree
+ case _: SingletonTypeTree => SINGLETONTYPEtree
+ case _: SelectFromTypeTree => SELECTFROMTYPEtree
+ case _: CompoundTypeTree => COMPOUNDTYPEtree
+ case _: AppliedTypeTree => APPLIEDTYPEtree
+ case _: TypeBoundsTree => TYPEBOUNDStree
+ case _: ExistentialTypeTree => EXISTENTIALTYPEtree
+ }
+}
+
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index f42dbf56e1..a6c34935ad 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -65,36 +65,38 @@ abstract class UnPickler {
/** A map from symbols to their associated `decls` scopes */
private val symScopes = mutable.HashMap[Symbol, Scope]()
+ private def expect(expected: Int, msg: => String) {
+ val tag = readByte()
+ if (tag != expected)
+ errorBadSignature(s"$msg ($tag)")
+ }
+
//println("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug
+ @inline private def runAtIndex[T](i: Int)(body: => T): T = {
+ val saved = readIndex
+ readIndex = index(i)
+ try body finally readIndex = saved
+ }
+
// Laboriously unrolled for performance.
def run() {
var i = 0
while (i < index.length) {
- if (entries(i) == null && isSymbolEntry(i)) {
- val savedIndex = readIndex
- readIndex = index(i)
- entries(i) = readSymbol()
- readIndex = savedIndex
- }
+ if (entries(i) == null && isSymbolEntry(i))
+ runAtIndex(i)(entries(i) = readSymbol())
+
i += 1
}
+
// read children last, fix for #3951
i = 0
while (i < index.length) {
if (entries(i) == null) {
- if (isSymbolAnnotationEntry(i)) {
- val savedIndex = readIndex
- readIndex = index(i)
- readSymbolAnnotation()
- readIndex = savedIndex
- }
- else if (isChildrenEntry(i)) {
- val savedIndex = readIndex
- readIndex = index(i)
- readChildren()
- readIndex = savedIndex
- }
+ if (isSymbolAnnotationEntry(i))
+ runAtIndex(i)(readSymbolAnnotation())
+ else if (isChildrenEntry(i))
+ runAtIndex(i)(readChildren())
}
i += 1
}
@@ -145,6 +147,11 @@ abstract class UnPickler {
tag == CHILDREN
}
+ private def maybeReadSymbol(): Either[Int, Symbol] = readNat() match {
+ case index if isSymbolRef(index) => Right(at(index, readSymbol))
+ case index => Left(index)
+ }
+
/** Does entry represent a refinement symbol?
* pre: Entry is a class symbol
*/
@@ -256,14 +263,11 @@ abstract class UnPickler {
val name = at(nameref, readName)
val owner = readSymbolRef()
val flags = pickledToRawFlags(readLongNat())
- var inforef = readNat()
- val privateWithin =
- if (!isSymbolRef(inforef)) NoSymbol
- else {
- val pw = at(inforef, readSymbol)
- inforef = readNat()
- pw
- }
+
+ val (privateWithin, inforef) = maybeReadSymbol() match {
+ case Left(index) => NoSymbol -> index
+ case Right(sym) => sym -> readNat()
+ }
def isModuleFlag = (flags & MODULE) != 0L
def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner)
@@ -305,7 +309,7 @@ abstract class UnPickler {
sym
case MODULEsym =>
- val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... ()
+ val clazz = at(inforef, () => readType()).typeSymbol // after NMT_TRANSITION, we can leave off the () => ... ()
if (isModuleRoot) moduleRoot setFlag pflags
else owner.newLinkedModule(clazz, pflags)
case VALsym =>
@@ -317,84 +321,48 @@ abstract class UnPickler {
})
}
- /** Read a type
- *
- * @param forceProperType is used to ease the transition to NullaryMethodTypes (commentmarker: NMT_TRANSITION)
- * the flag say that a type of kind * is expected, so that PolyType(tps, restpe) can be disambiguated to PolyType(tps, NullaryMethodType(restpe))
- * (if restpe is not a ClassInfoType, a MethodType or a NullaryMethodType, which leaves TypeRef/SingletonType -- the latter would make the polytype a type constructor)
- */
protected def readType(forceProperType: Boolean = false): Type = {
val tag = readByte()
val end = readEnd()
+ @inline def all[T](body: => T): List[T] = until(end, () => body)
+
+ def readTypes() = all(readTypeRef)
+ def readSymbols() = all(readSymbolRef)
+ def readAnnots() = all(readAnnotationRef)
+
+ // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType.
+ // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct
+ // alternative after parsing the arguments.
+ def MethodTypeRef(restpe: Type, params: List[Symbol]): Type = (
+ if (restpe == NoType || (params contains NoSymbol)) NoType
+ else MethodType(params, restpe)
+ )
+ def PolyOrNullaryType(restpe: Type, tparams: List[Symbol]): Type = tparams match {
+ case Nil => NullaryMethodType(restpe)
+ case _ => PolyType(tparams, restpe)
+ }
+ def CompoundType(clazz: Symbol, parents: List[Type]): Type = tag match {
+ case REFINEDtpe => RefinedType(parents, symScope(clazz), clazz)
+ case CLASSINFOtpe => ClassInfoType(parents, symScope(clazz), clazz)
+ }
+
+ // 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.
(tag: @switch) match {
- case NOtpe =>
- NoType
- case NOPREFIXtpe =>
- NoPrefix
- case THIStpe =>
- ThisType(readSymbolRef())
- case SINGLEtpe =>
- SingleType(readTypeRef(), readSymbolRef()) // !!! was singleType
- case SUPERtpe =>
- val thistpe = readTypeRef()
- val supertpe = readTypeRef()
- SuperType(thistpe, supertpe)
- case CONSTANTtpe =>
- ConstantType(readConstantRef())
- case TYPEREFtpe =>
- val pre = readTypeRef()
- val sym = readSymbolRef()
- val args = until(end, readTypeRef)
- TypeRef(pre, sym, args)
- case TYPEBOUNDStpe =>
- TypeBounds(readTypeRef(), readTypeRef())
- case REFINEDtpe =>
- val clazz = readSymbolRef()
- RefinedType(until(end, readTypeRef), symScope(clazz), clazz)
- case CLASSINFOtpe =>
- val clazz = readSymbolRef()
- ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz)
- case METHODtpe | IMPLICITMETHODtpe =>
- val restpe = readTypeRef()
- val params = until(end, readSymbolRef)
- // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType.
- // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct
- // alternative after parsing the arguments.
- if (params.contains(NoSymbol) || restpe == NoType) NoType
- else MethodType(params, restpe)
- case POLYtpe =>
- val restpe = readTypeRef()
- val typeParams = until(end, readSymbolRef)
- if (typeParams.nonEmpty) {
- // NMT_TRANSITION: old class files denoted a polymorphic nullary method as PolyType(tps, restpe), we now require PolyType(tps, NullaryMethodType(restpe))
- // when a type of kind * is expected (forceProperType is true), we know restpe should be wrapped in a NullaryMethodType (if it wasn't suitably wrapped yet)
- def transitionNMT(restpe: Type) = {
- val resTpeCls = restpe.getClass.toString // what's uglier than isInstanceOf? right! -- isInstanceOf does not work since the concrete types are defined in the compiler (not in scope here)
- if(forceProperType /*&& pickleformat < 2.9 */ && !(resTpeCls.endsWith("MethodType"))) { assert(!resTpeCls.contains("ClassInfoType"))
- NullaryMethodType(restpe) }
- else restpe
- }
- PolyType(typeParams, transitionNMT(restpe))
- }
- else
- NullaryMethodType(restpe)
- case EXISTENTIALtpe =>
- val restpe = readTypeRef()
- newExistentialType(until(end, readSymbolRef), restpe)
-
- case ANNOTATEDtpe =>
- var typeRef = readNat()
- val selfsym = if (isSymbolRef(typeRef)) {
- val s = at(typeRef, readSymbol)
- typeRef = readNat()
- s
- } else NoSymbol // selfsym can go.
- val tp = at(typeRef, () => readType(forceProperType)) // NMT_TRANSITION
- val annots = until(end, readAnnotationRef)
- if (selfsym == NoSymbol) AnnotatedType(annots, tp, selfsym)
- else tp
- case _ =>
- noSuchTypeTag(tag, end)
+ case NOtpe => NoType
+ case NOPREFIXtpe => NoPrefix
+ case THIStpe => ThisType(readSymbolRef())
+ case SINGLEtpe => SingleType(readTypeRef(), readSymbolRef())
+ case SUPERtpe => SuperType(readTypeRef(), readTypeRef())
+ case CONSTANTtpe => ConstantType(readConstantRef())
+ case TYPEREFtpe => TypeRef(readTypeRef(), readSymbolRef(), readTypes())
+ case TYPEBOUNDStpe => TypeBounds(readTypeRef(), readTypeRef())
+ case REFINEDtpe | CLASSINFOtpe => CompoundType(readSymbolRef(), readTypes())
+ case METHODtpe => MethodTypeRef(readTypeRef(), readSymbols())
+ case POLYtpe => PolyOrNullaryType(readTypeRef(), readSymbols())
+ case EXISTENTIALtpe => ExistentialType(underlying = readTypeRef(), quantified = readSymbols())
+ case ANNOTATEDtpe => AnnotatedType(underlying = readTypeRef(), annotations = readAnnots(), selfsym = NoSymbol)
}
}
@@ -483,9 +451,7 @@ abstract class UnPickler {
* the symbol it requests. Called at top-level, for all
* (symbol, annotInfo) entries. */
protected def readSymbolAnnotation() {
- val tag = readByte()
- if (tag != SYMANNOT)
- errorBadSignature("symbol annotation expected ("+ tag +")")
+ expect(SYMANNOT, "symbol annotation expected")
val end = readEnd()
val target = readSymbolRef()
target.addAnnotation(readAnnotationInfo(end))
@@ -501,260 +467,100 @@ abstract class UnPickler {
readAnnotationInfo(end)
}
- /* Read an abstract syntax tree */
- protected def readTree(): Tree = {
- val outerTag = readByte()
- if (outerTag != TREE)
- errorBadSignature("tree expected (" + outerTag + ")")
- val end = readEnd()
- val tag = readByte()
- val tpe = if (tag == EMPTYtree) NoType else readTypeRef()
-
- // Set by the three functions to follow. If symbol is non-null
- // after the new tree 't' has been created, t has its Symbol
- // set to symbol; and it always has its Type set to tpe.
- var symbol: Symbol = null
- var mods: Modifiers = null
- var name: Name = null
-
- /* Read a Symbol, Modifiers, and a Name */
- def setSymModsName() {
- symbol = readSymbolRef()
- mods = readModifiersRef()
- name = readNameRef()
+ private def readNonEmptyTree(tag: Int, end: Int): Tree = {
+ @inline def all[T](body: => T): List[T] = until(end, () => body)
+ @inline def rep[T](body: => T): List[T] = times(readNat(), () => body)
+
+ // !!! What is this doing here?
+ def fixApply(tree: Apply, tpe: Type): Apply = {
+ val Apply(fun, args) = tree
+ if (fun.symbol.isOverloaded) {
+ fun setType fun.symbol.info
+ inferMethodAlternative(fun, args map (_.tpe), tpe)
+ }
+ tree
}
- /* Read a Symbol and a Name */
- def setSymName() {
- symbol = readSymbolRef()
- name = readNameRef()
+ def ref() = readTreeRef()
+ def caseRef() = readCaseDefRef()
+ def modsRef() = readModifiersRef()
+ def implRef() = readTemplateRef()
+ def nameRef() = readNameRef()
+ def tparamRef() = readTypeDefRef()
+ def vparamRef() = readValDefRef()
+ def constRef() = readConstantRef()
+ def idRef() = readIdentRef()
+ def termNameRef() = readNameRef().toTermName
+ def typeNameRef() = readNameRef().toTypeName
+ def refTreeRef() = ref() match {
+ case t: RefTree => t
+ case t => errorBadSignature("RefTree expected, found " + t.shortClass)
}
- /* Read a Symbol */
- def setSym() {
- symbol = readSymbolRef()
+ def selectorsRef() = all(ImportSelector(nameRef(), -1, nameRef(), -1))
+
+ /** A few of the most popular trees have been pulled to the top for
+ * switch efficiency purposes.
+ */
+ def readTree(tpe: Type): Tree = (tag: @switch) match {
+ case IDENTtree => Ident(nameRef)
+ case SELECTtree => Select(ref, nameRef)
+ case APPLYtree => fixApply(Apply(ref, all(ref)), tpe) // !!!
+ case BINDtree => Bind(nameRef, ref)
+ case BLOCKtree => all(ref) match { case stats :+ expr => Block(stats, expr) }
+ case IFtree => If(ref, ref, ref)
+ case LITERALtree => Literal(constRef)
+ case TYPEAPPLYtree => TypeApply(ref, all(ref))
+ case TYPEDtree => Typed(ref, ref)
+ case ALTERNATIVEtree => Alternative(all(ref))
+ case ANNOTATEDtree => Annotated(ref, ref)
+ case APPLIEDTYPEtree => AppliedTypeTree(ref, all(ref))
+ case APPLYDYNAMICtree => ApplyDynamic(ref, all(ref))
+ case ARRAYVALUEtree => ArrayValue(ref, all(ref))
+ case ASSIGNtree => Assign(ref, ref)
+ case CASEtree => CaseDef(ref, ref, ref)
+ case CLASStree => ClassDef(modsRef, typeNameRef, rep(tparamRef), implRef)
+ case COMPOUNDTYPEtree => CompoundTypeTree(implRef)
+ case DEFDEFtree => DefDef(modsRef, termNameRef, rep(tparamRef), rep(rep(vparamRef)), ref, ref)
+ case EXISTENTIALTYPEtree => ExistentialTypeTree(ref, all(ref))
+ case FUNCTIONtree => Function(rep(vparamRef), ref)
+ case IMPORTtree => Import(ref, selectorsRef)
+ case LABELtree => LabelDef(termNameRef, rep(idRef), ref)
+ case MATCHtree => Match(ref, all(caseRef))
+ case MODULEtree => ModuleDef(modsRef, termNameRef, implRef)
+ case NEWtree => New(ref)
+ case PACKAGEtree => PackageDef(refTreeRef, all(ref))
+ case RETURNtree => Return(ref)
+ case SELECTFROMTYPEtree => SelectFromTypeTree(ref, typeNameRef)
+ case SINGLETONTYPEtree => SingletonTypeTree(ref)
+ case STARtree => Star(ref)
+ case SUPERtree => Super(ref, typeNameRef)
+ case TEMPLATEtree => Template(rep(ref), vparamRef, all(ref))
+ case THIStree => This(typeNameRef)
+ case THROWtree => Throw(ref)
+ case TREtree => Try(ref, rep(caseRef), ref)
+ case TYPEBOUNDStree => TypeBoundsTree(ref, ref)
+ case TYPEDEFtree => TypeDef(modsRef, typeNameRef, rep(tparamRef), ref)
+ case TYPEtree => TypeTree()
+ case UNAPPLYtree => UnApply(ref, all(ref))
+ case VALDEFtree => ValDef(modsRef, termNameRef, ref, ref)
+ case _ => noSuchTreeTag(tag, end)
}
- val t = tag match {
- case EMPTYtree =>
- EmptyTree
-
- case PACKAGEtree =>
- setSym()
- val pid = readTreeRef().asInstanceOf[RefTree]
- val stats = until(end, readTreeRef)
- PackageDef(pid, stats)
-
- case CLASStree =>
- setSymModsName()
- val impl = readTemplateRef()
- val tparams = until(end, readTypeDefRef)
- ClassDef(mods, name.toTypeName, tparams, impl)
-
- case MODULEtree =>
- setSymModsName()
- ModuleDef(mods, name.toTermName, readTemplateRef())
-
- case VALDEFtree =>
- setSymModsName()
- val tpt = readTreeRef()
- val rhs = readTreeRef()
- ValDef(mods, name.toTermName, tpt, rhs)
-
- case DEFDEFtree =>
- setSymModsName()
- val tparams = times(readNat(), readTypeDefRef)
- val vparamss = times(readNat(), () => times(readNat(), readValDefRef))
- val tpt = readTreeRef()
- val rhs = readTreeRef()
- DefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs)
-
- case TYPEDEFtree =>
- setSymModsName()
- val rhs = readTreeRef()
- val tparams = until(end, readTypeDefRef)
- TypeDef(mods, name.toTypeName, tparams, rhs)
-
- case LABELtree =>
- setSymName()
- val rhs = readTreeRef()
- val params = until(end, readIdentRef)
- LabelDef(name.toTermName, params, rhs)
-
- case IMPORTtree =>
- setSym()
- val expr = readTreeRef()
- val selectors = until(end, () => {
- val from = readNameRef()
- val to = readNameRef()
- ImportSelector(from, -1, to, -1)
- })
-
- Import(expr, selectors)
-
- case TEMPLATEtree =>
- setSym()
- val parents = times(readNat(), readTreeRef)
- val self = readValDefRef()
- val body = until(end, readTreeRef)
-
- Template(parents, self, body)
-
- case BLOCKtree =>
- val expr = readTreeRef()
- val stats = until(end, readTreeRef)
- Block(stats, expr)
-
- case CASEtree =>
- val pat = readTreeRef()
- val guard = readTreeRef()
- val body = readTreeRef()
- CaseDef(pat, guard, body)
-
- case ALTERNATIVEtree =>
- Alternative(until(end, readTreeRef))
-
- case STARtree =>
- Star(readTreeRef())
-
- case BINDtree =>
- setSymName()
- Bind(name, readTreeRef())
-
- case UNAPPLYtree =>
- val fun = readTreeRef()
- val args = until(end, readTreeRef)
- UnApply(fun, args)
-
- case ARRAYVALUEtree =>
- val elemtpt = readTreeRef()
- val trees = until(end, readTreeRef)
- ArrayValue(elemtpt, trees)
-
- case FUNCTIONtree =>
- setSym()
- val body = readTreeRef()
- val vparams = until(end, readValDefRef)
- Function(vparams, body)
-
- case ASSIGNtree =>
- val lhs = readTreeRef()
- val rhs = readTreeRef()
- Assign(lhs, rhs)
-
- case IFtree =>
- val cond = readTreeRef()
- val thenp = readTreeRef()
- val elsep = readTreeRef()
- If(cond, thenp, elsep)
-
- case MATCHtree =>
- val selector = readTreeRef()
- val cases = until(end, readCaseDefRef)
- Match(selector, cases)
-
- case RETURNtree =>
- setSym()
- Return(readTreeRef())
-
- case TREtree =>
- val block = readTreeRef()
- val finalizer = readTreeRef()
- val catches = until(end, readCaseDefRef)
- Try(block, catches, finalizer)
-
- case THROWtree =>
- Throw(readTreeRef())
-
- case NEWtree =>
- New(readTreeRef())
-
- case TYPEDtree =>
- val expr = readTreeRef()
- val tpt = readTreeRef()
- Typed(expr, tpt)
-
- case TYPEAPPLYtree =>
- val fun = readTreeRef()
- val args = until(end, readTreeRef)
- TypeApply(fun, args)
-
- case APPLYtree =>
- val fun = readTreeRef()
- val args = until(end, readTreeRef)
- if (fun.symbol.isOverloaded) {
- fun.setType(fun.symbol.info)
- inferMethodAlternative(fun, args map (_.tpe), tpe)
- }
- Apply(fun, args)
-
- case APPLYDYNAMICtree =>
- setSym()
- val qual = readTreeRef()
- val args = until(end, readTreeRef)
- ApplyDynamic(qual, args)
-
- case SUPERtree =>
- setSym()
- val qual = readTreeRef()
- val mix = readTypeNameRef()
- Super(qual, mix)
-
- case THIStree =>
- setSym()
- This(readTypeNameRef())
-
- case SELECTtree =>
- setSym()
- val qualifier = readTreeRef()
- val selector = readNameRef()
- Select(qualifier, selector)
-
- case IDENTtree =>
- setSymName()
- Ident(name)
-
- case LITERALtree =>
- Literal(readConstantRef())
-
- case TYPEtree =>
- TypeTree()
-
- case ANNOTATEDtree =>
- val annot = readTreeRef()
- val arg = readTreeRef()
- Annotated(annot, arg)
-
- case SINGLETONTYPEtree =>
- SingletonTypeTree(readTreeRef())
-
- case SELECTFROMTYPEtree =>
- val qualifier = readTreeRef()
- val selector = readTypeNameRef()
- SelectFromTypeTree(qualifier, selector)
-
- case COMPOUNDTYPEtree =>
- CompoundTypeTree(readTemplateRef())
-
- case APPLIEDTYPEtree =>
- val tpt = readTreeRef()
- val args = until(end, readTreeRef)
- AppliedTypeTree(tpt, args)
-
- case TYPEBOUNDStree =>
- val lo = readTreeRef()
- val hi = readTreeRef()
- TypeBoundsTree(lo, hi)
-
- case EXISTENTIALTYPEtree =>
- val tpt = readTreeRef()
- val whereClauses = until(end, readTreeRef)
- ExistentialTypeTree(tpt, whereClauses)
+ val tpe = readTypeRef()
+ val sym = if (isTreeSymbolPickled(tag)) readSymbolRef() else null
+ val result = readTree(tpe)
- case _ =>
- noSuchTreeTag(tag, end)
- }
+ if (sym ne null) result setSymbol sym
+ result setType tpe
+ }
- if (symbol == null) t setType tpe
- else t setSymbol symbol setType tpe
+ /* Read an abstract syntax tree */
+ protected def readTree(): Tree = {
+ expect(TREE, "tree expected")
+ val end = readEnd()
+ readByte() match {
+ case EMPTYtree => EmptyTree
+ case tag => readNonEmptyTree(tag, end)
+ }
}
def noSuchTreeTag(tag: Int, end: Int) =
@@ -853,7 +659,7 @@ abstract class UnPickler {
override def complete(sym: Symbol) : Unit = try {
val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType`
if (p ne null)
- enteringPhase(p) (sym setInfo tp)
+ slowButSafeEnteringPhase(p) (sym setInfo tp)
if (currentRunId != definedAtRunId)
sym.setInfo(adaptToNewRunMap(tp))
}
@@ -871,7 +677,7 @@ abstract class UnPickler {
super.complete(sym)
var alias = at(j, readSymbol)
if (alias.isOverloaded)
- alias = enteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
+ alias = slowButSafeEnteringPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
sym.asInstanceOf[TermSymbol].setAlias(alias)
}
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
index e21e95903b..28afd18fe0 100644
--- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -33,23 +33,26 @@ abstract class MutableSettings extends AbsSettings {
}
}
- def overrideObjects: BooleanSetting
- def printtypes: BooleanSetting
+ def Xexperimental: BooleanSetting
+ def XfullLubs: BooleanSetting
+ def XnoPatmatAnalysis: BooleanSetting
+ def Xprintpos: BooleanSetting
+ def Yposdebug: BooleanSetting
+ def Yrangepos: BooleanSetting
+ def Yshowsymkinds: BooleanSetting
+ def breakCycles: BooleanSetting
def debug: BooleanSetting
+ def developer: BooleanSetting
def explaintypes: BooleanSetting
- def verbose: BooleanSetting
+ def overrideObjects: BooleanSetting
+ def printtypes: BooleanSetting
def uniqid: BooleanSetting
- def Yshowsymkinds: BooleanSetting
- def Yposdebug: BooleanSetting
- def Yrangepos: BooleanSetting
- def Xprintpos: BooleanSetting
+ def verbose: BooleanSetting
+
def Yrecursion: IntSetting
def maxClassfileName: IntSetting
- def Xexperimental: BooleanSetting
- def XnoPatmatAnalysis: BooleanSetting
- def XfullLubs: BooleanSetting
- def breakCycles: BooleanSetting
}
+
object MutableSettings {
import scala.language.implicitConversions
/** Support the common use case, `if (settings.debug) println("Hello, martin.")` */
diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
index 6fa536d84c..6b33aca025 100644
--- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
+++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
@@ -251,8 +251,11 @@ private[internal] trait GlbLubs {
else if (isNumericSubType(t2, t1)) t1
else IntTpe)
- private val lubResults = new mutable.HashMap[(Depth, List[Type]), Type]
- private val glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ private val _lubResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ def lubResults = _lubResults
+
+ private val _glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ def glbResults = _glbResults
/** Given a list of types, finds all the base classes they have in
* common, then returns a list of type constructors derived directly
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
index 6532bce9f0..b60fecd66e 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
@@ -14,7 +14,8 @@ trait TypeComparers {
private final val LogPendingSubTypesThreshold = TypeConstants.DefaultLogThreshhold
- private val pendingSubTypes = new mutable.HashSet[SubTypePair]
+ private val _pendingSubTypes = new mutable.HashSet[SubTypePair]
+ def pendingSubTypes = _pendingSubTypes
class SubTypePair(val tp1: Type, val tp2: Type) {
override def hashCode = tp1.hashCode * 41 + tp2.hashCode
@@ -33,7 +34,9 @@ trait TypeComparers {
override def toString = tp1+" <:<? "+tp2
}
- private var subsametypeRecursions: Int = 0
+ private var _subsametypeRecursions: Int = 0
+ def subsametypeRecursions = _subsametypeRecursions
+ def subsametypeRecursions_=(value: Int) = _subsametypeRecursions = value
private def isUnifiable(pre1: Type, pre2: Type) = (
(isEligibleForPrefixUnification(pre1) || isEligibleForPrefixUnification(pre2))
@@ -100,17 +103,13 @@ trait TypeComparers {
// isSameType1(tp1, tp2)
// }
- undoLog.lock()
+ val before = undoLog.log
+ var result = false
try {
- val before = undoLog.log
- var result = false
- try {
- result = isSameType1(tp1, tp2)
- }
- finally if (!result) undoLog.undoTo(before)
- result
+ result = isSameType1(tp1, tp2)
}
- finally undoLog.unlock()
+ finally if (!result) undoLog.undoTo(before)
+ result
}
finally {
subsametypeRecursions -= 1
@@ -256,30 +255,27 @@ trait TypeComparers {
// }
// }
- undoLog.lock()
- try {
- val before = undoLog.log
- var result = false
-
- try result = { // if subtype test fails, it should not affect constraints on typevars
- if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
- val p = new SubTypePair(tp1, tp2)
- if (pendingSubTypes(p))
- false
- else
- try {
- pendingSubTypes += p
- isSubType1(tp1, tp2, depth)
- } finally {
- pendingSubTypes -= p
- }
- } else {
- isSubType1(tp1, tp2, depth)
- }
- } finally if (!result) undoLog.undoTo(before)
+ val before = undoLog.log
+ var result = false
+
+ try result = { // if subtype test fails, it should not affect constraints on typevars
+ if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+ val p = new SubTypePair(tp1, tp2)
+ if (pendingSubTypes(p))
+ false
+ else
+ try {
+ pendingSubTypes += p
+ isSubType1(tp1, tp2, depth)
+ } finally {
+ pendingSubTypes -= p
+ }
+ } else {
+ isSubType1(tp1, tp2, depth)
+ }
+ } finally if (!result) undoLog.undoTo(before)
- result
- } finally undoLog.unlock()
+ result
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
index fdfe376c18..e2159d30f5 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
@@ -13,34 +13,14 @@ private[internal] trait TypeConstraints {
/** A log of type variable with their original constraints. Used in order
* to undo constraints in the case of isSubType/isSameType failure.
*/
- lazy val undoLog = newUndoLog
-
- protected def newUndoLog = new UndoLog
+ private lazy val _undoLog = new UndoLog
+ def undoLog = _undoLog
class UndoLog extends Clearable {
private type UndoPairs = List[(TypeVar, TypeConstraint)]
//OPT this method is public so we can do `manual inlining`
var log: UndoPairs = List()
- /*
- * These two methods provide explicit locking mechanism that is overridden in SynchronizedUndoLog.
- *
- * The idea behind explicit locking mechanism is that all public methods that access mutable state
- * will have to obtain the lock for their entire execution so both reads and writes can be kept in
- * right order. Originally, that was achieved by overriding those public methods in
- * `SynchronizedUndoLog` which was fine but expensive. The reason is that those public methods take
- * thunk as argument and if we keep them non-final there's no way to make them inlined so thunks
- * can go away.
- *
- * By using explicit locking we can achieve inlining.
- *
- * NOTE: They are made public for now so we can apply 'manual inlining' (copy&pasting into hot
- * places implementation of `undo` or `undoUnless`). This should be changed back to protected
- * once inliner is fixed.
- */
- def lock(): Unit = ()
- def unlock(): Unit = ()
-
// register with the auto-clearing cache manager
perRunCaches.recordCache(this)
@@ -64,23 +44,16 @@ private[internal] trait TypeConstraints {
}
def clear() {
- lock()
- try {
- if (settings.debug)
- self.log("Clearing " + log.size + " entries from the undoLog.")
- log = Nil
- } finally unlock()
+ if (settings.debug)
+ self.log("Clearing " + log.size + " entries from the undoLog.")
+ log = Nil
}
// `block` should not affect constraints on typevars
def undo[T](block: => T): T = {
- lock()
- try {
- val before = log
-
- try block
- finally undoTo(before)
- } finally unlock()
+ val before = log
+ try block
+ finally undoTo(before)
}
}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
index 7e98ac03d5..9a54ad8217 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
@@ -581,6 +581,7 @@ private[internal] trait TypeMaps {
else if (!matchesPrefixAndClass(pre, clazz)(tparam.owner))
loop(nextBase.prefix, clazz.owner)
else nextBase match {
+ case NoType => loop(NoType, clazz.owner) // backstop for SI-2797, must remove `SingletonType#isHigherKinded` and run pos/t2797.scala to get here.
case applied @ TypeRef(_, _, _) => correspondingTypeArgument(classParam, applied)
case ExistentialType(eparams, qtpe) => captureSkolems(eparams) ; loop(qtpe, clazz)
case t => abort(s"$tparam in ${tparam.owner} cannot be instantiated from ${seenFromPrefix.widen}")
@@ -593,10 +594,8 @@ private[internal] trait TypeMaps {
// Since pre may be something like ThisType(A) where trait A { self: B => },
// we have to test the typeSymbol of the widened type, not pre.typeSymbol, or
// B will not be considered.
- private def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol) = pre.widen match {
- case _: TypeVar => false
- case wide => (clazz == candidate) && (wide.typeSymbol isSubClass clazz)
- }
+ private def matchesPrefixAndClass(pre: Type, clazz: Symbol)(candidate: Symbol) =
+ (clazz == candidate) && (pre.widen.typeSymbol isSubClass clazz)
// Whether the annotation tree currently being mapped over has had a This(_) node rewritten.
private[this] var wroteAnnotation = false
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
index 16929cca0f..ebc4394d25 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala
@@ -10,7 +10,9 @@ private[internal] trait TypeToStrings {
*/
final val maxTostringRecursions = 50
- private var tostringRecursions = 0
+ private var _tostringRecursions = 0
+ def tostringRecursions = _tostringRecursions
+ def tostringRecursions_=(value: Int) = _tostringRecursions = value
protected def typeToString(tpe: Type): String =
if (tostringRecursions >= maxTostringRecursions) {
diff --git a/src/reflect/scala/reflect/runtime/Gil.scala b/src/reflect/scala/reflect/runtime/Gil.scala
new file mode 100644
index 0000000000..0edb1e5748
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/Gil.scala
@@ -0,0 +1,25 @@
+package scala.reflect
+package runtime
+
+private[reflect] trait Gil {
+ self: SymbolTable =>
+
+ // fixme... please...
+ // there are the following avenues of optimization we discussed with Roland:
+ // 1) replace PackageScope locks with ConcurrentHashMap, because PackageScope materializers seem to be idempotent
+ // 2) unlock unpickling completers by verifying that they are idempotent or moving non-idempotent parts
+ // 3) remove the necessity in global state for isSubType
+ private lazy val gil = new java.util.concurrent.locks.ReentrantLock
+
+ @inline final def gilSynchronized[T](body: => T): T = {
+ if (isCompilerUniverse) body
+ else {
+ try {
+ gil.lock()
+ body
+ } finally {
+ gil.unlock()
+ }
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 1a15454500..1e2dd6b7d3 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -22,7 +22,7 @@ import ReflectionUtils.{staticSingletonInstance, innerSingletonInstance, scalacS
import scala.language.existentials
import scala.runtime.{ScalaRunTime, BoxesRunTime}
-private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUniverse: SymbolTable =>
+private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse with TwoWayCaches { thisUniverse: SymbolTable =>
private lazy val mirrors = new WeakHashMap[ClassLoader, WeakReference[JavaMirror]]()
@@ -44,19 +44,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
trait JavaClassCompleter extends FlagAssigningCompleter
- def init() = {
- definitions.AnyValClass // force it.
-
- // establish root association to avoid cyclic dependency errors later
- rootMirror.classToScala(classOf[java.lang.Object]).initialize
-
- // println("initializing definitions")
- definitions.init()
- }
-
- def runtimeMirror(cl: ClassLoader): Mirror = mirrors get cl match {
- case Some(WeakReference(m)) => m
- case _ => createMirror(rootMirror.RootClass, cl)
+ def runtimeMirror(cl: ClassLoader): Mirror = gilSynchronized {
+ mirrors get cl match {
+ case Some(WeakReference(m)) => m
+ case _ => createMirror(rootMirror.RootClass, cl)
+ }
}
/** The API of a mirror for a reflective universe */
@@ -69,6 +61,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
import definitions._
+ override lazy val RootPackage = new RootPackage with SynchronizedTermSymbol
+ override lazy val RootClass = new RootClass with SynchronizedModuleClassSymbol
+ override lazy val EmptyPackage = new EmptyPackage with SynchronizedTermSymbol
+ override lazy val EmptyPackageClass = new EmptyPackageClass with SynchronizedModuleClassSymbol
+
/** The lazy type for root.
*/
override lazy val rootLoader = new LazyType with FlagAgnosticCompleter {
@@ -689,7 +686,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
completeRest()
}
- def completeRest(): Unit = thisUniverse.synchronized {
+ def completeRest(): Unit = gilSynchronized {
val tparams = clazz.rawInfo.typeParams
val parents = try {
@@ -894,7 +891,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* The Scala package with given fully qualified name. Unlike `packageNameToScala`,
* this one bypasses the cache.
*/
- private[JavaMirrors] def makeScalaPackage(fullname: String): ModuleSymbol = {
+ private[JavaMirrors] def makeScalaPackage(fullname: String): ModuleSymbol = gilSynchronized {
val split = fullname lastIndexOf '.'
val ownerModule: ModuleSymbol =
if (split > 0) packageNameToScala(fullname take split) else this.RootPackage
@@ -1275,11 +1272,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
case _ => abort(s"${sym}.enclosingRootClass = ${sym.enclosingRootClass}, which is not a RootSymbol")
}
- private lazy val syntheticCoreClasses: Map[(String, Name), Symbol] = {
- def mapEntry(sym: Symbol): ((String, Name), Symbol) = (sym.owner.fullName, sym.name) -> sym
- Map() ++ (definitions.syntheticCoreClasses map mapEntry)
- }
-
/** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package
* <owner>.<name>, otherwise return NoSymbol.
* Exception: If owner is root and a java class with given name exists, create symbol in empty package instead
@@ -1289,20 +1281,20 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def missingHook(owner: Symbol, name: Name): Symbol = {
if (owner.hasPackageFlag) {
val mirror = mirrorThatLoaded(owner)
- // todo. this makes toolbox tests pass, but it's a mere workaround for SI-5865
-// assert((owner.info decl name) == NoSymbol, s"already exists: $owner . $name")
if (owner.isRootSymbol && mirror.tryJavaClass(name.toString).isDefined)
return mirror.EmptyPackageClass.info decl name
if (name.isTermName && !owner.isEmptyPackageClass)
return mirror.makeScalaPackage(
if (owner.isRootSymbol) name.toString else owner.fullName+"."+name)
- syntheticCoreClasses get ((owner.fullName, name)) foreach { tsym =>
- // synthetic core classes are only present in root mirrors
- // because Definitions.scala, which initializes and enters them, only affects rootMirror
- // therefore we need to enter them manually for non-root mirrors
- if (mirror ne thisUniverse.rootMirror) owner.info.decls enter tsym
- return tsym
- }
+ if (name == tpnme.AnyRef && owner.owner.isRoot && owner.name == tpnme.scala_)
+ // when we synthesize the scala.AnyRef symbol, we need to add it to the scope of the scala package
+ // the problem is that adding to the scope implies doing something like `owner.info.decls enter anyRef`
+ // which entails running a completer for the scala package
+ // which will try to unpickle the stuff in scala/package.class
+ // which will transitively load scala.AnyRef
+ // which doesn't exist yet, because it hasn't been added to the scope yet
+ // this missing hook ties the knot without introducing synchronization problems like before
+ return definitions.AnyRefClass
}
info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
super.missingHook(owner, name)
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
index 9d37edbacd..54b75b8e5b 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -8,7 +8,7 @@ package runtime
*
* @contentDiagram hideNodes "*Api" "*Extractor"
*/
-class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self =>
+class JavaUniverse extends internal.SymbolTable with JavaUniverseForce with ReflectSetup with runtime.SymbolTable { self =>
override def inform(msg: String): Unit = log(msg)
def picklerPhase = internal.SomePhase
@@ -29,4 +29,74 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S
} with internal.TreeInfo
init()
+
+ // ======= Initialization of runtime reflection =======
+ //
+ // This doc describes the carefully laid out sequence of actions used to initialize reflective universes.
+ //
+ // Before reading the text below, read up the section Mirrors in the reflection pre-SIP
+ // https://docs.google.com/document/d/1nAwSw4TmMplsIlzh2shYLUJ5mVh3wndDa1Zm1H6an9A/edit.
+ // Take an especially good look at Figure 2, because it illustrates fundamental principles underlying runtime reflection:
+ // 1) For each universe we have one mirror per classloader
+ // 2) Package symbols are per-mirror
+ // 3) Other symbols are per-universe, which means that a symbol (e.g. Seq on the picture) might be shared between multiple owners
+ //
+ // Main challenges that runtime reflection presents wrt initialization are:
+ // 1) Extravagant completion scheme that enters package members on-demand rather than a result of scanning a directory with class files.
+ // (That's a direct consequence of the fact that in general case we can't enumerate all classes in a classloader.
+ // As Paul rightfully mentioned, we could specialcase classloaders that point to filesystems, but that is left for future work).
+ // 2) Presence of synthetic symbols that aren't loaded by normal means (from classfiles) but are synthesized on-the-fly,
+ // and the necessity to propagate these synthetic symbols from rootMirror to other mirrors,
+ // complicated by the fact that such symbols depend on normal symbols (e.g. AnyRef depends on Object).
+ // 3) Necessity to remain thread-safe, which limits our options related to lazy initialization
+ // (E.g. we cannot use missingHook to enter synthetic symbols, because that's thread-unsafe).
+ //
+ // Directly addressing the challenge #3, we create all synthetic symbols fully in advance during init().
+ // However, it's not that simple as just calling definitions.symbolsNotPresentInBytecode.
+ // Before doing that, we need to first initialize ObjectClass, then ScalaPackageClass, and only then deal with synthetics.
+ // Below you can find a detailed explanation for that.
+ //
+ // ### Why ScalaPackageClass? ###
+ //
+ // Forcing ScalaPackageClass first thing during startup is important, because syntheticCoreClasses such as AnyRefClass
+ // need to be entered into ScalaPackageClass, which entails calling ScalaPackageClass.info.decls.enter.
+ // If ScalaPackageClass isn't initialized by that moment, the following will happen for runtime reflection:
+ // 1) Initialization of ScalaPackageClass will trigger unpickling.
+ // 2) Unpickling will need to load some auxiliary types such as, for example, String.
+ // 3) To load String, runtime reflection will call mirrorDefining(classOf[String]).
+ // 4) This, in turn, will call runtimeMirror(classOf[String].getClassLoader).
+ // 5) For some classloader configurations, the resulting mirror will be different from rootMirror.
+ // 6) In that case, initialization of the resulting mirror will try to import definitions.syntheticCoreClasses into the mirror.
+ // 7) This will force all the lazy vals corresponding to syntheticCoreClasses.
+ // 8) By that time, the completer of ScalaPackageClass will have already called setInfo on ScalaPackageClass, so there won't be any stack overflow.
+ //
+ // So far so good, no crashes, no problems, right? Not quite.
+ // If forcing of ScalaPackageClass was called by a syntheticCoreClasses lazy val,
+ // then this lazy val will be entered twice: once during step 7 and once when returning from the original call.
+ // To avoid this we need to initialize ScalaPackageClass prior to other synthetics.
+ //
+ // ### Why ObjectClass? ###
+ //
+ // 1) As explained in JavaMirrors.missingHook, initialization of ScalaPackageClass critically depends on AnyRefClass.
+ // 2) AnyRefClass is defined as "lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectTpe)",
+ // which means that initialization of AnyRefClass depends on ObjectClass.
+ // 3) ObjectClass is defined as "lazy val ObjectClass = getRequiredClass(sn.Object.toString)",
+ // which means that under some classloader configurations (see JavaMirrors.missingHook for more details)
+ // dereferencing ObjectClass might trigger an avalanche of initializations calling back into AnyRefClass
+ // while another AnyRefClass initializer is still on stack.
+ // 4) That will lead to AnyRefClass being entered two times (once when the recursive call returns and once when the original one returns)
+ // 5) That will crash PackageScope.enter that helpfully detects double-enters.
+ //
+ // Therefore, before initializing ScalaPackageClass, we must pre-initialize ObjectClass
+ def init() {
+ definitions.init()
+
+ // workaround for http://groups.google.com/group/scala-internals/browse_thread/thread/97840ba4fd37b52e
+ // constructors are by definition single-threaded, so we initialize all lazy vals (and local object) in advance
+ // in order to avoid deadlocks later (e.g. one thread holds a global reflection lock and waits for definitions.Something to initialize,
+ // whereas another thread holds a definitions.Something initialization lock and needs a global reflection lock to complete the initialization)
+
+ // TODO Convert this into a macro
+ force()
+ }
}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
new file mode 100644
index 0000000000..8fd58c42be
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -0,0 +1,496 @@
+// Generated Code, validated by run/t6240-universe-code-gen.scala
+package scala.reflect
+package runtime
+
+trait JavaUniverseForce { self: runtime.JavaUniverse =>
+ def force() {
+ Literal(Constant(42)).duplicate
+ nme.flattenedName()
+ nme.raw
+ WeakTypeTag
+ TypeTag
+ TypeTag.Byte.tpe
+ TypeTag.Short.tpe
+ TypeTag.Char.tpe
+ TypeTag.Int.tpe
+ TypeTag.Long.tpe
+ TypeTag.Float.tpe
+ TypeTag.Double.tpe
+ TypeTag.Boolean.tpe
+ TypeTag.Unit.tpe
+ TypeTag.Any.tpe
+ TypeTag.AnyVal.tpe
+ TypeTag.AnyRef.tpe
+ TypeTag.Object.tpe
+ TypeTag.Nothing.tpe
+ TypeTag.Null.tpe
+
+ this.settings
+ this.treeInfo
+ // inaccessible: this.scala$reflect$runtime$Gil$$gil
+ // inaccessible: this.uniqueLock
+ // inaccessible: this._skolemizationLevel
+ // inaccessible: this._undoLog
+ // inaccessible: this._intersectionWitness
+ // inaccessible: this._volatileRecursions
+ // inaccessible: this._pendingVolatiles
+ // inaccessible: this._subsametypeRecursions
+ // inaccessible: this._pendingSubTypes
+ // inaccessible: this._basetypeRecursions
+ // inaccessible: this._pendingBaseTypes
+ // inaccessible: this._lubResults
+ // inaccessible: this._glbResults
+ // inaccessible: this._indent
+ // inaccessible: this._tostringRecursions
+ // inaccessible: this.atomicIds
+ // inaccessible: this.atomicExistentialIds
+ // inaccessible: this._recursionTable
+ // inaccessible: this.mirrors
+ this.rootMirror
+ this.treeBuild
+ // inaccessible: this.SimpleNameOrdering
+ this.traceSymbols
+ this.perRunCaches
+ this.FixedMirrorTreeCreator
+ this.FixedMirrorTypeCreator
+ this.BackquotedIdentifierAttachment
+ this.CompoundTypeTreeOriginalAttachment
+ this.noPrint
+ this.typeDebug
+ // inaccessible: this.maxFree
+ this.Range
+ // inaccessible: this.posAssigner
+ this.ConsoleWriter
+ this.RefTree
+ this.PackageDef
+ this.ClassDef
+ this.ModuleDef
+ this.ValOrDefDef
+ this.ValDef
+ this.DefDef
+ this.TypeDef
+ this.LabelDef
+ this.ImportSelector
+ this.Import
+ this.Template
+ this.Block
+ this.CaseDef
+ this.Alternative
+ this.Star
+ this.Bind
+ this.UnApply
+ this.ArrayValue
+ this.Function
+ this.Assign
+ this.AssignOrNamedArg
+ this.If
+ this.Match
+ this.Return
+ this.Try
+ this.Throw
+ this.New
+ this.Typed
+ this.TypeApply
+ this.Apply
+ this.ApplyDynamic
+ this.Super
+ this.This
+ this.Select
+ this.Ident
+ this.ReferenceToBoxed
+ this.Literal
+ this.Annotated
+ this.SingletonTypeTree
+ this.SelectFromTypeTree
+ this.CompoundTypeTree
+ this.AppliedTypeTree
+ this.TypeBoundsTree
+ this.ExistentialTypeTree
+ this.TypeTree
+ this.Modifiers
+ this.EmptyTree
+ this.noSelfType
+ this.pendingSuperCall
+ this.emptyValDef
+ this.EmptyTreeTypeSubstituter
+ // inaccessible: this.duplicator
+ this.UnmappableAnnotArg
+ this.LiteralAnnotArg
+ this.ArrayAnnotArg
+ this.NestedAnnotArg
+ this.ScalaSigBytes
+ this.AnnotationInfo
+ this.Annotation
+ this.UnmappableAnnotation
+ this.ErroneousAnnotation
+ this.ThrownException
+ // inaccessible: this.compactify
+ this.tpnme
+ this.fulltpnme
+ this.binarynme
+ this.nme
+ this.sn
+ this.Constant
+ this.definitions
+ this.LookupSucceeded
+ this.LookupAmbiguous
+ this.LookupInaccessible
+ this.LookupNotFound
+ this.Scope
+ this.EmptyScope
+ this.Flag
+ this.KindErrors
+ this.Kind
+ this.ProperTypeKind
+ this.TypeConKind
+ this.inferKind
+ // inaccessible: this.substTypeMapCache
+ this.UnmappableTree
+ this.ErrorType
+ this.WildcardType
+ this.BoundedWildcardType
+ this.NoType
+ this.NoPrefix
+ this.ThisType
+ this.SingleType
+ this.SuperType
+ this.TypeBounds
+ this.CompoundType
+ this.baseClassesCycleMonitor
+ this.RefinedType
+ this.ClassInfoType
+ this.ConstantType
+ this.TypeRef
+ this.MethodType
+ this.NullaryMethodType
+ this.PolyType
+ this.ExistentialType
+ this.OverloadedType
+ this.AntiPolyType
+ this.HasTypeMember
+ this.ArrayTypeRef
+ this.TypeVar
+ this.AnnotatedType
+ this.StaticallyAnnotatedType
+ this.NamedType
+ this.RepeatedType
+ this.ErasedValueType
+ this.GenPolyType
+ this.unwrapToClass
+ this.unwrapToStableClass
+ this.unwrapWrapperTypes
+ this.RecoverableCyclicReference
+ // inaccessible: this._undoLog
+ // inaccessible: this.numericLoBound
+ // inaccessible: this.numericHiBound
+ this.TypeConstraint
+ this.normalizeAliases
+ this.dropSingletonType
+ this.abstractTypesToBounds
+ this.dropIllegalStarTypes
+ this.IsDependentCollector
+ this.ApproximateDependentMap
+ this.wildcardToTypeVarMap
+ this.typeVarToOriginMap
+ this.ErroneousCollector
+ this.adaptToNewRunMap
+ // inaccessible: this.commonOwnerMapObj
+ this.SymbolKind
+ this.NoSymbol
+ this.CyclicReference
+ // inaccessible: this.TypeHistory
+ this.TermName
+ this.TypeName
+ this.BooleanFlag
+ this.WeakTypeTag
+ this.TypeTag
+ this.Expr
+ this.NoMods
+ definitions.JavaLangPackage
+ definitions.JavaLangPackageClass
+ definitions.ScalaPackage
+ definitions.ScalaPackageClass
+ definitions.RuntimePackage
+ definitions.RuntimePackageClass
+ definitions.AnyClass
+ definitions.AnyRefClass
+ definitions.ObjectClass
+ definitions.AnyRefTpe
+ definitions.AnyTpe
+ definitions.AnyValTpe
+ definitions.BoxedUnitTpe
+ definitions.NothingTpe
+ definitions.NullTpe
+ definitions.ObjectTpe
+ definitions.SerializableTpe
+ definitions.StringTpe
+ definitions.ThrowableTpe
+ definitions.ConstantTrue
+ definitions.ConstantFalse
+ definitions.ConstantNull
+ definitions.AnyValClass
+ definitions.RuntimeNothingClass
+ definitions.RuntimeNullClass
+ definitions.NothingClass
+ definitions.NullClass
+ definitions.ClassCastExceptionClass
+ definitions.IndexOutOfBoundsExceptionClass
+ definitions.InvocationTargetExceptionClass
+ definitions.MatchErrorClass
+ definitions.NonLocalReturnControlClass
+ definitions.NullPointerExceptionClass
+ definitions.ThrowableClass
+ definitions.UninitializedErrorClass
+ definitions.UninitializedFieldConstructor
+ definitions.PartialFunctionClass
+ definitions.AbstractPartialFunctionClass
+ definitions.SymbolClass
+ definitions.StringClass
+ definitions.StringModule
+ definitions.ClassClass
+ definitions.DynamicClass
+ definitions.SysPackage
+ definitions.UnqualifiedModules
+ definitions.UnqualifiedOwners
+ definitions.PredefModule
+ definitions.SpecializableModule
+ definitions.GroupOfSpecializable
+ definitions.ScalaRunTimeModule
+ definitions.SymbolModule
+ definitions.Symbol_apply
+ definitions.StringAddClass
+ definitions.ArrowAssocClass
+ definitions.StringAdd_$plus
+ definitions.ScalaNumberClass
+ definitions.TraitSetterAnnotationClass
+ definitions.DelayedInitClass
+ definitions.TypeConstraintClass
+ definitions.SingletonClass
+ definitions.SerializableClass
+ definitions.JavaSerializableClass
+ definitions.ComparableClass
+ definitions.JavaCloneableClass
+ definitions.JavaNumberClass
+ definitions.RemoteInterfaceClass
+ definitions.RemoteExceptionClass
+ definitions.ByNameParamClass
+ definitions.JavaRepeatedParamClass
+ definitions.RepeatedParamClass
+ definitions.ExprClassOf
+ definitions.ConsClass
+ definitions.IteratorClass
+ definitions.IterableClass
+ definitions.ListClass
+ definitions.SeqClass
+ definitions.StringBuilderClass
+ definitions.TraversableClass
+ definitions.ListModule
+ definitions.List_apply
+ definitions.NilModule
+ definitions.SeqModule
+ definitions.ArrayModule
+ definitions.ArrayModule_overloadedApply
+ definitions.ArrayClass
+ definitions.Array_apply
+ definitions.Array_update
+ definitions.Array_length
+ definitions.Array_clone
+ definitions.SoftReferenceClass
+ definitions.MethodClass
+ definitions.EmptyMethodCacheClass
+ definitions.MethodCacheClass
+ definitions.ScalaXmlTopScope
+ definitions.ScalaXmlPackage
+ definitions.ReflectPackage
+ definitions.ReflectApiPackage
+ definitions.ReflectRuntimePackage
+ definitions.PartialManifestClass
+ definitions.PartialManifestModule
+ definitions.FullManifestClass
+ definitions.FullManifestModule
+ definitions.OptManifestClass
+ definitions.NoManifest
+ definitions.TreesClass
+ definitions.TreesTreeType
+ definitions.TreeType
+ definitions.SubtreeType
+ definitions.ExprsClass
+ definitions.ExprClass
+ definitions.ClassTagModule
+ definitions.ClassTagClass
+ definitions.TypeTagsClass
+ definitions.WeakTypeTagClass
+ definitions.WeakTypeTagModule
+ definitions.TypeTagClass
+ definitions.TypeTagModule
+ definitions.ApiUniverseClass
+ definitions.JavaUniverseClass
+ definitions.MirrorClass
+ definitions.TypeCreatorClass
+ definitions.TreeCreatorClass
+ definitions.LiftableClass
+ definitions.MacroClass
+ definitions.MacroContextClass
+ definitions.MacroImplAnnotation
+ definitions.StringContextClass
+ definitions.QuasiquoteClass
+ definitions.QuasiquoteClass_api
+ definitions.QuasiquoteClass_api_apply
+ definitions.QuasiquoteClass_api_unapply
+ definitions.ScalaSignatureAnnotation
+ definitions.ScalaLongSignatureAnnotation
+ definitions.OptionClass
+ definitions.OptionModule
+ definitions.Option_apply
+ definitions.SomeClass
+ definitions.NoneModule
+ definitions.SomeModule
+ definitions.VarArityClass
+ definitions.ProductClass
+ definitions.TupleClass
+ definitions.FunctionClass
+ definitions.AbstractFunctionClass
+ definitions.ProductRootClass
+ definitions.Any_$eq$eq
+ definitions.Any_$bang$eq
+ definitions.Any_equals
+ definitions.Any_hashCode
+ definitions.Any_toString
+ definitions.Any_$hash$hash
+ definitions.Any_getClass
+ definitions.Any_isInstanceOf
+ definitions.Any_asInstanceOf
+ definitions.primitiveGetClassMethods
+ definitions.getClassMethods
+ definitions.Object_$hash$hash
+ definitions.Object_$eq$eq
+ definitions.Object_$bang$eq
+ definitions.Object_eq
+ definitions.Object_ne
+ definitions.Object_isInstanceOf
+ definitions.Object_asInstanceOf
+ definitions.Object_synchronized
+ definitions.String_$plus
+ definitions.ObjectRefClass
+ definitions.VolatileObjectRefClass
+ definitions.RuntimeStaticsModule
+ definitions.BoxesRunTimeModule
+ definitions.BoxesRunTimeClass
+ definitions.BoxedNumberClass
+ definitions.BoxedCharacterClass
+ definitions.BoxedBooleanClass
+ definitions.BoxedByteClass
+ definitions.BoxedShortClass
+ definitions.BoxedIntClass
+ definitions.BoxedLongClass
+ definitions.BoxedFloatClass
+ definitions.BoxedDoubleClass
+ definitions.Boxes_isNumberOrBool
+ definitions.Boxes_isNumber
+ definitions.BoxedUnitClass
+ definitions.BoxedUnitModule
+ definitions.AnnotationClass
+ definitions.ClassfileAnnotationClass
+ definitions.StaticAnnotationClass
+ definitions.BridgeClass
+ definitions.ElidableMethodClass
+ definitions.ImplicitNotFoundClass
+ definitions.MigrationAnnotationClass
+ definitions.ScalaStrictFPAttr
+ definitions.SwitchClass
+ definitions.TailrecClass
+ definitions.VarargsClass
+ definitions.uncheckedStableClass
+ definitions.uncheckedVarianceClass
+ definitions.BeanPropertyAttr
+ definitions.BooleanBeanPropertyAttr
+ definitions.CompileTimeOnlyAttr
+ definitions.DeprecatedAttr
+ definitions.DeprecatedNameAttr
+ definitions.DeprecatedInheritanceAttr
+ definitions.DeprecatedOverridingAttr
+ definitions.NativeAttr
+ definitions.RemoteAttr
+ definitions.ScalaInlineClass
+ definitions.ScalaNoInlineClass
+ definitions.SerialVersionUIDAttr
+ definitions.SerialVersionUIDAnnotation
+ definitions.SpecializedClass
+ definitions.ThrowsClass
+ definitions.TransientAttr
+ definitions.UncheckedClass
+ definitions.UncheckedBoundsClass
+ definitions.UnspecializedClass
+ definitions.VolatileAttr
+ definitions.BeanGetterTargetClass
+ definitions.BeanSetterTargetClass
+ definitions.FieldTargetClass
+ definitions.GetterTargetClass
+ definitions.ParamTargetClass
+ definitions.SetterTargetClass
+ definitions.ObjectTargetClass
+ definitions.ClassTargetClass
+ definitions.MethodTargetClass
+ definitions.LanguageFeatureAnnot
+ definitions.languageFeatureModule
+ definitions.experimentalModule
+ definitions.MacrosFeature
+ definitions.DynamicsFeature
+ definitions.PostfixOpsFeature
+ definitions.ReflectiveCallsFeature
+ definitions.ImplicitConversionsFeature
+ definitions.HigherKindsFeature
+ definitions.ExistentialsFeature
+ definitions.metaAnnotations
+ definitions.AnnotationDefaultAttr
+ definitions.isUnbox
+ definitions.isBox
+ definitions.isPhantomClass
+ definitions.syntheticCoreClasses
+ definitions.syntheticCoreMethods
+ definitions.hijackedCoreClasses
+ definitions.symbolsNotPresentInBytecode
+ definitions.isPossibleSyntheticParent
+ // inaccessible: definitions.boxedValueClassesSet
+ definitions.abbrvTag
+ definitions.numericWeight
+ definitions.boxedModule
+ definitions.boxedClass
+ definitions.refClass
+ definitions.volatileRefClass
+ definitions.boxMethod
+ definitions.unboxMethod
+ definitions.UnitClass
+ definitions.ByteClass
+ definitions.ShortClass
+ definitions.CharClass
+ definitions.IntClass
+ definitions.LongClass
+ definitions.FloatClass
+ definitions.DoubleClass
+ definitions.BooleanClass
+ definitions.Boolean_and
+ definitions.Boolean_or
+ definitions.Boolean_not
+ definitions.UnitTpe
+ definitions.ByteTpe
+ definitions.ShortTpe
+ definitions.CharTpe
+ definitions.IntTpe
+ definitions.LongTpe
+ definitions.FloatTpe
+ definitions.DoubleTpe
+ definitions.BooleanTpe
+ definitions.ScalaNumericValueClasses
+ definitions.ScalaValueClassesNoUnit
+ definitions.ScalaValueClasses
+
+
+ erasure.GenericArray
+ erasure.scalaErasure
+ erasure.specialScalaErasure
+ erasure.javaErasure
+ erasure.verifiedJavaErasure
+ erasure.boxingErasure
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala
index d65e9329ed..11db83d7d5 100644
--- a/src/reflect/scala/reflect/runtime/Settings.scala
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -34,16 +34,17 @@ private[reflect] class Settings extends MutableSettings {
val XfullLubs = new BooleanSetting(false)
val XnoPatmatAnalysis = new BooleanSetting(false)
val Xprintpos = new BooleanSetting(false)
- val Yshowsymkinds = new BooleanSetting(false)
val Yposdebug = new BooleanSetting(false)
val Yrangepos = new BooleanSetting(false)
+ val Yshowsymkinds = new BooleanSetting(false)
+ val breakCycles = new BooleanSetting(false)
val debug = new BooleanSetting(false)
+ val developer = new BooleanSetting(false)
val explaintypes = new BooleanSetting(false)
val overrideObjects = new BooleanSetting(false)
val printtypes = new BooleanSetting(false)
val uniqid = new BooleanSetting(false)
val verbose = new BooleanSetting(false)
- val breakCycles = new BooleanSetting(false)
val Yrecursion = new IntSetting(0)
val maxClassfileName = new IntSetting(255)
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index 3e01a6df02..c6059ac402 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -17,37 +17,13 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
* is found, a package is created instead.
*/
class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader with FlagAssigningCompleter {
-// def makePackage() {
-// println("wrong guess; making package "+clazz)
-// val ptpe = newPackageType(module.moduleClass)
-// for (sym <- List(clazz, module, module.moduleClass)) {
-// sym setFlag Flags.PACKAGE
-// sym setInfo ptpe
-// }
-// }
-
override def complete(sym: Symbol) = {
debugInfo("completing "+sym+"/"+clazz.fullName)
assert(sym == clazz || sym == module || sym == module.moduleClass)
-// try {
- enteringPhaseNotLaterThan(picklerPhase) {
+ slowButSafeEnteringPhaseNotLaterThan(picklerPhase) {
val loadingMirror = mirrorThatLoaded(sym)
val javaClass = loadingMirror.javaClass(clazz.javaClassName)
loadingMirror.unpickleClass(clazz, module, javaClass)
-// } catch {
-// case ex: ClassNotFoundException => makePackage()
-// case ex: NoClassDefFoundError => makePackage()
- // Note: We catch NoClassDefFoundError because there are situations
- // where a package and a class have the same name except for capitalization.
- // It seems in this case the class is loaded even if capitalization differs
- // but then a NoClassDefFound error is issued with a ("wrong name: ...")
- // reason. (I guess this is a concession to Windows).
- // The present behavior is a bit too forgiving, in that it masks
- // all class load errors, not just wrong name errors. We should try
- // to be more discriminating. To get on the right track simply delete
- // the clause above and load a collection class such as collection.Iterable.
- // You'll see an error that class `parallel` has the wrong name.
-// }
}
}
override def load(sym: Symbol) = complete(sym)
@@ -91,12 +67,54 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
}
}
+
+ // Since runtime reflection doesn't have a luxury of enumerating all classes
+ // on the classpath, it has to materialize symbols for top-level definitions
+ // (packages, classes, objects) on demand.
+ //
+ // Someone asks us for a class named `foo.Bar`? Easy. Let's speculatively create
+ // a package named `foo` and then look up `newTypeName("bar")` in its decls.
+ // This lookup, implemented in `SymbolLoaders.PackageScope` tests the waters by
+ // trying to to `Class.forName("foo.Bar")` and then creates a ClassSymbol upon
+ // success (the whole story is a bit longer, but the rest is irrelevant here).
+ //
+ // That's all neat, but these non-deterministic mutations of the global symbol
+ // table give a lot of trouble in multi-threaded setting. One of the popular
+ // reflection crashes happens when multiple threads happen to trigger symbol
+ // materialization multiple times for the same symbol, making subsequent
+ // reflective operations stumble upon outrageous stuff like overloaded packages.
+ //
+ // Short of significantly changing SymbolLoaders I see no other way than just
+ // to slap a global lock on materialization in runtime reflection.
class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand
with SynchronizedScope {
assert(pkgClass.isType)
- // disable fingerprinting as we do not know entries beforehand
- private val negatives = mutable.Set[Name]() // Syncnote: Performance only, so need not be protected.
- override def lookupEntry(name: Name): ScopeEntry = {
+
+ // materializing multiple copies of the same symbol in PackageScope is a very popular bug
+ // this override does its best to guard against it
+ override def enter[T <: Symbol](sym: T): T = {
+ // workaround for SI-7728
+ if (isCompilerUniverse) super.enter(sym)
+ else {
+ val existing = super.lookupEntry(sym.name)
+ // commented out to provide a hotfix for strange class files that javac sometimes emits
+ // see more details at: https://groups.google.com/forum/#!topic/scala-internals/hcnUFk75MgQ
+ // assert(existing == null || existing.sym.isMethod, s"pkgClass = $pkgClass, sym = $sym, existing = $existing")
+ super.enter(sym)
+ }
+ }
+
+ override def enterIfNew[T <: Symbol](sym: T): T = {
+ val existing = super.lookupEntry(sym.name)
+ if (existing == null) enter(sym)
+ else existing.sym.asInstanceOf[T]
+ }
+
+ // package scopes need to synchronize on the GIL
+ // because lookupEntry might cause changes to the global symbol table
+ override def syncLockSynchronized[T](body: => T): T = gilSynchronized(body)
+ private val negatives = new mutable.HashSet[Name]
+ override def lookupEntry(name: Name): ScopeEntry = syncLockSynchronized {
val e = super.lookupEntry(name)
if (e != null)
e
@@ -119,8 +137,21 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
val module = origOwner.info decl name.toTermName
assert(clazz != NoSymbol)
assert(module != NoSymbol)
- pkgClass.info.decls enter clazz
- pkgClass.info.decls enter module
+ // currentMirror.mirrorDefining(cls) might side effect by entering symbols into pkgClass.info.decls
+ // therefore, even though in the beginning of this method, super.lookupEntry(name) returned null
+ // entering clazz/module now will result in a double-enter assertion in PackageScope.enter
+ // here's how it might happen
+ // 1) we are the rootMirror
+ // 2) cls.getClassLoader is different from our classloader
+ // 3) mirrorDefining(cls) looks up a mirror corresponding to that classloader and cannot find it
+ // 4) mirrorDefining creates a new mirror
+ // 5) that triggers Mirror.init() of the new mirror
+ // 6) that triggers definitions.syntheticCoreClasses
+ // 7) that might materialize symbols and enter them into our scope (because syntheticCoreClasses live in rootMirror)
+ // 8) now we come back here and try to enter one of the now entered symbols => BAM!
+ // therefore we use enterIfNew rather than just enter
+ enterIfNew(clazz)
+ enterIfNew(module)
(clazz, module)
}
debugInfo(s"created $module/${module.moduleClass} in $pkgClass")
diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala
index bcd4d16cde..ddbf3bd629 100644
--- a/src/reflect/scala/reflect/runtime/SymbolTable.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala
@@ -9,7 +9,7 @@ import scala.reflect.internal.Flags._
* It can be used either from a reflexive universe (class scala.reflect.runtime.JavaUniverse), or else from
* a runtime compiler that uses reflection to get a class information (class scala.tools.reflect.ReflectGlobal)
*/
-private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps {
+private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps with Gil with ThreadLocalStorage {
def info(msg: => String) =
if (settings.verbose) println("[reflect-compiler] "+msg)
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
index 6aa47a0405..c90901410a 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -14,20 +14,25 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
// BaseTypeSeqs
override protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) =
- new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq
+ // only need to synchronize BaseTypeSeqs if they contain refined types
+ if (elems.filter(_.isInstanceOf[RefinedType]).nonEmpty) new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq
+ else new BaseTypeSeq(parents, elems)
trait SynchronizedBaseTypeSeq extends BaseTypeSeq {
- override def apply(i: Int): Type = synchronized { super.apply(i) }
- override def rawElem(i: Int) = synchronized { super.rawElem(i) }
- override def typeSymbol(i: Int): Symbol = synchronized { super.typeSymbol(i) }
- override def toList: List[Type] = synchronized { super.toList }
- override def copy(head: Type, offset: Int): BaseTypeSeq = synchronized { super.copy(head, offset) }
- override def map(f: Type => Type): BaseTypeSeq = synchronized { super.map(f) }
- override def exists(p: Type => Boolean): Boolean = synchronized { super.exists(p) }
- override lazy val maxDepth = synchronized { maxDepthOfElems }
- override def toString = synchronized { super.toString }
-
- override def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq
+ override def apply(i: Int): Type = gilSynchronized { super.apply(i) }
+ override def rawElem(i: Int) = gilSynchronized { super.rawElem(i) }
+ override def typeSymbol(i: Int): Symbol = gilSynchronized { super.typeSymbol(i) }
+ override def toList: List[Type] = gilSynchronized { super.toList }
+ override def copy(head: Type, offset: Int): BaseTypeSeq = gilSynchronized { super.copy(head, offset) }
+ override def map(f: Type => Type): BaseTypeSeq = gilSynchronized { super.map(f) }
+ override def exists(p: Type => Boolean): Boolean = gilSynchronized { super.exists(p) }
+ override lazy val maxDepth = gilSynchronized { maxDepthOfElems }
+ override def toString = gilSynchronized { super.toString }
+
+ override def lateMap(f: Type => Type): BaseTypeSeq =
+ // only need to synchronize BaseTypeSeqs if they contain refined types
+ if (map(f).toList.filter(_.isInstanceOf[RefinedType]).nonEmpty) new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq
+ else new MappedBaseTypeSeq(this, f)
}
// Scopes
@@ -36,15 +41,19 @@ private[reflect] trait SynchronizedOps extends internal.SymbolTable
override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope
trait SynchronizedScope extends Scope {
- override def isEmpty: Boolean = synchronized { super.isEmpty }
- override def size: Int = synchronized { super.size }
- override def enter[T <: Symbol](sym: T): T = synchronized { super.enter(sym) }
- override def rehash(sym: Symbol, newname: Name) = synchronized { super.rehash(sym, newname) }
- override def unlink(e: ScopeEntry) = synchronized { super.unlink(e) }
- override def unlink(sym: Symbol) = synchronized { super.unlink(sym) }
- override def lookupAll(name: Name) = synchronized { super.lookupAll(name) }
- override def lookupEntry(name: Name) = synchronized { super.lookupEntry(name) }
- override def lookupNextEntry(entry: ScopeEntry) = synchronized { super.lookupNextEntry(entry) }
- override def toList: List[Symbol] = synchronized { super.toList }
+ // we can keep this lock fine-grained, because methods of Scope don't do anything extraordinary, which makes deadlocks impossible
+ // fancy subclasses of internal.Scopes#Scope should do synchronization themselves (e.g. see PackageScope for an example)
+ private lazy val syncLock = new Object
+ def syncLockSynchronized[T](body: => T): T = if (isCompilerUniverse) body else syncLock.synchronized { body }
+ override def isEmpty: Boolean = syncLockSynchronized { super.isEmpty }
+ override def size: Int = syncLockSynchronized { super.size }
+ override def enter[T <: Symbol](sym: T): T = syncLockSynchronized { super.enter(sym) }
+ override def rehash(sym: Symbol, newname: Name) = syncLockSynchronized { super.rehash(sym, newname) }
+ override def unlink(e: ScopeEntry) = syncLockSynchronized { super.unlink(e) }
+ override def unlink(sym: Symbol) = syncLockSynchronized { super.unlink(sym) }
+ override def lookupAll(name: Name) = syncLockSynchronized { super.lookupAll(name) }
+ override def lookupEntry(name: Name) = syncLockSynchronized { super.lookupEntry(name) }
+ override def lookupNextEntry(entry: ScopeEntry) = syncLockSynchronized { super.lookupNextEntry(entry) }
+ override def toList: List[Symbol] = syncLockSynchronized { super.toList }
}
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
index 98cad45db1..298d0ffebd 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -3,17 +3,23 @@ package reflect
package runtime
import scala.reflect.io.AbstractFile
+import scala.collection.{ immutable, mutable }
private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
- override protected def nextId() = synchronized { super.nextId() }
+ private lazy val atomicIds = new java.util.concurrent.atomic.AtomicInteger(0)
+ override protected def nextId() = atomicIds.incrementAndGet()
- override protected def freshExistentialName(suffix: String) =
- synchronized { super.freshExistentialName(suffix) }
+ private lazy val atomicExistentialIds = new java.util.concurrent.atomic.AtomicInteger(0)
+ override protected def nextExistentialId() = atomicExistentialIds.incrementAndGet()
+
+ private lazy val _recursionTable = mkThreadLocalStorage(immutable.Map.empty[Symbol, Int])
+ override def recursionTable = _recursionTable.get
+ override def recursionTable_=(value: immutable.Map[Symbol, Int]) = _recursionTable.set(value)
// Set the fields which point companions at one another. Returns the module.
override def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol =
- synchronized { super.connectModuleToClass(m, moduleClass) }
+ gilSynchronized { super.connectModuleToClass(m, moduleClass) }
override def newFreeTermSymbol(name: TermName, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
new FreeTermSymbol(name, value, origin) with SynchronizedTermSymbol initFlags flags
@@ -25,35 +31,40 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
trait SynchronizedSymbol extends Symbol {
- override def rawflags = synchronized { super.rawflags }
- override def rawflags_=(x: Long) = synchronized { super.rawflags_=(x) }
-
- override def rawowner = synchronized { super.rawowner }
- override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) }
-
- override def validTo = synchronized { super.validTo }
- override def validTo_=(x: Period) = synchronized { super.validTo_=(x) }
-
- override def pos = synchronized { super.pos }
- override def setPos(pos: Position): this.type = { synchronized { super.setPos(pos) }; this }
-
- override def privateWithin = synchronized { super.privateWithin }
- override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) }
-
- override def info = synchronized { super.info }
- override def info_=(info: Type) = synchronized { super.info_=(info) }
- override def updateInfo(info: Type): Symbol = synchronized { super.updateInfo(info) }
- override def rawInfo: Type = synchronized { super.rawInfo }
-
- override def typeParams: List[Symbol] = synchronized { super.typeParams }
-
- override def reset(completer: Type): this.type = synchronized { super.reset(completer) }
-
- override def infosString: String = synchronized { super.infosString }
-
- override def annotations: List[AnnotationInfo] = synchronized { super.annotations }
- override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this }
-
+ def gilSynchronizedIfNotInited[T](body: => T): T = {
+ if (isFullyInitialized) body
+ else gilSynchronized { body }
+ }
+
+ override def validTo = gilSynchronizedIfNotInited { super.validTo }
+ override def info = gilSynchronizedIfNotInited { super.info }
+ override def rawInfo: Type = gilSynchronizedIfNotInited { super.rawInfo }
+
+ override def typeParams: List[Symbol] = gilSynchronizedIfNotInited {
+ if (isCompilerUniverse) super.typeParams
+ else {
+ if (isMonomorphicType) Nil
+ else {
+ // analogously to the "info" getter, here we allow for two completions:
+ // one: sourceCompleter to LazyType, two: LazyType to completed type
+ if (validTo == NoPeriod)
+ rawInfo load this
+ if (validTo == NoPeriod)
+ rawInfo load this
+
+ rawInfo.typeParams
+ }
+ }
+ }
+ override def unsafeTypeParams: List[Symbol] = gilSynchronizedIfNotInited {
+ if (isCompilerUniverse) super.unsafeTypeParams
+ else {
+ if (isMonomorphicType) Nil
+ else rawInfo.typeParams
+ }
+ }
+
+ override def isStable: Boolean = gilSynchronized { super.isStable }
// ------ creators -------------------------------------------------------------------
@@ -90,50 +101,38 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
override protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
new ModuleSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
- override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol = createModuleSymbol(name, pos, newFlags)
+ override protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
+ createModuleSymbol(name, pos, newFlags)
+
+ override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long) =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
- // TODO
- // override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long)
- // override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long)
+ override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long) =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
}
// ------- subclasses ---------------------------------------------------------------------
- trait SynchronizedTermSymbol extends TermSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = synchronized { super.name_=(x) }
- override def rawname = synchronized { super.rawname }
- override def referenced: Symbol = synchronized { super.referenced }
- override def referenced_=(x: Symbol) = synchronized { super.referenced_=(x) }
- }
+ trait SynchronizedTermSymbol extends SynchronizedSymbol
trait SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol {
- override def typeAsMemberOf(pre: Type): Type = synchronized { super.typeAsMemberOf(pre) }
- override def paramss: List[List[Symbol]] = synchronized { super.paramss }
- override def returnType: Type = synchronized { super.returnType }
+ // we can keep this lock fine-grained, because it's just a cache over asSeenFrom, which makes deadlocks impossible
+ // unfortunately we cannot elide this lock, because the cache depends on `pre`
+ private lazy val typeAsMemberOfLock = new Object
+ override def typeAsMemberOf(pre: Type): Type = gilSynchronizedIfNotInited { typeAsMemberOfLock.synchronized { super.typeAsMemberOf(pre) } }
}
+ trait SynchronizedModuleSymbol extends ModuleSymbol with SynchronizedTermSymbol
+
trait SynchronizedTypeSymbol extends TypeSymbol with SynchronizedSymbol {
- override def name_=(x: Name) = synchronized { super.name_=(x) }
- override def rawname = synchronized { super.rawname }
- override def typeConstructor: Type = synchronized { super.typeConstructor }
- override def tpe_* : Type = synchronized { super.tpe_* }
- override def tpeHK : Type = synchronized { super.tpeHK }
+ // unlike with typeConstructor, a lock is necessary here, because tpe calculation relies on
+ // temporarily assigning NoType to tpeCache to detect cyclic reference errors
+ private lazy val tpeLock = new Object
+ override def tpe_* : Type = gilSynchronizedIfNotInited { tpeLock.synchronized { super.tpe_* } }
}
- trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol {
- override def associatedFile = synchronized { super.associatedFile }
- override def associatedFile_=(f: AbstractFile) = synchronized { super.associatedFile_=(f) }
- override def thisSym: Symbol = synchronized { super.thisSym }
- override def thisType: Type = synchronized { super.thisType }
- override def typeOfThis: Type = synchronized { super.typeOfThis }
- override def typeOfThis_=(tp: Type) = synchronized { super.typeOfThis_=(tp) }
- override def children = synchronized { super.children }
- override def addChild(sym: Symbol) = synchronized { super.addChild(sym) }
- }
+ trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol
- trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol {
- override def sourceModule = synchronized { super.sourceModule }
- override def implicitMembers: Scope = synchronized { super.implicitMembers }
- }
+ trait SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol
}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index c0146167df..de78e527a7 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -2,8 +2,9 @@ package scala
package reflect
package runtime
-import scala.collection.mutable.WeakHashMap
-import java.lang.ref.WeakReference
+import scala.collection.mutable
+import java.lang.ref.{WeakReference => jWeakRef}
+import scala.ref.{WeakReference => sWeakRef}
import scala.reflect.internal.Depth
/** This trait overrides methods in reflect.internal, bracketing
@@ -14,9 +15,10 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
// No sharing of map objects:
override protected def commonOwnerMap = new CommonOwnerMap
- private object uniqueLock
-
- private val uniques = WeakHashMap[Type, WeakReference[Type]]()
+ // we can keep this lock fine-grained, because super.unique just updates the cache
+ // and, in particular, doesn't call any reflection APIs which makes deadlocks impossible
+ private lazy val uniqueLock = new Object
+ private val uniques = mutable.WeakHashMap[Type, jWeakRef[Type]]()
override def unique[T <: Type](tp: T): T = uniqueLock.synchronized {
// we need to have weak uniques for runtime reflection
// because unlike the normal compiler universe, reflective universe isn't organized in runs
@@ -30,7 +32,7 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
val result = if (inCache.isDefined) inCache.get.get else null
if (result ne null) result.asInstanceOf[T]
else {
- uniques(tp) = new WeakReference(tp)
+ uniques(tp) = new jWeakRef(tp)
tp
}
} else {
@@ -38,47 +40,50 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
}
}
- class SynchronizedUndoLog extends UndoLog {
- private val actualLock = new java.util.concurrent.locks.ReentrantLock
-
- final override def lock(): Unit = actualLock.lock()
- final override def unlock(): Unit = actualLock.unlock()
- }
+ private lazy val _skolemizationLevel = mkThreadLocalStorage(0)
+ override def skolemizationLevel = _skolemizationLevel.get
+ override def skolemizationLevel_=(value: Int) = _skolemizationLevel.set(value)
- override protected def newUndoLog = new SynchronizedUndoLog
+ private lazy val _undoLog = mkThreadLocalStorage(new UndoLog)
+ override def undoLog = _undoLog.get
- override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) =
- synchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) }
+ private lazy val _intersectionWitness = mkThreadLocalStorage(perRunCaches.newWeakMap[List[Type], sWeakRef[Type]]())
+ override def intersectionWitness = _intersectionWitness.get
- private object subsametypeLock
+ private lazy val _volatileRecursions = mkThreadLocalStorage(0)
+ override def volatileRecursions = _volatileRecursions.get
+ override def volatileRecursions_=(value: Int) = _volatileRecursions.set(value)
- override def isSameType(tp1: Type, tp2: Type): Boolean =
- subsametypeLock.synchronized { super.isSameType(tp1, tp2) }
+ private lazy val _pendingVolatiles = mkThreadLocalStorage(new mutable.HashSet[Symbol])
+ override def pendingVolatiles = _pendingVolatiles.get
- override def isDifferentType(tp1: Type, tp2: Type): Boolean =
- subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) }
+ private lazy val _subsametypeRecursions = mkThreadLocalStorage(0)
+ override def subsametypeRecursions = _subsametypeRecursions.get
+ override def subsametypeRecursions_=(value: Int) = _subsametypeRecursions.set(value)
- override def isSubType(tp1: Type, tp2: Type, depth: Depth): Boolean =
- subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) }
+ private lazy val _pendingSubTypes = mkThreadLocalStorage(new mutable.HashSet[SubTypePair])
+ override def pendingSubTypes = _pendingSubTypes.get
- private object lubglbLock
+ private lazy val _basetypeRecursions = mkThreadLocalStorage(0)
+ override def basetypeRecursions = _basetypeRecursions.get
+ override def basetypeRecursions_=(value: Int) = _basetypeRecursions.set(value)
- override def glb(ts: List[Type]): Type =
- lubglbLock.synchronized { super.glb(ts) }
+ private lazy val _pendingBaseTypes = mkThreadLocalStorage(new mutable.HashSet[Type])
+ override def pendingBaseTypes = _pendingBaseTypes.get
- override def lub(ts: List[Type]): Type =
- lubglbLock.synchronized { super.lub(ts) }
+ private lazy val _lubResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type])
+ override def lubResults = _lubResults.get
- private object indentLock
-
- override protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = {
- indentLock.synchronized { super.explain(op, p, tp1, arg2) }
- }
+ private lazy val _glbResults = mkThreadLocalStorage(new mutable.HashMap[(Depth, List[Type]), Type])
+ override def glbResults = _glbResults.get
- private object toStringLock
+ private lazy val _indent = mkThreadLocalStorage("")
+ override def indent = _indent.get
+ override def indent_=(value: String) = _indent.set(value)
- override protected def typeToString(tpe: Type): String =
- toStringLock.synchronized(super.typeToString(tpe))
+ private lazy val _tostringRecursions = mkThreadLocalStorage(0)
+ override def tostringRecursions = _tostringRecursions.get
+ override def tostringRecursions_=(value: Int) = _tostringRecursions.set(value)
/* The idea of caches is as follows.
* When in reflexive mode, a cache is either null, or one sentinal
@@ -91,18 +96,18 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
*/
override protected def defineUnderlyingOfSingleType(tpe: SingleType) =
- tpe.synchronized { super.defineUnderlyingOfSingleType(tpe) }
+ gilSynchronized { super.defineUnderlyingOfSingleType(tpe) }
override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) =
- tpe.synchronized { super.defineBaseTypeSeqOfCompoundType(tpe) }
+ gilSynchronized { super.defineBaseTypeSeqOfCompoundType(tpe) }
override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) =
- tpe.synchronized { super.defineBaseClassesOfCompoundType(tpe) }
+ gilSynchronized { super.defineBaseClassesOfCompoundType(tpe) }
override protected def defineParentsOfTypeRef(tpe: TypeRef) =
- tpe.synchronized { super.defineParentsOfTypeRef(tpe) }
+ gilSynchronized { super.defineParentsOfTypeRef(tpe) }
override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) =
- tpe.synchronized { super.defineBaseTypeSeqOfTypeRef(tpe) }
+ gilSynchronized { super.defineBaseTypeSeqOfTypeRef(tpe) }
}
diff --git a/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala b/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala
new file mode 100644
index 0000000000..5edc051461
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/ThreadLocalStorage.scala
@@ -0,0 +1,28 @@
+package scala.reflect
+package runtime
+
+import java.lang.Thread._
+
+private[reflect] trait ThreadLocalStorage {
+ self: SymbolTable =>
+
+ // see a discussion at scala-internals for more information:
+ // http://groups.google.com/group/scala-internals/browse_thread/thread/337ce68aa5e51f79
+ trait ThreadLocalStorage[T] { def get: T; def set(newValue: T): Unit }
+ private class MyThreadLocalStorage[T](initialValue: => T) extends ThreadLocalStorage[T] {
+ // TODO: how do we use org.cliffc.high_scale_lib.NonBlockingHashMap here?
+ val values = new java.util.concurrent.ConcurrentHashMap[Thread, T]()
+ def get: T = {
+ if (values containsKey currentThread) values.get(currentThread)
+ else {
+ val value = initialValue
+ values.putIfAbsent(currentThread, value)
+ value
+ }
+ }
+ def set(newValue: T): Unit = {
+ values.put(currentThread, newValue)
+ }
+ }
+ @inline final def mkThreadLocalStorage[T](x: => T): ThreadLocalStorage[T] = new MyThreadLocalStorage(x)
+}
diff --git a/src/reflect/scala/reflect/runtime/TwoWayCaches.scala b/src/reflect/scala/reflect/runtime/TwoWayCaches.scala
new file mode 100644
index 0000000000..6e2890e536
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/TwoWayCaches.scala
@@ -0,0 +1,68 @@
+package scala.reflect
+package runtime
+
+import scala.collection.mutable.WeakHashMap
+import java.lang.ref.WeakReference
+
+/** A cache that maintains a bijection between Java reflection type `J`
+ * and Scala reflection type `S`.
+ *
+ * The cache is two-way weak (i.e. is powered by weak references),
+ * so that neither Java artifacts prevent Scala artifacts from being garbage collected,
+ * nor the other way around.
+ */
+private[runtime] trait TwoWayCaches { self: SymbolTable =>
+ class TwoWayCache[J, S] {
+
+ private val toScalaMap = new WeakHashMap[J, WeakReference[S]]
+ private val toJavaMap = new WeakHashMap[S, WeakReference[J]]
+
+ def enter(j: J, s: S) = gilSynchronized {
+ // debugInfo("cached: "+j+"/"+s)
+ toScalaMap(j) = new WeakReference(s)
+ toJavaMap(s) = new WeakReference(j)
+ }
+
+ private object SomeRef {
+ def unapply[T](optRef: Option[WeakReference[T]]): Option[T] =
+ if (optRef.nonEmpty) {
+ val result = optRef.get.get
+ if (result != null) Some(result) else None
+ } else None
+ }
+
+ def toScala(key: J)(body: => S): S = gilSynchronized {
+ toScalaMap get key match {
+ case SomeRef(v) =>
+ v
+ case _ =>
+ val result = body
+ enter(key, result)
+ result
+ }
+ }
+
+ def toJava(key: S)(body: => J): J = gilSynchronized {
+ toJavaMap get key match {
+ case SomeRef(v) =>
+ v
+ case _ =>
+ val result = body
+ enter(result, key)
+ result
+ }
+ }
+
+ def toJavaOption(key: S)(body: => Option[J]): Option[J] = gilSynchronized {
+ toJavaMap get key match {
+ case SomeRef(v) =>
+ Some(v)
+ case _ =>
+ val result = body
+ for (value <- result) enter(value, key)
+ result
+ }
+ }
+ }
+}
+