summaryrefslogtreecommitdiff
path: root/src/reflect/scala
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-06-08 02:36:10 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-06-08 15:32:28 +0200
commit0b2f1bcf75d31c59b25e19eebcb80f39c155365b (patch)
tree8d9dfc50ef01ca48c068b232af7e67a723325388 /src/reflect/scala
parent13213e3df0384b1fd815c0798758a22284572cdb (diff)
downloadscala-0b2f1bcf75d31c59b25e19eebcb80f39c155365b.tar.gz
scala-0b2f1bcf75d31c59b25e19eebcb80f39c155365b.tar.bz2
scala-0b2f1bcf75d31c59b25e19eebcb80f39c155365b.zip
Introduces scala-reflect.jar
Diffstat (limited to 'src/reflect/scala')
-rw-r--r--src/reflect/scala/reflect/api/AnnotationInfos.scala27
-rw-r--r--src/reflect/scala/reflect/api/Constants.scala33
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala62
-rw-r--r--src/reflect/scala/reflect/api/FlagSets.scala112
-rw-r--r--src/reflect/scala/reflect/api/FrontEnds.scala72
-rw-r--r--src/reflect/scala/reflect/api/Importers.scala21
-rw-r--r--src/reflect/scala/reflect/api/JavaUniverse.scala19
-rw-r--r--src/reflect/scala/reflect/api/Mirrors.scala213
-rw-r--r--src/reflect/scala/reflect/api/Names.scala44
-rw-r--r--src/reflect/scala/reflect/api/Positions.scala196
-rw-r--r--src/reflect/scala/reflect/api/StandardDefinitions.scala48
-rw-r--r--src/reflect/scala/reflect/api/StandardNames.scala163
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala268
-rw-r--r--src/reflect/scala/reflect/api/TagInterop.scala38
-rw-r--r--src/reflect/scala/reflect/api/TreePrinters.scala87
-rw-r--r--src/reflect/scala/reflect/api/Trees.scala689
-rw-r--r--src/reflect/scala/reflect/api/Types.scala368
-rw-r--r--src/reflect/scala/reflect/api/Universe.scala68
-rw-r--r--src/reflect/scala/reflect/api/package.scala12
-rw-r--r--src/reflect/scala/reflect/internal/AbstractFileApi.scala7
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationCheckers.scala121
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala293
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala260
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala69
-rw-r--r--src/reflect/scala/reflect/internal/CapturedVariables.scala36
-rw-r--r--src/reflect/scala/reflect/internal/Chars.scala98
-rw-r--r--src/reflect/scala/reflect/internal/ClassfileConstants.scala390
-rw-r--r--src/reflect/scala/reflect/internal/Constants.scala240
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1241
-rw-r--r--src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala50
-rw-r--r--src/reflect/scala/reflect/internal/FatalError.scala6
-rw-r--r--src/reflect/scala/reflect/internal/FlagSets.scala66
-rw-r--r--src/reflect/scala/reflect/internal/Flags.scala483
-rw-r--r--src/reflect/scala/reflect/internal/HasFlags.scala169
-rw-r--r--src/reflect/scala/reflect/internal/Importers.scala451
-rw-r--r--src/reflect/scala/reflect/internal/InfoTransformers.scala51
-rw-r--r--src/reflect/scala/reflect/internal/Kinds.scala232
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala243
-rw-r--r--src/reflect/scala/reflect/internal/MissingRequirementError.scala24
-rw-r--r--src/reflect/scala/reflect/internal/Names.scala527
-rw-r--r--src/reflect/scala/reflect/internal/Phase.scala66
-rw-r--r--src/reflect/scala/reflect/internal/Positions.scala63
-rw-r--r--src/reflect/scala/reflect/internal/Required.scala17
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala359
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala12
-rw-r--r--src/reflect/scala/reflect/internal/StdCreators.scala21
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1218
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala332
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala3190
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala280
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala571
-rw-r--r--src/reflect/scala/reflect/internal/TreePrinters.scala478
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala1592
-rw-r--r--src/reflect/scala/reflect/internal/TypeDebugging.scala71
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala6820
-rw-r--r--src/reflect/scala/reflect/internal/package.scala6
-rw-r--r--src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala221
-rw-r--r--src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala188
-rw-r--r--src/reflect/scala/reflect/internal/pickling/PickleFormat.scala225
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala871
-rw-r--r--src/reflect/scala/reflect/internal/settings/AbsSettings.scala23
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala48
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala336
-rw-r--r--src/reflect/scala/reflect/internal/transform/RefChecks.scala13
-rw-r--r--src/reflect/scala/reflect/internal/transform/Transforms.scala41
-rw-r--r--src/reflect/scala/reflect/internal/transform/UnCurry.scala64
-rw-r--r--src/reflect/scala/reflect/internal/util/Collections.scala213
-rw-r--r--src/reflect/scala/reflect/internal/util/HashSet.scala106
-rw-r--r--src/reflect/scala/reflect/internal/util/Origins.scala119
-rw-r--r--src/reflect/scala/reflect/internal/util/Position.scala277
-rw-r--r--src/reflect/scala/reflect/internal/util/Set.scala28
-rw-r--r--src/reflect/scala/reflect/internal/util/SourceFile.scala161
-rw-r--r--src/reflect/scala/reflect/internal/util/StatBase.scala97
-rw-r--r--src/reflect/scala/reflect/internal/util/Statistics.scala34
-rw-r--r--src/reflect/scala/reflect/internal/util/StringOps.scala99
-rw-r--r--src/reflect/scala/reflect/internal/util/TableDef.scala94
-rw-r--r--src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala169
-rw-r--r--src/reflect/scala/reflect/internal/util/WeakHashSet.scala61
-rw-r--r--src/reflect/scala/reflect/makro/Aliases.scala27
-rw-r--r--src/reflect/scala/reflect/makro/CapturedVariables.scala21
-rw-r--r--src/reflect/scala/reflect/makro/Context.scala40
-rw-r--r--src/reflect/scala/reflect/makro/Enclosures.scala54
-rw-r--r--src/reflect/scala/reflect/makro/Evals.scala9
-rw-r--r--src/reflect/scala/reflect/makro/ExprUtils.scala32
-rw-r--r--src/reflect/scala/reflect/makro/Exprs.scala8
-rw-r--r--src/reflect/scala/reflect/makro/FrontEnds.scala42
-rw-r--r--src/reflect/scala/reflect/makro/Infrastructure.scala103
-rw-r--r--src/reflect/scala/reflect/makro/Names.scala15
-rw-r--r--src/reflect/scala/reflect/makro/Parsers.scala18
-rw-r--r--src/reflect/scala/reflect/makro/Reifiers.scala91
-rw-r--r--src/reflect/scala/reflect/makro/Settings.scala40
-rw-r--r--src/reflect/scala/reflect/makro/TreeBuilder.scala60
-rw-r--r--src/reflect/scala/reflect/makro/TypeTags.scala9
-rw-r--r--src/reflect/scala/reflect/makro/Typers.scala86
-rw-r--r--src/reflect/scala/reflect/makro/Universe.scala118
-rw-r--r--src/reflect/scala/reflect/makro/package.scala6
-rw-r--r--src/reflect/scala/reflect/runtime/AbstractFile.scala7
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala981
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala33
-rw-r--r--src/reflect/scala/reflect/runtime/ReflectSetup.scala12
-rw-r--r--src/reflect/scala/reflect/runtime/ReflectionUtils.scala80
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala39
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala152
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolTable.scala17
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedOps.scala51
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala140
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala88
-rw-r--r--src/reflect/scala/reflect/runtime/TwoWayCache.scala52
-rw-r--r--src/reflect/scala/reflect/runtime/package.scala26
-rw-r--r--src/reflect/scala/tools/nsc/io/AbstractFile.scala258
-rw-r--r--src/reflect/scala/tools/nsc/io/Directory.scala75
-rw-r--r--src/reflect/scala/tools/nsc/io/File.scala193
-rw-r--r--src/reflect/scala/tools/nsc/io/FileOperationException.scala13
-rw-r--r--src/reflect/scala/tools/nsc/io/NoAbstractFile.scala31
-rw-r--r--src/reflect/scala/tools/nsc/io/Path.scala288
-rw-r--r--src/reflect/scala/tools/nsc/io/PlainFile.scala102
-rw-r--r--src/reflect/scala/tools/nsc/io/Streamable.scala122
-rw-r--r--src/reflect/scala/tools/nsc/io/VirtualDirectory.scala70
-rw-r--r--src/reflect/scala/tools/nsc/io/VirtualFile.scala101
-rw-r--r--src/reflect/scala/tools/nsc/io/ZipArchive.scala220
120 files changed, 30111 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/api/AnnotationInfos.scala b/src/reflect/scala/reflect/api/AnnotationInfos.scala
new file mode 100644
index 0000000000..d9f35024d9
--- /dev/null
+++ b/src/reflect/scala/reflect/api/AnnotationInfos.scala
@@ -0,0 +1,27 @@
+package scala.reflect
+package api
+
+trait AnnotationInfos extends base.AnnotationInfos { self: Universe =>
+
+ override type AnnotationInfo >: Null <: AnyRef with AnnotationInfoApi
+ trait AnnotationInfoApi {
+ def atp: Type
+ def args: List[Tree]
+ def assocs: List[(Name, ClassfileAnnotArg)]
+ }
+
+ override type LiteralAnnotArg >: Null <: ClassfileAnnotArg with LiteralAnnotArgApi
+ trait LiteralAnnotArgApi {
+ def const: Constant
+ }
+
+ override type ArrayAnnotArg >: Null <: ClassfileAnnotArg with ArrayAnnotArgApi
+ trait ArrayAnnotArgApi {
+ def args: Array[ClassfileAnnotArg]
+ }
+
+ override type NestedAnnotArg >: Null <: ClassfileAnnotArg with NestedAnnotArgApi
+ trait NestedAnnotArgApi {
+ def annInfo: AnnotationInfo
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/Constants.scala b/src/reflect/scala/reflect/api/Constants.scala
new file mode 100644
index 0000000000..7862ab0d25
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Constants.scala
@@ -0,0 +1,33 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package api
+
+trait Constants extends base.Constants {
+ self: Universe =>
+
+ override type Constant >: Null <: AnyRef with ConstantApi
+
+ abstract class ConstantApi {
+ val value: Any
+ def tpe: Type
+ def isNaN: Boolean
+
+ def booleanValue: Boolean
+ def byteValue: Byte
+ def shortValue: Short
+ def charValue: Char
+ def intValue: Int
+ def longValue: Long
+ def floatValue: Float
+ def doubleValue: Double
+ def stringValue: String
+ def typeValue: Type
+ def symbolValue: Symbol
+
+ def convertTo(pt: Type): Constant
+ }
+}
diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala
new file mode 100644
index 0000000000..bda125a1a1
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Exprs.scala
@@ -0,0 +1,62 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package api
+
+import scala.reflect.base.TreeCreator
+
+trait Exprs { self: Universe =>
+
+ /** An expression tree tagged with its type */
+ trait Expr[+T] extends Equals with Serializable {
+ val mirror: Mirror
+ def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # Expr[T]
+
+ def tree: Tree
+ def staticTpe: Type
+ def actualTpe: Type
+
+ def splice: T
+ val value: T
+
+ /** case class accessories */
+ override def canEqual(x: Any) = x.isInstanceOf[Expr[_]]
+ override def equals(x: Any) = x.isInstanceOf[Expr[_]] && this.mirror == x.asInstanceOf[Expr[_]].mirror && this.tree == x.asInstanceOf[Expr[_]].tree
+ override def hashCode = mirror.hashCode * 31 + tree.hashCode
+ override def toString = "Expr["+staticTpe+"]("+tree+")"
+ }
+
+ object Expr {
+ def apply[T: TypeTag](mirror: MirrorOf[self.type], treec: TreeCreator): Expr[T] = new ExprImpl[T](mirror.asInstanceOf[Mirror], treec)
+ def unapply[T](expr: Expr[T]): Option[Tree] = Some(expr.tree)
+ }
+
+ private class ExprImpl[+T: TypeTag](val mirror: Mirror, val treec: TreeCreator) extends Expr[T] {
+ def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # Expr[T] = {
+ val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]]
+ val tag1 = (implicitly[TypeTag[T]] in otherMirror).asInstanceOf[otherMirror.universe.TypeTag[T]]
+ otherMirror.universe.Expr[T](otherMirror1, treec)(tag1)
+ }
+
+ lazy val tree: Tree = treec[Exprs.this.type](mirror)
+ // [Eugene++] this is important
+ // !!! remove when we have improved type inference for singletons
+ // search for .type] to find other instances
+ lazy val staticTpe: Type = implicitly[TypeTag[T]].tpe
+ def actualTpe: Type = tree.tpe
+
+ def splice: T = throw new UnsupportedOperationException("""
+ |the function you're calling has not been spliced by the compiler.
+ |this means there is a cross-stage evaluation involved, and it needs to be invoked explicitly.
+ |if you're sure this is not an oversight, add scala-compiler.jar to the classpath,
+ |import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin)
+ lazy val value: T = throw new UnsupportedOperationException("""
+ |the value you're calling is only meant to be used in cross-stage path-dependent types.
+ |if you want to splice the underlying expression, use `<your expr>.splice`.
+ |if you want to get a value of the underlying expression, add scala-compiler.jar to the classpath,
+ |import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin)
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala
new file mode 100644
index 0000000000..969176d641
--- /dev/null
+++ b/src/reflect/scala/reflect/api/FlagSets.scala
@@ -0,0 +1,112 @@
+package scala.reflect
+package api
+
+import scala.language.implicitConversions
+
+trait FlagSets { self: Universe =>
+
+ type FlagSet
+
+ trait FlagOps extends Any {
+ def | (right: FlagSet): FlagSet
+ def & (right: FlagSet): FlagSet
+ def containsAll (right: FlagSet): Boolean
+ }
+
+ implicit def addFlagOps(left: FlagSet): FlagOps
+
+ val Flag: FlagValues
+
+ type FlagValues >: Null <: FlagValuesApi
+
+ // [Eugene++] any other flags we would like to expose?
+
+ trait FlagValuesApi {
+
+ /** Flag indicating that symbol or tree represents a trait */
+ val TRAIT: FlagSet
+
+ /** Flag indicating that symbol or tree represents a module or its internal module class */
+ val MODULE: FlagSet
+
+ /** Flag indicating that symbol or tree represents a mutable variable */
+ val MUTABLE: FlagSet
+
+ /** Flag indicating that symbol or tree represents a package or its internal package class */
+ val PACKAGE: FlagSet
+
+ /** Flag indicating that symbol or tree represents a method */
+ val METHOD: FlagSet
+
+ /** Flag indicating that symbol or tree represents a macro definition. */
+ val MACRO: FlagSet
+
+ /** Flag indicating that symbol or tree represents an abstract type, method, or value */
+ val DEFERRED: FlagSet
+
+ /** Flag indicating that symbol or tree represents an abstract class */
+ val ABSTRACT: FlagSet
+
+ /** Flag indicating that symbol or tree has `final` modifier set */
+ val FINAL: FlagSet
+
+ /** Flag indicating that symbol or tree has `sealed` modifier set */
+ val SEALED: FlagSet
+
+ /** Flag indicating that symbol or tree has `implicit` modifier set */
+ val IMPLICIT: FlagSet
+
+ /** Flag indicating that symbol or tree has `lazy` modifier set */
+ val LAZY: FlagSet
+
+ /** Flag indicating that symbol or tree has `override` modifier set */
+ val OVERRIDE: FlagSet
+
+ /** Flag indicating that symbol or tree has `private` modifier set */
+ val PRIVATE: FlagSet
+
+ /** Flag indicating that symbol or tree has `protected` modifier set */
+ val PROTECTED: FlagSet
+
+ /** Flag indicating that symbol or tree has `case` modifier set */
+ val CASE: FlagSet
+
+ /** Flag indicating that symbol or tree has `abstract` and `override` modifiers set */
+ val ABSOVERRIDE: FlagSet
+
+ /** Flag indicating that symbol or tree represents a by-name parameter */
+ val BYNAMEPARAM: FlagSet
+
+ /** Flag indicating that symbol or tree represents a class or parameter.
+ * Both type and value parameters carry the flag. */
+ val PARAM: FlagSet
+
+ /** Flag indicating that symbol or tree represents a field of a class
+ * that was generated from a parameter of that class */
+ val PARAMACCESSOR: FlagSet
+
+ /** Flag indicating that symbol or tree represents a field of a case class
+ * that corresponds to a parameter in the first parameter list of the
+ * primary constructor of that class */
+ val CASEACCESSOR: FlagSet
+
+ /** Flag indicating that symbol or tree represents a contravariant
+ * type parameter (marked with `+`). */
+ val COVARIANT: FlagSet
+
+ /** Flag indicating that symbol or tree represents a contravariant
+ * type parameter (marked with `-`). */
+ val CONTRAVARIANT: FlagSet
+
+ /** Flag indicating that parameter has a default value */
+ val DEFAULTPARAM: FlagSet
+
+ /** Flag indicating that trait has neither method implementations nor fields.
+ * This means the trait can be represented as a Java interface. */
+ val INTERFACE: FlagSet
+
+ def union(flags: FlagSet*): FlagSet
+ def intersection(flag: FlagSet*): FlagSet
+ def containsAll(superset: FlagSet, subset: FlagSet): Boolean
+ }
+}
diff --git a/src/reflect/scala/reflect/api/FrontEnds.scala b/src/reflect/scala/reflect/api/FrontEnds.scala
new file mode 100644
index 0000000000..a201b83444
--- /dev/null
+++ b/src/reflect/scala/reflect/api/FrontEnds.scala
@@ -0,0 +1,72 @@
+package scala.reflect
+package api
+
+// [Martin to Eugene] Todo: Needs to be evicted from API
+// [Eugene++ to Martin] but how? we need them for macros
+trait FrontEnds {
+
+ type Position >: Null
+
+ trait FrontEnd {
+ object severity extends Enumeration
+ class Severity(val id: Int) extends severity.Value {
+ var count: Int = 0
+ override def toString() = this match {
+ case INFO => "INFO"
+ case WARNING => "WARNING"
+ case ERROR => "ERROR"
+ case _ => "<unknown>"
+ }
+ }
+ val INFO = new Severity(0)
+ val WARNING = new Severity(1)
+ val ERROR = new Severity(2)
+
+ def hasErrors = ERROR.count > 0
+ def hasWarnings = WARNING.count > 0
+
+ case class Info(val pos: Position, val msg: String, val severity: Severity)
+ val infos = new collection.mutable.LinkedHashSet[Info]
+
+ /** Handles incoming info */
+ def log(pos: Position, msg: String, severity: Severity) {
+ infos += new Info(pos, msg, severity)
+ severity.count += 1
+ display(infos.last)
+ }
+
+ /** Displays incoming info */
+ def display(info: Info): Unit
+
+ /** Services a request to drop into interactive mode */
+ def interactive(): Unit
+
+ /** Refreshes the UI */
+ def flush(): Unit = {}
+
+ /** Resets the reporter */
+ def reset(): Unit = {
+ INFO.count = 0
+ WARNING.count = 0
+ ERROR.count = 0
+ infos.clear()
+ }
+ }
+
+ class SilentFrontEnd extends FrontEnd {
+ def display(info: Info) {}
+ def interactive() {}
+ }
+
+ /** Creates a UI-less reporter that simply accumulates all the messages
+ */
+ def mkSilentFrontEnd(): FrontEnd = new SilentFrontEnd()
+
+ /** Creates a reporter that prints messages to the console according to the settings.
+ *
+ * ``minSeverity'' determines minimum severity of the messages to be printed.
+ * 0 stands for INFO, 1 stands for WARNING and 2 stands for ERROR.
+ */
+ // todo. untangle warningsAsErrors from Reporters. I don't feel like moving this flag here!
+ def mkConsoleFrontEnd(minSeverity: Int = 1): FrontEnd
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala
new file mode 100644
index 0000000000..69d6414f4f
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Importers.scala
@@ -0,0 +1,21 @@
+package scala.reflect
+package api
+
+// [Martin] Importers need to be made mirror aware.
+// [Eugene++] this is important
+trait Importers { self: Universe =>
+
+ def mkImporter(from0: Universe): Importer { val from: from0.type }
+
+ trait Importer {
+ val from: Universe
+
+ val reverse: from.Importer { val from: self.type }
+
+ def importSymbol(sym: from.Symbol): Symbol
+
+ def importType(tpe: from.Type): Type
+
+ def importTree(tree: from.Tree): Tree
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/JavaUniverse.scala b/src/reflect/scala/reflect/api/JavaUniverse.scala
new file mode 100644
index 0000000000..8bf62a357c
--- /dev/null
+++ b/src/reflect/scala/reflect/api/JavaUniverse.scala
@@ -0,0 +1,19 @@
+package scala.reflect
+package api
+
+// [Martin] Moved to compiler because it needs to see runtime.Universe
+// The two will be united in scala-reflect anyway.
+trait JavaUniverse extends Universe with Mirrors with TagInterop { self =>
+
+ type RuntimeClass = java.lang.Class[_]
+
+ override type Mirror >: Null <: JavaMirror
+
+ trait JavaMirror extends MirrorOf[self.type] with RuntimeMirror {
+ val classLoader: ClassLoader
+ override def toString = s"JavaMirror with ${runtime.ReflectionUtils.show(classLoader)}"
+ }
+
+ def runtimeMirror(cl: ClassLoader): Mirror
+}
+
diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala
new file mode 100644
index 0000000000..2fcee8f227
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Mirrors.scala
@@ -0,0 +1,213 @@
+package scala.reflect
+package api
+
+trait Mirrors { self: Universe =>
+
+ type RuntimeClass >: Null
+
+ // [Eugene++ to Martin] how do we reflect against inner classes?
+ // presumably, we should add `reflectClass` to both InstanceMirror (inner classes) and TemplateMirror (nested classes)
+ // in the former case, the resulting ClassMirror should remember the outer instance that spawned it to use it in reflective construction
+
+ // [Eugene] also, it might make sense to provide shortcuts for the API
+ //
+ // for example, right now to invoke the same method for several different instances, you need:
+ // 1) get the method symbol
+ // 2) get the instance mirror for every instance
+ // 3) call reflectMethod on the instance mirrors for every instance
+ // 4) call apply for every instance (okay, this can be united with step #3, but still)
+ //
+ // I have several suggestions that we can discuss later:
+ // 1) For every `reflectXXX(sym: Symbol): XXXMirror`, add `reflectXXX(name: String, types: Type*): XXXMirror` and `reflectXXXs(): List[XXXMirror]`
+ // 2) Provide a way to skip obtaining InstanceMirror (step #2 in the outline provided above)
+
+ // [Eugene] another improvement would be have mirrors reproduce the structure of the reflection domain
+ // e.g. a ClassMirror could also have a list of fields, methods, constructors and so on
+ // read up more on the proposed design in "Reflecting Scala" by Y. Coppel
+
+ /** A mirror that reflects a runtime value */
+ trait InstanceMirror {
+
+ /** The instance value reflected by this mirror */
+ def instance: Any
+
+ /** The mirror corresponding to the run-time class of the reflected instance. */
+ def reflectClass: ClassMirror
+
+ /** Get value of field in reflected instance.
+ * @field A field symbol that should represent a field of the instance class.
+ * @return The value associated with that field in the reflected instance
+ * @throws ???
+ */
+ def reflectField(field: TermSymbol): FieldMirror
+
+ /** Invokes a method on the reflected instance.
+ * @param meth A method symbol that should represent a method of the instance class
+ * @param args The arguments to pass to the method
+ * @return The result of invoking `meth(args)` on the reflected instance.
+ * @throws ???
+ */
+ def reflectMethod(method: MethodSymbol): MethodMirror
+ }
+
+ /** A mirror that reflects a field */
+ trait FieldMirror {
+
+ /** The object containing the field */
+ def receiver: AnyRef
+
+ /** The field symbol representing the field */
+ def field: TermSymbol
+
+ /** Retrieves the value stored in the field */
+ def get: Any
+
+ /** Updates the value stored in the field */
+ def set(value: Any): Unit
+ }
+
+ /** A mirror that reflects a method handle */
+ trait MethodMirror {
+
+ /** The receiver object of the method */
+ def receiver: AnyRef
+
+ /** The method symbol representing the method */
+ def method: MethodSymbol
+
+ /** The result of applying the method to the given arguments */
+ def apply(args: Any*): Any
+ }
+
+ /** A mirror that reflects the instance or static parts of a runtime class */
+ trait TemplateMirror {
+
+ /** The runtime class reflected by this mirror */
+ def runtimeClass: RuntimeClass
+
+ /** True if the mirror represents the static part
+ * if a runtime class or the companion object of a Scala class.
+ * One has:
+ *
+ * this.isStatic == this.isInstanceOf[ModuleMirror]
+ * !this.isStatic == this.isInstanceOf[ClassMirror]
+ */
+ def isStatic: Boolean
+
+ /** The Scala symbol corresponding to the reflected runtime class or module. */
+ def symbol: Symbol
+
+ // [Eugene++ to Martin] I've removed `typeSignature`, because we can obtain it via `symbol.typeSignature`
+
+ /** Optionally, the mirror of the companion reflected by this mirror.
+ * If this mirror reflects a Scala object, the mirror for the companion class, or None
+ * if the mirror represents a Scala object that comes without a class.
+ * Otherwise, if the mirror represents the static part of a runtime class, the
+ * mirror representing the instance part of the same class.
+ * Otherwise, if the mirror represents a Scala instance class, the mirror for the companion
+ * object of that class, or None if no such object exists.
+ * Otherwise, if the mirror represents a runtime instance class, a mirror representing the static
+ * part of the same class.
+ */
+ def companion: Option[TemplateMirror]
+ }
+
+ /** A mirror that reflects a Scala object definition or the static parts of a runtime class */
+ trait ModuleMirror extends TemplateMirror {
+
+ /** The Scala module symbol corresponding to the reflected module. */
+ override def symbol: ModuleSymbol
+
+ /** If the reflected runtime class corresponds to a Scala object definition,
+ * returns the single instance representing that object.
+ * If this mirror reflects the static part of a runtime class, returns `null`.
+ */
+ def instance: Any
+
+ /** Optionally, the mirror of the companion class if the object reflected by this mirror.
+ * If this mirror reflects a Scala object, the mirror for the companion class, or None
+ * if the mirror represents a Scala object that comes without a class.
+ * Otherwise, if the mirror represents the static part of a runtime class, the
+ * mirror representing the instance part of the same class.
+ */
+ def companion: Option[ClassMirror]
+ }
+
+ /** A mirror that reflects the instance parts of a runtime class */
+ trait ClassMirror extends TemplateMirror {
+
+ /** The Scala class symbol corresponding to the reflected class. */
+ override def symbol: ClassSymbol
+
+ /** Returns a fresh instance of by invoking that constructor.
+ * @throws InstantiationException if the class does not have a public
+ * constructor with an empty parameter list.
+ * @throws IllegalAccessException if the class or its constructor is not accessible.
+ * @throws ExceptionInInitializerError if the initialization of the constructor fails.
+ * @throws SecurityException if creating a new instance is not permitted.
+ */
+ def reflectConstructor(constructor: MethodSymbol): MethodMirror
+
+ /** Optionally, the mirror of the companion object of the class reflected by this mirror.
+ * If this mirror represents a Scala instance class, the mirror for the companion
+ * object of that class, or None if no such object exists.
+ * Otherwise, if the mirror represents a runtime instance class, a mirror representing the static
+ * part of the same class.
+ */
+ def companion: Option[ModuleMirror]
+ }
+
+ /** The API of a mirror for a reflective universe */
+ trait RuntimeMirror extends MirrorOf[Mirrors.this.type] { self =>
+
+ /** A reflective mirror for the given object
+ * @param obj An arbitrary value
+ * @return The mirror for `obj`.
+ */
+ def reflect(obj: Any): InstanceMirror
+
+ /** A reflective mirror for the given Runtime class
+ * @param runtimeClass A Runtime class object
+ * @return The mirror for `runtimeClass`
+ */
+ def reflectClass(runtimeClass: RuntimeClass): ClassMirror
+
+ /** A reflective mirror for the Runtime class with the given name in the
+ * current classloader.
+ * @param name The fully qualified name of the class
+ * @return The mirror for the runtime class with fully qualified name
+ * `name` in the current class loader.
+ * @throws java.lang.ClassNotFoundException if no class with that name exists
+ * to do: throws anything else?
+ */
+ def reflectClass(fullName: String): ClassMirror
+
+ /** A reflective mirror for the given Runtime class
+ * @param runtimeClass A Runtime class object
+ * @return The mirror for `runtimeClass`
+ */
+ def reflectModule(runtimeClass: RuntimeClass): ModuleMirror
+
+ /** A reflective mirror for the Runtime class with the given name in the
+ * current classloader.
+ * @param name The fully qualified name of the class
+ * @return The mirror for the runtime class with fully qualified name
+ * `name` in the current class loader.
+ * @throws java.lang.ClassNotFoundException if no class with that name exists
+ * to do: throws anything else?
+ */
+ def reflectModule(fullName: String): ModuleMirror
+
+ /** Maps a Scala type to the corresponding Java class object
+ */
+ def runtimeClass(tpe: Type): RuntimeClass
+
+ /** Maps a Scala class symbol to the corresponding Java class object
+ * @throws ClassNotFoundException if there is no Java class
+ * corresponding to the given Scala class symbol.
+ * Note: If the Scala symbol is ArrayClass, a ClassNotFound exception is thrown
+ * because there is no unique Java class corresponding to a Scala generic array
+ */
+ def runtimeClass(cls: ClassSymbol): RuntimeClass
+ }
+}
diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala
new file mode 100644
index 0000000000..222ee5024b
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Names.scala
@@ -0,0 +1,44 @@
+package scala.reflect
+package api
+
+/** A trait that manages names.
+ * A name is a string in one of two name universes: terms and types.
+ * The same string can be a name in both universes.
+ * Two names are equal if they represent the same string and they are
+ * members of the same universe.
+ *
+ * Names are interned. That is, for two names `name11 and `name2`,
+ * `name1 == name2` implies `name1 eq name2`.
+ */
+trait Names extends base.Names {
+
+ /** The abstract type of names */
+ type Name >: Null <: NameApi
+
+ /** The extended API of names that's supported on reflect mirror via an
+ * implicit conversion in reflect.ops
+ */
+ abstract class NameApi extends NameBase {
+
+ // [Eugene++] this functionality should be in base
+ // this is because stuff will be reified in mangled state, and people will need a way to figure it out
+
+ /** Replaces all occurrences of \$op_names in this name by corresponding operator symbols.
+ * Example: `foo_\$plus\$eq` becomes `foo_+=`
+ */
+ def decoded: String
+
+ /** Replaces all occurrences of operator symbols in this name by corresponding \$op_names.
+ * Example: `foo_+=` becomes `foo_\$plus\$eq`.
+ */
+ def encoded: String
+
+ /** The decoded name, still represented as a name.
+ */
+ def decodedName: Name
+
+ /** The encoded name, still represented as a name.
+ */
+ def encodedName: Name
+ }
+}
diff --git a/src/reflect/scala/reflect/api/Positions.scala b/src/reflect/scala/reflect/api/Positions.scala
new file mode 100644
index 0000000000..9d3d90d9f8
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Positions.scala
@@ -0,0 +1,196 @@
+package scala.reflect
+package api
+
+trait Positions extends base.Positions {
+ self: Universe =>
+
+ /** .. */
+ type Position >: Null <: PositionApi { type Pos = Position }
+
+ /** A position that wraps a set of trees.
+ * The point of the wrapping position is the point of the default position.
+ * If some of the trees are ranges, returns a range position enclosing all ranges
+ * Otherwise returns default position.
+ */
+ def wrappingPos(default: Position, trees: List[Tree]): Position
+
+ /** A position that wraps the non-empty set of trees.
+ * The point of the wrapping position is the point of the first trees' position.
+ * If all some the trees are non-synthetic, returns a range position enclosing the non-synthetic trees
+ * Otherwise returns a synthetic offset position to point.
+ */
+ def wrappingPos(trees: List[Tree]): Position
+
+ /** Ensure that given tree has no positions that overlap with
+ * any of the positions of `others`. This is done by
+ * shortening the range or assigning TransparentPositions
+ * to some of the nodes in `tree`.
+ */
+ //def ensureNonOverlapping(tree: Tree, others: List[Tree])
+ // [Eugene++] can this method be of use for macros?
+}
+
+/** The Position class and its subclasses represent positions of ASTs and symbols.
+ * Except for NoPosition and FakePos, every position refers to a SourceFile
+ * and to an offset in the sourcefile (its `point`). For batch compilation,
+ * that's all. For interactive IDE's there are also RangePositions
+ * and TransparentPositions. A RangePosition indicates a start and an end
+ * in addition to its point. TransparentPositions are a subclass of RangePositions.
+ * Range positions that are not transparent are called opaque.
+ * Trees with RangePositions need to satisfy the following invariants.
+ *
+ * INV1: A tree with an offset position never contains a child
+ * with a range position
+ * INV2: If the child of a tree with a range position also has a range position,
+ * then the child's range is contained in the parent's range.
+ * INV3: Opaque range positions of children of the same node are non-overlapping
+ * (this means their overlap is at most a single point).
+ *
+ * The following tests are useful on positions:
+ *
+ * pos.isDefined true if position is not a NoPosition nor a FakePosition
+ * pos.isRange true if position is a range
+ * pos.isOpaqueRange true if position is an opaque range
+ *
+ * The following accessor methods are provided:
+ *
+ * pos.source The source file of the position, which must be defined
+ * pos.point The offset of the position's point, which must be defined
+ * pos.start The start of the position, which must be a range
+ * pos.end The end of the position, which must be a range
+ *
+ * There are also convenience methods, such as
+ *
+ * pos.startOrPoint
+ * pos.endOrPoint
+ * pos.pointOrElse(default)
+ *
+ * These are less strict about the kind of position on which they can be applied.
+ *
+ * The following conversion methods are often used:
+ *
+ * pos.focus converts a range position to an offset position, keeping its point;
+ * returns all other positions unchanged.
+ * pos.makeTransparent converts an opaque range position into a transparent one.
+ * returns all other positions unchanged.
+ */
+trait PositionApi extends Attachments {
+
+ type Pos >: Null <: PositionApi
+
+ /** Java file corresponding to the source file of this position.
+ */
+ def fileInfo: java.io.File
+
+ /** Content of the source file that contains this position.
+ */
+ def fileContent: Array[Char]
+
+ /** Is this position neither a NoPosition nor a FakePosition?
+ * If isDefined is true, offset and source are both defined.
+ */
+ def isDefined: Boolean
+
+ /** Is this position a range position? */
+ def isRange: Boolean
+
+ /** Is this position a transparent position? */
+ def isTransparent: Boolean
+
+ /** Is this position a non-transparent range position? */
+ def isOpaqueRange: Boolean
+
+ /** if opaque range, make this position transparent */
+ def makeTransparent: Pos
+
+ /** The start of the position's range, error if not a range position */
+ def start: Int
+
+ /** The start of the position's range, or point if not a range position */
+ def startOrPoint: Int
+
+ /** The point (where the ^ is) of the position */
+ def point: Int
+
+ /** The point (where the ^ is) of the position, or else `default` if undefined */
+ def pointOrElse(default: Int): Int
+
+ /** The end of the position's range, error if not a range position */
+ def end: Int
+
+ /** The end of the position's range, or point if not a range position */
+ def endOrPoint: Int
+
+ /** The same position with a different start value (if a range) */
+ def withStart(off: Int): Pos
+
+ /** The same position with a different end value (if a range) */
+ def withEnd(off: Int): Pos
+
+ /** The same position with a different point value (if a range or offset) */
+ def withPoint(off: Int): Pos
+
+ /** If this is a range, the union with the other range, with the point of this position.
+ * Otherwise, this position
+ */
+ def union(pos: Pos): Pos
+
+ /** If this is a range position, the offset position of its point.
+ * Otherwise the position itself
+ */
+ def focus: Pos
+
+ /** If this is a range position, the offset position of its start.
+ * Otherwise the position itself
+ */
+ def focusStart: Pos
+
+ /** If this is a range position, the offset position of its end.
+ * Otherwise the position itself
+ */
+ def focusEnd: Pos
+
+ /** Does this position include the given position `pos`.
+ * This holds if `this` is a range position and its range [start..end]
+ * is the same or covers the range of the given position, which may or may not be a range position.
+ */
+ def includes(pos: Pos): Boolean
+
+ /** Does this position properly include the given position `pos` ("properly" meaning their
+ * ranges are not the same)?
+ */
+ def properlyIncludes(pos: Pos): Boolean
+
+ /** Does this position precede that position?
+ * This holds if both positions are defined and the end point of this position
+ * is not larger than the start point of the given position.
+ */
+ def precedes(pos: Pos): Boolean
+
+ /** Does this position properly precede the given position `pos` ("properly" meaning their ranges
+ * do not share a common point).
+ */
+ def properlyPrecedes(pos: Pos): Boolean
+
+ /** Does this position overlap with that position?
+ * This holds if both positions are ranges and there is an interval of
+ * non-zero length that is shared by both position ranges.
+ */
+ def overlaps(pos: Pos): Boolean
+
+ /** Does this position cover the same range as that position?
+ * Holds only if both position are ranges
+ */
+ def sameRange(pos: Pos): Boolean
+
+ def line: Int
+
+ def column: Int
+
+ /** Convert this to a position around `point` that spans a single source line */
+ def toSingleLine: Pos
+
+ def lineContent: String
+
+ def show: String
+}
diff --git a/src/reflect/scala/reflect/api/StandardDefinitions.scala b/src/reflect/scala/reflect/api/StandardDefinitions.scala
new file mode 100644
index 0000000000..c2a89f92dd
--- /dev/null
+++ b/src/reflect/scala/reflect/api/StandardDefinitions.scala
@@ -0,0 +1,48 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect
+package api
+
+trait StandardDefinitions extends base.StandardDefinitions {
+ self: Universe =>
+
+ val definitions: DefinitionsApi
+
+ trait DefinitionsApi extends DefinitionsBase {
+ def JavaLangPackageClass: ClassSymbol
+ def JavaLangPackage: ModuleSymbol
+ def ArrayModule: ModuleSymbol
+ def ArrayModule_overloadedApply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+ def Array_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+ def Array_clone: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+ def Array_length: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+ def Array_update: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+ def ByNameParamClass: ClassSymbol
+ def ConsClass: ClassSymbol
+ def FunctionClass : Array[ClassSymbol]
+ def IterableClass: ClassSymbol
+ def IteratorClass: ClassSymbol
+ def IteratorModule: ModuleSymbol
+ def Iterator_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+ def JavaRepeatedParamClass: ClassSymbol
+ def ListModule: ModuleSymbol
+ def List_apply: TermSymbol // todo. fix the bug in Definitions.getMemberMethod
+ def NilModule: ModuleSymbol
+ def NoneModule: ModuleSymbol
+ def OptionClass: ClassSymbol
+ def ProductClass : Array[ClassSymbol]
+ def RepeatedParamClass: ClassSymbol
+ def SeqClass: ClassSymbol
+ def SeqModule: ModuleSymbol
+ def SomeClass: ClassSymbol
+ def SomeModule: ModuleSymbol
+ def StringBuilderClass: ClassSymbol
+ def SymbolClass : ClassSymbol
+ def TraversableClass: ClassSymbol
+ def TupleClass: Array[Symbol] // cannot make it Array[ClassSymbol], because TupleClass(0) is supposed to be NoSymbol. weird
+ def ScalaPrimitiveValueClasses: List[ClassSymbol]
+ def ScalaNumericValueClasses: List[ClassSymbol]
+ }
+}
diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala
new file mode 100644
index 0000000000..9ec66b8531
--- /dev/null
+++ b/src/reflect/scala/reflect/api/StandardNames.scala
@@ -0,0 +1,163 @@
+/* NSC -- new Scala compiler
+* Copyright 2005-2011 LAMP/EPFL
+* @author Martin Odersky
+*/
+package scala.reflect
+package api
+
+trait StandardNames extends base.StandardNames {
+ self: Universe =>
+
+ val nme: TermNamesApi
+ val tpnme: TypeNamesApi
+
+ trait NamesApi extends NamesBase {
+ val ANON_CLASS_NAME: NameType
+ val ANON_FUN_NAME: NameType
+ val EMPTY: NameType
+ val ERROR: NameType
+ val IMPORT: NameType
+ val MODULE_VAR_SUFFIX: NameType
+ val PACKAGE: NameType
+ val ROOT: NameType
+ val SPECIALIZED_SUFFIX: NameType
+
+ def flattenedName(segments: Name*): NameType
+ }
+
+ trait TermNamesApi extends NamesApi with TermNamesBase {
+ val EXPAND_SEPARATOR_STRING: String
+ val IMPL_CLASS_SUFFIX: String
+ val INTERPRETER_IMPORT_WRAPPER: String
+ val INTERPRETER_LINE_PREFIX: String
+ val INTERPRETER_VAR_PREFIX: String
+ val INTERPRETER_WRAPPER_SUFFIX: String
+ val LOCALDUMMY_PREFIX: String
+ val LOCAL_SUFFIX_STRING: String
+ val MODULE_SUFFIX_NAME: TermName
+ val NAME_JOIN_NAME: TermName
+ val PROTECTED_PREFIX: String
+ val PROTECTED_SET_PREFIX: String
+ val SETTER_SUFFIX: TermName
+ val SINGLETON_SUFFIX: String
+ val SUPER_PREFIX_STRING: String
+ val TRAIT_SETTER_SEPARATOR_STRING: String
+
+ val ANYNAME: TermName
+ val FAKE_LOCAL_THIS: TermName
+ val INITIALIZER: TermName
+ val LAZY_LOCAL: TermName
+ val UNIVERSE_BUILD: NameType
+ val UNIVERSE_BUILD_PREFIX: NameType
+ val UNIVERSE_PREFIX: NameType
+ val UNIVERSE_SHORT: NameType
+ val MIRROR_PREFIX: NameType
+ val MIRROR_SHORT: NameType
+ val MIRROR_UNTYPED: NameType
+ val REIFY_FREE_PREFIX: NameType
+ val REIFY_FREE_THIS_SUFFIX: NameType
+ val REIFY_FREE_VALUE_SUFFIX: NameType
+ val REIFY_SYMDEF_PREFIX: NameType
+ val MIXIN_CONSTRUCTOR: TermName
+ val MODULE_INSTANCE_FIELD: TermName
+ val OUTER: TermName
+ val OUTER_LOCAL: TermName
+ val OUTER_SYNTH: TermName
+ val SELECTOR_DUMMY: TermName
+ val SELF: TermName
+ val SPECIALIZED_INSTANCE: TermName
+ val STAR: TermName
+ val THIS: TermName
+
+ val BITMAP_NORMAL: TermName
+ val BITMAP_TRANSIENT: TermName
+ val BITMAP_CHECKINIT: TermName
+ val BITMAP_CHECKINIT_TRANSIENT: TermName
+
+ val ROOTPKG: TermName
+
+ val ADD: TermName
+ val AND: TermName
+ val ASR: TermName
+ val DIV: TermName
+ val EQ: TermName
+ val EQL: TermName
+ val GE: TermName
+ val GT: TermName
+ val HASHHASH: TermName
+ val LE: TermName
+ val LSL: TermName
+ val LSR: TermName
+ val LT: TermName
+ val MINUS: TermName
+ val MOD: TermName
+ val MUL: TermName
+ val NE: TermName
+ val OR: TermName
+ val PLUS : TermName
+ val SUB: TermName
+ val XOR: TermName
+ val ZAND: TermName
+ val ZOR: TermName
+
+ val UNARY_~ : TermName
+ val UNARY_+ : TermName
+ val UNARY_- : TermName
+ val UNARY_! : TermName
+
+ val ??? : TermName
+
+ def isConstructorName(name: Name): Boolean
+ def isExceptionResultName(name: Name): Boolean
+ def isImplClassName(name: Name): Boolean
+ def isLocalDummyName(name: Name): Boolean
+ def isLocalName(name: Name): Boolean
+ def isLoopHeaderLabel(name: Name): Boolean
+ def isModuleName(name: Name): Boolean
+ def isOpAssignmentName(name: Name): Boolean
+ def isProtectedAccessorName(name: Name): Boolean
+ def isReplWrapperName(name: Name): Boolean
+ def isSetterName(name: Name): Boolean
+ def isSingletonName(name: Name): Boolean
+ def isSuperAccessorName(name: Name): Boolean
+ def isTraitSetterName(name: Name): Boolean
+
+ def defaultGetterName(name: Name, pos: Int): TermName
+ def defaultGetterToMethod(name: Name): TermName
+ def expandedName(name: TermName, base: Symbol, separator: String): TermName
+ def expandedSetterName(name: TermName, base: Symbol): TermName
+ def getterName(name: TermName): TermName
+ def getterToLocal(name: TermName): TermName
+ def getterToSetter(name: TermName): TermName
+ def localDummyName(clazz: Symbol): TermName
+ def localToGetter(name: TermName): TermName
+ def protName(name: Name): TermName
+ def protSetterName(name: Name): TermName
+ def setterToGetter(name: TermName): TermName
+ def superName(name: Name): TermName
+
+ def dropLocalSuffix(name: Name): Name
+ def originalName(name: Name): Name
+ def stripModuleSuffix(name: Name): Name
+ def unspecializedName(name: Name): Name
+ def segments(name: String, assumeTerm: Boolean): List[Name]
+ def splitSpecializedName(name: Name): (Name, String, String)
+ }
+
+ trait TypeNamesApi extends NamesApi with TypeNamesBase {
+ val BYNAME_PARAM_CLASS_NAME: TypeName
+ val EQUALS_PATTERN_NAME: TypeName
+ val JAVA_REPEATED_PARAM_CLASS_NAME: TypeName
+ val LOCAL_CHILD: TypeName
+ val REFINE_CLASS_NAME: TypeName
+ val REPEATED_PARAM_CLASS_NAME: TypeName
+ val WILDCARD_STAR: TypeName
+ val REIFY_TYPECREATOR_PREFIX: NameType
+ val REIFY_TREECREATOR_PREFIX: NameType
+
+ def dropSingletonName(name: Name): TypeName
+ def implClassName(name: Name): TypeName
+ def interfaceName(implname: Name): TypeName
+ def singletonName(name: Name): TypeName
+ }
+}
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
new file mode 100644
index 0000000000..1d266dc778
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -0,0 +1,268 @@
+package scala.reflect
+package api
+
+trait Symbols extends base.Symbols { self: Universe =>
+
+ override type Symbol >: Null <: SymbolApi
+ override type TypeSymbol >: Null <: Symbol with TypeSymbolApi
+ override type TermSymbol >: Null <: Symbol with TermSymbolApi
+ override type MethodSymbol >: Null <: TermSymbol with MethodSymbolApi
+ override type ModuleSymbol >: Null <: TermSymbol with ModuleSymbolApi
+ override type ClassSymbol >: Null <: TypeSymbol with ClassSymbolApi
+ override type FreeTermSymbol >: Null <: TermSymbol with FreeTermSymbolApi
+ override type FreeTypeSymbol >: Null <: TypeSymbol with FreeTypeSymbolApi
+
+ trait HasFlagsApi {
+ def flags: FlagSet
+ def hasFlag(fs: FlagSet): Boolean
+ def hasAllFlags(fs: FlagSet): Boolean
+ def flagString: String
+ }
+
+ /** The API of symbols */
+ trait SymbolApi extends SymbolBase with HasFlagsApi { this: Symbol =>
+
+ /** The position of this symbol
+ */
+ def pos: Position
+
+ /** A list of annotations attached to this Symbol.
+ */
+ // [Eugene++] we cannot expose the `annotations` method because it doesn't auto-initialize a symbol (see SI-5423)
+ // there was an idea to use the `isCompilerUniverse` flag and auto-initialize symbols in `annotations` whenever this flag is false
+ // but it doesn't work, because the unpickler (that is shared between reflective universes and global universes) is very picky about initialization
+ // scala.reflect.internal.Types$TypeError: bad reference while unpickling scala.collection.immutable.Nil: type Nothing not found in scala.type not found.
+ // at scala.reflect.internal.pickling.UnPickler$Scan.toTypeError(UnPickler.scala:836)
+ // at scala.reflect.internal.pickling.UnPickler$Scan$LazyTypeRef.complete(UnPickler.scala:849) // auto-initialize goes boom
+ // at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1140)
+ // at scala.reflect.internal.Symbols$Symbol.initialize(Symbols.scala:1272) // this triggers auto-initialize
+ // at scala.reflect.internal.Symbols$Symbol.annotations(Symbols.scala:1438) // unpickler first tries to get pre-existing annotations
+ // at scala.reflect.internal.Symbols$Symbol.addAnnotation(Symbols.scala:1458) // unpickler tries to add the annotation being read
+ // at scala.reflect.internal.pickling.UnPickler$Scan.readSymbolAnnotation(UnPickler.scala:489) // unpickler detects an annotation
+ // at scala.reflect.internal.pickling.UnPickler$Scan.run(UnPickler.scala:88)
+ // at scala.reflect.internal.pickling.UnPickler.unpickle(UnPickler.scala:37)
+ // at scala.reflect.runtime.JavaMirrors$JavaMirror.unpickleClass(JavaMirrors.scala:253) // unpickle from within a reflexive mirror
+ // def annotations: List[AnnotationInfo]
+ def getAnnotations: List[AnnotationInfo]
+
+ /** Whether this symbol carries an annotation for which the given
+ * symbol is its typeSymbol.
+ */
+ def hasAnnotation(sym: Symbol): Boolean
+
+ /** ...
+ */
+ def orElse(alt: => Symbol): Symbol
+
+ /** ...
+ */
+ def filter(cond: Symbol => Boolean): Symbol
+
+ /** If this is a NoSymbol, returns NoSymbol, otherwise
+ * returns the result of applying `f` to this symbol.
+ */
+ def map(f: Symbol => Symbol): Symbol
+
+ /** ...
+ */
+ def suchThat(cond: Symbol => Boolean): Symbol
+
+ /**
+ * Set when symbol has a modifier of the form private[X], NoSymbol otherwise.
+ *
+ * Access level encoding: there are three scala flags (PRIVATE, PROTECTED,
+ * and LOCAL) which combine with value privateWithin (the "foo" in private[foo])
+ * to define from where an entity can be accessed. The meanings are as follows:
+ *
+ * PRIVATE access restricted to class only.
+ * PROTECTED access restricted to class and subclasses only.
+ * LOCAL can only be set in conjunction with PRIVATE or PROTECTED.
+ * Further restricts access to the same object instance.
+ *
+ * In addition, privateWithin can be used to set a visibility barrier.
+ * When set, everything contained in the named enclosing package or class
+ * has access. It is incompatible with PRIVATE or LOCAL, but is additive
+ * with PROTECTED (i.e. if either the flags or privateWithin allow access,
+ * then it is allowed.)
+ *
+ * The java access levels translate as follows:
+ *
+ * java private: hasFlag(PRIVATE) && (privateWithin == NoSymbol)
+ * java package: !hasFlag(PRIVATE | PROTECTED) && (privateWithin == enclosingPackage)
+ * java protected: hasFlag(PROTECTED) && (privateWithin == enclosingPackage)
+ * java public: !hasFlag(PRIVATE | PROTECTED) && (privateWithin == NoSymbol)
+ */
+ def privateWithin: Symbol
+
+ /** For a class: the module or case class factory with the same name in the same package.
+ * For a module: the class with the same name in the same package.
+ * For all others: NoSymbol
+ */
+ def companionSymbol: Symbol
+
+ /** If this symbol is a package class, this symbol; otherwise the next enclosing
+ * package class, or `NoSymbol` if none exists.
+ */
+ def enclosingPackageClass: Symbol
+
+ /** If this symbol is a top-level class, this symbol; otherwise the next enclosing
+ * top-level class, or `NoSymbol` if none exists.
+ */
+ def enclosingTopLevelClass: Symbol
+
+ /** Does this symbol represent a value, i.e. not a module and not a method?
+ * If yes, `isTerm` is also guaranteed to be true.
+ * [Eugene++] I need a review of the implementation
+ */
+ def isValue: Boolean
+
+ /** Does this symbol represent a mutable value?
+ * If yes, `isTerm` and `isValue` are also guaranteed to be true.
+ */
+ def isVariable: Boolean
+
+ /** Does this symbol represent the definition of a package?
+ * If yes, `isTerm` is also guaranteed to be true.
+ */
+ def isPackage: Boolean
+
+ /** Does this symbol represent a package class?
+ * If yes, `isClass` is also guaranteed to be true.
+ */
+ def isPackageClass: Boolean
+
+ /** Is this symbol an overloaded method?
+ */
+ def isOverloaded : Boolean
+
+ /** Does this symbol represent the definition of a primitive class?
+ * Namely, is it one of [[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]],
+ * [[scala.Short]], [[scala.Byte]], [[scala.Unit]] or [[scala.Boolean]]?
+ */
+ def isPrimitiveValueClass: Boolean
+
+ /** Does this symbol represent the definition of a numeric value class?
+ * Namely, is it one of [[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]],
+ * [[scala.Short]], [[scala.Byte]], [[scala.Unit]] or [[scala.Boolean]]?
+ */
+ def isNumericValueClass: Boolean
+
+ /** Does this symbol represent the definition of a custom value class?
+ * Namely, is AnyVal among its parent classes?
+ * TODO: Why not just have in reflect.internal?
+ * [Eugene++] because it's useful for macros
+ */
+ def isDerivedValueClass: Boolean
+
+ /** Does this symbol represent the definition of a type alias?
+ * If yes, `isType` is also guaranteed to be true.
+ */
+ def isAliasType : Boolean
+
+ /** Does this symbol represent the definition of an abstract type?
+ * If yes, `isType` is also guaranteed to be true.
+ */
+ def isAbstractType : Boolean
+
+ /** Does this symbol represent an existentially bound type?
+ * If yes, `isType` is also guaranteed to be true.
+ */
+ def isExistential : Boolean
+
+ /** Does this symbol represent a free type captured by reification?
+ */
+ def isFreeType : Boolean
+
+ /** Does this symbol or its underlying type represent a typechecking error?
+ */
+ def isErroneous : Boolean
+
+ /** The type signature of this symbol seen as a member of given type `site`.
+ */
+ def typeSignatureIn(site: Type): Type
+
+ /** The type signature of this symbol.
+ * Note if the symbol is a member of a class, one almost always is interested
+ * in `typeSignatureIn` with a site type instead.
+ */
+ def typeSignature: Type
+
+ /** The string discriminator of this symbol; useful for debugging */
+ def kind: String
+ }
+
+ /** The API of term symbols */
+ trait TermSymbolApi extends SymbolApi with HasFlagsApi with TermSymbolBase { this: TermSymbol =>
+ /** The overloaded alternatives of this symbol */
+ def alternatives: List[Symbol]
+
+ def resolveOverloaded(pre: Type = NoPrefix, targs: Seq[Type] = List(), actuals: Seq[Type]): Symbol
+ }
+
+ /** The API of type symbols */
+ trait TypeSymbolApi extends SymbolApi with HasFlagsApi with TypeSymbolBase { this: TypeSymbol =>
+ /** Is the type parameter represented by this symbol contravariant?
+ */
+ def isContravariant : Boolean
+
+ /** Is the type parameter represented by this symbol contravariant?
+ */
+ def isCovariant : Boolean
+
+ /** Does this symbol represent the definition of a skolem?
+ * Skolems are used during typechecking to represent type parameters viewed from inside their scopes.
+ * If yes, `isType` is also guaranteed to be true.
+ */
+ def isSkolem : Boolean
+
+ /** A type reference that refers to this type symbol seen
+ * as a member of given type `site`.
+ */
+ def asTypeIn(site: Type): Type
+
+ /** A type reference that refers to this type symbol
+ * Note if symbol is a member of a class, one almost always is interested
+ * in `asTypeIn` with a site type instead.
+ *
+ * Example: Given a class declaration `class C[T] { ... } `, that generates a symbol
+ * `C`. Then `C.asType` is the type `C[T]`.
+ *
+ * By contrast, `C.typeSignature` would be a type signature of form
+ * `PolyType(ClassInfoType(...))` that describes type parameters, value
+ * parameters, parent types, and members of `C`.
+ */
+ def asType: Type // !!! Same as typeSignature.
+ }
+
+ /** The API of method symbols */
+ type MethodSymbolApi = MethodSymbolBase
+
+ /** The API of module symbols */
+ type ModuleSymbolApi = ModuleSymbolBase
+
+ /** The API of class symbols */
+ trait ClassSymbolApi extends TypeSymbolApi with ClassSymbolBase { this: ClassSymbol =>
+ /** If this symbol is a class or trait, its self type, otherwise the type
+ * of the symbol itself.
+ */
+ def selfType: Type
+
+ /** The type `C.this`, where `C` is the current class */
+ def thisPrefix: Type
+ }
+
+ /** The API of free term symbols */
+ trait FreeTermSymbolApi extends TermSymbolApi with FreeTermSymbolBase { this: FreeTermSymbol =>
+ /** The place where this symbol has been spawned */
+ def origin: String
+
+ /** The valus this symbol refers to */
+ def value: Any
+ }
+
+ /** The API of free term symbols */
+ trait FreeTypeSymbolApi extends TypeSymbolApi with FreeTypeSymbolBase { this: FreeTypeSymbol =>
+ /** The place where this symbol has been spawned */
+ def origin: String
+ }
+}
diff --git a/src/reflect/scala/reflect/api/TagInterop.scala b/src/reflect/scala/reflect/api/TagInterop.scala
new file mode 100644
index 0000000000..e10b89d1c6
--- /dev/null
+++ b/src/reflect/scala/reflect/api/TagInterop.scala
@@ -0,0 +1,38 @@
+package scala.reflect
+package api
+
+import scala.reflect.base.TypeCreator
+import scala.reflect.base.{Universe => BaseUniverse}
+
+// [Martin] Moved to compiler because it needs to see runtime.Universe
+// The two will be united in scala-reflect anyway.
+trait TagInterop { self: JavaUniverse =>
+
+ // [Eugene++] would be great if we could approximate the interop without any mirrors
+ // todo. think how to implement that
+
+ override def concreteTypeTagToManifest[T: ClassTag](mirror0: Any, tag: base.Universe # ConcreteTypeTag[T]): Manifest[T] = {
+ // [Eugene++] implement more sophisticated logic
+ // Martin said it'd be okay to simply copypaste `Implicits.manifestOfType`
+ val mirror = mirror0.asInstanceOf[Mirror]
+ val runtimeClass = mirror.runtimeClass(tag.in(mirror).tpe)
+ Manifest.classType(runtimeClass).asInstanceOf[Manifest[T]]
+ }
+
+ override def manifestToConcreteTypeTag[T](mirror0: Any, manifest: Manifest[T]): base.Universe # ConcreteTypeTag[T] =
+ ConcreteTypeTag(mirror0.asInstanceOf[Mirror], new TypeCreator {
+ def apply[U <: BaseUniverse with Singleton](mirror: MirrorOf[U]): U # Type = {
+ mirror.universe match {
+ case ju: JavaUniverse =>
+ val jm = mirror.asInstanceOf[ju.Mirror]
+ val sym = jm.reflectClass(manifest.erasure).symbol
+ val tpe =
+ if (manifest.typeArguments.isEmpty) sym.asType
+ else ju.appliedType(sym.asTypeConstructor, manifest.typeArguments map (targ => ju.manifestToConcreteTypeTag(jm, targ)) map (_.in(jm).tpe))
+ tpe.asInstanceOf[U # Type]
+ case u =>
+ u.manifestToConcreteTypeTag(mirror.asInstanceOf[u.Mirror], manifest).in(mirror).tpe
+ }
+ }
+ })
+}
diff --git a/src/reflect/scala/reflect/api/TreePrinters.scala b/src/reflect/scala/reflect/api/TreePrinters.scala
new file mode 100644
index 0000000000..08a08e7b90
--- /dev/null
+++ b/src/reflect/scala/reflect/api/TreePrinters.scala
@@ -0,0 +1,87 @@
+package scala.reflect
+package api
+
+import java.io.{ PrintWriter, StringWriter }
+
+trait TreePrinters { self: Universe =>
+
+ trait TreePrinter {
+ def print(args: Any*)
+ protected var typesPrinted = false
+ protected var uniqueIds = false
+ def withTypesPrinted: this.type = { typesPrinted = true; this }
+ def withUniqueIds: this.type = { uniqueIds = true; this }
+ }
+
+ def show(tree: Tree): String = show(tree, newTreePrinter)
+
+ def show(tree: Tree, mkPrinter: PrintWriter => TreePrinter): String = {
+ val buffer = new StringWriter()
+ val writer = new PrintWriter(buffer)
+ val printer = mkPrinter(writer)
+ printer.print(tree)
+ writer.flush()
+ buffer.toString
+ }
+
+ def showRaw(tree: Tree): String = show(tree, new RawTreePrinter(_))
+
+ /** Hook to define what `show(tree)` means.
+ */
+ def newTreePrinter(out: PrintWriter): TreePrinter
+
+ // emits more or less verbatim representation of the provided tree
+ // [Eugene] todo. needs to be refined
+ // http://groups.google.com/group/scala-user/browse_thread/thread/de5a5be2e083cf8e
+ class RawTreePrinter(out: PrintWriter) extends TreePrinter {
+ def print(args: Any*): Unit = args foreach {
+ case EmptyTree =>
+ print("EmptyTree")
+ case tree @ TypeTree() =>
+ print("TypeTree()")
+ if (tree.tpe != null)
+ print(".setType(", tree.tpe, ")")
+ else if (tree.original != null)
+ print(".setOriginal(", tree.original, ")")
+ case Literal(Constant(s: String)) =>
+ print("Literal(Constant(\"" + s + "\"))")
+ case tree: Tree =>
+ print(tree.productPrefix+"(")
+ val it = tree.productIterator
+ while (it.hasNext) {
+ it.next() match {
+ case name: Name if uniqueIds && tree.hasSymbol && tree.symbol != NoSymbol =>
+ print(tree.symbol.name, "#", tree.symbol.id)
+ case arg =>
+ print(arg)
+ }
+ print(if (it.hasNext) ", " else "")
+ }
+ print(")")
+ if (typesPrinted)
+ print(".setType(", tree.tpe, ")")
+ case list: List[_] =>
+ print("List(")
+ val it = list.iterator
+ while (it.hasNext) {
+ print(it.next())
+ print(if (it.hasNext) ", " else "")
+ }
+ print(")")
+ case mods: Modifiers =>
+ val parts = collection.mutable.ListBuffer[String]()
+ parts += mods.flagString
+ if (mods.privateWithin.toString.nonEmpty)
+ parts += "newTypeName(\"" + mods.privateWithin.toString + "\")"
+ if (mods.annotations.nonEmpty)
+ parts += mods.annotations map showRaw mkString ("List(", ", ", ")")
+ print(parts mkString ("Modifiers(", ", ", ")"))
+ case name: Name =>
+ if (name.isTermName) print("newTermName(\"") else print("newTypeName(\"")
+ print(name.toString)
+ print("\")")
+ case arg =>
+ out.print(arg)
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala
new file mode 100644
index 0000000000..2d130daa4e
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Trees.scala
@@ -0,0 +1,689 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect
+package api
+
+// Syncnote: Trees are currently not thread-safe.
+trait Trees extends base.Trees { self: Universe =>
+
+ override type Tree >: Null <: TreeApi
+
+ /** ... */
+ trait TreeApi extends TreeBase { this: Tree =>
+
+ /** ... */
+ def pos: Position
+
+ /** ... */
+ def tpe: Type
+
+ /** Note that symbol is fixed as null at this level. In SymTrees,
+ * it is overridden and implemented with a var, initialized to NoSymbol.
+ *
+ * Trees which are not SymTrees but which carry symbols do so by
+ * overriding `def symbol` to forward it elsewhere. Examples:
+ *
+ * Super(qual, _) // has qual's symbol
+ * Apply(fun, args) // has fun's symbol
+ * TypeApply(fun, args) // has fun's symbol
+ * AppliedTypeTree(tpt, args) // has tpt's symbol
+ * TypeTree(tpe) // has tpe's typeSymbol, if tpe != null
+ *
+ * Attempting to set the symbol of a Tree which does not support
+ * it will induce an exception.
+ */
+ def symbol: Symbol
+
+ /** ... */
+ def hasSymbol: Boolean
+
+ /** Provides an alternate if tree is empty
+ * @param alt The alternate tree
+ * @return If this tree is non empty, this tree, otherwise `alt`.
+ */
+ def orElse(alt: => Tree): Tree
+
+ /** Apply `f` to each subtree */
+ def foreach(f: Tree => Unit): Unit
+
+ /** Find all subtrees matching predicate `p`. Same as `filter` */
+ def withFilter(f: Tree => Boolean): List[Tree]
+
+ /** Find all subtrees matching predicate `p`. Same as `withFilter` */
+ def filter(f: Tree => Boolean): List[Tree]
+
+ /** Apply `pf' to each subtree on which the function is defined and collect the results.
+ */
+ def collect[T](pf: PartialFunction[Tree, T]): List[T]
+
+ /** Returns optionally first tree (in a preorder traversal) which satisfies predicate `p`,
+ * or None if none exists.
+ */
+ def find(p: Tree => Boolean): Option[Tree]
+
+ /** Is there exists a part of this tree which satisfies predicate `p`? */
+ def exists(p: Tree => Boolean): Boolean
+
+ /** Do all parts of this tree satisfy predicate `p`? */
+ def forAll(p: Tree => Boolean): Boolean
+
+ /** Tests whether two trees are structurall equal.
+ * Note that `==` on trees is reference equality.
+ */
+ def equalsStructure(that : Tree): Boolean
+
+ /** The direct child trees of this tree.
+ * EmptyTrees are always omitted. Lists are flattened.
+ */
+ def children: List[Tree]
+
+ /** Extracts free term symbols from a tree that is reified or contains reified subtrees.
+ */
+ def freeTerms: List[FreeTermSymbol]
+
+ /** Extracts free type symbols from a tree that is reified or contains reified subtrees.
+ */
+ def freeTypes: List[FreeTypeSymbol]
+
+ /** Substitute symbols in `to` for corresponding occurrences of references to
+ * symbols `from` in this type.
+ */
+ def substituteSymbols(from: List[Symbol], to: List[Symbol]): Tree
+
+ /** Substitute types in `to` for corresponding occurrences of references to
+ * symbols `from` in this tree.
+ */
+ def substituteTypes(from: List[Symbol], to: List[Type]): Tree
+
+ /** Substitute given tree `to` for occurrences of nodes that represent
+ * `C.this`, where `C` referes to the given class `clazz`.
+ */
+ def substituteThis(clazz: Symbol, to: Tree): Tree
+
+ /** Make a copy of this tree, keeping all attributes,
+ * except that all positions are focused (so nothing
+ * in this tree will be found when searching by position).
+ */
+ def duplicate: this.type
+ }
+
+ override type TermTree >: Null <: Tree with TermTreeApi
+
+ /** The API that all term trees support */
+ trait TermTreeApi extends TreeApi { this: TermTree =>
+ }
+
+ override type TypTree >: Null <: Tree with TypTreeApi
+
+ /** The API that all typ trees support */
+ trait TypTreeApi extends TreeApi { this: TypTree =>
+ }
+
+ override type SymTree >: Null <: Tree with SymTreeApi
+
+ /** The API that all sym trees support */
+ trait SymTreeApi extends TreeApi { this: SymTree =>
+ def symbol: Symbol
+ }
+
+ override type NameTree >: Null <: Tree with NameTreeApi
+
+ /** The API that all name trees support */
+ trait NameTreeApi extends TreeApi { this: NameTree =>
+ def name: Name
+ }
+
+ override type RefTree >: Null <: SymTree with NameTree with RefTreeApi
+
+ /** The API that all ref trees support */
+ trait RefTreeApi extends SymTreeApi with NameTreeApi { this: RefTree =>
+ def qualifier: Tree // empty for Idents
+ def name: Name
+ }
+
+ override type DefTree >: Null <: SymTree with NameTree with DefTreeApi
+
+ /** The API that all def trees support */
+ trait DefTreeApi extends SymTreeApi with NameTreeApi { this: DefTree =>
+ def name: Name
+ }
+
+ override type MemberDef >: Null <: DefTree with MemberDefApi
+
+ /** The API that all member defs support */
+ trait MemberDefApi extends DefTreeApi { this: MemberDef =>
+ def mods: Modifiers
+ }
+
+ override type PackageDef >: Null <: MemberDef with PackageDefApi
+
+ /** The API that all package defs support */
+ trait PackageDefApi extends MemberDefApi { this: PackageDef =>
+ val pid: RefTree
+ val stats: List[Tree]
+ }
+
+ override type ImplDef >: Null <: MemberDef with ImplDefApi
+
+ /** The API that all impl defs support */
+ trait ImplDefApi extends MemberDefApi { this: ImplDef =>
+ val impl: Template
+ }
+
+ override type ClassDef >: Null <: ImplDef with ClassDefApi
+
+ /** The API that all class defs support */
+ trait ClassDefApi extends ImplDefApi { this: ClassDef =>
+ val mods: Modifiers
+ val name: TypeName
+ val tparams: List[TypeDef]
+ val impl: Template
+ }
+
+ override type ModuleDef >: Null <: ImplDef with ModuleDefApi
+
+ /** The API that all module defs support */
+ trait ModuleDefApi extends ImplDefApi { this: ModuleDef =>
+ val mods: Modifiers
+ val name: TermName
+ val impl: Template
+ }
+
+ override type ValOrDefDef >: Null <: MemberDef with ValOrDefDefApi
+
+ /** The API that all val defs and def defs support */
+ trait ValOrDefDefApi extends MemberDefApi { this: ValOrDefDef =>
+ def name: Name // can't be a TermName because macros can be type names.
+ def tpt: Tree
+ def rhs: Tree
+ }
+
+ override type ValDef >: Null <: ValOrDefDef with ValDefApi
+
+ /** The API that all val defs support */
+ trait ValDefApi extends ValOrDefDefApi { this: ValDef =>
+ val mods: Modifiers
+ val name: TermName
+ val tpt: Tree
+ val rhs: Tree
+ }
+
+ override type DefDef >: Null <: ValOrDefDef with DefDefApi
+
+ /** The API that all def defs support */
+ trait DefDefApi extends ValOrDefDefApi { this: DefDef =>
+ val mods: Modifiers
+ val name: Name
+ val tparams: List[TypeDef]
+ val vparamss: List[List[ValDef]]
+ val tpt: Tree
+ val rhs: Tree
+ }
+
+ override type TypeDef >: Null <: MemberDef with TypeDefApi
+
+ /** The API that all type defs support */
+ trait TypeDefApi extends MemberDefApi { this: TypeDef =>
+ val mods: Modifiers
+ val name: TypeName
+ val tparams: List[TypeDef]
+ val rhs: Tree
+ }
+
+ override type LabelDef >: Null <: DefTree with TermTree with LabelDefApi
+
+ /** The API that all label defs support */
+ trait LabelDefApi extends DefTreeApi with TermTreeApi { this: LabelDef =>
+ val name: TermName
+ val params: List[Ident]
+ val rhs: Tree
+ }
+
+ override type ImportSelector >: Null <: ImportSelectorApi
+
+ /** The API that all import selectors support */
+ trait ImportSelectorApi { this: ImportSelector =>
+ val name: Name
+ val namePos: Int
+ val rename: Name
+ val renamePos: Int
+ }
+
+ override type Import >: Null <: SymTree with ImportApi
+
+ /** The API that all imports support */
+ trait ImportApi extends SymTreeApi { this: Import =>
+ val expr: Tree
+ val selectors: List[ImportSelector]
+ }
+
+ override type Template >: Null <: SymTree with TemplateApi
+
+ /** The API that all templates support */
+ trait TemplateApi extends SymTreeApi { this: Template =>
+ val parents: List[Tree]
+ val self: ValDef
+ val body: List[Tree]
+ }
+
+ override type Block >: Null <: TermTree with BlockApi
+
+ /** The API that all blocks support */
+ trait BlockApi extends TermTreeApi { this: Block =>
+ val stats: List[Tree]
+ val expr: Tree
+ }
+
+ override type CaseDef >: Null <: Tree with CaseDefApi
+
+ /** The API that all case defs support */
+ trait CaseDefApi extends TreeApi { this: CaseDef =>
+ val pat: Tree
+ val guard: Tree
+ val body: Tree
+ }
+
+ override type Alternative >: Null <: TermTree with AlternativeApi
+
+ /** The API that all alternatives support */
+ trait AlternativeApi extends TermTreeApi { this: Alternative =>
+ val trees: List[Tree]
+ }
+
+ override type Star >: Null <: TermTree with StarApi
+
+ /** The API that all stars support */
+ trait StarApi extends TermTreeApi { this: Star =>
+ val elem: Tree
+ }
+
+ override type Bind >: Null <: DefTree with BindApi
+
+ /** The API that all binds support */
+ trait BindApi extends DefTreeApi { this: Bind =>
+ val name: Name
+ val body: Tree
+ }
+
+ override type UnApply >: Null <: TermTree with UnApplyApi
+
+ /** The API that all unapplies support */
+ trait UnApplyApi extends TermTreeApi { this: UnApply =>
+ val fun: Tree
+ val args: List[Tree]
+ }
+
+ override type ArrayValue >: Null <: TermTree with ArrayValueApi
+
+ /** The API that all array values support */
+ trait ArrayValueApi extends TermTreeApi { this: ArrayValue =>
+ val elemtpt: Tree
+ val elems: List[Tree]
+ }
+
+ override type Function >: Null <: TermTree with SymTree with FunctionApi
+
+ /** The API that all functions support */
+ trait FunctionApi extends TermTreeApi with SymTreeApi { this: Function =>
+ val vparams: List[ValDef]
+ val body: Tree
+ }
+
+ override type Assign >: Null <: TermTree with AssignApi
+
+ /** The API that all assigns support */
+ trait AssignApi extends TermTreeApi { this: Assign =>
+ val lhs: Tree
+ val rhs: Tree
+ }
+
+ override type AssignOrNamedArg >: Null <: TermTree with AssignOrNamedArgApi
+
+ /** The API that all assigns support */
+ trait AssignOrNamedArgApi extends TermTreeApi { this: AssignOrNamedArg =>
+ val lhs: Tree
+ val rhs: Tree
+ }
+
+ override type If >: Null <: TermTree with IfApi
+
+ /** The API that all ifs support */
+ trait IfApi extends TermTreeApi { this: If =>
+ val cond: Tree
+ val thenp: Tree
+ val elsep: Tree
+ }
+
+ override type Match >: Null <: TermTree with MatchApi
+
+ /** The API that all matches support */
+ trait MatchApi extends TermTreeApi { this: Match =>
+ val selector: Tree
+ val cases: List[CaseDef]
+ }
+
+ override type Return >: Null <: TermTree with SymTree with ReturnApi
+
+ /** The API that all returns support */
+ trait ReturnApi extends TermTreeApi { this: Return =>
+ val expr: Tree
+ }
+
+ override type Try >: Null <: TermTree with TryApi
+
+ /** The API that all tries support */
+ trait TryApi extends TermTreeApi { this: Try =>
+ val block: Tree
+ val catches: List[CaseDef]
+ val finalizer: Tree
+ }
+
+ override type Throw >: Null <: TermTree with ThrowApi
+
+ /** The API that all tries support */
+ trait ThrowApi extends TermTreeApi { this: Throw =>
+ val expr: Tree
+ }
+
+ override type New >: Null <: TermTree with NewApi
+
+ /** The API that all news support */
+ trait NewApi extends TermTreeApi { this: New =>
+ val tpt: Tree
+ }
+
+ override type Typed >: Null <: TermTree with TypedApi
+
+ /** The API that all typeds support */
+ trait TypedApi extends TermTreeApi { this: Typed =>
+ val expr: Tree
+ val tpt: Tree
+ }
+
+ override type GenericApply >: Null <: TermTree with GenericApplyApi
+
+ /** The API that all applies support */
+ trait GenericApplyApi extends TermTreeApi { this: GenericApply =>
+ val fun: Tree
+ val args: List[Tree]
+ }
+
+ override type TypeApply >: Null <: GenericApply with TypeApplyApi
+
+ /** The API that all type applies support */
+ trait TypeApplyApi extends GenericApplyApi { this: TypeApply =>
+ }
+
+ override type Apply >: Null <: GenericApply with ApplyApi
+
+ /** The API that all applies support */
+ trait ApplyApi extends GenericApplyApi { this: Apply =>
+ }
+
+ override type ApplyDynamic >: Null <: TermTree with SymTree with ApplyDynamicApi
+
+ /** The API that all apply dynamics support */
+ trait ApplyDynamicApi extends TermTreeApi with SymTreeApi { this: ApplyDynamic =>
+ val qual: Tree
+ val args: List[Tree]
+ }
+
+ override type Super >: Null <: TermTree with SuperApi
+
+ /** The API that all supers support */
+ trait SuperApi extends TermTreeApi { this: Super =>
+ val qual: Tree
+ val mix: TypeName
+ }
+
+ override type This >: Null <: TermTree with SymTree with ThisApi
+
+ /** The API that all thises support */
+ trait ThisApi extends TermTreeApi with SymTreeApi { this: This =>
+ val qual: TypeName
+ }
+
+ override type Select >: Null <: RefTree with SelectApi
+
+ /** The API that all selects support */
+ trait SelectApi extends RefTreeApi { this: Select =>
+ val qualifier: Tree
+ val name: Name
+ }
+
+ override type Ident >: Null <: RefTree with IdentApi
+
+ /** The API that all idents support */
+ trait IdentApi extends RefTreeApi { this: Ident =>
+ val name: Name
+ }
+
+ override type ReferenceToBoxed >: Null <: TermTree with ReferenceToBoxedApi
+
+ /** The API that all references support */
+ trait ReferenceToBoxedApi extends TermTreeApi { this: ReferenceToBoxed =>
+ val ident: Tree
+ }
+
+ override type Literal >: Null <: TermTree with LiteralApi
+
+ /** The API that all literals support */
+ trait LiteralApi extends TermTreeApi { this: Literal =>
+ val value: Constant
+ }
+
+ override type Annotated >: Null <: Tree with AnnotatedApi
+
+ /** The API that all annotateds support */
+ trait AnnotatedApi extends TreeApi { this: Annotated =>
+ val annot: Tree
+ val arg: Tree
+ }
+
+ override type SingletonTypeTree >: Null <: TypTree with SingletonTypeTreeApi
+
+ /** The API that all singleton type trees support */
+ trait SingletonTypeTreeApi extends TypTreeApi { this: SingletonTypeTree =>
+ val ref: Tree
+ }
+
+ override type SelectFromTypeTree >: Null <: TypTree with RefTree with SelectFromTypeTreeApi
+
+ /** The API that all selects from type trees support */
+ trait SelectFromTypeTreeApi extends TypTreeApi with RefTreeApi { this: SelectFromTypeTree =>
+ val qualifier: Tree
+ val name: TypeName
+ }
+
+ override type CompoundTypeTree >: Null <: TypTree with CompoundTypeTreeApi
+
+ /** The API that all compound type trees support */
+ trait CompoundTypeTreeApi extends TypTreeApi { this: CompoundTypeTree =>
+ val templ: Template
+ }
+
+ override type AppliedTypeTree >: Null <: TypTree with AppliedTypeTreeApi
+
+ /** The API that all applied type trees support */
+ trait AppliedTypeTreeApi extends TypTreeApi { this: AppliedTypeTree =>
+ val tpt: Tree
+ val args: List[Tree]
+ }
+
+ override type TypeBoundsTree >: Null <: TypTree with TypeBoundsTreeApi
+
+ /** The API that all type bound trees support */
+ trait TypeBoundsTreeApi extends TypTreeApi { this: TypeBoundsTree =>
+ val lo: Tree
+ val hi: Tree
+ }
+
+ override type ExistentialTypeTree >: Null <: TypTree with ExistentialTypeTreeApi
+
+ /** The API that all existential type trees support */
+ trait ExistentialTypeTreeApi extends TypTreeApi { this: ExistentialTypeTree =>
+ val tpt: Tree
+ val whereClauses: List[Tree]
+ }
+
+ override type TypeTree >: Null <: TypTree with TypeTreeApi
+
+ /** The API that all type trees support */
+ trait TypeTreeApi extends TypTreeApi { this: TypeTree =>
+ def original: Tree
+ }
+
+ /** An empty deferred value definition corresponding to:
+ * val _: _
+ * This is used as a placeholder in the `self` parameter Template if there is
+ * no definition of a self value of self type.
+ */
+ val emptyValDef: ValDef
+
+// ---------------------- copying ------------------------------------------------
+
+ /** The standard (lazy) tree copier
+ */
+ type TreeCopier <: TreeCopierOps
+ val treeCopy: TreeCopier = newLazyTreeCopier
+
+ def newStrictTreeCopier: TreeCopier
+ def newLazyTreeCopier: TreeCopier
+
+ /** The API of a tree copier
+ * tree copiers are made available by an implicit conversion in reflect.ops
+ */
+ abstract class TreeCopierOps {
+ def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template): ClassDef
+ def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]): PackageDef
+ def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template): ModuleDef
+ def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree): ValDef
+ def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef
+ def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree): TypeDef
+ def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef
+ def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]): Import
+ def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]): Template
+ def Block(tree: Tree, stats: List[Tree], expr: Tree): Block
+ def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree): CaseDef
+ def Alternative(tree: Tree, trees: List[Tree]): Alternative
+ def Star(tree: Tree, elem: Tree): Star
+ def Bind(tree: Tree, name: Name, body: Tree): Bind
+ def UnApply(tree: Tree, fun: Tree, args: List[Tree]): UnApply
+ def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue
+ def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function
+ def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign
+ def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg
+ def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If
+ def Match(tree: Tree, selector: Tree, cases: List[CaseDef]): Match
+ def Return(tree: Tree, expr: Tree): Return
+ def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree): Try
+ def Throw(tree: Tree, expr: Tree): Throw
+ def New(tree: Tree, tpt: Tree): New
+ def Typed(tree: Tree, expr: Tree, tpt: Tree): Typed
+ def TypeApply(tree: Tree, fun: Tree, args: List[Tree]): TypeApply
+ def Apply(tree: Tree, fun: Tree, args: List[Tree]): Apply
+ def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]): ApplyDynamic
+ def Super(tree: Tree, qual: Tree, mix: TypeName): Super
+ def This(tree: Tree, qual: Name): This
+ def Select(tree: Tree, qualifier: Tree, selector: Name): Select
+ def Ident(tree: Tree, name: Name): Ident
+ def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed
+ def Literal(tree: Tree, value: Constant): Literal
+ def TypeTree(tree: Tree): TypeTree
+ def Annotated(tree: Tree, annot: Tree, arg: Tree): Annotated
+ def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree
+ def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree
+ def CompoundTypeTree(tree: Tree, templ: Template): CompoundTypeTree
+ def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]): AppliedTypeTree
+ def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree): TypeBoundsTree
+ def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree
+ }
+
+// ---------------------- traversing and transforming ------------------------------
+
+ class Traverser {
+ protected[scala] var currentOwner: Symbol = rootMirror.RootClass
+
+ def traverse(tree: Tree): Unit = itraverse(this, tree)
+
+ def traverseTrees(trees: List[Tree]) {
+ trees foreach traverse
+ }
+ def traverseTreess(treess: List[List[Tree]]) {
+ treess foreach traverseTrees
+ }
+ def traverseStats(stats: List[Tree], exprOwner: Symbol) {
+ stats foreach (stat =>
+ if (exprOwner != currentOwner) atOwner(exprOwner)(traverse(stat))
+ else traverse(stat)
+ )
+ }
+
+ def atOwner(owner: Symbol)(traverse: => Unit) {
+ val prevOwner = currentOwner
+ currentOwner = owner
+ traverse
+ currentOwner = prevOwner
+ }
+
+ /** Leave apply available in the generic traverser to do something else.
+ */
+ def apply[T <: Tree](tree: T): T = { traverse(tree); tree }
+ }
+
+ protected def itraverse(traverser: Traverser, tree: Tree): Unit = throw new MatchError(tree)
+
+ protected def xtraverse(traverser: Traverser, tree: Tree): Unit = throw new MatchError(tree)
+
+ abstract class Transformer {
+ val treeCopy: TreeCopier = newLazyTreeCopier
+ protected[scala] var currentOwner: Symbol = rootMirror.RootClass
+ protected def currentMethod = currentOwner.enclosingMethod
+ protected def currentClass = currentOwner.enclosingClass
+// protected def currentPackage = currentOwner.enclosingTopLevelClass.owner
+ def transform(tree: Tree): Tree = itransform(this, tree)
+
+ def transformTrees(trees: List[Tree]): List[Tree] =
+ trees mapConserve (transform(_))
+ def transformTemplate(tree: Template): Template =
+ transform(tree: Tree).asInstanceOf[Template]
+ def transformTypeDefs(trees: List[TypeDef]): List[TypeDef] =
+ trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef])
+ def transformValDef(tree: ValDef): ValDef =
+ if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef]
+ def transformValDefs(trees: List[ValDef]): List[ValDef] =
+ trees mapConserve (transformValDef(_))
+ def transformValDefss(treess: List[List[ValDef]]): List[List[ValDef]] =
+ treess mapConserve (transformValDefs(_))
+ def transformCaseDefs(trees: List[CaseDef]): List[CaseDef] =
+ trees mapConserve (tree => transform(tree).asInstanceOf[CaseDef])
+ def transformIdents(trees: List[Ident]): List[Ident] =
+ trees mapConserve (tree => transform(tree).asInstanceOf[Ident])
+ def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
+ stats mapConserve (stat =>
+ if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(transform(stat))
+ else transform(stat)) filter (EmptyTree != _)
+ def transformModifiers(mods: Modifiers): Modifiers =
+ mods.mapAnnotations(transformTrees)
+
+ def atOwner[A](owner: Symbol)(trans: => A): A = {
+ val prevOwner = currentOwner
+ currentOwner = owner
+ val result = trans
+ currentOwner = prevOwner
+ result
+ }
+ }
+
+ protected def itransform(transformer: Transformer, tree: Tree): Tree = throw new MatchError(tree)
+
+ protected def xtransform(transformer: Transformer, tree: Tree): Tree = throw new MatchError(tree)
+
+ type Modifiers >: Null <: ModifiersApi
+
+ abstract class ModifiersApi extends ModifiersBase with HasFlagsApi
+
+}
+
diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala
new file mode 100644
index 0000000000..b62a92cbd7
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Types.scala
@@ -0,0 +1,368 @@
+package scala.reflect
+package api
+
+trait Types extends base.Types { self: Universe =>
+
+ override type Type >: Null <: TypeApi
+
+ /** The extended API of types
+ */
+ abstract class TypeApi extends TypeBase {
+
+ /** The defined or declared members with name `name` in this type;
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ * Alternatives of overloaded symbol appear in the order they are declared.
+ */
+ def declaration(name: Name): Symbol
+
+ /** The collection of declarations in this type
+ * [Eugene++] why not List?
+ */
+ def declarations: Iterable[Symbol]
+
+ /** The member with given name, either directly declared or inherited,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ */
+ def member(name: Name): Symbol
+
+ /** The non-private member with given name, either directly declared or inherited,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ */
+ def nonPrivateMember(name: Name): Symbol
+
+ /** An iterable containing all members of this type (directly declared or inherited)
+ * Members appear in the linearization order of their owners.
+ * Members with the same owner appear in reverse order of their declarations.
+ * [Eugene++] the order needs to be reversed back, at least in the public API
+ */
+ def members: Iterable[Symbol]
+
+ /** An iterable containing all non-private members of this type (directly declared or inherited)
+ * Members appear in the linearization order of their owners.
+ * Members with the same owner appear in reverse order of their declarations.
+ */
+ def nonPrivateMembers: Iterable[Symbol]
+
+ /** Substitute symbols in `to` for corresponding occurrences of references to
+ * symbols `from` in this type.
+ */
+ def substituteSymbols(from: List[Symbol], to: List[Symbol]): Type
+
+ /** Substitute types in `to` for corresponding occurrences of references to
+ * symbols `from` in this type.
+ */
+ def substituteTypes(from: List[Symbol], to: List[Type]): Type
+
+ /** If this is a parameterized types, the type arguments.
+ * Otherwise the empty list
+ */
+ def typeArguments: List[Type]
+
+ /** For a (potentially wrapped) poly type, its type parameters,
+ * the empty list for all other types */
+ def typeParams: List[Symbol]
+
+ /** Is this type a type constructor that is missing its type arguments?
+ */
+ def isHigherKinded: Boolean // !!! This should be called "isTypeConstructor", no?
+
+ /** Returns the corresponding type constructor (e.g. List for List[T] or List[String])
+ */
+ def typeConstructor: Type
+
+ /** Does this type refer to spliceable types or is a spliceable type?
+ */
+ def isConcrete: Boolean
+
+ /** Is this type an abstract type that needs to be resolved?
+ */
+ def isSpliceable: Boolean
+
+ /**
+ * Expands type aliases and converts higher-kinded TypeRefs to PolyTypes.
+ * Functions on types are also implemented as PolyTypes.
+ *
+ * Example: (in the below, <List> is the type constructor of List)
+ * TypeRef(pre, <List>, List()) is replaced by
+ * PolyType(X, TypeRef(pre, <List>, List(X)))
+ */
+ def normalize: Type // !!! Alternative name? "normalize" is used to mean too many things.
+
+ /** Does this type conform to given type argument `that`? */
+ def <:< (that: Type): Boolean
+
+ /** Is this type equivalent to given type argument `that`? */
+ def =:= (that: Type): Boolean
+
+ /** The list of all base classes of this type (including its own typeSymbol)
+ * in reverse linearization order, starting with the class itself and ending
+ * in class Any.
+ */
+ def baseClasses: List[Symbol] // !!! Alternative name, perhaps linearization?
+
+ /** The least type instance of given class which is a supertype
+ * of this type. Example:
+ * {{{
+ * class D[T]
+ * class C extends p.D[Int]
+ * ThisType(C).baseType(D) = p.D[Int]
+ * }}}
+ */
+ def baseType(clazz: Symbol): Type
+
+ /** This type as seen from prefix `pre` and class `clazz`. This means:
+ * Replace all thistypes of `clazz` or one of its subclasses
+ * by `pre` and instantiate all parameters by arguments of `pre`.
+ * Proceed analogously for thistypes referring to outer classes.
+ *
+ * Example:
+ * {{{
+ * class D[T] { def m: T }
+ * class C extends p.D[Int]
+ * T.asSeenFrom(ThisType(C), D) (where D is owner of m)
+ * = Int
+ * }}}
+ */
+ def asSeenFrom(pre: Type, clazz: Symbol): Type
+
+ /** The erased type corresponding to this type after
+ * all transformations from Scala to Java have been performed.
+ */
+ def erasure: Type // !!! "erasedType", compare with "widen" (so "erase") or "underlying" (so "erased")
+ // why not name it "erasure"?
+
+ /** Apply `f` to each part of this type, returning
+ * a new type. children get mapped before their parents */
+ def map(f: Type => Type): Type
+
+ /** Apply `f` to each part of this type, for side effects only */
+ def foreach(f: Type => Unit)
+
+ /** Returns optionally first type (in a preorder traversal) which satisfies predicate `p`,
+ * or None if none exists.
+ */
+ def find(p: Type => Boolean): Option[Type]
+
+ /** Is there part of this type which satisfies predicate `p`? */
+ def exists(p: Type => Boolean): Boolean
+
+ /** Does this type contain a reference to given symbol? */
+ def contains(sym: Symbol): Boolean
+
+ /** If this is a compound type, the list of its parent types;
+ * otherwise the empty list
+ */
+ def parents: List[Type]
+
+ /** If this is a singleton type, returns the type underlying it;
+ * otherwise returns this type itself.
+ */
+ def underlying: Type
+
+ /** If this is a singleton type, widen it to its nearest underlying non-singleton
+ * base type by applying one or more `underlying` dereferences.
+ * If this is not a singleton type, returns this type itself.
+ *
+ * Example:
+ *
+ * class Outer { class C ; val x: C }
+ * val o: Outer
+ * <o.x.type>.widen = o.C
+ */
+ def widen: Type
+
+ /** The string discriminator of this type; useful for debugging */
+ def kind: String
+ }
+
+ /** .. */
+ override type ThisType >: Null <: SingletonType with ThisTypeApi
+
+ /** The API that all this types support */
+ trait ThisTypeApi extends TypeApi { this: ThisType =>
+ val sym: Symbol
+ }
+
+ /** .. */
+ override type SingleType >: Null <: SingletonType with SingleTypeApi
+
+ /** The API that all single types support */
+ trait SingleTypeApi extends TypeApi { this: SingleType =>
+ val pre: Type
+ val sym: Symbol
+ }
+
+ /** .. */
+ override type SuperType >: Null <: SingletonType with SuperTypeApi
+
+ /** The API that all super types support */
+ trait SuperTypeApi extends TypeApi { this: SuperType =>
+ val thistpe: Type
+ val supertpe: Type
+ }
+
+ /** .. */
+ override type ConstantType >: Null <: SingletonType with ConstantTypeApi
+
+ /** The API that all constant types support */
+ trait ConstantTypeApi extends TypeApi { this: ConstantType =>
+ val value: Constant
+ }
+
+ /** .. */
+ override type TypeRef >: Null <: Type with TypeRefApi
+
+ /** The API that all type refs support */
+ trait TypeRefApi extends TypeApi { this: TypeRef =>
+ val pre: Type
+ val sym: Symbol
+ val args: List[Type]
+ }
+
+ /** .. */
+ override type RefinedType >: Null <: CompoundType with RefinedTypeApi
+
+ /** The API that all refined types support */
+ trait RefinedTypeApi extends TypeApi { this: RefinedType =>
+ val parents: List[Type]
+ val decls: Scope
+ }
+
+ /** .. */
+ override type ClassInfoType >: Null <: CompoundType with ClassInfoTypeApi
+
+ /** The API that all class info types support */
+ trait ClassInfoTypeApi extends TypeApi { this: ClassInfoType =>
+ val parents: List[Type]
+ val decls: Scope
+ val typeSymbol: Symbol
+ }
+
+ /** .. */
+ override type MethodType >: Null <: Type with MethodTypeApi
+
+ /** The API that all method types support */
+ trait MethodTypeApi extends TypeApi { this: MethodType =>
+ val params: List[Symbol]
+ val resultType: Type
+ }
+
+ /** .. */
+ override type NullaryMethodType >: Null <: Type with NullaryMethodTypeApi
+
+ /** The API that all nullary method types support */
+ trait NullaryMethodTypeApi extends TypeApi { this: NullaryMethodType =>
+ val resultType: Type
+ }
+
+ /** .. */
+ override type PolyType >: Null <: Type with PolyTypeApi
+
+ /** The API that all polymorphic types support */
+ trait PolyTypeApi extends TypeApi { this: PolyType =>
+ val typeParams: List[Symbol]
+ val resultType: Type
+ }
+
+ /** .. */
+ override type ExistentialType >: Null <: Type with ExistentialTypeApi
+
+ /** The API that all existential types support */
+ trait ExistentialTypeApi extends TypeApi { this: ExistentialType =>
+ val quantified: List[Symbol]
+ val underlying: Type
+ }
+
+ /** .. */
+ override type AnnotatedType >: Null <: Type with AnnotatedTypeApi
+
+ /** The API that all annotated types support */
+ trait AnnotatedTypeApi extends TypeApi { this: AnnotatedType =>
+ val annotations: List[AnnotationInfo]
+ val underlying: Type
+ val selfsym: Symbol
+ }
+
+ /** .. */
+ override type TypeBounds >: Null <: Type with TypeBoundsApi
+
+ /** The API that all type bounds support */
+ trait TypeBoundsApi extends TypeApi { this: TypeBounds =>
+ val lo: Type
+ val hi: Type
+ }
+
+ /** .. */
+ override type BoundedWildcardType >: Null <: Type with BoundedWildcardTypeApi
+
+ /** The API that all this types support */
+ trait BoundedWildcardTypeApi extends TypeApi { this: BoundedWildcardType =>
+ val bounds: TypeBounds
+ }
+
+ /** The least upper bound of a list of types, as determined by `<:<`. */
+ def lub(xs: List[Type]): Type
+
+ /** The greatest lower bound of a list of types, as determined by `<:<`. */
+ def glb(ts: List[Type]): Type
+
+ // Creators ---------------------------------------------------------------
+ // too useful and too non-trivial to be left out of public API
+ // [Eugene to Paul] needs review!
+
+ /** The canonical creator for single-types */
+ def singleType(pre: Type, sym: Symbol): Type
+
+ /** the canonical creator for a refined type with a given scope */
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): Type
+
+ /** The canonical creator for a refined type with an initially empty scope.
+ */
+ def refinedType(parents: List[Type], owner: Symbol): Type
+
+ /** The canonical creator for typerefs
+ */
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type
+
+ /** A creator for intersection type where intersections of a single type are
+ * replaced by the type itself. */
+ def intersectionType(tps: List[Type]): Type
+
+ /** A creator for intersection type where intersections of a single type are
+ * replaced by the type itself, and repeated parent classes are merged.
+ *
+ * !!! Repeated parent classes are not merged - is this a bug in the
+ * comment or in the code?
+ */
+ def intersectionType(tps: List[Type], owner: Symbol): Type
+
+ /** A creator for type applications */
+ def appliedType(tycon: Type, args: List[Type]): Type
+
+ /** A creator for type parameterizations that strips empty type parameter lists.
+ * Use this factory method to indicate the type has kind * (it's a polymorphic value)
+ * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty).
+ */
+ def polyType(tparams: List[Symbol], tpe: Type): Type
+
+ /** A creator for existential types. This generates:
+ *
+ * {{{
+ * tpe1 where { tparams }
+ * }}}
+ *
+ * where `tpe1` is the result of extrapolating `tpe` with regard to `tparams`.
+ * Extrapolating means that type variables in `tparams` occurring
+ * in covariant positions are replaced by upper bounds, (minus any
+ * SingletonClass markers), type variables in `tparams` occurring in
+ * contravariant positions are replaced by upper bounds, provided the
+ * resulting type is legal with regard to stability, and does not contain
+ * any type variable in `tparams`.
+ *
+ * The abstraction drops all type parameters that are not directly or
+ * indirectly referenced by type `tpe1`. If there are no remaining type
+ * parameters, simply returns result type `tpe`.
+ */
+ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type
+}
+
diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala
new file mode 100644
index 0000000000..002cd2e673
--- /dev/null
+++ b/src/reflect/scala/reflect/api/Universe.scala
@@ -0,0 +1,68 @@
+package scala.reflect
+package api
+
+import language.experimental.macros
+
+abstract class Universe extends base.Universe
+ with Symbols
+ with Types
+ with FlagSets
+ with Names
+ with Trees
+ with TreePrinters
+ with Constants
+ with Positions
+ with Mirrors
+ with StandardDefinitions
+ with StandardNames
+ with Importers
+ with Exprs
+ with AnnotationInfos
+{
+
+ /** Given an expression, generate a tree that when compiled and executed produces the original tree.
+ * The produced tree will be bound to the Universe it was called from.
+ *
+ * For instance, given the abstract syntax tree representation of the <[ x + 1 ]> expression:
+ *
+ * {{{
+ * Apply(Select(Ident("x"), "+"), List(Literal(Constant(1))))
+ * }}}
+ *
+ * The reifier transforms it to the following expression:
+ *
+ * {{{
+ * <[
+ * val $u: u.type = u // where u is a reference to the Universe that calls the reify
+ * $u.Expr[Int]($u.Apply($u.Select($u.Ident($u.newFreeVar("x", <Int>, x), "+"), List($u.Literal($u.Constant(1))))))
+ * ]>
+ * }}}
+ *
+ * Reification performs expression splicing (when processing Expr.splice)
+ * and type splicing (for every type T that has a TypeTag[T] implicit in scope):
+ *
+ * {{{
+ * val two = mirror.reify(2) // Literal(Constant(2))
+ * val four = mirror.reify(two.splice + two.splice) // Apply(Select(two.tree, newTermName("$plus")), List(two.tree))
+ *
+ * def macroImpl[T](c: Context) = {
+ * ...
+ * // T here is just a type parameter, so the tree produced by reify won't be of much use in a macro expansion
+ * // however, if T were annotated with c.TypeTag (which would declare an implicit parameter for macroImpl)
+ * // then reification would subtitute T with the TypeTree that was used in a TypeApply of this particular macro invocation
+ * val factory = c.reify{ new Queryable[T] }
+ * ...
+ * }
+ * }}}
+ *
+ * The transformation looks mostly straightforward, but it has its tricky parts:
+ * * Reifier retains symbols and types defined outside the reified tree, however
+ * locally defined entities get erased and replaced with their original trees
+ * * Free variables are detected and wrapped in symbols of the type FreeVar
+ * * Mutable variables that are accessed from a local function are wrapped in refs
+ * * Since reified trees can be compiled outside of the scope they've been created in,
+ * special measures are taken to ensure that all members accessed in the reifee remain visible
+ */
+ // implementation is magically hardwired to `scala.reflect.reify.Taggers`
+ def reify[T](expr: T): Expr[T] = macro ???
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/api/package.scala b/src/reflect/scala/reflect/api/package.scala
new file mode 100644
index 0000000000..d2fce7cf1d
--- /dev/null
+++ b/src/reflect/scala/reflect/api/package.scala
@@ -0,0 +1,12 @@
+package scala.reflect
+
+package object api {
+
+ // type and value aliases for slices of the base Universe cake that are not
+ // repeated in api.Universe
+ type Scopes = base.Scopes
+ type BuildUtils = base.BuildUtils
+ type Attachments = base.Attachments
+
+ type MirrorOf[U <: base.Universe with Singleton] = base.MirrorOf[U]
+}
diff --git a/src/reflect/scala/reflect/internal/AbstractFileApi.scala b/src/reflect/scala/reflect/internal/AbstractFileApi.scala
new file mode 100644
index 0000000000..9f37f4536f
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/AbstractFileApi.scala
@@ -0,0 +1,7 @@
+package scala.reflect
+package internal
+
+trait AbstractFileApi {
+ def path: String
+ def canonicalPath: String
+}
diff --git a/src/reflect/scala/reflect/internal/AnnotationCheckers.scala b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
new file mode 100644
index 0000000000..449b0ca0bc
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/AnnotationCheckers.scala
@@ -0,0 +1,121 @@
+/* NSC -- new Scala compiler
+ * Copyright 2007-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+/** Additions to the type checker that can be added at
+ * run time. Typically these are added by
+ * compiler plugins. */
+trait AnnotationCheckers {
+ self: SymbolTable =>
+
+
+ /** An additional checker for annotations on types.
+ * Typically these are registered by compiler plugins
+ * with the addAnnotationChecker method. */
+ abstract class AnnotationChecker {
+ /** Check the annotations on two types conform. */
+ def annotationsConform(tpe1: Type, tpe2: Type): Boolean
+
+ /** Refine the computed least upper bound of a list of types.
+ * All this should do is add annotations. */
+ def annotationsLub(tp: Type, ts: List[Type]): Type = tp
+
+ /** Refine the computed greatest lower bound of a list of types.
+ * All this should do is add annotations. */
+ def annotationsGlb(tp: Type, ts: List[Type]): Type = tp
+
+ /** Refine the bounds on type parameters to the given type arguments. */
+ def adaptBoundsToAnnotations(bounds: List[TypeBounds],
+ tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = bounds
+
+ /** Modify the type that has thus far been inferred
+ * for a tree. All this should do is add annotations. */
+ def addAnnotations(tree: Tree, tpe: Type): Type = tpe
+
+ /** Decide whether this annotation checker can adapt a tree
+ * that has an annotated type to the given type tp, taking
+ * into account the given mode (see method adapt in trait Typers).*/
+ def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = false
+
+ /** Adapt a tree that has an annotated type to the given type tp,
+ * taking into account the given mode (see method adapt in trait Typers).
+ * An implementation cannot rely on canAdaptAnnotations being called
+ * before. If the implementing class cannot do the adaptiong, it
+ * should return the tree unchanged.*/
+ def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = tree
+ }
+
+ // Syncnote: Annotation checkers inaccessible to reflection, so no sync in var necessary.
+ /** The list of annotation checkers that have been registered */
+ private var annotationCheckers: List[AnnotationChecker] = Nil
+
+ /** Register an annotation checker. Typically these
+ * are added by compiler plugins. */
+ def addAnnotationChecker(checker: AnnotationChecker) {
+ if (!(annotationCheckers contains checker))
+ annotationCheckers = checker :: annotationCheckers
+ }
+
+ /** Remove all annotation checkers */
+ def removeAllAnnotationCheckers() {
+ annotationCheckers = Nil
+ }
+
+ /** Check that the annotations on two types conform. To do
+ * so, consult all registered annotation checkers. */
+ def annotationsConform(tp1: Type, tp2: Type): Boolean = {
+ /* Finish quickly if there are no annotations */
+ if (tp1.annotations.isEmpty && tp2.annotations.isEmpty)
+ true
+ else
+ annotationCheckers.forall(
+ _.annotationsConform(tp1,tp2))
+ }
+
+ /** Refine the computed least upper bound of a list of types.
+ * All this should do is add annotations. */
+ def annotationsLub(tpe: Type, ts: List[Type]): Type = {
+ annotationCheckers.foldLeft(tpe)((tpe, checker) =>
+ checker.annotationsLub(tpe, ts))
+ }
+
+ /** Refine the computed greatest lower bound of a list of types.
+ * All this should do is add annotations. */
+ def annotationsGlb(tpe: Type, ts: List[Type]): Type = {
+ annotationCheckers.foldLeft(tpe)((tpe, checker) =>
+ checker.annotationsGlb(tpe, ts))
+ }
+
+ /** Refine the bounds on type parameters to the given type arguments. */
+ def adaptBoundsToAnnotations(bounds: List[TypeBounds],
+ tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = {
+ annotationCheckers.foldLeft(bounds)((bounds, checker) =>
+ checker.adaptBoundsToAnnotations(bounds, tparams, targs))
+ }
+
+ /** Let all annotations checkers add extra annotations
+ * to this tree's type. */
+ def addAnnotations(tree: Tree, tpe: Type): Type = {
+ annotationCheckers.foldLeft(tpe)((tpe, checker) =>
+ checker.addAnnotations(tree, tpe))
+ }
+
+ /** Find out whether any annotation checker can adapt a tree
+ * to a given type. Called by Typers.adapt. */
+ def canAdaptAnnotations(tree: Tree, mode: Int, pt: Type): Boolean = {
+ annotationCheckers.exists(_.canAdaptAnnotations(tree, mode, pt))
+ }
+
+ /** Let registered annotation checkers adapt a tree
+ * to a given type (called by Typers.adapt). Annotation checkers
+ * that cannot do the adaption should pass the tree through
+ * unchanged. */
+ def adaptAnnotations(tree: Tree, mode: Int, pt: Type): Tree = {
+ annotationCheckers.foldLeft(tree)((tree, checker) =>
+ checker.adaptAnnotations(tree, mode, pt))
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
new file mode 100644
index 0000000000..c283ae408e
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -0,0 +1,293 @@
+/* NSC -- new Scala compiler
+ * Copyright 2007-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import util._
+import pickling.ByteCodecs
+
+/** AnnotationInfo and its helpers */
+trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
+ import definitions.{ ThrowsClass, StaticAnnotationClass, isMetaAnnotation }
+
+ // Common annotation code between Symbol and Type.
+ // For methods altering the annotation list, on Symbol it mutates
+ // the Symbol's field directly. For Type, a new AnnotatedType is
+ // created which wraps the original type.
+ trait Annotatable[Self] {
+ /** The annotations on this type. */
+ def annotations: List[AnnotationInfo] // Annotations on this type.
+ def setAnnotations(annots: List[AnnotationInfo]): Self // Replace annotations with argument list.
+ def withAnnotations(annots: List[AnnotationInfo]): Self // Add annotations to this type.
+ def filterAnnotations(p: AnnotationInfo => Boolean): Self // Retain only annotations meeting the condition.
+ def withoutAnnotations: Self // Remove all annotations from this type.
+
+ /** Symbols of any @throws annotations on this symbol.
+ */
+ def throwsAnnotations(): List[Symbol] = annotations collect {
+ case AnnotationInfo(tp, Literal(Constant(tpe: Type)) :: Nil, _) if tp.typeSymbol == ThrowsClass => tpe.typeSymbol
+ }
+
+ /** Test for, get, or remove an annotation */
+ def hasAnnotation(cls: Symbol) = annotations exists (_ matches cls)
+ def getAnnotation(cls: Symbol) = annotations find (_ matches cls)
+ def removeAnnotation(cls: Symbol): Self = filterAnnotations(ann => !(ann matches cls))
+ final def withAnnotation(annot: AnnotationInfo): Self = withAnnotations(List(annot))
+ }
+
+ /** Arguments to classfile annotations (which are written to
+ * bytecode as java annotations) are either:
+ *
+ * - constants
+ * - arrays of constants
+ * - or nested classfile annotations
+ */
+ abstract class ClassfileAnnotArg extends Product
+ implicit val ClassfileAnnotArgTag = ClassTag[ClassfileAnnotArg](classOf[ClassfileAnnotArg])
+
+ /** Represents a compile-time Constant (`Boolean`, `Byte`, `Short`,
+ * `Char`, `Int`, `Long`, `Float`, `Double`, `String`, `java.lang.Class` or
+ * an instance of a Java enumeration value).
+ */
+ case class LiteralAnnotArg(const: Constant)
+ extends ClassfileAnnotArg with LiteralAnnotArgApi {
+ override def toString = const.escapedStringValue
+ }
+ implicit val LiteralAnnotArgTag = ClassTag[LiteralAnnotArg](classOf[LiteralAnnotArg])
+
+ object LiteralAnnotArg extends LiteralAnnotArgExtractor
+
+ /** Represents an array of classfile annotation arguments */
+ case class ArrayAnnotArg(args: Array[ClassfileAnnotArg])
+ extends ClassfileAnnotArg with ArrayAnnotArgApi {
+ override def toString = args.mkString("[", ", ", "]")
+ }
+ implicit val ArrayAnnotArgTag = ClassTag[ArrayAnnotArg](classOf[ArrayAnnotArg])
+
+ object ArrayAnnotArg extends ArrayAnnotArgExtractor
+
+ /** A specific annotation argument that encodes an array of bytes as an
+ * array of `Long`. The type of the argument declared in the annotation
+ * must be `String`. This specialised class is used to encode Scala
+ * signatures for reasons of efficiency, both in term of class-file size
+ * and in term of compiler performance.
+ */
+ case class ScalaSigBytes(bytes: Array[Byte]) extends ClassfileAnnotArg {
+ override def toString = (bytes map { byte => (byte & 0xff).toHexString }).mkString("[ ", " ", " ]")
+ lazy val encodedBytes = ByteCodecs.encode(bytes) // TODO remove after migration to ASM-based GenJVM complete
+ def isLong: Boolean = (encodedBytes.length > 65535) // TODO remove after migration to ASM-based GenJVM complete
+ lazy val sevenBitsMayBeZero: Array[Byte] = {
+ mapToNextModSevenBits(scala.reflect.internal.pickling.ByteCodecs.encode8to7(bytes))
+ }
+ def fitsInOneString: Boolean = {
+ val numZeros = (sevenBitsMayBeZero count { b => b == 0 })
+ val res = (sevenBitsMayBeZero.length + numZeros) <= 65535
+ assert(this.isLong == !res, "As things stand, can't just swap in `fitsInOneString()` for `isLong()`")
+ res
+ }
+ def sigAnnot: Type =
+ if (this.isLong)
+ definitions.ScalaLongSignatureAnnotation.tpe
+ else
+ definitions.ScalaSignatureAnnotation.tpe
+
+ private def mapToNextModSevenBits(src: Array[Byte]): Array[Byte] = {
+ var i = 0
+ val srclen = src.length
+ while (i < srclen) {
+ val in = src(i)
+ src(i) = (if (in == 0x7f) 0.toByte else (in + 1).toByte)
+ i += 1
+ }
+ src
+ }
+
+ }
+
+ /** Represents a nested classfile annotation */
+ case class NestedAnnotArg(annInfo: AnnotationInfo) extends ClassfileAnnotArg with NestedAnnotArgApi {
+ // The nested annotation should not have any Scala annotation arguments
+ assert(annInfo.args.isEmpty, annInfo.args)
+ override def toString = annInfo.toString
+ }
+ implicit val NestedAnnotArgTag = ClassTag[NestedAnnotArg](classOf[NestedAnnotArg])
+
+ object NestedAnnotArg extends NestedAnnotArgExtractor
+
+ object AnnotationInfo extends AnnotationInfoExtractor {
+ def marker(atp: Type): AnnotationInfo =
+ apply(atp, Nil, Nil)
+
+ def lazily(lazyInfo: => AnnotationInfo) =
+ new LazyAnnotationInfo(lazyInfo)
+
+ def apply(atp: Type, args: List[Tree], assocs: List[(Name, ClassfileAnnotArg)]): AnnotationInfo =
+ new CompleteAnnotationInfo(atp, args, assocs)
+
+ def unapply(info: AnnotationInfo): Option[(Type, List[Tree], List[(Name, ClassfileAnnotArg)])] =
+ Some((info.atp, info.args, info.assocs))
+ }
+
+ class CompleteAnnotationInfo(
+ val atp: Type,
+ val args: List[Tree],
+ val assocs: List[(Name, ClassfileAnnotArg)]
+ ) extends AnnotationInfo {
+ // Classfile annot: args empty. Scala annot: assocs empty.
+ assert(args.isEmpty || assocs.isEmpty, atp)
+
+ // necessary for reification, see Reifiers.scala for more info
+ private var orig: Tree = EmptyTree
+ def original = orig
+ def setOriginal(t: Tree): this.type = {
+ orig = t
+ this setPos t.pos
+ this
+ }
+
+ override def toString = (
+ atp +
+ (if (!args.isEmpty) args.mkString("(", ", ", ")") else "") +
+ (if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "")
+ )
+ }
+
+ /** Symbol annotations parsed in `Namer` (typeCompleter of
+ * definitions) have to be lazy (#1782)
+ */
+ final class LazyAnnotationInfo(lazyInfo: => AnnotationInfo) extends AnnotationInfo {
+ private var forced = false
+ private lazy val forcedInfo =
+ try {
+ val result = lazyInfo
+ if (result.pos == NoPosition) result setPos pos
+ result
+ } finally forced = true
+
+ def atp: Type = forcedInfo.atp
+ def args: List[Tree] = forcedInfo.args
+ def assocs: List[(Name, ClassfileAnnotArg)] = forcedInfo.assocs
+ def original: Tree = forcedInfo.original
+ def setOriginal(t: Tree): this.type = { forcedInfo.setOriginal(t); this }
+
+ // We should always be able to print things without forcing them.
+ override def toString = if (forced) forcedInfo.toString else "@<?>"
+
+ override def pos: Position = if (forced) forcedInfo.pos else NoPosition
+ }
+
+ /** Typed information about an annotation. It can be attached to either
+ * a symbol or an annotated type.
+ *
+ * Annotations are written to the classfile as Java annotations
+ * if `atp` conforms to `ClassfileAnnotation` (the classfile parser adds
+ * this interface to any Java annotation class).
+ *
+ * Annotations are pickled (written to scala symtab attribute in the
+ * classfile) if `atp` inherits form `StaticAnnotation`.
+ *
+ * `args` stores arguments to Scala annotations, represented as typed
+ * trees. Note that these trees are not transformed by any phases
+ * following the type-checker.
+ *
+ * `assocs` stores arguments to classfile annotations as name-value pairs.
+ */
+ sealed abstract class AnnotationInfo extends AnnotationInfoApi {
+ def atp: Type
+ def args: List[Tree]
+ def assocs: List[(Name, ClassfileAnnotArg)]
+
+ // necessary for reification, see Reifiers.scala for more info
+ def original: Tree
+ def setOriginal(t: Tree): this.type
+
+ // see annotationArgRewriter
+ lazy val isTrivial = atp.isTrivial && !hasArgWhich(_.isInstanceOf[This])
+
+ private var rawpos: Position = NoPosition
+ def pos = rawpos
+ def setPos(pos: Position): this.type = { // Syncnote: Setpos inaccessible to reflection, so no sync in rawpos necessary.
+ rawpos = pos
+ this
+ }
+
+ /** Annotations annotating annotations are confusing so I drew
+ * an example. Given the following code:
+ *
+ * class A {
+ * @(deprecated @setter) @(inline @getter)
+ * var x: Int = 0
+ * }
+ *
+ * For the setter `x_=` in A, annotations contains one AnnotationInfo =
+ * List(deprecated @setter)
+ * The single AnnotationInfo in that list, i.e. `@(deprecated @setter)`, has metaAnnotations =
+ * List(setter)
+ *
+ * Similarly, the getter `x` in A has an @inline annotation, which has
+ * metaAnnotations = List(getter).
+ */
+ def symbol = atp.typeSymbol
+
+ /** These are meta-annotations attached at the use site; they
+ * only apply to this annotation usage. For instance, in
+ * `@(deprecated @setter @field) val ...`
+ * metaAnnotations = List(setter, field).
+ */
+ def metaAnnotations: List[AnnotationInfo] = atp match {
+ case AnnotatedType(metas, _, _) => metas
+ case _ => Nil
+ }
+
+ /** The default kind of members to which this annotation is attached.
+ * For instance, for scala.deprecated defaultTargets =
+ * List(getter, setter, beanGetter, beanSetter).
+ */
+ def defaultTargets = symbol.annotations map (_.symbol) filter isMetaAnnotation
+ // Test whether the typeSymbol of atp conforms to the given class.
+ def matches(clazz: Symbol) = symbol isNonBottomSubClass clazz
+ // All subtrees of all args are considered.
+ def hasArgWhich(p: Tree => Boolean) = args exists (_ exists p)
+
+ /** Check whether the type or any of the arguments are erroneous */
+ def isErroneous = atp.isErroneous || args.exists(_.isErroneous)
+
+ def isStatic = symbol isNonBottomSubClass StaticAnnotationClass
+
+ /** Check whether any of the arguments mention a symbol */
+ def refsSymbol(sym: Symbol) = hasArgWhich(_.symbol == sym)
+
+ /** Change all ident's with Symbol "from" to instead use symbol "to" */
+ def substIdentSyms(from: Symbol, to: Symbol) =
+ AnnotationInfo(atp, args map (_ substituteSymbols (List(from), List(to))), assocs) setPos pos
+
+ def stringArg(index: Int) = constantAtIndex(index) map (_.stringValue)
+ def intArg(index: Int) = constantAtIndex(index) map (_.intValue)
+ def symbolArg(index: Int) = argAtIndex(index) collect {
+ case Apply(fun, Literal(str) :: Nil) if fun.symbol == definitions.Symbol_apply =>
+ newTermName(str.stringValue)
+ }
+
+ // !!! when annotation arguments are not literals, but any sort of
+ // expression, there is a fair chance they will turn up here not as
+ // Literal(const) but some arbitrary AST.
+ def constantAtIndex(index: Int): Option[Constant] =
+ argAtIndex(index) collect { case Literal(x) => x }
+
+ def argAtIndex(index: Int): Option[Tree] =
+ if (index < args.size) Some(args(index)) else None
+
+ override def hashCode = atp.## + args.## + assocs.##
+ override def equals(other: Any) = other match {
+ case x: AnnotationInfo => (atp == x.atp) && (args == x.args) && (assocs == x.assocs)
+ case _ => false
+ }
+ }
+
+ implicit val AnnotationInfoTag = ClassTag[AnnotationInfo](classOf[AnnotationInfo])
+
+ object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil)
+}
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
new file mode 100644
index 0000000000..e07f1bac49
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -0,0 +1,260 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect
+package internal
+
+// todo implement in terms of BitSet
+import scala.collection.{ mutable, immutable }
+import math.max
+import util.Statistics._
+
+/** A base type sequence (BaseTypeSeq) is an ordered sequence spanning all the base types
+ * of a type. It characterized by the following two laws:
+ *
+ * (1) Each element of `tp.baseTypeSeq` is a basetype of `tp`
+ * (2) For each basetype `bt1` of `tp` there is an element `bt` in `tp.baseTypeSeq` such that
+ *
+ * bt.typeSymbol = bt1.typeSymbol
+ * bt <: bt1
+ *
+ * (3) The type symbols of different elements are different.
+ *
+ * Elements in the sequence are ordered by Symbol.isLess.
+ * @note base type sequences were called closures up to 2.7.1. The name has been changed
+ * to avoid confusion with function closures.
+ */
+trait BaseTypeSeqs {
+ this: SymbolTable =>
+ import definitions._
+
+ protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) =
+ new BaseTypeSeq(parents, elems)
+
+ /** Note: constructor is protected to force everyone to use the factory method newBaseTypeSeq instead.
+ * 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]) {
+ self =>
+ incCounter(baseTypeSeqCount)
+ incCounter(baseTypeSeqLenTotal, elems.length)
+
+ /** The number of types in the sequence */
+ def length: Int = elems.length
+
+ // #3676 shows why we can't store NoType in elems to mark cycles
+ // (while NoType is in there to indicate a cycle in this BTS, during the execution of
+ // the mergePrefixAndArgs below, the elems get copied without the pending map,
+ // so that NoType's are seen instead of the original type --> spurious compile error)
+ private val pending = new mutable.BitSet(length)
+
+ /** The type at i'th position in this sequence; lazy types are returned evaluated. */
+ def apply(i: Int): Type =
+ if(pending contains i) {
+ pending.clear()
+ throw CyclicInheritance
+ } else
+ elems(i) match {
+ case rtp @ RefinedType(variants, decls) =>
+ // can't assert decls.isEmpty; see t0764
+ //if (!decls.isEmpty) assert(false, "computing closure of "+this+":"+this.isInstanceOf[RefinedType]+"/"+closureCache(j))
+ //Console.println("compute closure of "+this+" => glb("+variants+")")
+ pending += i
+ try {
+ mergePrefixAndArgs(variants, -1, lubDepth(variants)) match {
+ case Some(tp0) =>
+ pending(i) = false
+ elems(i) = tp0
+ tp0
+ case None =>
+ typeError(
+ "no common type instance of base types "+(variants mkString ", and ")+" exists.")
+ }
+ } catch {
+ case CyclicInheritance =>
+ typeError(
+ "computing the common type instance of base types "+(variants mkString ", and ")+" leads to a cycle.")
+ }
+ case tp =>
+ tp
+ }
+
+ def rawElem(i: Int) = elems(i)
+
+ /** The type symbol of the type at i'th position in this sequence;
+ * no evaluation needed.
+ */
+ def typeSymbol(i: Int): Symbol = {
+ elems(i) match {
+ case RefinedType(v :: vs, _) => v.typeSymbol
+ case tp => tp.typeSymbol
+ }
+ }
+
+ /** Return all evaluated types in this sequence as a list */
+ def toList: List[Type] = elems.toList
+
+ def copy(head: Type, offset: Int): BaseTypeSeq = {
+ val arr = new Array[Type](elems.length + offset)
+ compat.Platform.arraycopy(elems, 0, arr, offset, elems.length)
+ arr(0) = head
+ newBaseTypeSeq(parents, arr)
+ }
+
+ /** Compute new base type sequence with `tp` prepended to this sequence */
+ def prepend(tp: Type): BaseTypeSeq = copy(tp, 1)
+
+ /** Compute new base type sequence with `tp` replacing the head of this sequence */
+ def updateHead(tp: Type): BaseTypeSeq = copy(tp, 0)
+
+ /** Compute new base type sequence where every element is mapped
+ * with function `f`. Lazy types are mapped but not evaluated */
+ def map(f: Type => Type): BaseTypeSeq = {
+ // inlined `elems map f` for performance
+ val len = length
+ var arr = new Array[Type](len)
+ var i = 0
+ while (i < len) {
+ arr(i) = f(elems(i))
+ i += 1
+ }
+ newBaseTypeSeq(parents, arr)
+ }
+
+ def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f)
+
+ def exists(p: Type => Boolean): Boolean = elems exists p
+
+ lazy val maxDepth: Int = maxDepthOfElems
+
+ protected def maxDepthOfElems = {
+ var d = 0
+ for (i <- 0 until length) d = max(d, maxDpth(elems(i)))
+ d
+ }
+
+ /** The maximum depth of type `tp` */
+ protected def maxDpth(tp: Type): Int = tp match {
+ case TypeRef(pre, sym, args) =>
+ max(maxDpth(pre), maxDpth(args) + 1)
+ case RefinedType(parents, decls) =>
+ max(maxDpth(parents), maxDpth(decls.toList.map(_.info)) + 1)
+ case TypeBounds(lo, hi) =>
+ max(maxDpth(lo), maxDpth(hi))
+ case MethodType(paramtypes, result) =>
+ maxDpth(result)
+ case NullaryMethodType(result) =>
+ maxDpth(result)
+ case PolyType(tparams, result) =>
+ max(maxDpth(result), maxDpth(tparams map (_.info)) + 1)
+ case ExistentialType(tparams, result) =>
+ max(maxDpth(result), maxDpth(tparams map (_.info)) + 1)
+ case _ =>
+ 1
+ }
+
+ /** The maximum depth of all types `tps` */
+ private def maxDpth(tps: Seq[Type]): Int = {
+ var d = 0
+ for (tp <- tps) d = max(d, maxDpth(tp))
+ d
+ }
+
+ override def toString = elems.mkString("BTS(", ",", ")")
+
+ private def typeError(msg: String): Nothing =
+ throw new TypeError(
+ "the type intersection "+(parents mkString " with ")+" is malformed"+
+ "\n --- because ---\n"+msg)
+ }
+
+ /** A merker object for a base type sequence that's no yet computed.
+ * used to catch inheritance cycles
+ */
+ val undetBaseTypeSeq: BaseTypeSeq = newBaseTypeSeq(List(), Array())
+
+ /** Create a base type sequence consisting of a single type */
+ def baseTypeSingletonSeq(tp: Type): BaseTypeSeq = newBaseTypeSeq(List(), Array(tp))
+
+ /** Create the base type sequence of a compound type wuth given tp.parents */
+ def compoundBaseTypeSeq(tp: Type): BaseTypeSeq = {
+ val tsym = tp.typeSymbol
+ val parents = tp.parents
+// Console.println("computing baseTypeSeq of " + tsym.tpe + " " + parents)//DEBUG
+ val buf = new mutable.ListBuffer[Type]
+ buf += tsym.tpe
+ var btsSize = 1
+ if (parents.nonEmpty) {
+ val nparents = parents.length
+ val pbtss = new Array[BaseTypeSeq](nparents)
+ val index = new Array[Int](nparents)
+ var i = 0
+ for (p <- parents) {
+ pbtss(i) =
+ if (p.baseTypeSeq eq undetBaseTypeSeq) AnyClass.info.baseTypeSeq
+ else p.baseTypeSeq
+ index(i) = 0
+ i += 1
+ }
+ def nextTypeSymbol(i: Int): Symbol = {
+ val j = index(i)
+ val pbts = pbtss(i)
+ if (j < pbts.length) pbts.typeSymbol(j) else AnyClass
+ }
+ def nextRawElem(i: Int): Type = {
+ val j = index(i)
+ val pbts = pbtss(i)
+ if (j < pbts.length) pbts.rawElem(j) else AnyClass.tpe
+ }
+ var minSym: Symbol = NoSymbol
+ while (minSym != AnyClass) {
+ minSym = nextTypeSymbol(0)
+ i = 1
+ while (i < nparents) {
+ val nextSym = nextTypeSymbol(i)
+ if (nextSym isLess minSym)
+ minSym = nextSym
+ i += 1
+ }
+ var minTypes: List[Type] = List()
+ i = 0
+ while (i < nparents) {
+ if (nextTypeSymbol(i) == minSym) {
+ nextRawElem(i) match {
+ case RefinedType(variants, decls) =>
+ for (tp <- variants)
+ if (!(minTypes exists (tp =:= _))) minTypes = tp :: minTypes
+ case tp =>
+ if (!(minTypes exists (tp =:= _))) minTypes = tp :: minTypes
+ }
+ index(i) = index(i) + 1
+ }
+ i += 1
+ }
+ buf += intersectionType(minTypes)
+ btsSize += 1
+ }
+ }
+ val elems = new Array[Type](btsSize)
+ buf.copyToArray(elems, 0)
+// Console.println("computed baseTypeSeq of " + tsym.tpe + " " + parents + ": "+elems.toString)//DEBUG
+ newBaseTypeSeq(parents, elems)
+ }
+
+ class MappedBaseTypeSeq(orig: BaseTypeSeq, f: Type => Type) extends BaseTypeSeq(orig.parents map f, orig.elems) {
+ override def apply(i: Int) = f(orig.apply(i))
+ override def rawElem(i: Int) = f(orig.rawElem(i))
+ override def typeSymbol(i: Int) = orig.typeSymbol(i)
+ override def toList = orig.toList map f
+ override def copy(head: Type, offset: Int) = (orig map f).copy(head, offset)
+ override def map(g: Type => Type) = lateMap(g)
+ override def lateMap(g: Type => Type) = orig.lateMap(x => g(f(x)))
+ override def exists(p: Type => Boolean) = elems exists (x => p(f(x)))
+ override protected def maxDepthOfElems: Int = (elems map (x => maxDpth(f(x)))).max
+ override def toString = elems.mkString("MBTS(", ",", ")")
+ }
+
+ val CyclicInheritance = new Throwable
+}
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
new file mode 100644
index 0000000000..3bde57ded8
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -0,0 +1,69 @@
+package scala.reflect
+package internal
+
+import Flags._
+
+trait BuildUtils extends base.BuildUtils { self: SymbolTable =>
+
+ class BuildImpl extends BuildBase {
+
+ def selectType(owner: Symbol, name: String): TypeSymbol = {
+ val result = owner.info.decl(newTypeName(name))
+ if (result ne NoSymbol) result.asTypeSymbol
+ else MissingRequirementError.notFound("type %s in %s".format(name, owner.fullName))
+ }
+
+ def selectTerm(owner: Symbol, name: String): TermSymbol = {
+ val sym = owner.info.decl(newTermName(name))
+ val result =
+ if (sym.isOverloaded) sym.suchThat(!_.isMethod)
+ else sym
+ if (result ne NoSymbol) result.asTermSymbol
+ else MissingRequirementError.notFound("term %s in %s".format(name, owner.fullName))
+ }
+
+ def selectOverloadedMethod(owner: Symbol, name: String, index: Int): MethodSymbol = {
+ val result = owner.info.decl(newTermName(name)).alternatives(index)
+ if (result ne NoSymbol) result.asMethodSymbol
+ else MissingRequirementError.notFound("overloaded method %s #%d in %s".format(name, index, owner.fullName))
+ }
+
+ def newFreeTerm(name: String, info: Type, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
+ newFreeTermSymbol(newTermName(name), info, value, flags, origin)
+
+ def newFreeType(name: String, info: Type, value: => Any, flags: Long = 0L, origin: String = null): FreeTypeSymbol =
+ newFreeTypeSymbol(newTypeName(name), info, value, (if (flags == 0L) PARAM else flags) | DEFERRED, origin)
+
+ def newFreeExistential(name: String, info: Type, value: => Any, flags: Long = 0L, origin: String = null): FreeTypeSymbol =
+ newFreeTypeSymbol(newTypeName(name), info, value, (if (flags == 0L) EXISTENTIAL else flags) | DEFERRED, origin)
+
+ def newNestedSymbol(owner: Symbol, name: Name, pos: Position, flags: Long, isClass: Boolean): Symbol =
+ owner.newNestedSymbol(name, pos, flags, isClass)
+
+ def setAnnotations[S <: Symbol](sym: S, annots: List[AnnotationInfo]): S =
+ sym.setAnnotations(annots)
+
+ def setTypeSignature[S <: Symbol](sym: S, tpe: Type): S =
+ sym.setTypeSignature(tpe)
+
+ def flagsFromBits(bits: Long): FlagSet = bits
+
+ def emptyValDef: ValDef = self.emptyValDef
+
+ def This(sym: Symbol): Tree = self.This(sym)
+
+ def Select(qualifier: Tree, sym: Symbol): Select = self.Select(qualifier, sym)
+
+ def Ident(sym: Symbol): Ident = self.Ident(sym)
+
+ def TypeTree(tp: Type): TypeTree = self.TypeTree(tp)
+
+ def thisPrefix(sym: Symbol): Type = sym.thisPrefix
+
+ def setType[T <: Tree](tree: T, tpe: Type): T = { tree.setType(tpe); tree }
+
+ def setSymbol[T <: Tree](tree: T, sym: Symbol): T = { tree.setSymbol(sym); tree }
+ }
+
+ val build: BuildBase = new BuildImpl
+}
diff --git a/src/reflect/scala/reflect/internal/CapturedVariables.scala b/src/reflect/scala/reflect/internal/CapturedVariables.scala
new file mode 100644
index 0000000000..77909d9157
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/CapturedVariables.scala
@@ -0,0 +1,36 @@
+package scala.reflect
+package internal
+
+import Flags._
+
+trait CapturedVariables { self: SymbolTable =>
+
+ import definitions._
+
+ /** Mark a variable as captured; i.e. force boxing in a *Ref type.
+ */
+ def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED
+
+ /** Mark given identifier as a reference to a captured variable itself
+ * suppressing dereferencing with the `elem` field.
+ */
+ def referenceCapturedVariable(vble: Symbol): Tree = ReferenceToBoxed(Ident(vble))
+
+ /** Convert type of a captured variable to *Ref type.
+ */
+ def capturedVariableType(vble: Symbol): Type =
+ capturedVariableType(vble, NoType, false)
+
+ /** Convert type of a captured variable to *Ref type.
+ */
+ def capturedVariableType(vble: Symbol, tpe: Type = NoType, erasedTypes: Boolean = false): Type = {
+ val tpe1 = if (tpe == NoType) vble.tpe else tpe
+ val symClass = tpe1.typeSymbol
+ def refType(valueRef: Map[Symbol, Symbol], objectRefClass: Symbol) =
+ if (isPrimitiveValueClass(symClass) && symClass != UnitClass) valueRef(symClass).tpe
+ else if (erasedTypes) objectRefClass.tpe
+ else appliedType(objectRefClass, tpe)
+ if (vble.hasAnnotation(VolatileAttr)) refType(volatileRefClass, VolatileObjectRefClass)
+ else refType(refClass, ObjectRefClass)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/Chars.scala b/src/reflect/scala/reflect/internal/Chars.scala
new file mode 100644
index 0000000000..50ec71094a
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Chars.scala
@@ -0,0 +1,98 @@
+/* NSC -- new Scala compiler
+ * Copyright 2006-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect
+package internal
+
+import annotation.{ tailrec, switch }
+import java.lang.{ Character => JCharacter }
+import language.postfixOps
+
+/** Contains constants and classifier methods for characters */
+trait Chars {
+ // Be very careful touching these.
+ // Apparently trivial changes to the way you write these constants
+ // will cause Scanners.scala to go from a nice efficient switch to
+ // a ghastly nested if statement which will bring the type checker
+ // to its knees. See ticket #1456
+ // Martin: (this should be verified now that the pattern rules have been redesigned).
+ final val LF = '\u000A'
+ final val FF = '\u000C'
+ final val CR = '\u000D'
+ final val SU = '\u001A'
+
+ /** Convert a character digit to an Int according to given base,
+ * -1 if no success
+ */
+ def digit2int(ch: Char, base: Int): Int = {
+ val num = (
+ if (ch <= '9') ch - '0'
+ else if ('a' <= ch && ch <= 'z') ch - 'a' + 10
+ else if ('A' <= ch && ch <= 'Z') ch - 'A' + 10
+ else -1
+ )
+ if (0 <= num && num < base) num else -1
+ }
+ /** Buffer for creating '\ u XXXX' strings. */
+ private[this] val char2uescapeArray = Array[Char]('\\', 'u', 0, 0, 0, 0)
+
+ /** Convert a character to a backslash-u escape */
+ def char2uescape(c: Char): String = {
+ @inline def hexChar(ch: Int): Char =
+ ( if (ch < 10) '0' else 'A' - 10 ) + ch toChar
+
+ char2uescapeArray(2) = hexChar((c >> 12) )
+ char2uescapeArray(3) = hexChar((c >> 8) % 16)
+ char2uescapeArray(4) = hexChar((c >> 4) % 16)
+ char2uescapeArray(5) = hexChar((c ) % 16)
+
+ new String(char2uescapeArray)
+ }
+
+ /** Is character a line break? */
+ @inline def isLineBreakChar(c: Char) = (c: @switch) match {
+ case LF|FF|CR|SU => true
+ case _ => false
+ }
+
+ /** Is character a whitespace character (but not a new line)? */
+ def isWhitespace(c: Char) =
+ c == ' ' || c == '\t' || c == CR
+
+ /** Can character form part of a doc comment variable $xxx? */
+ def isVarPart(c: Char) =
+ '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+
+ /** Can character start an alphanumeric Scala identifier? */
+ def isIdentifierStart(c: Char): Boolean =
+ (c == '_') || (c == '$') || Character.isUnicodeIdentifierStart(c)
+
+ /** Can character form part of an alphanumeric Scala identifier? */
+ def isIdentifierPart(c: Char) =
+ (c == '$') || Character.isUnicodeIdentifierPart(c)
+
+ /** Is character a math or other symbol in Unicode? */
+ def isSpecial(c: Char) = {
+ val chtp = Character.getType(c)
+ chtp == Character.MATH_SYMBOL.toInt || chtp == Character.OTHER_SYMBOL.toInt
+ }
+
+ private final val otherLetters = Set[Char]('\u0024', '\u005F') // '$' and '_'
+ private final val letterGroups = {
+ import JCharacter._
+ Set[Byte](LOWERCASE_LETTER, UPPERCASE_LETTER, OTHER_LETTER, TITLECASE_LETTER, LETTER_NUMBER)
+ }
+ def isScalaLetter(ch: Char) = letterGroups(JCharacter.getType(ch).toByte) || otherLetters(ch)
+
+ /** Can character form part of a Scala operator name? */
+ def isOperatorPart(c : Char) : Boolean = (c: @switch) match {
+ case '~' | '!' | '@' | '#' | '%' |
+ '^' | '*' | '+' | '-' | '<' |
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '/' | '\\' => true
+ case c => isSpecial(c)
+ }
+}
+
+object Chars extends Chars { }
diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala
new file mode 100644
index 0000000000..3346e9cccb
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala
@@ -0,0 +1,390 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import annotation.switch
+
+object ClassfileConstants {
+
+ final val JAVA_MAGIC = 0xCAFEBABE
+ final val JAVA_MAJOR_VERSION = 45
+ final val JAVA_MINOR_VERSION = 3
+
+ /** (see http://java.sun.com/docs/books/jvms/second_edition/jvms-clarify.html)
+ *
+ * If the `ACC_INTERFACE` flag is set, the `ACC_ABSTRACT` flag must also
+ * be set (ch. 2.13.1).
+ *
+ * A class file cannot have both its `ACC_FINAL` and `ACC_ABSTRACT` flags
+ * set (ch. 2.8.2).
+ *
+ * A field may have at most one of its `ACC_PRIVATE`, `ACC_PROTECTED`,
+ * `ACC_PUBLIC` flags set (ch. 2.7.4).
+ *
+ * A field may not have both its `ACC_FINAL` and `ACC_VOLATILE` flags set
+ * (ch. 2.9.1).
+ *
+ * If a method has its `ACC_ABSTRACT` flag set it must not have any of its
+ * `ACC_FINAL`, `ACC_NATIVE`, `ACC_PRIVATE`, `ACC_STATIC`, `ACC_STRICT`,
+ * or `ACC_SYNCHRONIZED` flags set (ch. 2.13.3.2).
+ *
+ * All interface methods must have their `ACC_ABSTRACT` and
+ * `ACC_PUBLIC` flags set.
+ *
+ * Note for future reference: see this thread on ACC_SUPER and
+ * how its enforcement differs on the android vm.
+ * https://groups.google.com/forum/?hl=en#!topic/jvm-languages/jVhzvq8-ZIk
+ *
+ */ // Class Field Method
+ final val JAVA_ACC_PUBLIC = 0x0001 // X X X
+ final val JAVA_ACC_PRIVATE = 0x0002 // X X
+ final val JAVA_ACC_PROTECTED = 0x0004 // X X
+ final val JAVA_ACC_STATIC = 0x0008 // X X
+ final val JAVA_ACC_FINAL = 0x0010 // X X X
+ final val JAVA_ACC_SUPER = 0x0020 // X
+ final val JAVA_ACC_SYNCHRONIZED = 0x0020 // X
+ final val JAVA_ACC_VOLATILE = 0x0040 // X
+ final val JAVA_ACC_BRIDGE = 0x0040 // X
+ final val JAVA_ACC_TRANSIENT = 0x0080 // X
+ final val JAVA_ACC_VARARGS = 0x0080 // X
+ final val JAVA_ACC_NATIVE = 0x0100 // X
+ final val JAVA_ACC_INTERFACE = 0x0200 // X
+ final val JAVA_ACC_ABSTRACT = 0x0400 // X X
+ final val JAVA_ACC_STRICT = 0x0800 // X
+ final val JAVA_ACC_SYNTHETIC = 0x1000 // X X X
+ final val JAVA_ACC_ANNOTATION = 0x2000 // X
+ final val JAVA_ACC_ENUM = 0x4000 // X X
+
+ // tags describing the type of a literal in the constant pool
+ final val CONSTANT_UTF8 = 1
+ final val CONSTANT_UNICODE = 2
+ final val CONSTANT_INTEGER = 3
+ final val CONSTANT_FLOAT = 4
+ final val CONSTANT_LONG = 5
+ final val CONSTANT_DOUBLE = 6
+ final val CONSTANT_CLASS = 7
+ final val CONSTANT_STRING = 8
+ final val CONSTANT_FIELDREF = 9
+ final val CONSTANT_METHODREF = 10
+ final val CONSTANT_INTFMETHODREF = 11
+ final val CONSTANT_NAMEANDTYPE = 12
+
+ // tags describing the type of a literal in attribute values
+ final val BYTE_TAG = 'B'
+ final val CHAR_TAG = 'C'
+ final val DOUBLE_TAG = 'D'
+ final val FLOAT_TAG = 'F'
+ final val INT_TAG = 'I'
+ final val LONG_TAG = 'J'
+ final val SHORT_TAG = 'S'
+ final val BOOL_TAG = 'Z'
+ final val STRING_TAG = 's'
+ final val ENUM_TAG = 'e'
+ final val CLASS_TAG = 'c'
+ final val ARRAY_TAG = '['
+ final val VOID_TAG = 'V'
+ final val TVAR_TAG = 'T'
+ final val OBJECT_TAG = 'L'
+ final val ANNOTATION_TAG = '@'
+ final val SCALA_NOTHING = "scala.runtime.Nothing$"
+ final val SCALA_NULL = "scala.runtime.Null$"
+
+
+ // tags describing the type of newarray
+ final val T_BOOLEAN = 4
+ final val T_CHAR = 5
+ final val T_FLOAT = 6
+ final val T_DOUBLE = 7
+ final val T_BYTE = 8
+ final val T_SHORT = 9
+ final val T_INT = 10
+ final val T_LONG = 11
+
+ // JVM mnemonics
+ final val nop = 0x00
+ final val aconst_null = 0x01
+ final val iconst_m1 = 0x02
+
+ final val iconst_0 = 0x03
+ final val iconst_1 = 0x04
+ final val iconst_2 = 0x05
+ final val iconst_3 = 0x06
+ final val iconst_4 = 0x07
+ final val iconst_5 = 0x08
+
+ final val lconst_0 = 0x09
+ final val lconst_1 = 0x0a
+ final val fconst_0 = 0x0b
+ final val fconst_1 = 0x0c
+ final val fconst_2 = 0x0d
+ final val dconst_0 = 0x0e
+ final val dconst_1 = 0x0f
+
+ final val bipush = 0x10
+ final val sipush = 0x11
+ final val ldc = 0x12
+ final val ldc_w = 0x13
+ final val ldc2_w = 0x14
+
+ final val iload = 0x15
+ final val lload = 0x16
+ final val fload = 0x17
+ final val dload = 0x18
+ final val aload = 0x19
+
+ final val iload_0 = 0x1a
+ final val iload_1 = 0x1b
+ final val iload_2 = 0x1c
+ final val iload_3 = 0x1d
+ final val lload_0 = 0x1e
+ final val lload_1 = 0x1f
+ final val lload_2 = 0x20
+ final val lload_3 = 0x21
+ final val fload_0 = 0x22
+ final val fload_1 = 0x23
+ final val fload_2 = 0x24
+ final val fload_3 = 0x25
+ final val dload_0 = 0x26
+ final val dload_1 = 0x27
+ final val dload_2 = 0x28
+ final val dload_3 = 0x29
+ final val aload_0 = 0x2a
+ final val aload_1 = 0x2b
+ final val aload_2 = 0x2c
+ final val aload_3 = 0x2d
+ final val iaload = 0x2e
+ final val laload = 0x2f
+ final val faload = 0x30
+ final val daload = 0x31
+ final val aaload = 0x32
+ final val baload = 0x33
+ final val caload = 0x34
+ final val saload = 0x35
+
+ final val istore = 0x36
+ final val lstore = 0x37
+ final val fstore = 0x38
+ final val dstore = 0x39
+ final val astore = 0x3a
+ final val istore_0 = 0x3b
+ final val istore_1 = 0x3c
+ final val istore_2 = 0x3d
+ final val istore_3 = 0x3e
+ final val lstore_0 = 0x3f
+ final val lstore_1 = 0x40
+ final val lstore_2 = 0x41
+ final val lstore_3 = 0x42
+ final val fstore_0 = 0x43
+ final val fstore_1 = 0x44
+ final val fstore_2 = 0x45
+ final val fstore_3 = 0x46
+ final val dstore_0 = 0x47
+ final val dstore_1 = 0x48
+ final val dstore_2 = 0x49
+ final val dstore_3 = 0x4a
+ final val astore_0 = 0x4b
+ final val astore_1 = 0x4c
+ final val astore_2 = 0x4d
+ final val astore_3 = 0x4e
+ final val iastore = 0x4f
+ final val lastore = 0x50
+ final val fastore = 0x51
+ final val dastore = 0x52
+ final val aastore = 0x53
+ final val bastore = 0x54
+ final val castore = 0x55
+ final val sastore = 0x56
+
+ final val pop = 0x57
+ final val pop2 = 0x58
+ final val dup = 0x59
+ final val dup_x1 = 0x5a
+ final val dup_x2 = 0x5b
+ final val dup2 = 0x5c
+ final val dup2_x1 = 0x5d
+ final val dup2_x2 = 0x5e
+ final val swap = 0x5f
+
+ final val iadd = 0x60
+ final val ladd = 0x61
+ final val fadd = 0x62
+ final val dadd = 0x63
+ final val isub = 0x64
+ final val lsub = 0x65
+ final val fsub = 0x66
+ final val dsub = 0x67
+ final val imul = 0x68
+ final val lmul = 0x69
+ final val fmul = 0x6a
+ final val dmul = 0x6b
+ final val idiv = 0x6c
+ final val ldiv = 0x6d
+ final val fdiv = 0x6e
+ final val ddiv = 0x6f
+ final val irem = 0x70
+ final val lrem = 0x71
+ final val frem = 0x72
+ final val drem = 0x73
+
+ final val ineg = 0x74
+ final val lneg = 0x75
+ final val fneg = 0x76
+ final val dneg = 0x77
+
+ final val ishl = 0x78
+ final val lshl = 0x79
+ final val ishr = 0x7a
+ final val lshr = 0x7b
+ final val iushr = 0x7c
+ final val lushr = 0x7d
+ final val iand = 0x7e
+ final val land = 0x7f
+ final val ior = 0x80
+ final val lor = 0x81
+ final val ixor = 0x82
+ final val lxor = 0x83
+ final val iinc = 0x84
+
+ final val i2l = 0x85
+ final val i2f = 0x86
+ final val i2d = 0x87
+ final val l2i = 0x88
+ final val l2f = 0x89
+ final val l2d = 0x8a
+ final val f2i = 0x8b
+ final val f2l = 0x8c
+ final val f2d = 0x8d
+ final val d2i = 0x8e
+ final val d2l = 0x8f
+ final val d2f = 0x90
+ final val i2b = 0x91
+ final val i2c = 0x92
+ final val i2s = 0x93
+
+ final val lcmp = 0x94
+ final val fcmpl = 0x95
+ final val fcmpg = 0x96
+ final val dcmpl = 0x97
+ final val dcmpg = 0x98
+
+ final val ifeq = 0x99
+ final val ifne = 0x9a
+ final val iflt = 0x9b
+ final val ifge = 0x9c
+ final val ifgt = 0x9d
+ final val ifle = 0x9e
+ final val if_icmpeq = 0x9f
+ final val if_icmpne = 0xa0
+ final val if_icmplt = 0xa1
+ final val if_icmpge = 0xa2
+ final val if_icmpgt = 0xa3
+ final val if_icmple = 0xa4
+ final val if_acmpeq = 0xa5
+ final val if_acmpne = 0xa6
+ final val goto = 0xa7
+ final val jsr = 0xa8
+ final val ret = 0xa9
+ final val tableswitch = 0xaa
+ final val lookupswitch = 0xab
+ final val ireturn = 0xac
+ final val lreturn = 0xad
+ final val freturn = 0xae
+ final val dreturn = 0xaf
+ final val areturn = 0xb0
+ final val return_ = 0xb1
+
+ final val getstatic = 0xb2
+ final val putstatic = 0xb3
+ final val getfield = 0xb4
+ final val putfield = 0xb5
+
+ final val invokevirtual = 0xb6
+ final val invokespecial = 0xb7
+ final val invokestatic = 0xb8
+ final val invokeinterface = 0xb9
+ final val xxxunusedxxxx = 0xba
+
+ final val new_ = 0xbb
+ final val newarray = 0xbc
+ final val anewarray = 0xbd
+ final val arraylength = 0xbe
+ final val athrow = 0xbf
+ final val checkcast = 0xc0
+ final val instanceof = 0xc1
+ final val monitorenter = 0xc2
+ final val monitorexit = 0xc3
+ final val wide = 0xc4
+ final val multianewarray = 0xc5
+ final val ifnull = 0xc6
+ final val ifnonnull = 0xc7
+ final val goto_w = 0xc8
+ final val jsr_w = 0xc9
+
+ // reserved opcodes
+ final val breakpoint = 0xca
+ final val impdep1 = 0xfe
+ final val impdep2 = 0xff
+
+ abstract class FlagTranslation {
+ import Flags._
+
+ private var isAnnotation = false
+ private var isClass = false
+ private def initFields(flags: Int) = {
+ isAnnotation = (flags & JAVA_ACC_ANNOTATION) != 0
+ isClass = false
+ }
+ private def translateFlag(jflag: Int): Long = (jflag: @switch) match {
+ case JAVA_ACC_PRIVATE => PRIVATE
+ case JAVA_ACC_PROTECTED => PROTECTED
+ case JAVA_ACC_FINAL => FINAL
+ case JAVA_ACC_SYNTHETIC => SYNTHETIC
+ case JAVA_ACC_STATIC => STATIC
+ case JAVA_ACC_ABSTRACT => if (isAnnotation) 0L else if (isClass) ABSTRACT else DEFERRED
+ case JAVA_ACC_INTERFACE => if (isAnnotation) 0L else TRAIT | INTERFACE | ABSTRACT
+ case _ => 0L
+ }
+ private def translateFlags(jflags: Int, baseFlags: Long): Long = {
+ var res: Long = JAVA | baseFlags
+ /** fast, elegant, maintainable, pick any two... */
+ res |= translateFlag(jflags & JAVA_ACC_PRIVATE)
+ res |= translateFlag(jflags & JAVA_ACC_PROTECTED)
+ res |= translateFlag(jflags & JAVA_ACC_FINAL)
+ res |= translateFlag(jflags & JAVA_ACC_SYNTHETIC)
+ res |= translateFlag(jflags & JAVA_ACC_STATIC)
+ res |= translateFlag(jflags & JAVA_ACC_ABSTRACT)
+ res |= translateFlag(jflags & JAVA_ACC_INTERFACE)
+ res
+ }
+
+ def classFlags(jflags: Int): Long = {
+ initFields(jflags)
+ isClass = true
+ translateFlags(jflags, 0)
+ }
+ def fieldFlags(jflags: Int): Long = {
+ initFields(jflags)
+ translateFlags(jflags, if ((jflags & JAVA_ACC_FINAL) == 0) MUTABLE else 0)
+ }
+ def methodFlags(jflags: Int): Long = {
+ initFields(jflags)
+ translateFlags(jflags, if ((jflags & JAVA_ACC_BRIDGE) != 0) BRIDGE else 0)
+ }
+ }
+ object FlagTranslation extends FlagTranslation { }
+
+ def toScalaMethodFlags(flags: Int): Long = FlagTranslation methodFlags flags
+ def toScalaClassFlags(flags: Int): Long = FlagTranslation classFlags flags
+ def toScalaFieldFlags(flags: Int): Long = FlagTranslation fieldFlags flags
+
+ @deprecated("Use another method in this object", "2.10.0")
+ def toScalaFlags(flags: Int, isClass: Boolean = false, isField: Boolean = false): Long = (
+ if (isClass) toScalaClassFlags(flags)
+ else if (isField) toScalaFieldFlags(flags)
+ else toScalaMethodFlags(flags)
+ )
+}
diff --git a/src/reflect/scala/reflect/internal/Constants.scala b/src/reflect/scala/reflect/internal/Constants.scala
new file mode 100644
index 0000000000..820dfe0868
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Constants.scala
@@ -0,0 +1,240 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import java.lang.Integer.toOctalString
+import annotation.switch
+
+trait Constants extends api.Constants {
+ self: SymbolTable =>
+
+ import definitions._
+
+ final val NoTag = 0
+ final val UnitTag = 1
+ final val BooleanTag = 2
+ final val ByteTag = 3
+ final val ShortTag = 4
+ final val CharTag = 5
+ final val IntTag = 6
+ final val LongTag = 7
+ final val FloatTag = 8
+ final val DoubleTag = 9
+ final val StringTag = 10
+ final val NullTag = 11
+ final val ClazzTag = 12
+ // For supporting java enumerations inside java annotations (see ClassfileParser)
+ final val EnumTag = 13
+
+ case class Constant(value: Any) extends ConstantApi {
+ val tag: Int = value match {
+ case null => NullTag
+ case x: Unit => UnitTag
+ case x: Boolean => BooleanTag
+ case x: Byte => ByteTag
+ case x: Short => ShortTag
+ case x: Int => IntTag
+ case x: Long => LongTag
+ case x: Float => FloatTag
+ case x: Double => DoubleTag
+ case x: String => StringTag
+ case x: Char => CharTag
+ case x: Type => ClazzTag
+ case x: Symbol => EnumTag
+ case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass)
+ }
+
+ def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue
+ def isShortRange: Boolean = isIntRange && Short.MinValue <= intValue && intValue <= Short.MaxValue
+ def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue
+ def isIntRange: Boolean = ByteTag <= tag && tag <= IntTag
+ def isLongRange: Boolean = ByteTag <= tag && tag <= LongTag
+ def isFloatRange: Boolean = ByteTag <= tag && tag <= FloatTag
+ def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag
+ def isNonUnitAnyVal = BooleanTag <= tag && tag <= DoubleTag
+ def isAnyVal = UnitTag <= tag && tag <= DoubleTag
+
+ def tpe: Type = tag match {
+ case UnitTag => UnitClass.tpe
+ case BooleanTag => BooleanClass.tpe
+ case ByteTag => ByteClass.tpe
+ case ShortTag => ShortClass.tpe
+ case CharTag => CharClass.tpe
+ case IntTag => IntClass.tpe
+ case LongTag => LongClass.tpe
+ case FloatTag => FloatClass.tpe
+ case DoubleTag => DoubleClass.tpe
+ case StringTag => StringClass.tpe
+ case NullTag => NullClass.tpe
+ case ClazzTag => ClassType(value.asInstanceOf[Type])
+ case EnumTag =>
+ // given (in java): "class A { enum E { VAL1 } }"
+ // - symbolValue: the symbol of the actual enumeration value (VAL1)
+ // - .owner: the ModuleClasSymbol of the enumeration (object E)
+ // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E)
+ symbolValue.owner.linkedClassOfClass.tpe
+ }
+
+ /** We need the equals method to take account of tags as well as values.
+ */
+ override def equals(other: Any): Boolean = other match {
+ case that: Constant =>
+ this.tag == that.tag &&
+ (this.value == that.value || this.isNaN && that.isNaN)
+ case _ => false
+ }
+
+ def isNaN = value match {
+ case f: Float => f.isNaN
+ case d: Double => d.isNaN
+ case _ => false
+ }
+
+ def booleanValue: Boolean =
+ if (tag == BooleanTag) value.asInstanceOf[Boolean]
+ else throw new Error("value " + value + " is not a boolean");
+
+ def byteValue: Byte = tag match {
+ case ByteTag => value.asInstanceOf[Byte]
+ case ShortTag => value.asInstanceOf[Short].toByte
+ case CharTag => value.asInstanceOf[Char].toByte
+ case IntTag => value.asInstanceOf[Int].toByte
+ case LongTag => value.asInstanceOf[Long].toByte
+ case FloatTag => value.asInstanceOf[Float].toByte
+ case DoubleTag => value.asInstanceOf[Double].toByte
+ case _ => throw new Error("value " + value + " is not a Byte")
+ }
+
+ def shortValue: Short = tag match {
+ case ByteTag => value.asInstanceOf[Byte].toShort
+ case ShortTag => value.asInstanceOf[Short]
+ case CharTag => value.asInstanceOf[Char].toShort
+ case IntTag => value.asInstanceOf[Int].toShort
+ case LongTag => value.asInstanceOf[Long].toShort
+ case FloatTag => value.asInstanceOf[Float].toShort
+ case DoubleTag => value.asInstanceOf[Double].toShort
+ case _ => throw new Error("value " + value + " is not a Short")
+ }
+
+ def charValue: Char = tag match {
+ case ByteTag => value.asInstanceOf[Byte].toChar
+ case ShortTag => value.asInstanceOf[Short].toChar
+ case CharTag => value.asInstanceOf[Char]
+ case IntTag => value.asInstanceOf[Int].toChar
+ case LongTag => value.asInstanceOf[Long].toChar
+ case FloatTag => value.asInstanceOf[Float].toChar
+ case DoubleTag => value.asInstanceOf[Double].toChar
+ case _ => throw new Error("value " + value + " is not a Char")
+ }
+
+ def intValue: Int = tag match {
+ case ByteTag => value.asInstanceOf[Byte].toInt
+ case ShortTag => value.asInstanceOf[Short].toInt
+ case CharTag => value.asInstanceOf[Char].toInt
+ case IntTag => value.asInstanceOf[Int]
+ case LongTag => value.asInstanceOf[Long].toInt
+ case FloatTag => value.asInstanceOf[Float].toInt
+ case DoubleTag => value.asInstanceOf[Double].toInt
+ case _ => throw new Error("value " + value + " is not an Int")
+ }
+
+ def longValue: Long = tag match {
+ case ByteTag => value.asInstanceOf[Byte].toLong
+ case ShortTag => value.asInstanceOf[Short].toLong
+ case CharTag => value.asInstanceOf[Char].toLong
+ case IntTag => value.asInstanceOf[Int].toLong
+ case LongTag => value.asInstanceOf[Long]
+ case FloatTag => value.asInstanceOf[Float].toLong
+ case DoubleTag => value.asInstanceOf[Double].toLong
+ case _ => throw new Error("value " + value + " is not a Long")
+ }
+
+ def floatValue: Float = tag match {
+ case ByteTag => value.asInstanceOf[Byte].toFloat
+ case ShortTag => value.asInstanceOf[Short].toFloat
+ case CharTag => value.asInstanceOf[Char].toFloat
+ case IntTag => value.asInstanceOf[Int].toFloat
+ case LongTag => value.asInstanceOf[Long].toFloat
+ case FloatTag => value.asInstanceOf[Float]
+ case DoubleTag => value.asInstanceOf[Double].toFloat
+ case _ => throw new Error("value " + value + " is not a Float")
+ }
+
+ def doubleValue: Double = tag match {
+ case ByteTag => value.asInstanceOf[Byte].toDouble
+ case ShortTag => value.asInstanceOf[Short].toDouble
+ case CharTag => value.asInstanceOf[Char].toDouble
+ case IntTag => value.asInstanceOf[Int].toDouble
+ case LongTag => value.asInstanceOf[Long].toDouble
+ case FloatTag => value.asInstanceOf[Float].toDouble
+ case DoubleTag => value.asInstanceOf[Double]
+ case _ => throw new Error("value " + value + " is not a Double")
+ }
+
+ /** Convert constant value to conform to given type.
+ */
+ def convertTo(pt: Type): Constant = {
+ val target = pt.typeSymbol
+ if (target == tpe.typeSymbol)
+ this
+ else if (target == ByteClass && isByteRange)
+ Constant(byteValue)
+ else if (target == ShortClass && isShortRange)
+ Constant(shortValue)
+ else if (target == CharClass && isCharRange)
+ Constant(charValue)
+ else if (target == IntClass && isIntRange)
+ Constant(intValue)
+ else if (target == LongClass && isLongRange)
+ Constant(longValue)
+ else if (target == FloatClass && isFloatRange)
+ Constant(floatValue)
+ else if (target == DoubleClass && isNumeric)
+ Constant(doubleValue)
+ else
+ null
+ }
+
+ def stringValue: String =
+ if (value == null) "null"
+ else if (tag == ClazzTag) signature(typeValue)
+ else value.toString()
+
+ @switch def escapedChar(ch: Char): String = ch match {
+ case '\b' => "\\b"
+ case '\t' => "\\t"
+ case '\n' => "\\n"
+ case '\f' => "\\f"
+ case '\r' => "\\r"
+ case '"' => "\\\""
+ case '\'' => "\\\'"
+ case '\\' => "\\\\"
+ case _ => if (ch.isControl) "\\0" + toOctalString(ch) else String.valueOf(ch)
+ }
+
+ def escapedStringValue: String = {
+ def escape(text: String): String = text flatMap escapedChar
+ tag match {
+ case NullTag => "null"
+ case StringTag => "\"" + escape(stringValue) + "\""
+ case ClazzTag => "classOf[" + signature(typeValue) + "]"
+ case CharTag => "'" + escapedChar(charValue) + "'"
+ case LongTag => longValue.toString() + "L"
+ case EnumTag => symbolValue.name.toString()
+ case _ => String.valueOf(value)
+ }
+ }
+ def typeValue: Type = value.asInstanceOf[Type]
+ def symbolValue: Symbol = value.asInstanceOf[Symbol]
+
+ override def hashCode: Int = value.## * 41 + 17
+ }
+
+ object Constant extends ConstantExtractor
+
+ implicit val ConstantTag = ClassTag[Constant](classOf[Constant])
+}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
new file mode 100644
index 0000000000..d55b38224d
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -0,0 +1,1241 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import annotation.{ switch, meta }
+import scala.collection.{ mutable, immutable }
+import Flags._
+import PartialFunction._
+import scala.reflect.base.{Universe => BaseUniverse}
+
+trait Definitions extends api.StandardDefinitions {
+ self: SymbolTable =>
+
+ import rootMirror.{getModule, getClassByName, getRequiredClass, getRequiredModule, getRequiredPackage, getClassIfDefined, getModuleIfDefined, getPackageObject, getPackageObjectIfDefined, requiredClass, requiredModule}
+
+ object definitions extends DefinitionsClass
+
+ // [Eugene] find a way to make these non-lazy
+ lazy val ByteTpe = definitions.ByteClass.asType
+ lazy val ShortTpe = definitions.ShortClass.asType
+ lazy val CharTpe = definitions.CharClass.asType
+ lazy val IntTpe = definitions.IntClass.asType
+ lazy val LongTpe = definitions.LongClass.asType
+ lazy val FloatTpe = definitions.FloatClass.asType
+ lazy val DoubleTpe = definitions.DoubleClass.asType
+ lazy val BooleanTpe = definitions.BooleanClass.asType
+ lazy val UnitTpe = definitions.UnitClass.asType
+ lazy val AnyTpe = definitions.AnyClass.asType
+ lazy val ObjectTpe = definitions.ObjectClass.asType
+ lazy val AnyValTpe = definitions.AnyValClass.asType
+ lazy val AnyRefTpe = definitions.AnyRefClass.asType
+ lazy val NothingTpe = definitions.NothingClass.asType
+ lazy val NullTpe = definitions.NullClass.asType
+ lazy val StringTpe = definitions.StringClass.asType
+
+ /** Since both the value parameter types and the result type may
+ * require access to the type parameter symbols, we model polymorphic
+ * creation as a function from those symbols to (formal types, result type).
+ * The Option is to distinguish between nullary methods and empty-param-list
+ * methods.
+ */
+ private type PolyMethodCreator = List[Symbol] => (Option[List[Type]], Type)
+
+ private def enterNewClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): ClassSymbol = {
+ val clazz = owner.newClassSymbol(name, NoPosition, flags)
+ clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz)
+ }
+ private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): MethodSymbol = {
+ val msym = owner.newMethod(name.encode, NoPosition, flags)
+ val params = msym.newSyntheticValueParams(formals)
+ msym setInfo MethodType(params, restpe)
+ }
+ private def enterNewMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): MethodSymbol =
+ owner.info.decls enter newMethod(owner, name, formals, restpe, flags)
+
+ // the scala value classes
+ trait ValueClassDefinitions {
+ self: DefinitionsClass =>
+
+ import ClassfileConstants._
+
+ private val nameToWeight = Map[Name, Int](
+ tpnme.Byte -> 2,
+ tpnme.Char -> 3,
+ tpnme.Short -> 4,
+ tpnme.Int -> 12,
+ tpnme.Long -> 24,
+ tpnme.Float -> 48,
+ tpnme.Double -> 96
+ )
+
+ private val nameToTag = Map[Name, Char](
+ tpnme.Byte -> BYTE_TAG,
+ tpnme.Char -> CHAR_TAG,
+ tpnme.Short -> SHORT_TAG,
+ tpnme.Int -> INT_TAG,
+ tpnme.Long -> LONG_TAG,
+ tpnme.Float -> FLOAT_TAG,
+ tpnme.Double -> DOUBLE_TAG,
+ tpnme.Boolean -> BOOL_TAG,
+ tpnme.Unit -> VOID_TAG
+ )
+
+ private def catastrophicFailure() =
+ abort("Could not find value classes! This is a catastrophic failure. scala " +
+ scala.util.Properties.versionString)
+
+ private def valueClassSymbol(name: TypeName): ClassSymbol = {
+ getMember(ScalaPackageClass, name) match {
+ case x: ClassSymbol => x
+ case _ => catastrophicFailure()
+ }
+ }
+ private def valueClassCompanion(name: TermName): ModuleSymbol = {
+ getMember(ScalaPackageClass, name) match {
+ case x: ModuleSymbol => x
+ case _ => catastrophicFailure()
+ }
+ }
+ private def valueCompanionMember(className: Name, methodName: TermName): TermSymbol =
+ getMemberMethod(valueClassCompanion(className.toTermName).moduleClass, methodName)
+
+ private def classesMap[T](f: Name => T) = symbolsMap(ScalaValueClassesNoUnit, f)
+ private def symbolsMap[T](syms: List[Symbol], f: Name => T): Map[Symbol, T] = mapFrom(syms)(x => f(x.name))
+ private def symbolsMapFilt[T](syms: List[Symbol], p: Name => Boolean, f: Name => T) = symbolsMap(syms filter (x => p(x.name)), f)
+
+ private def boxedName(name: Name) = sn.Boxed(name.toTypeName)
+
+ lazy val abbrvTag = symbolsMap(ScalaValueClasses, nameToTag) withDefaultValue OBJECT_TAG
+ lazy val numericWeight = symbolsMapFilt(ScalaValueClasses, nameToWeight.keySet, nameToWeight)
+ lazy val boxedModule = classesMap(x => getModule(boxedName(x)))
+ lazy val boxedClass = classesMap(x => getClassByName(boxedName(x)))
+ lazy val refClass = classesMap(x => getRequiredClass("scala.runtime." + x + "Ref"))
+ lazy val volatileRefClass = classesMap(x => getRequiredClass("scala.runtime.Volatile" + x + "Ref"))
+ lazy val boxMethod = classesMap(x => valueCompanionMember(x, nme.box))
+ lazy val unboxMethod = classesMap(x => valueCompanionMember(x, nme.unbox))
+
+ def isNumericSubClass(sub: Symbol, sup: Symbol) = (
+ (numericWeight contains sub)
+ && (numericWeight contains sup)
+ && (numericWeight(sup) % numericWeight(sub) == 0)
+ )
+
+ /** Is symbol a numeric value class? */
+ def isNumericValueClass(sym: Symbol) = ScalaNumericValueClasses contains sym
+
+ def isGetClass(sym: Symbol) =
+ (sym.name == nme.getClass_) && flattensToEmpty(sym.paramss)
+
+ lazy val UnitClass = valueClassSymbol(tpnme.Unit)
+ lazy val ByteClass = valueClassSymbol(tpnme.Byte)
+ lazy val ShortClass = valueClassSymbol(tpnme.Short)
+ lazy val CharClass = valueClassSymbol(tpnme.Char)
+ lazy val IntClass = valueClassSymbol(tpnme.Int)
+ lazy val LongClass = valueClassSymbol(tpnme.Long)
+ lazy val FloatClass = valueClassSymbol(tpnme.Float)
+ lazy val DoubleClass = valueClassSymbol(tpnme.Double)
+ lazy val BooleanClass = valueClassSymbol(tpnme.Boolean)
+ lazy val Boolean_and = getMemberMethod(BooleanClass, nme.ZAND)
+ lazy val Boolean_or = getMemberMethod(BooleanClass, nme.ZOR)
+ lazy val Boolean_not = getMemberMethod(BooleanClass, nme.UNARY_!)
+
+ lazy val ScalaNumericValueClasses = ScalaValueClasses filterNot Set[Symbol](UnitClass, BooleanClass)
+
+ def ScalaValueClassesNoUnit = ScalaValueClasses filterNot (_ eq UnitClass)
+ def ScalaValueClasses: List[ClassSymbol] = List(
+ UnitClass,
+ BooleanClass,
+ ByteClass,
+ ShortClass,
+ CharClass,
+ IntClass,
+ LongClass,
+ FloatClass,
+ DoubleClass
+ )
+ def ScalaValueClassCompanions: List[Symbol] = ScalaValueClasses map (_.companionSymbol)
+ def ScalaPrimitiveValueClasses: List[ClassSymbol] = ScalaValueClasses
+ }
+
+ abstract class DefinitionsClass extends DefinitionsApi with ValueClassDefinitions {
+ private var isInitialized = false
+ def isDefinitionsInitialized = isInitialized
+
+ // symbols related to packages
+ var emptypackagescope: Scope = null //debug
+
+ // It becomes tricky to create dedicated objects for other symbols because
+ // of initialization order issues.
+ lazy val JavaLangPackage = getRequiredPackage(sn.JavaLang)
+ lazy val JavaLangPackageClass = JavaLangPackage.moduleClass.asClassSymbol
+ lazy val ScalaPackage = getRequiredPackage(nme.scala_)
+ lazy val ScalaPackageClass = ScalaPackage.moduleClass.asClassSymbol
+ lazy val RuntimePackage = getRequiredPackage("scala.runtime")
+ lazy val RuntimePackageClass = RuntimePackage.moduleClass.asClassSymbol
+
+ lazy val JavaLangEnumClass = requiredClass[java.lang.Enum[_]]
+
+ // convenient one-argument parameter lists
+ lazy val anyparam = List(AnyClass.tpe)
+ lazy val anyvalparam = List(AnyValClass.typeConstructor)
+ lazy val anyrefparam = List(AnyRefClass.typeConstructor)
+
+ // private parameter conveniences
+ private def booltype = BooleanClass.tpe
+ private def inttype = IntClass.tpe
+ private def stringtype = StringClass.tpe
+
+ def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match {
+ case java.lang.Void.TYPE => UnitClass
+ case java.lang.Byte.TYPE => ByteClass
+ case java.lang.Character.TYPE => CharClass
+ case java.lang.Short.TYPE => ShortClass
+ case java.lang.Integer.TYPE => IntClass
+ case java.lang.Long.TYPE => LongClass
+ case java.lang.Float.TYPE => FloatClass
+ case java.lang.Double.TYPE => DoubleClass
+ case java.lang.Boolean.TYPE => BooleanClass
+ case _ => NoSymbol
+ }
+ def valueClassToJavaType(sym: Symbol): Class[_] = sym match {
+ case UnitClass => java.lang.Void.TYPE
+ case ByteClass => java.lang.Byte.TYPE
+ case CharClass => java.lang.Character.TYPE
+ case ShortClass => java.lang.Short.TYPE
+ case IntClass => java.lang.Integer.TYPE
+ case LongClass => java.lang.Long.TYPE
+ case FloatClass => java.lang.Float.TYPE
+ case DoubleClass => java.lang.Double.TYPE
+ case BooleanClass => java.lang.Boolean.TYPE
+ case _ => null
+ }
+
+ private def fixupAsAnyTrait(tpe: Type): Type = tpe match {
+ case ClassInfoType(parents, decls, clazz) =>
+ if (parents.head.typeSymbol == AnyClass) tpe
+ else {
+ assert(parents.head.typeSymbol == ObjectClass, parents)
+ ClassInfoType(AnyClass.tpe :: parents.tail, decls, clazz)
+ }
+ case PolyType(tparams, restpe) =>
+ PolyType(tparams, fixupAsAnyTrait(restpe))
+// case _ => tpe
+ }
+
+ // top types
+ lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT)
+ lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.tpe)
+ lazy val ObjectClass = getRequiredClass(sn.Object.toString)
+
+ // 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, List(AnyClass.tpe, NotNullClass.tpe), ABSTRACT)
+ val av_constr = anyval.newClassConstructor(NoPosition)
+ anyval.info.decls enter av_constr
+ anyval
+ }).asInstanceOf[ClassSymbol]
+
+ // bottom types
+ lazy val RuntimeNothingClass = getClassByName(fulltpnme.RuntimeNothing)
+ lazy val RuntimeNullClass = getClassByName(fulltpnme.RuntimeNull)
+
+ sealed abstract class BottomClassSymbol(name: TypeName, parent: Symbol) extends ClassSymbol(ScalaPackageClass, NoPosition, name) {
+ locally {
+ this initFlags ABSTRACT | FINAL
+ this setInfoAndEnter ClassInfoType(List(parent.tpe), newScope, this)
+ }
+ final override def isBottomClass = true
+ }
+ final object NothingClass extends BottomClassSymbol(tpnme.Nothing, AnyClass) {
+ override def isSubClass(that: Symbol) = true
+ }
+ final object NullClass extends BottomClassSymbol(tpnme.Null, AnyRefClass) {
+ override def isSubClass(that: Symbol) = (
+ (that eq AnyClass)
+ || (that ne NothingClass) && (that isSubClass ObjectClass)
+ )
+ }
+
+ // exceptions and other throwables
+ lazy val ClassCastExceptionClass = requiredClass[ClassCastException]
+ lazy val IndexOutOfBoundsExceptionClass = getClassByName(sn.IOOBException)
+ lazy val InvocationTargetExceptionClass = getClassByName(sn.InvTargetException)
+ lazy val MatchErrorClass = requiredClass[MatchError]
+ lazy val NonLocalReturnControlClass = requiredClass[scala.runtime.NonLocalReturnControl[_]]
+ lazy val NullPointerExceptionClass = getClassByName(sn.NPException)
+ lazy val ThrowableClass = getClassByName(sn.Throwable)
+ lazy val UninitializedErrorClass = requiredClass[UninitializedFieldError]
+
+ // fundamental reference classes
+ lazy val PartialFunctionClass = requiredClass[PartialFunction[_,_]]
+ lazy val AbstractPartialFunctionClass = requiredClass[scala.runtime.AbstractPartialFunction[_,_]]
+ lazy val SymbolClass = requiredClass[scala.Symbol]
+ lazy val StringClass = requiredClass[java.lang.String]
+ lazy val StringModule = StringClass.linkedClassOfClass
+ lazy val ClassClass = requiredClass[java.lang.Class[_]]
+ def Class_getMethod = getMemberMethod(ClassClass, nme.getMethod_)
+ lazy val DynamicClass = requiredClass[Dynamic]
+
+ // fundamental modules
+ lazy val SysPackage = getPackageObject("scala.sys")
+ def Sys_error = getMemberMethod(SysPackage, nme.error)
+
+ // Modules whose members are in the default namespace
+ // [Eugene++] ScalaPackage and JavaLangPackage are never ever shared between mirrors
+ // as a result, `Int` becomes `scala.Int` and `String` becomes `java.lang.String`
+ // I could just change `isOmittablePrefix`, but there's more to it, so I'm leaving this as a todo for now
+ lazy val UnqualifiedModules = List(PredefModule, ScalaPackage, JavaLangPackage)
+ // Those modules and their module classes
+ lazy val UnqualifiedOwners = UnqualifiedModules.toSet ++ UnqualifiedModules.map(_.moduleClass)
+
+ lazy val PredefModule = requiredModule[scala.Predef.type]
+ lazy val PredefModuleClass = PredefModule.moduleClass
+
+ def Predef_classOf = getMemberMethod(PredefModule, nme.classOf)
+ def Predef_identity = getMemberMethod(PredefModule, nme.identity)
+ def Predef_conforms = getMemberMethod(PredefModule, nme.conforms)
+ def Predef_wrapRefArray = getMemberMethod(PredefModule, nme.wrapRefArray)
+ def Predef_??? = getMemberMethod(PredefModule, nme.???)
+ def Predef_implicitly = getMemberMethod(PredefModule, nme.implicitly)
+
+ /** Is `sym` a member of Predef with the given name?
+ * Note: DON't replace this by sym == Predef_conforms/etc, as Predef_conforms is a `def`
+ * which does a member lookup (it can't be a lazy val because we might reload Predef
+ * during resident compilations).
+ */
+ def isPredefMemberNamed(sym: Symbol, name: Name) = (
+ (sym.name == name) && (sym.owner == PredefModule.moduleClass)
+ )
+
+ /** Specialization.
+ */
+ lazy val SpecializableModule = requiredModule[Specializable]
+ lazy val GroupOfSpecializable = getMemberClass(SpecializableModule, tpnme.Group)
+
+ lazy val ConsoleModule = requiredModule[scala.Console.type]
+ lazy val ScalaRunTimeModule = requiredModule[scala.runtime.ScalaRunTime.type]
+ lazy val SymbolModule = requiredModule[scala.Symbol.type]
+ lazy val Symbol_apply = getMemberMethod(SymbolModule, nme.apply)
+
+ def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq) // [Eugene++] obsolete?
+ def arrayApplyMethod = getMemberMethod(ScalaRunTimeModule, nme.array_apply)
+ def arrayUpdateMethod = getMemberMethod(ScalaRunTimeModule, nme.array_update)
+ def arrayLengthMethod = getMemberMethod(ScalaRunTimeModule, nme.array_length)
+ def arrayCloneMethod = getMemberMethod(ScalaRunTimeModule, nme.array_clone)
+ def ensureAccessibleMethod = getMemberMethod(ScalaRunTimeModule, nme.ensureAccessible)
+ def scalaRuntimeSameElements = getMemberMethod(ScalaRunTimeModule, nme.sameElements)
+ def arrayClassMethod = getMemberMethod(ScalaRunTimeModule, nme.arrayClass)
+ def arrayElementClassMethod = getMemberMethod(ScalaRunTimeModule, nme.arrayElementClass)
+
+ // classes with special meanings
+ lazy val StringAddClass = requiredClass[scala.runtime.StringAdd]
+ lazy val ArrowAssocClass = getRequiredClass("scala.Predef.ArrowAssoc") // SI-5731
+ lazy val StringAdd_+ = getMemberMethod(StringAddClass, nme.PLUS)
+ lazy val NotNullClass = getRequiredClass("scala.NotNull")
+ lazy val ScalaNumberClass = requiredClass[scala.math.ScalaNumber]
+ lazy val TraitSetterAnnotationClass = requiredClass[scala.runtime.TraitSetter]
+ lazy val DelayedInitClass = requiredClass[scala.DelayedInit]
+ def delayedInitMethod = getMemberMethod(DelayedInitClass, nme.delayedInit)
+ // a dummy value that communicates that a delayedInit call is compiler-generated
+ // from phase UnCurry to phase Constructors
+ // !!! This is not used anywhere (it was checked in that way.)
+ // def delayedInitArgVal = EmptyPackageClass.newValue(NoPosition, nme.delayedInitArg)
+ // .setInfo(UnitClass.tpe)
+
+ lazy val TypeConstraintClass = requiredClass[scala.annotation.TypeConstraint]
+ lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL)
+ lazy val SerializableClass = requiredClass[scala.Serializable]
+ lazy val JavaSerializableClass = requiredClass[java.io.Serializable] modifyInfo fixupAsAnyTrait
+ lazy val ComparableClass = requiredClass[java.lang.Comparable[_]] modifyInfo fixupAsAnyTrait
+ lazy val JavaCloneableClass = requiredClass[java.lang.Cloneable]
+ lazy val JavaNumberClass = requiredClass[java.lang.Number]
+ lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote]
+ lazy val RemoteExceptionClass = requiredClass[java.rmi.RemoteException]
+
+ lazy val ByNameParamClass = specialPolyClass(tpnme.BYNAME_PARAM_CLASS_NAME, COVARIANT)(_ => AnyClass.tpe)
+ lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN_NAME, 0L)(_ => AnyClass.tpe)
+ lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => arrayType(tparam.tpe))
+ lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => seqType(tparam.tpe))
+
+ def isByNameParamType(tp: Type) = tp.typeSymbol == ByNameParamClass
+ def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass
+ def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass
+ def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp)
+ def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf
+
+ def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params)
+ def isJavaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe)
+ def isScalaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe)
+ def isVarArgsList(params: Seq[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe)
+ def isVarArgTypes(formals: Seq[Type]) = formals.nonEmpty && isRepeatedParamType(formals.last)
+
+ def hasRepeatedParam(tp: Type): Boolean = tp match {
+ case MethodType(formals, restpe) => isScalaVarArgs(formals) || hasRepeatedParam(restpe)
+ case PolyType(_, restpe) => hasRepeatedParam(restpe)
+ case _ => false
+ }
+
+ def isPrimitiveArray(tp: Type) = tp match {
+ case TypeRef(_, ArrayClass, arg :: Nil) => isPrimitiveValueClass(arg.typeSymbol)
+ case _ => false
+ }
+ def isReferenceArray(tp: Type) = tp match {
+ case TypeRef(_, ArrayClass, arg :: Nil) => arg <:< AnyRefClass.tpe
+ case _ => false
+ }
+ def isArrayOfSymbol(tp: Type, elem: Symbol) = tp match {
+ case TypeRef(_, ArrayClass, arg :: Nil) => arg.typeSymbol == elem
+ case _ => false
+ }
+
+ lazy val MatchingStrategyClass = getRequiredClass("scala.MatchingStrategy")
+
+ // collections classes
+ lazy val ConsClass = requiredClass[scala.collection.immutable.::[_]]
+ lazy val IterableClass = requiredClass[scala.collection.Iterable[_]]
+ lazy val IteratorClass = requiredClass[scala.collection.Iterator[_]]
+ lazy val ListClass = requiredClass[scala.collection.immutable.List[_]]
+ lazy val SeqClass = requiredClass[scala.collection.Seq[_]]
+ lazy val StringBuilderClass = requiredClass[scala.collection.mutable.StringBuilder]
+ lazy val TraversableClass = requiredClass[scala.collection.Traversable[_]]
+
+ lazy val ListModule = requiredModule[scala.collection.immutable.List.type]
+ lazy val List_apply = getMemberMethod(ListModule, nme.apply)
+ lazy val NilModule = requiredModule[scala.collection.immutable.Nil.type]
+ lazy val SeqModule = requiredModule[scala.collection.Seq.type]
+ lazy val IteratorModule = requiredModule[scala.collection.Iterator.type]
+ lazy val Iterator_apply = getMemberMethod(IteratorModule, nme.apply)
+
+ // arrays and their members
+ lazy val ArrayModule = requiredModule[scala.Array.type]
+ lazy val ArrayModule_overloadedApply = getMemberMethod(ArrayModule, nme.apply)
+ lazy val ArrayClass = getRequiredClass("scala.Array") // requiredClass[scala.Array[_]]
+ lazy val Array_apply = getMemberMethod(ArrayClass, nme.apply)
+ lazy val Array_update = getMemberMethod(ArrayClass, nme.update)
+ lazy val Array_length = getMemberMethod(ArrayClass, nme.length)
+ lazy val Array_clone = getMemberMethod(ArrayClass, nme.clone_)
+
+ // reflection / structural types
+ lazy val SoftReferenceClass = requiredClass[java.lang.ref.SoftReference[_]]
+ lazy val WeakReferenceClass = requiredClass[java.lang.ref.WeakReference[_]]
+ lazy val MethodClass = getClassByName(sn.MethodAsObject)
+ def methodClass_setAccessible = getMemberMethod(MethodClass, nme.setAccessible)
+ lazy val EmptyMethodCacheClass = requiredClass[scala.runtime.EmptyMethodCache]
+ lazy val MethodCacheClass = requiredClass[scala.runtime.MethodCache]
+ def methodCache_find = getMemberMethod(MethodCacheClass, nme.find_)
+ def methodCache_add = getMemberMethod(MethodCacheClass, nme.add_)
+
+ // scala.reflect
+ lazy val ReflectPackage = requiredModule[scala.reflect.`package`.type]
+ def ReflectBasis = getMemberValue(ReflectPackage, nme.basis)
+ lazy val ReflectRuntimePackage = getPackageObjectIfDefined("scala.reflect.runtime") // defined in scala-reflect.jar, so we need to be careful
+ def ReflectRuntimeUniverse = if (ReflectRuntimePackage != NoSymbol) getMemberValue(ReflectRuntimePackage, nme.universe) else NoSymbol
+ def ReflectRuntimeCurrentMirror = if (ReflectRuntimePackage != NoSymbol) getMemberMethod(ReflectRuntimePackage, nme.currentMirror) else NoSymbol
+
+ lazy val PartialManifestClass = requiredClass[scala.reflect.ClassManifest[_]]
+ lazy val PartialManifestModule = requiredModule[scala.reflect.ClassManifest.type]
+ lazy val FullManifestClass = requiredClass[scala.reflect.Manifest[_]]
+ lazy val FullManifestModule = requiredModule[scala.reflect.Manifest.type]
+ lazy val OptManifestClass = requiredClass[scala.reflect.OptManifest[_]]
+ lazy val NoManifest = requiredModule[scala.reflect.NoManifest.type]
+
+ lazy val ExprsClass = getClassIfDefined("scala.reflect.api.Exprs") // defined in scala-reflect.jar, so we need to be careful
+ lazy val ExprClass = if (ExprsClass != NoSymbol) getMemberClass(ExprsClass, tpnme.Expr) else NoSymbol
+ def ExprSplice = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.splice) else NoSymbol
+ def ExprValue = if (ExprsClass != NoSymbol) getMemberMethod(ExprClass, nme.value) else NoSymbol
+ lazy val ExprModule = if (ExprsClass != NoSymbol) getMemberModule(ExprsClass, nme.Expr) else NoSymbol
+
+ lazy val ArrayTagClass = requiredClass[scala.reflect.ArrayTag[_]]
+ lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]]
+ lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]]
+ lazy val TypeTagsClass = requiredClass[scala.reflect.base.TypeTags]
+ lazy val TypeTagClass = getMemberClass(TypeTagsClass, tpnme.TypeTag)
+ lazy val TypeTagModule = getMemberModule(TypeTagsClass, nme.TypeTag)
+ lazy val ConcreteTypeTagClass = getMemberClass(TypeTagsClass, tpnme.ConcreteTypeTag)
+ lazy val ConcreteTypeTagModule = getMemberModule(TypeTagsClass, nme.ConcreteTypeTag)
+
+ lazy val BaseUniverseClass = requiredClass[scala.reflect.base.Universe]
+ lazy val ApiUniverseClass = getClassIfDefined("scala.reflect.api.Universe") // defined in scala-reflect.jar, so we need to be careful
+ def ApiUniverseReify = if (ApiUniverseClass != NoSymbol) getMemberMethod(ApiUniverseClass, nme.reify) else NoSymbol
+ lazy val JavaUniverseClass = getClassIfDefined("scala.reflect.api.JavaUniverse") // defined in scala-reflect.jar, so we need to be careful
+
+ lazy val MirrorOfClass = requiredClass[scala.reflect.base.MirrorOf[_]]
+
+ lazy val TypeCreatorClass = requiredClass[scala.reflect.base.TypeCreator]
+ lazy val TreeCreatorClass = requiredClass[scala.reflect.base.TreeCreator]
+
+ lazy val MacroContextClass = getClassIfDefined("scala.reflect.makro.Context") // defined in scala-reflect.jar, so we need to be careful
+ def MacroContextPrefix = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.prefix) else NoSymbol
+ def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getMemberType(MacroContextClass, tpnme.PrefixType) else NoSymbol
+ def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol
+ def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol
+ def MacroContextReify = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.reify) else NoSymbol
+ lazy val MacroImplAnnotation = requiredClass[scala.reflect.makro.internal.macroImpl]
+ lazy val MacroInternalPackage = getPackageObject("scala.reflect.makro.internal")
+ def MacroInternal_materializeArrayTag = getMemberMethod(MacroInternalPackage, nme.materializeArrayTag)
+ def MacroInternal_materializeClassTag = getMemberMethod(MacroInternalPackage, nme.materializeClassTag)
+ def MacroInternal_materializeTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeTypeTag)
+ def MacroInternal_materializeConcreteTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeConcreteTypeTag)
+
+ lazy val ScalaSignatureAnnotation = requiredClass[scala.reflect.ScalaSignature]
+ lazy val ScalaLongSignatureAnnotation = requiredClass[scala.reflect.ScalaLongSignature]
+
+ // Option classes
+ lazy val OptionClass: ClassSymbol = requiredClass[Option[_]]
+ lazy val SomeClass: ClassSymbol = requiredClass[Some[_]]
+ lazy val NoneModule: ModuleSymbol = requiredModule[scala.None.type]
+ lazy val SomeModule: ModuleSymbol = requiredModule[scala.Some.type]
+
+ def compilerTypeFromTag(tt: BaseUniverse # TypeTag[_]): Type = tt.in(rootMirror).tpe
+ def compilerSymbolFromTag(tt: BaseUniverse # TypeTag[_]): Symbol = tt.in(rootMirror).tpe.typeSymbol
+
+ // The given symbol represents either String.+ or StringAdd.+
+ def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+
+ def isArrowAssoc(sym: Symbol) = ArrowAssocClass.tpe.decls.toList contains sym
+
+ // The given symbol is a method with the right name and signature to be a runnable java program.
+ def isJavaMainMethod(sym: Symbol) = (sym.name == nme.main) && (sym.info match {
+ case MethodType(p :: Nil, restpe) => isArrayOfSymbol(p.tpe, StringClass) && restpe.typeSymbol == UnitClass
+ case _ => false
+ })
+ // The given class has a main method.
+ def hasJavaMainMethod(sym: Symbol): Boolean =
+ (sym.tpe member nme.main).alternatives exists isJavaMainMethod
+ def hasJavaMainMethod(path: String): Boolean =
+ hasJavaMainMethod(getModuleIfDefined(path))
+
+ def isOptionType(tp: Type) = tp.typeSymbol isSubClass OptionClass
+ def isSomeType(tp: Type) = tp.typeSymbol eq SomeClass
+ def isNoneType(tp: Type) = tp.typeSymbol eq NoneModule
+
+ // Product, Tuple, Function, AbstractFunction
+ private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = {
+ val list = countFrom to arity map (i => getRequiredClass("scala." + name + i))
+ list.toArray
+ }
+ def prepend[S >: ClassSymbol : ClassTag](elem0: S, elems: Array[ClassSymbol]): Array[S] = elem0 +: elems
+
+ private def aritySpecificType[S <: Symbol](symbolArray: Array[S], args: List[Type], others: Type*): Type = {
+ val arity = args.length
+ if (arity >= symbolArray.length) NoType
+ else appliedType(symbolArray(arity), args ++ others: _*)
+ }
+
+ val MaxTupleArity, MaxProductArity, MaxFunctionArity = 22
+ lazy val ProductClass: Array[ClassSymbol] = prepend(UnitClass, mkArityArray("Product", MaxProductArity, 1))
+ lazy val TupleClass: Array[Symbol] = prepend(NoSymbol, mkArityArray("Tuple", MaxTupleArity, 1))
+ lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0)
+ lazy val AbstractFunctionClass = mkArityArray("runtime.AbstractFunction", MaxFunctionArity, 0)
+
+ /** Creators for TupleN, ProductN, FunctionN. */
+ def tupleType(elems: List[Type]) = aritySpecificType(TupleClass, elems)
+ def productType(elems: List[Type]) = aritySpecificType(ProductClass, elems)
+ def functionType(formals: List[Type], restpe: Type) = aritySpecificType(FunctionClass, formals, restpe)
+ def abstractFunctionType(formals: List[Type], restpe: Type) = aritySpecificType(AbstractFunctionClass, formals, restpe)
+
+ def wrapArrayMethodName(elemtp: Type): TermName = elemtp.typeSymbol match {
+ case ByteClass => nme.wrapByteArray
+ case ShortClass => nme.wrapShortArray
+ case CharClass => nme.wrapCharArray
+ case IntClass => nme.wrapIntArray
+ case LongClass => nme.wrapLongArray
+ case FloatClass => nme.wrapFloatArray
+ case DoubleClass => nme.wrapDoubleArray
+ case BooleanClass => nme.wrapBooleanArray
+ case UnitClass => nme.wrapUnitArray
+ case _ =>
+ if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray
+ else nme.genericWrapArray
+ }
+
+ @deprecated("Use isTupleType", "2.10.0")
+ def isTupleTypeOrSubtype(tp: Type) = isTupleType(tp)
+
+ def tupleField(n: Int, j: Int) = getMemberValue(TupleClass(n), nme.productAccessorName(j))
+ // NOTE: returns true for NoSymbol since it's included in the TupleClass array -- is this intensional?
+ def isTupleSymbol(sym: Symbol) = TupleClass contains unspecializedSymbol(sym)
+ def isProductNClass(sym: Symbol) = ProductClass contains sym
+
+ def unspecializedSymbol(sym: Symbol): Symbol = {
+ if (sym hasFlag SPECIALIZED) {
+ // add initialization from its generic class constructor
+ val genericName = nme.unspecializedName(sym.name)
+ val member = sym.owner.info.decl(genericName.toTypeName)
+ member
+ }
+ else sym
+ }
+
+ // Checks whether the given type is true for the given condition,
+ // or if it is a specialized subtype of a type for which it is true.
+ //
+ // Origins notes:
+ // An issue was introduced with specialization in that the implementation
+ // of "isTupleType" in Definitions relied upon sym == TupleClass(elems.length).
+ // This test is untrue for specialized tuples, causing mysterious behavior
+ // because only some tuples are specialized.
+ def isPossiblySpecializedType(tp: Type)(cond: Type => Boolean) = {
+ cond(tp) || (tp match {
+ case TypeRef(pre, sym, args) if sym hasFlag SPECIALIZED =>
+ cond(tp baseType unspecializedSymbol(sym))
+ case _ =>
+ false
+ })
+ }
+ // No normalization.
+ def isTupleTypeDirect(tp: Type) = isPossiblySpecializedType(tp) {
+ case TypeRef(_, sym, args) if args.nonEmpty =>
+ val len = args.length
+ len <= MaxTupleArity && sym == TupleClass(len)
+ case _ => false
+ }
+ def isTupleType(tp: Type) = isTupleTypeDirect(tp.normalize)
+
+ lazy val ProductRootClass: ClassSymbol = requiredClass[scala.Product]
+ def Product_productArity = getMemberMethod(ProductRootClass, nme.productArity)
+ def Product_productElement = getMemberMethod(ProductRootClass, nme.productElement)
+ def Product_iterator = getMemberMethod(ProductRootClass, nme.productIterator)
+ def Product_productPrefix = getMemberMethod(ProductRootClass, nme.productPrefix)
+ def Product_canEqual = getMemberMethod(ProductRootClass, nme.canEqual_)
+ // def Product_productElementName = getMemberMethod(ProductRootClass, nme.productElementName)
+
+ def productProj(z:Symbol, j: Int): TermSymbol = getMemberValue(z, nme.productAccessorName(j))
+ def productProj(n: Int, j: Int): TermSymbol = productProj(ProductClass(n), j)
+
+ /** returns true if this type is exactly ProductN[T1,...,Tn], not some subclass */
+ def isExactProductType(tp: Type): Boolean = isProductNClass(tp.typeSymbol)
+
+ /** if tpe <: ProductN[T1,...,TN], returns List(T1,...,TN) else Nil */
+ def getProductArgs(tpe: Type): List[Type] = tpe.baseClasses find isProductNClass match {
+ case Some(x) => tpe.baseType(x).typeArgs
+ case _ => Nil
+ }
+
+ def unapplyUnwrap(tpe:Type) = tpe.finalResultType.normalize match {
+ case RefinedType(p :: _, _) => p.normalize
+ case tp => tp
+ }
+
+ def functionApply(n: Int) = getMemberMethod(FunctionClass(n), nme.apply)
+
+ def abstractFunctionForFunctionType(tp: Type) =
+ if (isFunctionType(tp)) abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last)
+ else NoType
+
+ def isFunctionType(tp: Type): Boolean = tp.normalize match {
+ case TypeRef(_, sym, args) if args.nonEmpty =>
+ val arity = args.length - 1 // -1 is the return type
+ arity <= MaxFunctionArity && sym == FunctionClass(arity)
+ case _ =>
+ false
+ }
+
+ def isPartialFunctionType(tp: Type): Boolean = {
+ val sym = tp.typeSymbol
+ (sym eq PartialFunctionClass) || (sym eq AbstractPartialFunctionClass)
+ }
+
+ def isSeqType(tp: Type) = elementType(SeqClass, tp.normalize) != NoType
+
+ def elementType(container: Symbol, tp: Type): Type = tp match {
+ case TypeRef(_, `container`, arg :: Nil) => arg
+ case _ => NoType
+ }
+
+ def arrayType(arg: Type) = appliedType(ArrayClass, arg)
+ def byNameType(arg: Type) = appliedType(ByNameParamClass, arg)
+ def iteratorOfType(tp: Type) = appliedType(IteratorClass, tp)
+ def javaRepeatedType(arg: Type) = appliedType(JavaRepeatedParamClass, arg)
+ def optionType(tp: Type) = appliedType(OptionClass, tp)
+ def scalaRepeatedType(arg: Type) = appliedType(RepeatedParamClass, arg)
+ def seqType(arg: Type) = appliedType(SeqClass, arg)
+ def someType(tp: Type) = appliedType(SomeClass, tp)
+
+ def StringArray = arrayType(StringClass.tpe)
+ lazy val ObjectArray = arrayType(ObjectClass.tpe)
+
+ def ClassType(arg: Type) =
+ if (phase.erasedTypes || forMSIL) ClassClass.tpe
+ else appliedType(ClassClass, arg)
+
+ def vmClassType(arg: Type): Type = ClassType(arg)
+ def vmSignature(sym: Symbol, info: Type): String = signature(info) // !!!
+
+ /** Given a class symbol C with type parameters T1, T2, ... Tn
+ * which have upper/lower bounds LB1/UB1, LB1/UB2, ..., LBn/UBn,
+ * returns an existential type of the form
+ *
+ * C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... en >: LBn <: UBn }.
+ */
+ def classExistentialType(clazz: Symbol): Type =
+ newExistentialType(clazz.typeParams, clazz.tpe)
+
+ /** Given type U, creates a Type representing Class[_ <: U].
+ */
+ def boundedClassType(upperBound: Type) =
+ appliedTypeAsUpperBounds(ClassClass.typeConstructor, List(upperBound))
+
+ /** To avoid unchecked warnings on polymorphic classes, translate
+ * a Foo[T] into a Foo[_] for use in the pattern matcher.
+ */
+ @deprecated("Use classExistentialType", "2.10.0")
+ def typeCaseType(clazz: Symbol): Type = classExistentialType(clazz)
+
+ //
+ // .NET backend
+ //
+
+ lazy val ComparatorClass = getRequiredClass("scala.runtime.Comparator")
+ // System.ValueType
+ lazy val ValueTypeClass: ClassSymbol = getClassByName(sn.ValueType)
+ // System.MulticastDelegate
+ lazy val DelegateClass: ClassSymbol = getClassByName(sn.Delegate)
+ var Delegate_scalaCallers: List[Symbol] = List() // Syncnote: No protection necessary yet as only for .NET where reflection is not supported.
+ // Symbol -> (Symbol, Type): scalaCaller -> (scalaMethodSym, DelegateType)
+ // var Delegate_scalaCallerInfos: HashMap[Symbol, (Symbol, Type)] = _
+ lazy val Delegate_scalaCallerTargets: mutable.HashMap[Symbol, Symbol] = mutable.HashMap()
+
+ def isCorrespondingDelegate(delegateType: Type, functionType: Type): Boolean = {
+ isSubType(delegateType, DelegateClass.tpe) &&
+ (delegateType.member(nme.apply).tpe match {
+ case MethodType(delegateParams, delegateReturn) =>
+ isFunctionType(functionType) &&
+ (functionType.normalize match {
+ case TypeRef(_, _, args) =>
+ (delegateParams.map(pt => {
+ if (pt.tpe == AnyClass.tpe) definitions.ObjectClass.tpe else pt})
+ ::: List(delegateReturn)) == args
+ case _ => false
+ })
+ case _ => false
+ })
+ }
+
+ // members of class scala.Any
+ lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL)
+ lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, anyparam, booltype, FINAL)
+ lazy val Any_equals = enterNewMethod(AnyClass, nme.equals_, anyparam, booltype)
+ lazy val Any_hashCode = enterNewMethod(AnyClass, nme.hashCode_, Nil, inttype)
+ lazy val Any_toString = enterNewMethod(AnyClass, nme.toString_, Nil, stringtype)
+ lazy val Any_## = enterNewMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL)
+
+ // Any_getClass requires special handling. The return type is determined on
+ // a per-call-site basis as if the function being called were actually:
+ //
+ // // Assuming `target.getClass()`
+ // def getClass[T](target: T): Class[_ <: T]
+ //
+ // Since getClass is not actually a polymorphic method, this requires compiler
+ // participation. At the "Any" level, the return type is Class[_] as it is in
+ // java.lang.Object. Java also special cases the return type.
+ lazy val Any_getClass = enterNewMethod(AnyClass, nme.getClass_, Nil, getMemberMethod(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED)
+ lazy val Any_isInstanceOf = newT1NullaryMethod(AnyClass, nme.isInstanceOf_, FINAL)(_ => booltype)
+ lazy val Any_asInstanceOf = newT1NullaryMethod(AnyClass, nme.asInstanceOf_, FINAL)(_.typeConstructor)
+
+ // A type function from T => Class[U], used to determine the return
+ // type of getClass calls. The returned type is:
+ //
+ // 1. If T is a value type, Class[T].
+ // 2. If T is a phantom type (Any or AnyVal), Class[_].
+ // 3. If T is a local class, Class[_ <: |T|].
+ // 4. Otherwise, Class[_ <: T].
+ //
+ // Note: AnyVal cannot be Class[_ <: AnyVal] because if the static type of the
+ // receiver is AnyVal, it implies the receiver is boxed, so the correct
+ // class object is that of java.lang.Integer, not Int.
+ //
+ // TODO: If T is final, return type could be Class[T]. Should it?
+ def getClassReturnType(tp: Type): Type = {
+ val sym = tp.typeSymbol
+
+ if (phase.erasedTypes) ClassClass.tpe
+ else if (isPrimitiveValueClass(sym)) ClassType(tp.widen)
+ else {
+ val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams)
+ val upperBound = (
+ if (isPhantomClass(sym)) AnyClass.tpe
+ else if (sym.isLocalClass) erasure.intersectionDominator(tp.parents)
+ else tp.widen
+ )
+
+ existentialAbstraction(
+ eparams,
+ ClassType((eparams.head setInfo TypeBounds.upper(upperBound)).tpe)
+ )
+ }
+ }
+
+ /** Remove references to class Object (other than the head) in a list of parents */
+ def removeLaterObjects(tps: List[Type]): List[Type] = tps match {
+ case Nil => Nil
+ case x :: xs => x :: xs.filterNot(_.typeSymbol == ObjectClass)
+ }
+ /** Remove all but one reference to class Object from a list of parents. */
+ def removeRedundantObjects(tps: List[Type]): List[Type] = tps match {
+ case Nil => Nil
+ case x :: xs =>
+ if (x.typeSymbol == ObjectClass)
+ x :: xs.filterNot(_.typeSymbol == ObjectClass)
+ else
+ x :: removeRedundantObjects(xs)
+ }
+ /** Order a list of types with non-trait classes before others. */
+ def classesFirst(tps: List[Type]): List[Type] = {
+ val (classes, others) = tps partition (t => t.typeSymbol.isClass && !t.typeSymbol.isTrait)
+ if (classes.isEmpty || others.isEmpty || (tps startsWith classes)) tps
+ else classes ::: others
+ }
+ /** The following transformations applied to a list of parents.
+ * If any parent is a class/trait, all parents which normalize to
+ * Object are discarded. Otherwise, all parents which normalize
+ * to Object except the first one found are discarded.
+ */
+ def normalizedParents(parents: List[Type]): List[Type] = {
+ if (parents exists (t => (t.typeSymbol ne ObjectClass) && t.typeSymbol.isClass))
+ parents filterNot (_.typeSymbol eq ObjectClass)
+ else
+ removeRedundantObjects(parents)
+ }
+
+ def typeStringNoPackage(tp: Type) =
+ "" + tp stripPrefix tp.typeSymbol.enclosingPackage.fullName + "."
+
+ def briefParentsString(parents: List[Type]) =
+ normalizedParents(parents) map typeStringNoPackage mkString " with "
+
+ def parentsString(parents: List[Type]) =
+ normalizedParents(parents) mkString " with "
+
+ def typeParamsString(tp: Type) = tp match {
+ case PolyType(tparams, _) => tparams map (_.defString) mkString ("[", ",", "]")
+ case _ => ""
+ }
+ def valueParamsString(tp: Type) = tp match {
+ case MethodType(params, _) => params map (_.defString) mkString ("(", ",", ")")
+ case _ => ""
+ }
+
+ // members of class java.lang.{ Object, String }
+ lazy val Object_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL)
+ lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL)
+ lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL)
+ lazy val Object_eq = enterNewMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL)
+ lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL)
+ lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC)(_ => booltype)
+ lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC)(_.typeConstructor)
+ lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps =>
+ (Some(List(tps.head.typeConstructor)), tps.head.typeConstructor)
+ )
+ lazy val String_+ = enterNewMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL)
+
+ def Object_getClass = getMemberMethod(ObjectClass, nme.getClass_)
+ def Object_clone = getMemberMethod(ObjectClass, nme.clone_)
+ def Object_finalize = getMemberMethod(ObjectClass, nme.finalize_)
+ def Object_notify = getMemberMethod(ObjectClass, nme.notify_)
+ def Object_notifyAll = getMemberMethod(ObjectClass, nme.notifyAll_)
+ def Object_equals = getMemberMethod(ObjectClass, nme.equals_)
+ def Object_hashCode = getMemberMethod(ObjectClass, nme.hashCode_)
+ def Object_toString = getMemberMethod(ObjectClass, nme.toString_)
+
+ // boxed classes
+ lazy val ObjectRefClass = requiredClass[scala.runtime.ObjectRef[_]]
+ lazy val VolatileObjectRefClass = requiredClass[scala.runtime.VolatileObjectRef[_]]
+ lazy val RuntimeStaticsModule = getRequiredModule("scala.runtime.Statics")
+ lazy val BoxesRunTimeModule = getRequiredModule("scala.runtime.BoxesRunTime")
+ lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass
+ lazy val BoxedNumberClass = getClassByName(sn.BoxedNumber)
+ lazy val BoxedCharacterClass = getClassByName(sn.BoxedCharacter)
+ lazy val BoxedBooleanClass = getClassByName(sn.BoxedBoolean)
+ lazy val BoxedByteClass = requiredClass[java.lang.Byte]
+ lazy val BoxedShortClass = requiredClass[java.lang.Short]
+ lazy val BoxedIntClass = requiredClass[java.lang.Integer]
+ lazy val BoxedLongClass = requiredClass[java.lang.Long]
+ lazy val BoxedFloatClass = requiredClass[java.lang.Float]
+ lazy val BoxedDoubleClass = requiredClass[java.lang.Double]
+
+ lazy val Boxes_isNumberOrBool = getDecl(BoxesRunTimeClass, nme.isBoxedNumberOrBoolean)
+ lazy val Boxes_isNumber = getDecl(BoxesRunTimeClass, nme.isBoxedNumber)
+
+ lazy val BoxedUnitClass = requiredClass[scala.runtime.BoxedUnit]
+ lazy val BoxedUnitModule = getRequiredModule("scala.runtime.BoxedUnit")
+ def BoxedUnit_UNIT = getMemberValue(BoxedUnitModule, nme.UNIT)
+ def BoxedUnit_TYPE = getMemberValue(BoxedUnitModule, nme.TYPE_)
+
+ // Annotation base classes
+ lazy val AnnotationClass = requiredClass[scala.annotation.Annotation]
+ lazy val ClassfileAnnotationClass = requiredClass[scala.annotation.ClassfileAnnotation]
+ lazy val StaticAnnotationClass = requiredClass[scala.annotation.StaticAnnotation]
+
+ // Annotations
+ lazy val BridgeClass = requiredClass[scala.annotation.bridge]
+ lazy val ElidableMethodClass = requiredClass[scala.annotation.elidable]
+ lazy val ImplicitNotFoundClass = requiredClass[scala.annotation.implicitNotFound]
+ lazy val MigrationAnnotationClass = requiredClass[scala.annotation.migration]
+ lazy val ScalaStrictFPAttr = requiredClass[scala.annotation.strictfp]
+ lazy val SerializableAttr = requiredClass[scala.annotation.serializable] // @serializable is deprecated
+ lazy val SwitchClass = requiredClass[scala.annotation.switch]
+ lazy val TailrecClass = requiredClass[scala.annotation.tailrec]
+ lazy val VarargsClass = requiredClass[scala.annotation.varargs]
+ lazy val uncheckedStableClass = requiredClass[scala.annotation.unchecked.uncheckedStable]
+ lazy val uncheckedVarianceClass = requiredClass[scala.annotation.unchecked.uncheckedVariance]
+
+ lazy val BeanPropertyAttr = requiredClass[scala.beans.BeanProperty]
+ lazy val BooleanBeanPropertyAttr = requiredClass[scala.beans.BooleanBeanProperty]
+ lazy val CloneableAttr = requiredClass[scala.cloneable]
+ lazy val DeprecatedAttr = requiredClass[scala.deprecated]
+ lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName]
+ lazy val NativeAttr = requiredClass[scala.native]
+ lazy val RemoteAttr = requiredClass[scala.remote]
+ lazy val ScalaInlineClass = requiredClass[scala.inline]
+ lazy val ScalaNoInlineClass = requiredClass[scala.noinline]
+ lazy val SerialVersionUIDAttr = requiredClass[scala.SerialVersionUID]
+ lazy val SpecializedClass = requiredClass[scala.specialized]
+ lazy val ThrowsClass = requiredClass[scala.throws]
+ lazy val TransientAttr = requiredClass[scala.transient]
+ lazy val UncheckedClass = requiredClass[scala.unchecked]
+ lazy val UnspecializedClass = requiredClass[scala.annotation.unspecialized]
+ lazy val VolatileAttr = requiredClass[scala.volatile]
+
+ // Meta-annotations
+ lazy val BeanGetterTargetClass = requiredClass[meta.beanGetter]
+ lazy val BeanSetterTargetClass = requiredClass[meta.beanSetter]
+ lazy val FieldTargetClass = requiredClass[meta.field]
+ lazy val GetterTargetClass = requiredClass[meta.getter]
+ lazy val ParamTargetClass = requiredClass[meta.param]
+ lazy val SetterTargetClass = requiredClass[meta.setter]
+ lazy val ClassTargetClass = requiredClass[meta.companionClass]
+ lazy val ObjectTargetClass = requiredClass[meta.companionObject]
+ lazy val MethodTargetClass = requiredClass[meta.companionMethod] // TODO: module, moduleClass? package, packageObject?
+ lazy val LanguageFeatureAnnot = requiredClass[meta.languageFeature]
+
+ // Language features
+ lazy val languageFeatureModule = getRequiredModule("scala.languageFeature")
+ lazy val experimentalModule = getMemberModule(languageFeatureModule, nme.experimental)
+ lazy val MacrosFeature = getLanguageFeature("macros", experimentalModule)
+ lazy val DynamicsFeature = getLanguageFeature("dynamics")
+ lazy val PostfixOpsFeature = getLanguageFeature("postfixOps")
+ lazy val ReflectiveCallsFeature = getLanguageFeature("reflectiveCalls")
+ lazy val ImplicitConversionsFeature = getLanguageFeature("implicitConversions")
+ lazy val HigherKindsFeature = getLanguageFeature("higherKinds")
+ lazy val ExistentialsFeature = getLanguageFeature("existentials")
+
+ def isMetaAnnotation(sym: Symbol): Boolean = metaAnnotations(sym) || (
+ // Trying to allow for deprecated locations
+ sym.isAliasType && isMetaAnnotation(sym.info.typeSymbol)
+ )
+ lazy val metaAnnotations = Set[Symbol](
+ FieldTargetClass, ParamTargetClass,
+ GetterTargetClass, SetterTargetClass,
+ BeanGetterTargetClass, BeanSetterTargetClass
+ )
+
+ 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
+ }
+
+ private def fatalMissingSymbol(owner: Symbol, name: Name, what: String = "member") = {
+ throw new FatalError(owner + " does not have a " + what + " " + name)
+ }
+
+ def getLanguageFeature(name: String, owner: Symbol = languageFeatureModule): Symbol =
+ // [Eugene++] `getMemberClass` leads to crashes in mixin:
+ // "object languageFeature does not have a member class implicitConversions"
+ // that's because by that time `implicitConversions` becomes a module
+ // getMemberClass(owner, newTypeName(name))
+ getMember(owner, newTypeName(name))
+
+ def termMember(owner: Symbol, name: String): Symbol = owner.info.member(newTermName(name))
+ def typeMember(owner: Symbol, name: String): Symbol = owner.info.member(newTypeName(name))
+
+ def findNamedMember(fullName: Name, root: Symbol): Symbol = {
+ val segs = nme.segments(fullName.toString, fullName.isTermName)
+ if (segs.isEmpty || segs.head != root.simpleName) NoSymbol
+ else findNamedMember(segs.tail, root)
+ }
+ def findNamedMember(segs: List[Name], root: Symbol): Symbol =
+ if (segs.isEmpty) root
+ else findNamedMember(segs.tail, root.info member segs.head)
+
+ def getMember(owner: Symbol, name: Name): Symbol = {
+ getMemberIfDefined(owner, name) orElse {
+ if (phase.flatClasses && name.isTypeName && !owner.isPackageObjectOrClass) {
+ val pkg = owner.owner
+ val flatname = nme.flattenedName(owner.name, name)
+ getMember(pkg, flatname)
+ }
+ else fatalMissingSymbol(owner, name)
+ }
+ }
+ def getMemberValue(owner: Symbol, name: Name): TermSymbol = {
+ // [Eugene++] should be a ClassCastException instead?
+ getMember(owner, name.toTermName) match {
+ case x: TermSymbol => x
+ case _ => fatalMissingSymbol(owner, name, "member value")
+ }
+ }
+ def getMemberModule(owner: Symbol, name: Name): ModuleSymbol = {
+ // [Eugene++] should be a ClassCastException instead?
+ getMember(owner, name.toTermName) match {
+ case x: ModuleSymbol => x
+ case _ => fatalMissingSymbol(owner, name, "member object")
+ }
+ }
+ def getMemberType(owner: Symbol, name: Name): TypeSymbol = {
+ // [Eugene++] should be a ClassCastException instead?
+ getMember(owner, name.toTypeName) match {
+ case x: TypeSymbol => x
+ case _ => fatalMissingSymbol(owner, name, "member type")
+ }
+ }
+ def getMemberClass(owner: Symbol, name: Name): ClassSymbol = {
+ // [Eugene++] should be a ClassCastException instead?
+ val y = getMember(owner, name.toTypeName)
+ getMember(owner, name.toTypeName) match {
+ case x: ClassSymbol => x
+ case _ => fatalMissingSymbol(owner, name, "member class")
+ }
+ }
+ def getMemberMethod(owner: Symbol, name: Name): TermSymbol = {
+ // [Eugene++] is this a bug?
+ //
+ // System.err.println(result.getClass)
+ // System.err.println(result.flags)
+ // System.err.println("isMethod = " + result.isMethod)
+ // System.err.println("isTerm = " + result.isTerm)
+ // System.err.println("isValue = " + result.isValue)
+ // result.asMethodSymbol
+ //
+ // prints this:
+ //
+ // quick.lib:
+ // [javac] Compiling 1 source file to C:\Projects\KeplerUnderRefactoring\build\quick\classes\library
+ // [scalacfork] Compiling 769 files to C:\Projects\KeplerUnderRefactoring\build\quick\classes\library
+ // [scalacfork] class scala.reflect.internal.Symbols$TermSymbol
+ // [scalacfork] 8589934592
+ // [scalacfork] isMethod = false
+ // [scalacfork] isTerm = true
+ // [scalacfork] isValue = true
+ // [scalacfork]
+ // [scalacfork] while compiling: C:\Projects\KeplerUnderRefactoring\src\library\scala\LowPriorityImplicits.scala
+ // [scalacfork] current phase: cleanup
+ // [scalacfork] library version: version 2.10.0-20120507-185519-665d1d9127
+ // [scalacfork] compiler version: version 2.10.0-20120507-185519-665d1d9127
+ // [scalacfork] reconstructed args: -Xmacros -classpath C:\\Projects\\KeplerUnderRefactoring\\build\\quick\\classes\\library;C:\\Projects\\KeplerUnderRefactoring\\lib\\forkjoin.jar -d C:\\Projects\\KeplerUnderRefactoring\\build\\quick\\classes\\library -sourcepath C:\\Projects\\KeplerUnderRefactoring\\src\\library
+ // [scalacfork]
+ // [scalacfork] unhandled exception while transforming LowPriorityImplicits.scala
+ // [scalacfork] error:
+ // [scalacfork] while compiling: C:\Projects\KeplerUnderRefactoring\src\library\scala\LowPriorityImplicits.scala
+ // [scalacfork] current phase: cleanup
+ // [scalacfork] library version: version 2.10.0-20120507-185519-665d1d9127
+ // [scalacfork] compiler version: version 2.10.0-20120507-185519-665d1d9127
+ // [scalacfork] reconstructed args: -Xmacros -classpath C:\\Projects\\KeplerUnderRefactoring\\build\\quick\\classes\\library;C:\\Projects\\KeplerUnderRefactoring\\lib\\forkjoin.jar -d C:\\Projects\\KeplerUnderRefactoring\\build\\quick\\classes\\library -sourcepath C:\\Projects\\KeplerUnderRefactoring\\src\\library
+ // [scalacfork]
+ // [scalacfork] uncaught exception during compilation: java.lang.ClassCastException
+ // [scalacfork] error: java.lang.ClassCastException: value apply
+ // [scalacfork] at scala.reflect.base.Symbols$SymbolBase$class.asMethodSymbol(Symbols.scala:118)
+ // [scalacfork] at scala.reflect.internal.Symbols$SymbolContextApiImpl.asMethodSymbol(Symbols.scala:63)
+ // [scalacfork] at scala.reflect.internal.Definitions$DefinitionsClass.Symbol_apply(Definitions.scala:381)
+
+ // [Eugene++] should be a ClassCastException instead?
+ getMember(owner, name.toTermName) match {
+ // case x: MethodSymbol => x
+ case x: TermSymbol => x
+ case _ => fatalMissingSymbol(owner, name, "method")
+ }
+ }
+
+ def getMemberIfDefined(owner: Symbol, name: Name): Symbol =
+ owner.info.nonPrivateMember(name)
+
+ /** Using getDecl rather than getMember may avoid issues with
+ * OverloadedTypes turning up when you don't want them, if you
+ * know the method in question is uniquely declared in the given owner.
+ */
+ def getDecl(owner: Symbol, name: Name): Symbol = {
+ getDeclIfDefined(owner, name) orElse fatalMissingSymbol(owner, name, "decl")
+ }
+ def getDeclIfDefined(owner: Symbol, name: Name): Symbol =
+ owner.info.nonPrivateDecl(name)
+
+ def packageExists(packageName: String): Boolean =
+ getModuleIfDefined(packageName).isPackage
+
+ private def newAlias(owner: Symbol, name: TypeName, alias: Type): AliasTypeSymbol =
+ owner.newAliasType(name) setInfoAndEnter alias
+
+ private def specialPolyClass(name: TypeName, flags: Long)(parentFn: Symbol => Type): ClassSymbol = {
+ val clazz = enterNewClass(ScalaPackageClass, name, Nil)
+ val tparam = clazz.newSyntheticTypeParam("T0", flags)
+ val parents = List(AnyRefClass.tpe, parentFn(tparam))
+
+ clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz))
+ }
+
+ def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): MethodSymbol = {
+ val msym = owner.newMethod(name.encode, NoPosition, flags)
+ val tparams = msym.newSyntheticTypeParams(typeParamCount)
+ val mtpe = createFn(tparams) match {
+ case (Some(formals), restpe) => MethodType(msym.newSyntheticValueParams(formals), restpe)
+ case (_, restpe) => NullaryMethodType(restpe)
+ }
+
+ msym setInfoAndEnter genPolyType(tparams, mtpe)
+ }
+
+ /** T1 means one type parameter.
+ */
+ def newT1NullaryMethod(owner: Symbol, name: TermName, flags: Long)(createFn: Symbol => Type): MethodSymbol = {
+ newPolyMethod(1, owner, name, flags)(tparams => (None, createFn(tparams.head)))
+ }
+ def newT1NoParamsMethod(owner: Symbol, name: TermName, flags: Long)(createFn: Symbol => Type): MethodSymbol = {
+ newPolyMethod(1, owner, name, flags)(tparams => (Some(Nil), createFn(tparams.head)))
+ }
+
+ lazy val boxedClassValues = boxedClass.values.toSet[Symbol]
+ lazy val isUnbox = unboxMethod.values.toSet[Symbol]
+ lazy val isBox = boxMethod.values.toSet[Symbol]
+
+ /** Is symbol a phantom class for which no runtime representation exists? */
+ lazy val isPhantomClass = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
+
+ /** Is the symbol that of a parent which is added during parsing? */
+ lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass
+
+ private lazy val boxedValueClassesSet = boxedClass.values.toSet[Symbol] + BoxedUnitClass
+
+ /** Is symbol a value class? */
+ def isPrimitiveValueClass(sym: Symbol) = ScalaValueClasses contains sym
+ def isNonUnitValueClass(sym: Symbol) = isPrimitiveValueClass(sym) && (sym != UnitClass)
+ def isSpecializableClass(sym: Symbol) = isPrimitiveValueClass(sym) || (sym == AnyRefClass)
+ def isPrimitiveValueType(tp: Type) = isPrimitiveValueClass(tp.typeSymbol)
+
+ /** Is symbol a boxed value class, e.g. java.lang.Integer? */
+ def isBoxedValueClass(sym: Symbol) = boxedValueClassesSet(sym)
+
+ /** If symbol is a value class (boxed or not), return the unboxed
+ * value class. Otherwise, NoSymbol.
+ */
+ def unboxedValueClass(sym: Symbol): Symbol =
+ if (isPrimitiveValueClass(sym)) sym
+ else if (sym == BoxedUnitClass) UnitClass
+ else boxedClass.map(kvp => (kvp._2: Symbol, kvp._1)).getOrElse(sym, NoSymbol)
+
+ /** Is type's symbol a numeric value class? */
+ def isNumericValueType(tp: Type): Boolean = tp match {
+ case TypeRef(_, sym, _) => isNumericValueClass(sym)
+ case _ => false
+ }
+
+ // todo: reconcile with javaSignature!!!
+ def signature(tp: Type): String = {
+ def erasure(tp: Type): Type = tp match {
+ case st: SubType => erasure(st.supertype)
+ case RefinedType(parents, _) => erasure(parents.head)
+ case _ => tp
+ }
+ def flatNameString(sym: Symbol, separator: Char): String =
+ if (sym == NoSymbol) "" // be more resistant to error conditions, e.g. neg/t3222.scala
+ else if (sym.owner.isPackageClass) sym.javaClassName
+ else flatNameString(sym.owner, separator) + nme.NAME_JOIN_STRING + sym.simpleName
+ def signature1(etp: Type): String = {
+ if (etp.typeSymbol == ArrayClass) "[" + signature1(erasure(etp.normalize.typeArgs.head))
+ else if (isPrimitiveValueClass(etp.typeSymbol)) abbrvTag(etp.typeSymbol).toString()
+ else "L" + flatNameString(etp.typeSymbol, '/') + ";"
+ }
+ val etp = erasure(tp)
+ if (etp.typeSymbol == ArrayClass) signature1(etp)
+ else flatNameString(etp.typeSymbol, '.')
+ }
+
+ /** Surgery on the value classes. Without this, AnyVals defined in source
+ * files end up with an AnyRef parent. It is likely there is a better way
+ * to evade that AnyRef.
+ */
+ private def setParents(sym: Symbol, parents: List[Type]): Symbol = sym.rawInfo match {
+ case ClassInfoType(_, scope, clazz) =>
+ sym setInfo ClassInfoType(parents, scope, clazz)
+ case _ =>
+ sym
+ }
+
+ def init() {
+ if (isInitialized) return
+
+ val forced = List( // force initialization of every symbol that is entered as a side effect
+ AnnotationDefaultAttr, // #2264
+ RepeatedParamClass,
+ JavaRepeatedParamClass,
+ ByNameParamClass,
+ AnyClass,
+ AnyRefClass,
+ AnyValClass,
+ NullClass,
+ NothingClass,
+ SingletonClass,
+ EqualsPatternClass,
+ Any_==,
+ Any_!=,
+ Any_equals,
+ Any_hashCode,
+ Any_toString,
+ Any_getClass,
+ Any_isInstanceOf,
+ Any_asInstanceOf,
+ Any_##,
+ Object_eq,
+ Object_ne,
+ Object_==,
+ Object_!=,
+ Object_##,
+ Object_synchronized,
+ Object_isInstanceOf,
+ Object_asInstanceOf,
+ String_+,
+ ComparableClass,
+ JavaSerializableClass
+ )
+
+ isInitialized = true
+ } //init
+
+ var nbScalaCallers: Int = 0
+ def newScalaCaller(delegateType: Type): MethodSymbol = {
+ assert(forMSIL, "scalaCallers can only be created if target is .NET")
+ // object: reference to object on which to call (scala-)method
+ val paramTypes: List[Type] = List(ObjectClass.tpe)
+ val name = newTermName("$scalaCaller$$" + nbScalaCallers)
+ // tparam => resultType, which is the resultType of PolyType, i.e. the result type after applying the
+ // type parameter =-> a MethodType in this case
+ // TODO: set type bounds manually (-> MulticastDelegate), see newTypeParam
+ val newCaller = enterNewMethod(DelegateClass, name, paramTypes, delegateType, FINAL | STATIC)
+ // val newCaller = newPolyMethod(DelegateClass, name,
+ // tparam => MethodType(paramTypes, tparam.typeConstructor)) setFlag (FINAL | STATIC)
+ Delegate_scalaCallers = Delegate_scalaCallers ::: List(newCaller)
+ nbScalaCallers += 1
+ newCaller
+ }
+
+ // def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol, delType: Type) {
+ // assert(Delegate_scalaCallers contains scalaCaller)
+ // Delegate_scalaCallerInfos += (scalaCaller -> (methSym, delType))
+ // }
+
+ def addScalaCallerInfo(scalaCaller: Symbol, methSym: Symbol) {
+ assert(Delegate_scalaCallers contains scalaCaller)
+ Delegate_scalaCallerTargets += (scalaCaller -> methSym)
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
new file mode 100644
index 0000000000..f1fe4fc118
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/ExistentialsAndSkolems.scala
@@ -0,0 +1,50 @@
+/* NSC -- new scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable }
+import util._
+
+/** The name of this trait defines the eventual intent better than
+ * it does the initial contents.
+ */
+trait ExistentialsAndSkolems {
+ self: SymbolTable =>
+
+ /** Map a list of type parameter symbols to skolemized symbols, which
+ * can be deskolemized to the original type parameter. (A skolem is a
+ * representation of a bound variable when viewed inside its scope.)
+ * !!!Adriaan: this does not work for hk types.
+ */
+ def deriveFreshSkolems(tparams: List[Symbol]): List[Symbol] = {
+ class Deskolemizer extends LazyType {
+ override val typeParams = tparams
+ val typeSkolems = typeParams map (_.newTypeSkolem setInfo this)
+ override def complete(sym: Symbol) {
+ // The info of a skolem is the skolemized info of the
+ // actual type parameter of the skolem
+ sym setInfo sym.deSkolemize.info.substSym(typeParams, typeSkolems)
+ }
+ }
+ (new Deskolemizer).typeSkolems
+ }
+
+ /** Convert to corresponding type parameters all skolems of method
+ * parameters which appear in `tparams`.
+ */
+ def deskolemizeTypeParams(tparams: List[Symbol])(tp: Type): Type = {
+ class DeSkolemizeMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) if sym.isTypeSkolem && (tparams contains sym.deSkolemize) =>
+ mapOver(typeRef(NoPrefix, sym.deSkolemize, args))
+ case _ =>
+ mapOver(tp)
+ }
+ }
+ new DeSkolemizeMap mapOver tp
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/FatalError.scala b/src/reflect/scala/reflect/internal/FatalError.scala
new file mode 100644
index 0000000000..c843308480
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/FatalError.scala
@@ -0,0 +1,6 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect.internal
+case class FatalError(msg: String) extends Exception(msg)
diff --git a/src/reflect/scala/reflect/internal/FlagSets.scala b/src/reflect/scala/reflect/internal/FlagSets.scala
new file mode 100644
index 0000000000..0354d2513c
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/FlagSets.scala
@@ -0,0 +1,66 @@
+package scala.reflect
+package internal
+
+import language.implicitConversions
+
+trait FlagSets extends api.FlagSets { self: SymbolTable =>
+
+ type FlagSet = Long
+ implicit val FlagSetTag = ClassTag[FlagSet](classOf[FlagSet])
+
+ implicit def addFlagOps(left: FlagSet): FlagOps =
+ new FlagOpsImpl(left)
+
+ private class FlagOpsImpl(left: Long) extends FlagOps {
+ def | (right: Long): Long = left | right
+ def & (right: Long): Long = left & right
+ def containsAll (right: Long): Boolean = (right & ~left) == 0
+ }
+
+ val NoFlags: FlagSet = 0L
+
+ trait FlagValues extends FlagValuesApi
+
+ object Flag extends FlagValues {
+ val TRAIT : FlagSet = Flags.TRAIT
+ val MODULE : FlagSet = Flags.MODULE
+ val MUTABLE : FlagSet = Flags.MUTABLE
+ val PACKAGE : FlagSet = Flags.PACKAGE
+ val METHOD : FlagSet = Flags.METHOD
+ val MACRO : FlagSet = Flags.MACRO
+ val DEFERRED : FlagSet = Flags.DEFERRED
+ val ABSTRACT : FlagSet = Flags.ABSTRACT
+ val FINAL : FlagSet = Flags.FINAL
+ val SEALED : FlagSet = Flags.SEALED
+ val IMPLICIT : FlagSet = Flags.IMPLICIT
+ val LAZY : FlagSet = Flags.LAZY
+ val OVERRIDE : FlagSet = Flags.OVERRIDE
+ val PRIVATE : FlagSet = Flags.PRIVATE
+ val PROTECTED : FlagSet = Flags.PROTECTED
+ val CASE : FlagSet = Flags.CASE
+ val ABSOVERRIDE : FlagSet = Flags.ABSOVERRIDE
+ val BYNAMEPARAM : FlagSet = Flags.BYNAMEPARAM
+ val PARAM : FlagSet = Flags.PARAM
+ val PARAMACCESSOR : FlagSet = Flags.PARAMACCESSOR
+ val CASEACCESSOR : FlagSet = Flags.CASEACCESSOR
+ val COVARIANT : FlagSet = Flags.COVARIANT
+ val CONTRAVARIANT : FlagSet = Flags.CONTRAVARIANT
+ val DEFAULTPARAM : FlagSet = Flags.DEFAULTPARAM
+ val INTERFACE : FlagSet = Flags.INTERFACE
+
+ def union(flags: FlagSet*): FlagSet = {
+ var acc = 0L
+ for (flag <- flags) acc |= flag
+ acc
+ }
+
+ def intersection(flags: FlagSet*): FlagSet = {
+ var acc = -1L
+ for (flag <- flags) acc &= flag
+ acc
+ }
+
+ def containsAll(superset: FlagSet, subset: FlagSet): Boolean =
+ (subset & ~superset) == 0
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala
new file mode 100644
index 0000000000..37e5a23819
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Flags.scala
@@ -0,0 +1,483 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable }
+
+// Flags at each index of a flags Long. Those marked with /M are used in
+// Parsers/JavaParsers and therefore definitely appear on Modifiers; but the
+// absence of /M on the other flags does not imply they aren't.
+//
+// Generated by mkFlagsTable() at Thu Feb 02 20:31:52 PST 2012
+//
+// 0: PROTECTED/M
+// 1: OVERRIDE/M
+// 2: PRIVATE/M
+// 3: ABSTRACT/M
+// 4: DEFERRED/M
+// 5: FINAL/M
+// 6: METHOD
+// 7: INTERFACE/M
+// 8: MODULE
+// 9: IMPLICIT/M
+// 10: SEALED/M
+// 11: CASE/M
+// 12: MUTABLE/M
+// 13: PARAM/M
+// 14: PACKAGE
+// 15: MACRO/M
+// 16: BYNAMEPARAM/M CAPTURED COVARIANT/M
+// 17: CONTRAVARIANT/M INCONSTRUCTOR LABEL
+// 18: ABSOVERRIDE/M
+// 19: LOCAL/M
+// 20: JAVA/M
+// 21: SYNTHETIC
+// 22: STABLE
+// 23: STATIC/M
+// 24: CASEACCESSOR/M
+// 25: DEFAULTPARAM/M TRAIT/M
+// 26: BRIDGE
+// 27: ACCESSOR
+// 28: SUPERACCESSOR
+// 29: PARAMACCESSOR/M
+// 30: MODULEVAR
+// 31: LAZY/M
+// 32: IS_ERROR
+// 33: OVERLOADED
+// 34: LIFTED
+// 35: EXISTENTIAL MIXEDIN
+// 36: EXPANDEDNAME
+// 37: IMPLCLASS PRESUPER/M
+// 38: TRANS_FLAG
+// 39: LOCKED
+// 40: SPECIALIZED
+// 41: DEFAULTINIT/M
+// 42: VBRIDGE
+// 43: VARARGS
+// 44: TRIEDCOOKING
+// 45:
+// 46:
+// 47:
+// 48:
+// 49:
+// 50:
+// 51: lateDEFERRED
+// 52: lateFINAL
+// 53: lateMETHOD
+// 54: lateINTERFACE
+// 55: lateMODULE
+// 56: notPROTECTED
+// 57: notOVERRIDE
+// 58: notPRIVATE
+// 59:
+// 60:
+// 61:
+// 62:
+// 63:
+
+/** Flags set on Modifiers instances in the parsing stage.
+ */
+class ModifierFlags {
+ final val IMPLICIT = 1 << 9
+ final val FINAL = 1 << 5 // May not be overridden. Note that java final implies much more than scala final.
+ final val PRIVATE = 1 << 2
+ final val PROTECTED = 1 << 0
+
+ final val SEALED = 1 << 10
+ final val OVERRIDE = 1 << 1
+ final val CASE = 1 << 11
+ final val ABSTRACT = 1 << 3 // abstract class, or used in conjunction with abstract override.
+ // Note difference to DEFERRED!
+ final val DEFERRED = 1 << 4 // was `abstract' for members | trait is virtual
+ final val INTERFACE = 1 << 7 // symbol is an interface (i.e. a trait which defines only abstract methods)
+ final val MUTABLE = 1 << 12 // symbol is a mutable variable.
+ final val PARAM = 1 << 13 // symbol is a (value or type) parameter to a method
+ final val MACRO = 1 << 15 // symbol is a macro definition
+
+ final val COVARIANT = 1 << 16 // symbol is a covariant type variable
+ final val BYNAMEPARAM = 1 << 16 // parameter is by name
+ final val CONTRAVARIANT = 1 << 17 // symbol is a contravariant type variable
+ final val ABSOVERRIDE = 1 << 18 // combination of abstract & override
+ final val LOCAL = 1 << 19 // symbol is local to current class (i.e. private[this] or protected[this]
+ // pre: PRIVATE or PROTECTED are also set
+ final val JAVA = 1 << 20 // symbol was defined by a Java class
+ final val STATIC = 1 << 23 // static field, method or class
+ final val CASEACCESSOR = 1 << 24 // symbol is a case parameter (or its accessor, or a GADT skolem)
+ final val TRAIT = 1 << 25 // symbol is a trait
+ final val DEFAULTPARAM = 1 << 25 // the parameter has a default value
+ final val PARAMACCESSOR = 1 << 29 // for field definitions generated for primary constructor
+ // parameters (no matter if it's a 'val' parameter or not)
+ // for parameters of a primary constructor ('val' or not)
+ // for the accessor methods generated for 'val' or 'var' parameters
+ final val LAZY = 1L << 31 // symbol is a lazy val. can't have MUTABLE unless transformed by typer
+ final val PRESUPER = 1L << 37 // value is evaluated before super call
+ final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit
+
+ // Overridden.
+ def flagToString(flag: Long): String = ""
+
+ final val PrivateLocal = PRIVATE | LOCAL
+ final val ProtectedLocal = PROTECTED | LOCAL
+ final val AccessFlags = PRIVATE | PROTECTED | LOCAL
+}
+object ModifierFlags extends ModifierFlags
+
+/** All flags and associated operatins */
+class Flags extends ModifierFlags {
+ final val METHOD = 1 << 6 // a method
+ final val MODULE = 1 << 8 // symbol is module or class implementing a module
+ final val PACKAGE = 1 << 14 // symbol is a java package
+
+ final val CAPTURED = 1 << 16 // variable is accessed from nested function. Set by LambdaLift.
+ final val LABEL = 1 << 17 // method symbol is a label. Set by TailCall
+ final val INCONSTRUCTOR = 1 << 17 // class symbol is defined in this/superclass constructor.
+ final val SYNTHETIC = 1 << 21 // symbol is compiler-generated
+ final val STABLE = 1 << 22 // functions that are assumed to be stable
+ // (typically, access methods for valdefs)
+ // or classes that do not contain abstract types.
+ final val BRIDGE = 1 << 26 // function is a bridge method. Set by Erasure
+ final val ACCESSOR = 1 << 27 // a value or variable accessor (getter or setter)
+
+ final val SUPERACCESSOR = 1 << 28 // a super accessor
+ final val MODULEVAR = 1 << 30 // for variables: is the variable caching a module value
+
+ final val IS_ERROR = 1L << 32 // symbol is an error symbol
+ final val OVERLOADED = 1L << 33 // symbol is overloaded
+ final val LIFTED = 1L << 34 // class has been lifted out to package level
+ // local value has been lifted out to class level
+ // todo: make LIFTED = latePRIVATE?
+ final val MIXEDIN = 1L << 35 // term member has been mixed in
+ final val EXISTENTIAL = 1L << 35 // type is an existential parameter or skolem
+ final val EXPANDEDNAME = 1L << 36 // name has been expanded with class suffix
+ final val IMPLCLASS = 1L << 37 // symbol is an implementation class
+ final val TRANS_FLAG = 1L << 38 // transient flag guaranteed to be reset after each phase.
+
+ final val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies
+ final val SPECIALIZED = 1L << 40 // symbol is a generated specialized member
+ final val VBRIDGE = 1L << 42 // symbol is a varargs bridge
+
+ final val VARARGS = 1L << 43 // symbol is a Java-style varargs method
+ final val TRIEDCOOKING = 1L << 44 // ``Cooking'' has been tried on this symbol
+ // A Java method's type is ``cooked'' by transforming raw types to existentials
+
+ final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED
+ // ------- shift definitions -------------------------------------------------------
+
+ final val InitialFlags = 0x0001FFFFFFFFFFFFL // flags that are enabled from phase 1.
+ final val LateFlags = 0x00FE000000000000L // flags that override flags in 0x1FC.
+ final val AntiFlags = 0x7F00000000000000L // flags that cancel flags in 0x07F
+ final val LateShift = 47L
+ final val AntiShift = 56L
+
+ // Flags which sketchily share the same slot
+ val OverloadedFlagsMask = 0L | BYNAMEPARAM | CONTRAVARIANT | DEFAULTPARAM | EXISTENTIAL | IMPLCLASS
+
+ // ------- late flags (set by a transformer phase) ---------------------------------
+ //
+ // Summary of when these are claimed to be first used.
+ // You can get this output with scalac -Xshow-phases -Ydebug.
+ //
+ // refchecks 7 [START] <latemethod>
+ // specialize 13 [START] <latefinal> <notprivate>
+ // explicitouter 14 [START] <notprotected>
+ // erasure 15 [START] <latedeferred> <lateinterface>
+ // mixin 20 [START] <latemodule> <notoverride>
+ //
+ // lateMETHOD set in RefChecks#transformInfo.
+ // lateFINAL set in Symbols#makeNotPrivate.
+ // notPRIVATE set in Symbols#makeNotPrivate, IExplicitOuter#transform, Inliners.
+ // notPROTECTED set in ExplicitOuter#transform.
+ // lateDEFERRED set in AddInterfaces, Mixin, etc.
+ // lateINTERFACE set in AddInterfaces#transformMixinInfo.
+ // lateMODULE set in Mixin#transformInfo.
+ // notOVERRIDE set in Mixin#preTransform.
+
+ final val lateDEFERRED = (DEFERRED: Long) << LateShift
+ final val lateFINAL = (FINAL: Long) << LateShift
+ final val lateINTERFACE = (INTERFACE: Long) << LateShift
+ final val lateMETHOD = (METHOD: Long) << LateShift
+ final val lateMODULE = (MODULE: Long) << LateShift
+
+ final val notOVERRIDE = (OVERRIDE: Long) << AntiShift
+ final val notPRIVATE = (PRIVATE: Long) << AntiShift
+ final val notPROTECTED = (PROTECTED: Long) << AntiShift
+
+ // ------- masks -----------------------------------------------------------------------
+
+ /** To be a little clearer to people who aren't habitual bit twiddlers.
+ */
+ final val AllFlags = -1L
+
+ /** These flags can be set when class or module symbol is first created.
+ * They are the only flags to survive a call to resetFlags().
+ */
+ final val TopLevelCreationFlags =
+ MODULE | PACKAGE | FINAL | JAVA
+
+ // TODO - there's no call to slap four flags onto every package.
+ final val PackageFlags = TopLevelCreationFlags
+
+ // FINAL not included here due to possibility of object overriding.
+ // In fact, FINAL should not be attached regardless. We should be able
+ // to reconstruct whether an object was marked final in source.
+ final val ModuleFlags = MODULE
+
+ /** These modifiers can be set explicitly in source programs. This is
+ * used only as the basis for the default flag mask (which ones to display
+ * when printing a normal message.)
+ */
+ final val ExplicitFlags =
+ PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED |
+ OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY
+
+ /** The two bridge flags */
+ final val BridgeFlags = BRIDGE | VBRIDGE
+ final val BridgeAndPrivateFlags = BridgeFlags | PRIVATE
+
+ /** These modifiers appear in TreePrinter output. */
+ final val PrintableFlags =
+ ExplicitFlags | BridgeFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO |
+ ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | STATIC | SPECIALIZED | SYNCHRONIZED
+
+ /** When a symbol for a field is created, only these flags survive
+ * from Modifiers. Others which may be applied at creation time are:
+ * PRIVATE, LOCAL.
+ */
+ final val FieldFlags =
+ MUTABLE | CASEACCESSOR | PARAMACCESSOR | STATIC | FINAL | PRESUPER | LAZY
+
+ /** Masks for getters and setters, where the flags are derived from those
+ * on the field's modifiers. Both getters and setters get the ACCESSOR flag.
+ * Getters of immutable values also get STABLE.
+ */
+ final val GetterFlags = ~(PRESUPER | MUTABLE)
+ final val SetterFlags = ~(PRESUPER | MUTABLE | STABLE | CASEACCESSOR)
+
+ /** When a symbol for a default getter is created, it inherits these
+ * flags from the method with the default. Other flags applied at creation
+ * time are SYNTHETIC, DEFAULTPARAM, and possibly OVERRIDE, and maybe PRESUPER.
+ */
+ final val DefaultGetterFlags = PRIVATE | PROTECTED | FINAL
+
+ /** When a symbol for a method parameter is created, only these flags survive
+ * from Modifiers. Others which may be applied at creation time are:
+ * SYNTHETIC.
+ */
+ final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM
+ final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC
+ final val VarianceFlags = COVARIANT | CONTRAVARIANT
+
+ /** These appear to be flags which should be transferred from owner symbol
+ * to a newly created constructor symbol.
+ */
+ final val ConstrFlags = JAVA
+
+ /** Module flags inherited by their module-class */
+ final val ModuleToClassFlags = AccessFlags | TopLevelCreationFlags | CASE | SYNTHETIC
+
+ def getterFlags(fieldFlags: Long): Long = ACCESSOR + (
+ if ((fieldFlags & MUTABLE) != 0) fieldFlags & ~MUTABLE & ~PRESUPER
+ else fieldFlags & ~PRESUPER | STABLE
+ )
+
+ def setterFlags(fieldFlags: Long): Long =
+ getterFlags(fieldFlags) & ~STABLE & ~CASEACCESSOR
+
+ // ------- pickling and unpickling of flags -----------------------------------------------
+
+ // The flags from 0x001 to 0x800 are different in the raw flags
+ // and in the pickled format.
+
+ private final val IMPLICIT_PKL = (1 << 0)
+ private final val FINAL_PKL = (1 << 1)
+ private final val PRIVATE_PKL = (1 << 2)
+ private final val PROTECTED_PKL = (1 << 3)
+ private final val SEALED_PKL = (1 << 4)
+ private final val OVERRIDE_PKL = (1 << 5)
+ private final val CASE_PKL = (1 << 6)
+ private final val ABSTRACT_PKL = (1 << 7)
+ private final val DEFERRED_PKL = (1 << 8)
+ private final val METHOD_PKL = (1 << 9)
+ private final val MODULE_PKL = (1 << 10)
+ private final val INTERFACE_PKL = (1 << 11)
+
+ private final val PKL_MASK = 0x00000FFF
+
+ final val PickledFlags = 0xFFFFFFFFL
+
+ private def rawPickledCorrespondence = Array(
+ (IMPLICIT, IMPLICIT_PKL),
+ (FINAL, FINAL_PKL),
+ (PRIVATE, PRIVATE_PKL),
+ (PROTECTED, PROTECTED_PKL),
+ (SEALED, SEALED_PKL),
+ (OVERRIDE, OVERRIDE_PKL),
+ (CASE, CASE_PKL),
+ (ABSTRACT, ABSTRACT_PKL),
+ (DEFERRED, DEFERRED_PKL),
+ (METHOD, METHOD_PKL),
+ (MODULE, MODULE_PKL),
+ (INTERFACE, INTERFACE_PKL)
+ )
+ private val rawFlags: Array[Int] = rawPickledCorrespondence map (_._1)
+ private val pickledFlags: Array[Int] = rawPickledCorrespondence map (_._2)
+
+ private def r2p(flags: Int): Int = {
+ var result = 0
+ var i = 0
+ while (i < rawFlags.length) {
+ if ((flags & rawFlags(i)) != 0)
+ result |= pickledFlags(i)
+
+ i += 1
+ }
+ result
+ }
+ private def p2r(flags: Int): Int = {
+ var result = 0
+ var i = 0
+ while (i < rawFlags.length) {
+ if ((flags & pickledFlags(i)) != 0)
+ result |= rawFlags(i)
+
+ i += 1
+ }
+ result
+ }
+
+ // ------ displaying flags --------------------------------------------------------
+
+ // Generated by mkFlagToStringMethod() at Thu Feb 02 20:31:52 PST 2012
+ @annotation.switch override def flagToString(flag: Long): String = flag match {
+ case PROTECTED => "protected" // (1L << 0)
+ case OVERRIDE => "override" // (1L << 1)
+ case PRIVATE => "private" // (1L << 2)
+ case ABSTRACT => "abstract" // (1L << 3)
+ case DEFERRED => "<deferred>" // (1L << 4)
+ case FINAL => "final" // (1L << 5)
+ case METHOD => "<method>" // (1L << 6)
+ case INTERFACE => "<interface>" // (1L << 7)
+ case MODULE => "<module>" // (1L << 8)
+ case IMPLICIT => "implicit" // (1L << 9)
+ case SEALED => "sealed" // (1L << 10)
+ case CASE => "case" // (1L << 11)
+ case MUTABLE => "<mutable>" // (1L << 12)
+ case PARAM => "<param>" // (1L << 13)
+ case PACKAGE => "<package>" // (1L << 14)
+ case MACRO => "<macro>" // (1L << 15)
+ case BYNAMEPARAM => "<bynameparam/captured/covariant>" // (1L << 16)
+ case CONTRAVARIANT => "<contravariant/inconstructor/label>" // (1L << 17)
+ case ABSOVERRIDE => "absoverride" // (1L << 18)
+ case LOCAL => "<local>" // (1L << 19)
+ case JAVA => "<java>" // (1L << 20)
+ case SYNTHETIC => "<synthetic>" // (1L << 21)
+ case STABLE => "<stable>" // (1L << 22)
+ case STATIC => "<static>" // (1L << 23)
+ case CASEACCESSOR => "<caseaccessor>" // (1L << 24)
+ case DEFAULTPARAM => "<defaultparam/trait>" // (1L << 25)
+ case BRIDGE => "<bridge>" // (1L << 26)
+ case ACCESSOR => "<accessor>" // (1L << 27)
+ case SUPERACCESSOR => "<superaccessor>" // (1L << 28)
+ case PARAMACCESSOR => "<paramaccessor>" // (1L << 29)
+ case MODULEVAR => "<modulevar>" // (1L << 30)
+ case LAZY => "lazy" // (1L << 31)
+ case IS_ERROR => "<is_error>" // (1L << 32)
+ case OVERLOADED => "<overloaded>" // (1L << 33)
+ case LIFTED => "<lifted>" // (1L << 34)
+ case EXISTENTIAL => "<existential/mixedin>" // (1L << 35)
+ case EXPANDEDNAME => "<expandedname>" // (1L << 36)
+ case IMPLCLASS => "<implclass/presuper>" // (1L << 37)
+ case TRANS_FLAG => "<trans_flag>" // (1L << 38)
+ case LOCKED => "<locked>" // (1L << 39)
+ case SPECIALIZED => "<specialized>" // (1L << 40)
+ case DEFAULTINIT => "<defaultinit>" // (1L << 41)
+ case VBRIDGE => "<vbridge>" // (1L << 42)
+ case VARARGS => "<varargs>" // (1L << 43)
+ case TRIEDCOOKING => "<triedcooking>" // (1L << 44)
+ case SYNCHRONIZED => "<synchronized>" // (1L << 45)
+ case 0x400000000000L => "" // (1L << 46)
+ case 0x800000000000L => "" // (1L << 47)
+ case 0x1000000000000L => "" // (1L << 48)
+ case 0x2000000000000L => "" // (1L << 49)
+ case 0x4000000000000L => "" // (1L << 50)
+ case `lateDEFERRED` => "<latedeferred>" // (1L << 51)
+ case `lateFINAL` => "<latefinal>" // (1L << 52)
+ case `lateMETHOD` => "<latemethod>" // (1L << 53)
+ case `lateINTERFACE` => "<lateinterface>" // (1L << 54)
+ case `lateMODULE` => "<latemodule>" // (1L << 55)
+ case `notPROTECTED` => "<notprotected>" // (1L << 56)
+ case `notOVERRIDE` => "<notoverride>" // (1L << 57)
+ case `notPRIVATE` => "<notprivate>" // (1L << 58)
+ case 0x800000000000000L => "" // (1L << 59)
+ case 0x1000000000000000L => "" // (1L << 60)
+ case 0x2000000000000000L => "" // (1L << 61)
+ case 0x4000000000000000L => "" // (1L << 62)
+ case 0x8000000000000000L => "" // (1L << 63)
+ case _ => ""
+ }
+
+ private def accessString(flags: Long, privateWithin: String)= (
+ if (privateWithin == "") {
+ if ((flags & PrivateLocal) == PrivateLocal) "private[this]"
+ else if ((flags & ProtectedLocal) == ProtectedLocal) "protected[this]"
+ else if ((flags & PRIVATE) != 0) "private"
+ else if ((flags & PROTECTED) != 0) "protected"
+ else ""
+ }
+ else if ((flags & PROTECTED) != 0) "protected[" + privateWithin + "]"
+ else "private[" + privateWithin + "]"
+ )
+
+ @deprecated("Use flagString on the flag-carrying member", "2.10.0")
+ def flagsToString(flags: Long, privateWithin: String): String = {
+ val access = accessString(flags, privateWithin)
+ val nonAccess = flagsToString(flags & ~AccessFlags)
+
+ List(nonAccess, access) filterNot (_ == "") mkString " "
+ }
+
+ @deprecated("Use flagString on the flag-carrying member", "2.10.0")
+ def flagsToString(flags: Long): String = {
+ // Fast path for common case
+ if (flags == 0L) "" else {
+ var sb: StringBuilder = null
+ var i = 0
+ while (i <= MaxBitPosition) {
+ val mask = rawFlagPickledOrder(i)
+ if ((flags & mask) != 0L) {
+ val s = flagToString(mask)
+ if (s.length > 0) {
+ if (sb eq null) sb = new StringBuilder append s
+ else if (sb.length == 0) sb append s
+ else sb append " " append s
+ }
+ }
+ i += 1
+ }
+ if (sb eq null) "" else sb.toString
+ }
+ }
+
+ def rawFlagsToPickled(flags: Long): Long =
+ (flags & ~PKL_MASK) | r2p(flags.toInt & PKL_MASK)
+
+ def pickledToRawFlags(pflags: Long): Long =
+ (pflags & ~PKL_MASK) | p2r(pflags.toInt & PKL_MASK)
+
+ // List of the raw flags, in pickled order
+ final val MaxBitPosition = 62
+
+ final val pickledListOrder: List[Long] = {
+ val all = 0 to MaxBitPosition map (1L << _)
+ val front = rawFlags map (_.toLong)
+
+ front.toList ++ (all filterNot (front contains _))
+ }
+ final val rawFlagPickledOrder: Array[Long] = pickledListOrder.toArray
+}
+
+object Flags extends Flags { }
diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala
new file mode 100644
index 0000000000..c7c0882209
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/HasFlags.scala
@@ -0,0 +1,169 @@
+package scala.reflect
+package internal
+
+import Flags._
+
+/** Common code utilized by Modifiers (which carry the flags associated
+ * with Trees) and Symbol.
+ */
+trait HasFlags {
+ type AccessBoundaryType
+ type AnnotationType
+
+ /** Though both Symbol and Modifiers widen this method to public, it's
+ * defined protected here to give us the option in the future to route
+ * flag methods through accessors and disallow raw flag manipulation.
+ * And after that, perhaps, on some magical day: a typesafe enumeration.
+ */
+ protected def flags: Long
+
+ /** Access level encoding: there are three scala flags (PRIVATE, PROTECTED,
+ * and LOCAL) which combine with value privateWithin (the "foo" in private[foo])
+ * to define from where an entity can be accessed. The meanings are as follows:
+ *
+ * PRIVATE access restricted to class only.
+ * PROTECTED access restricted to class and subclasses only.
+ * LOCAL can only be set in conjunction with PRIVATE or PROTECTED.
+ * Further restricts access to the same object instance.
+ *
+ * In addition, privateWithin can be used to set a visibility barrier.
+ * When set, everything contained in the named enclosing package or class
+ * has access. It is incompatible with PRIVATE or LOCAL, but is additive
+ * with PROTECTED (i.e. if either the flags or privateWithin allow access,
+ * then it is allowed.)
+ *
+ * The java access levels translate as follows:
+ *
+ * java private: hasFlag(PRIVATE) && !hasAccessBoundary
+ * java package: !hasFlag(PRIVATE | PROTECTED) && (privateWithin == enclosing package)
+ * java protected: hasFlag(PROTECTED) && (privateWithin == enclosing package)
+ * java public: !hasFlag(PRIVATE | PROTECTED) && !hasAccessBoundary
+ */
+ def privateWithin: AccessBoundaryType
+
+ /** A list of annotations attached to this entity.
+ */
+ def annotations: List[AnnotationType]
+
+ /** Whether this entity has a "privateWithin" visibility barrier attached.
+ */
+ def hasAccessBoundary: Boolean
+
+ /** Whether this entity has ANY of the flags in the given mask.
+ */
+ def hasFlag(flag: Long): Boolean
+
+ /** Whether this entity has ALL of the flags in the given mask.
+ */
+ def hasAllFlags(mask: Long): Boolean
+
+ /** Whether this entity has NONE of the flags in the given mask.
+ */
+ def hasNoFlags(mask: Long): Boolean = !hasFlag(mask)
+
+ /** The printable representation of this entity's flags and access boundary,
+ * restricted to flags in the given mask.
+ */
+ def flagString: String = flagString(flagMask)
+ def flagString(mask: Long): String = calculateFlagString(flags & mask)
+
+ /** The default mask determining which flags to display.
+ */
+ def flagMask: Long = AllFlags
+
+ /** The string representation of a single bit, seen from this
+ * flag carrying entity.
+ */
+ def resolveOverloadedFlag(flag: Long): String = Flags.flagToString(flag)
+
+ // Tests which come through cleanly: both Symbol and Modifiers use these
+ // identically, testing for a single flag.
+ def hasAbstractFlag = hasFlag(ABSTRACT)
+ def hasAccessorFlag = hasFlag(ACCESSOR)
+ def hasDefault = hasAllFlags(DEFAULTPARAM | PARAM)
+ def hasLocalFlag = hasFlag(LOCAL)
+ def hasModuleFlag = hasFlag(MODULE)
+ def hasPackageFlag = hasFlag(PACKAGE)
+ def hasStableFlag = hasFlag(STABLE)
+ def hasStaticFlag = hasFlag(STATIC)
+ def isAbstractOverride = hasFlag(ABSOVERRIDE)
+ def isAnyOverride = hasFlag(OVERRIDE | ABSOVERRIDE)
+ def isCase = hasFlag(CASE)
+ def isCaseAccessor = hasFlag(CASEACCESSOR)
+ def isDeferred = hasFlag(DEFERRED)
+ def isFinal = hasFlag(FINAL)
+ def isImplicit = hasFlag(IMPLICIT)
+ def isInterface = hasFlag(INTERFACE)
+ def isJavaDefined = hasFlag(JAVA)
+ def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag
+ def isLazy = hasFlag(LAZY)
+ def isLifted = hasFlag(LIFTED)
+ def isMutable = hasFlag(MUTABLE)
+ def isOverride = hasFlag(OVERRIDE)
+ def isParamAccessor = hasFlag(PARAMACCESSOR)
+ def isPrivate = hasFlag(PRIVATE)
+ def isPackage = hasFlag(PACKAGE)
+ def isPrivateLocal = hasAllFlags(PrivateLocal)
+ def isProtected = hasFlag(PROTECTED)
+ def isProtectedLocal = hasAllFlags(ProtectedLocal)
+ def isPublic = hasNoFlags(PRIVATE | PROTECTED) && !hasAccessBoundary
+ def isSealed = hasFlag(SEALED)
+ def isSuperAccessor = hasFlag(SUPERACCESSOR)
+ def isSynthetic = hasFlag(SYNTHETIC)
+ def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM)
+
+ def flagBitsToString(bits: Long): String = {
+ // Fast path for common case
+ if (bits == 0L) "" else {
+ var sb: StringBuilder = null
+ var i = 0
+ while (i <= MaxBitPosition) {
+ val flag = Flags.rawFlagPickledOrder(i)
+ if ((bits & flag) != 0L) {
+ val s = resolveOverloadedFlag(flag)
+ if (s.length > 0) {
+ if (sb eq null) sb = new StringBuilder append s
+ else if (sb.length == 0) sb append s
+ else sb append " " append s
+ }
+ }
+ i += 1
+ }
+ if (sb eq null) "" else sb.toString
+ }
+ }
+
+ def accessString: String = {
+ val pw = if (hasAccessBoundary) privateWithin.toString else ""
+
+ if (pw == "") {
+ if (hasAllFlags(PrivateLocal)) "private[this]"
+ else if (hasAllFlags(ProtectedLocal)) "protected[this]"
+ else if (hasFlag(PRIVATE)) "private"
+ else if (hasFlag(PROTECTED)) "protected"
+ else ""
+ }
+ else if (hasFlag(PROTECTED)) "protected[" + pw + "]"
+ else "private[" + pw + "]"
+ }
+ protected def calculateFlagString(basis: Long): String = {
+ val access = accessString
+ val nonAccess = flagBitsToString(basis & ~AccessFlags)
+
+ if (access == "") nonAccess
+ else if (nonAccess == "") access
+ else nonAccess + " " + access
+ }
+
+ // Backward compat section
+ @deprecated( "Use isTrait", "2.10.0")
+ def hasTraitFlag = hasFlag(TRAIT)
+ @deprecated("Use hasDefault", "2.10.0")
+ def hasDefaultFlag = hasFlag(DEFAULTPARAM)
+ @deprecated("Use isValueParameter or isTypeParameter", "2.10.0")
+ def isParameter = hasFlag(PARAM)
+ @deprecated("Use flagString", "2.10.0")
+ def defaultFlagString = flagString
+ @deprecated("Use flagString(mask)", "2.10.0")
+ def hasFlagsToString(mask: Long): String = flagString(mask)
+}
diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala
new file mode 100644
index 0000000000..431d9819a5
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Importers.scala
@@ -0,0 +1,451 @@
+package scala.reflect
+package internal
+import scala.collection.mutable.WeakHashMap
+
+// todo: move importers to a mirror
+trait Importers { self: SymbolTable =>
+
+ // [Eugene] possible to make this less cast-heavy?
+ def mkImporter(from0: api.Universe): Importer { val from: from0.type } = (
+ if (self eq from0) {
+ new Importer {
+ val from = from0
+ val reverse = this.asInstanceOf[from.Importer{ val from: self.type }]
+ def importSymbol(sym: from.Symbol) = sym.asInstanceOf[self.Symbol]
+ def importType(tpe: from.Type) = tpe.asInstanceOf[self.Type]
+ def importTree(tree: from.Tree) = tree.asInstanceOf[self.Tree]
+ }
+ } else {
+ // todo. fix this loophole
+ assert(from0.isInstanceOf[SymbolTable], "`from` should be an instance of scala.reflect.internal.SymbolTable")
+ new StandardImporter { val from = from0.asInstanceOf[SymbolTable] }
+ }
+ ).asInstanceOf[Importer { val from: from0.type }]
+
+ abstract class StandardImporter extends Importer {
+
+ val from: SymbolTable
+
+ lazy val symMap: WeakHashMap[from.Symbol, Symbol] = new WeakHashMap
+ lazy val tpeMap: WeakHashMap[from.Type, Type] = new WeakHashMap
+
+ // fixups and maps prevent stackoverflows in importer
+ var pendingSyms = 0
+ var pendingTpes = 0
+ lazy val fixups = collection.mutable.MutableList[Function0[Unit]]()
+ def addFixup(fixup: => Unit): Unit = fixups += (() => fixup)
+ def tryFixup(): Unit = {
+ if (pendingSyms == 0 && pendingTpes == 0) {
+ val fixups = this.fixups.toList
+ this.fixups.clear()
+ fixups foreach { _() }
+ }
+ }
+
+ object reverse extends from.StandardImporter {
+ val from: self.type = self
+ for ((fromsym, mysym) <- StandardImporter.this.symMap) symMap += ((mysym, fromsym))
+ for ((fromtpe, mytpe) <- StandardImporter.this.tpeMap) tpeMap += ((mytpe, fromtpe))
+ }
+
+ // todo. careful import of positions
+ def importPosition(pos: from.Position): Position =
+ pos.asInstanceOf[Position]
+
+ def importSymbol(sym0: from.Symbol): Symbol = {
+ def doImport(sym: from.Symbol): Symbol = {
+ if (symMap.contains(sym))
+ return symMap(sym)
+
+ val myowner = importSymbol(sym.owner)
+ val mypos = importPosition(sym.pos)
+ val myname = importName(sym.name).toTermName
+ val myflags = sym.flags
+ def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = {
+ symMap(x) = mysym
+ mysym.referenced = op(x.referenced)
+ mysym
+ }
+ val mysym = sym match {
+ case x: from.MethodSymbol =>
+ linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol)
+ case x: from.ModuleSymbol =>
+ linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, importSymbol)
+ case x: from.FreeTermSymbol =>
+ newFreeTermSymbol(importName(x.name).toTermName, importType(x.info), x.value, x.flags, x.origin)
+ case x: from.FreeTypeSymbol =>
+ newFreeTypeSymbol(importName(x.name).toTypeName, importType(x.info), x.value, x.flags, x.origin)
+ case x: from.TermSymbol =>
+ linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol)
+ case x: from.TypeSkolem =>
+ val origin = x.unpackLocation match {
+ case null => null
+ case y: from.Tree => importTree(y)
+ case y: from.Symbol => importSymbol(y)
+ }
+ myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags)
+ case x: from.ModuleClassSymbol =>
+ val mysym = myowner.newModuleClass(myname.toTypeName, mypos, myflags)
+ symMap(x) = mysym
+ mysym.sourceModule = importSymbol(x.sourceModule)
+ mysym
+ case x: from.ClassSymbol =>
+ val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags)
+ symMap(x) = mysym
+ if (sym.thisSym != sym) {
+ mysym.typeOfThis = importType(sym.typeOfThis)
+ mysym.thisSym setName importName(sym.thisSym.name)
+ }
+ mysym
+ case x: from.TypeSymbol =>
+ myowner.newTypeSymbol(myname.toTypeName, mypos, myflags)
+ }
+ symMap(sym) = mysym
+ mysym setFlag Flags.LOCKED
+ mysym setInfo {
+ val mytypeParams = sym.typeParams map importSymbol
+ new LazyPolyType(mytypeParams) {
+ override def complete(s: Symbol) {
+ val result = sym.info match {
+ case from.PolyType(_, res) => res
+ case result => result
+ }
+ s setInfo GenPolyType(mytypeParams, importType(result))
+ s setAnnotations (sym.annotations map importAnnotationInfo)
+ }
+ }
+ }
+ mysym resetFlag Flags.LOCKED
+ } // end doImport
+
+ def importOrRelink: Symbol = {
+ val sym = sym0 // makes sym visible in the debugger
+ if (sym == null)
+ null
+ else if (sym == from.NoSymbol)
+ NoSymbol
+ else if (sym.isRoot)
+ rootMirror.RootClass // !!! replace with actual mirror when we move importers to the mirror
+ else {
+ val name = sym.name
+ val owner = sym.owner
+ var scope = if (owner.isClass && !owner.isRefinementClass) owner.info else from.NoType
+ var existing = scope.decl(name)
+ if (sym.isModuleClass)
+ existing = existing.moduleClass
+
+ if (!existing.exists) scope = from.NoType
+
+ val myname = importName(name)
+ val myowner = importSymbol(owner)
+ val myscope = if (scope != from.NoType && !(myowner hasFlag Flags.LOCKED)) myowner.info else NoType
+ var myexisting = if (myscope != NoType) myowner.info.decl(myname) else NoSymbol // cannot load myexisting in general case, because it creates cycles for methods
+ if (sym.isModuleClass)
+ myexisting = importSymbol(sym.sourceModule).moduleClass
+
+ if (!sym.isOverloaded && myexisting.isOverloaded) {
+ myexisting =
+ if (sym.isMethod) {
+ val localCopy = doImport(sym)
+ myexisting filter (_.tpe matches localCopy.tpe)
+ } else {
+ myexisting filter (!_.isMethod)
+ }
+ assert(!myexisting.isOverloaded,
+ "import failure: cannot determine unique overloaded method alternative from\n "+
+ (myexisting.alternatives map (_.defString) mkString "\n")+"\n that matches "+sym+":"+sym.tpe)
+ }
+
+ val mysym = {
+ if (sym.isOverloaded) {
+ myowner.newOverloaded(myowner.thisType, sym.alternatives map importSymbol)
+ } else if (sym.isTypeParameter && sym.paramPos >= 0 && !(myowner hasFlag Flags.LOCKED)) {
+ assert(myowner.typeParams.length > sym.paramPos,
+ "import failure: cannot determine parameter "+sym+" (#"+sym.paramPos+") in "+
+ myowner+typeParamsString(myowner.rawInfo)+"\n original symbol was: "+
+ sym.owner+from.typeParamsString(sym.owner.info))
+ myowner.typeParams(sym.paramPos)
+ } else {
+ if (myexisting != NoSymbol) {
+ myexisting
+ } else {
+ val mysym = doImport(sym)
+
+ if (myscope != NoType) {
+ assert(myowner.info.decls.lookup(myname) == NoSymbol, myname+" "+myowner.info.decl(myname)+" "+myexisting)
+ myowner.info.decls enter mysym
+ }
+
+ mysym
+ }
+ }
+ }
+
+ mysym
+ }
+ } // end importOrRelink
+
+ val sym = sym0
+ if (symMap contains sym) {
+ symMap(sym)
+ } else {
+ pendingSyms += 1
+
+ try {
+ symMap getOrElseUpdate (sym, importOrRelink)
+ } finally {
+ pendingSyms -= 1
+ tryFixup()
+ }
+ }
+ }
+
+ def importType(tpe: from.Type): Type = {
+ def doImport(tpe: from.Type): Type = tpe match {
+ case from.TypeRef(pre, sym, args) =>
+ TypeRef(importType(pre), importSymbol(sym), args map importType)
+ case from.ThisType(clazz) =>
+ ThisType(importSymbol(clazz))
+ case from.SingleType(pre, sym) =>
+ SingleType(importType(pre), importSymbol(sym))
+ case from.MethodType(params, restpe) =>
+ MethodType(params map importSymbol, importType(restpe))
+ case from.PolyType(tparams, restpe) =>
+ PolyType(tparams map importSymbol, importType(restpe))
+ case from.NullaryMethodType(restpe) =>
+ NullaryMethodType(importType(restpe))
+ case from.ConstantType(constant @ from.Constant(_)) =>
+ ConstantType(importConstant(constant))
+ case from.SuperType(thistpe, supertpe) =>
+ SuperType(importType(thistpe), importType(supertpe))
+ case from.TypeBounds(lo, hi) =>
+ TypeBounds(importType(lo), importType(hi))
+ case from.BoundedWildcardType(bounds) =>
+ BoundedWildcardType(importTypeBounds(bounds))
+ case from.ClassInfoType(parents, decls, clazz) =>
+ val myclazz = importSymbol(clazz)
+ val myscope = if (myclazz.isPackageClass) newPackageScope(myclazz) else newScope
+ val myclazzTpe = ClassInfoType(parents map importType, myscope, myclazz)
+ myclazz setInfo GenPolyType(myclazz.typeParams, myclazzTpe) // needed so that newly created symbols find their scope
+ decls foreach importSymbol // will enter itself into myclazz
+ myclazzTpe
+ case from.RefinedType(parents, decls) =>
+ RefinedType(parents map importType, importScope(decls), importSymbol(tpe.typeSymbol))
+ case from.ExistentialType(tparams, restpe) =>
+ newExistentialType(tparams map importSymbol, importType(restpe))
+ case from.OverloadedType(pre, alts) =>
+ OverloadedType(importType(pre), alts map importSymbol)
+ case from.AntiPolyType(pre, targs) =>
+ AntiPolyType(importType(pre), targs map importType)
+ case x: from.TypeVar =>
+ TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol)
+ case from.NotNullType(tpe) =>
+ NotNullType(importType(tpe))
+ case from.AnnotatedType(annots, tpe, selfsym) =>
+ AnnotatedType(annots map importAnnotationInfo, importType(tpe), importSymbol(selfsym))
+ case from.ErrorType =>
+ ErrorType
+ case from.WildcardType =>
+ WildcardType
+ case from.NoType =>
+ NoType
+ case from.NoPrefix =>
+ NoPrefix
+ case null =>
+ null
+ } // end doImport
+
+ def importOrRelink: Type =
+ doImport(tpe)
+
+ if (tpeMap contains tpe) {
+ tpeMap(tpe)
+ } else {
+ pendingTpes += 1
+
+ try {
+ tpeMap getOrElseUpdate (tpe, importOrRelink)
+ } finally {
+ pendingTpes -= 1
+ tryFixup()
+ }
+ }
+ }
+
+ def importTypeBounds(bounds: from.TypeBounds) = importType(bounds).asInstanceOf[TypeBounds]
+
+ def importAnnotationInfo(ann: from.AnnotationInfo): AnnotationInfo = {
+ val atp1 = importType(ann.atp)
+ val args1 = ann.args map importTree
+ val assocs1 = ann.assocs map { case (name, arg) => (importName(name), importAnnotArg(arg)) }
+ val original1 = importTree(ann.original)
+ AnnotationInfo(atp1, args1, assocs1) setOriginal original1
+ }
+
+ def importAnnotArg(arg: from.ClassfileAnnotArg): ClassfileAnnotArg = arg match {
+ case from.LiteralAnnotArg(constant @ from.Constant(_)) =>
+ LiteralAnnotArg(importConstant(constant))
+ case from.ArrayAnnotArg(args) =>
+ ArrayAnnotArg(args map importAnnotArg)
+ case from.ScalaSigBytes(bytes) =>
+ ScalaSigBytes(bytes)
+ case from.NestedAnnotArg(annInfo) =>
+ NestedAnnotArg(importAnnotationInfo(annInfo))
+ }
+
+ def importTypeConstraint(constr: from.TypeConstraint): TypeConstraint = {
+ val result = new TypeConstraint(constr.loBounds map importType, constr.hiBounds map importType)
+ result.inst = importType(constr.inst)
+ result
+ }
+
+ // !!! todo: override to cater for PackageScopes
+ def importScope(decls: from.Scope): Scope =
+ newScopeWith(decls.toList map importSymbol: _*)
+
+ def importName(name: from.Name): Name =
+ if (name.isTypeName) newTypeName(name.toString) else newTermName(name.toString)
+ def importTypeName(name: from.TypeName): TypeName = importName(name).toTypeName
+ def importTermName(name: from.TermName): TermName = importName(name).toTermName
+
+ def importModifiers(mods: from.Modifiers): Modifiers =
+ new Modifiers(mods.flags, importName(mods.privateWithin), mods.annotations map importTree)
+
+ def importImportSelector(sel: from.ImportSelector): ImportSelector =
+ new ImportSelector(importName(sel.name), sel.namePos, if (sel.rename != null) importName(sel.rename) else null, sel.renamePos)
+
+ def importTree(tree: from.Tree): Tree = {
+ val mytree = tree match {
+ case from.ClassDef(mods, name, tparams, impl) =>
+ new ClassDef(importModifiers(mods), importName(name).toTypeName, tparams map importTypeDef, importTemplate(impl))
+ case from.PackageDef(pid, stats) =>
+ new PackageDef(importRefTree(pid), stats map importTree)
+ case from.ModuleDef(mods, name, impl) =>
+ new ModuleDef(importModifiers(mods), importName(name).toTermName, importTemplate(impl))
+ case from.emptyValDef =>
+ emptyValDef
+ case from.ValDef(mods, name, tpt, rhs) =>
+ new ValDef(importModifiers(mods), importName(name).toTermName, importTree(tpt), importTree(rhs))
+ case from.DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ new DefDef(importModifiers(mods), importName(name).toTermName, tparams map importTypeDef, mmap(vparamss)(importValDef), importTree(tpt), importTree(rhs))
+ case from.TypeDef(mods, name, tparams, rhs) =>
+ new TypeDef(importModifiers(mods), importName(name).toTypeName, tparams map importTypeDef, importTree(rhs))
+ case from.LabelDef(name, params, rhs) =>
+ new LabelDef(importName(name).toTermName, params map importIdent, importTree(rhs))
+ case from.Import(expr, selectors) =>
+ new Import(importTree(expr), selectors map importImportSelector)
+ case from.Template(parents, self, body) =>
+ new Template(parents map importTree, importValDef(self), body map importTree)
+ case from.Block(stats, expr) =>
+ new Block(stats map importTree, importTree(expr))
+ case from.CaseDef(pat, guard, body) =>
+ new CaseDef(importTree(pat), importTree(guard), importTree(body))
+ case from.Alternative(trees) =>
+ new Alternative(trees map importTree)
+ case from.Star(elem) =>
+ new Star(importTree(elem))
+ case from.Bind(name, body) =>
+ new Bind(importName(name), importTree(body))
+ case from.UnApply(fun, args) =>
+ new UnApply(importTree(fun), args map importTree)
+ case from.ArrayValue(elemtpt ,elems) =>
+ new ArrayValue(importTree(elemtpt), elems map importTree)
+ case from.Function(vparams, body) =>
+ new Function(vparams map importValDef, importTree(body))
+ case from.Assign(lhs, rhs) =>
+ new Assign(importTree(lhs), importTree(rhs))
+ case from.AssignOrNamedArg(lhs, rhs) =>
+ new AssignOrNamedArg(importTree(lhs), importTree(rhs))
+ case from.If(cond, thenp, elsep) =>
+ new If(importTree(cond), importTree(thenp), importTree(elsep))
+ case from.Match(selector, cases) =>
+ new Match(importTree(selector), cases map importCaseDef)
+ case from.Return(expr) =>
+ new Return(importTree(expr))
+ case from.Try(block, catches, finalizer) =>
+ new Try(importTree(block), catches map importCaseDef, importTree(finalizer))
+ case from.Throw(expr) =>
+ new Throw(importTree(expr))
+ case from.New(tpt) =>
+ new New(importTree(tpt))
+ case from.Typed(expr, tpt) =>
+ new Typed(importTree(expr), importTree(tpt))
+ case from.TypeApply(fun, args) =>
+ new TypeApply(importTree(fun), args map importTree)
+ case from.Apply(fun, args) => tree match {
+ case _: from.ApplyToImplicitArgs =>
+ new ApplyToImplicitArgs(importTree(fun), args map importTree)
+ case _: from.ApplyImplicitView =>
+ new ApplyImplicitView(importTree(fun), args map importTree)
+ case _ =>
+ new Apply(importTree(fun), args map importTree)
+ }
+ case from.ApplyDynamic(qual, args) =>
+ new ApplyDynamic(importTree(qual), args map importTree)
+ case from.Super(qual, mix) =>
+ new Super(importTree(qual), importTypeName(mix))
+ case from.This(qual) =>
+ new This(importName(qual).toTypeName)
+ case from.Select(qual, name) =>
+ new Select(importTree(qual), importName(name))
+ case from.Ident(name) =>
+ new Ident(importName(name))
+ case from.ReferenceToBoxed(ident) =>
+ new ReferenceToBoxed(importTree(ident) match { case ident: Ident => ident })
+ case from.Literal(constant @ from.Constant(_)) =>
+ new Literal(importConstant(constant))
+ case from.TypeTree() =>
+ new TypeTree()
+ case from.Annotated(annot, arg) =>
+ new Annotated(importTree(annot), importTree(arg))
+ case from.SingletonTypeTree(ref) =>
+ new SingletonTypeTree(importTree(ref))
+ case from.SelectFromTypeTree(qual, name) =>
+ new SelectFromTypeTree(importTree(qual), importName(name).toTypeName)
+ case from.CompoundTypeTree(templ) =>
+ new CompoundTypeTree(importTemplate(templ))
+ case from.AppliedTypeTree(tpt, args) =>
+ new AppliedTypeTree(importTree(tpt), args map importTree)
+ case from.TypeBoundsTree(lo, hi) =>
+ new TypeBoundsTree(importTree(lo), importTree(hi))
+ case from.ExistentialTypeTree(tpt, whereClauses) =>
+ new ExistentialTypeTree(importTree(tpt), whereClauses map importTree)
+ case from.EmptyTree =>
+ EmptyTree
+ case null =>
+ null
+ }
+ addFixup({
+ if (mytree != null) {
+ val mysym = if (tree.hasSymbol) importSymbol(tree.symbol) else NoSymbol
+ val mytpe = importType(tree.tpe)
+
+ mytree match {
+ case mytt: TypeTree =>
+ val tt = tree.asInstanceOf[from.TypeTree]
+ if (mytree.hasSymbol) mytt.symbol = mysym
+ if (tt.wasEmpty) mytt.defineType(mytpe) else mytt.setType(mytpe)
+ if (tt.original != null) mytt.setOriginal(importTree(tt.original))
+ case _ =>
+ if (mytree.hasSymbol) mytree.symbol = importSymbol(tree.symbol)
+ mytree.tpe = importType(tree.tpe)
+ }
+ }
+ })
+ tryFixup()
+ mytree
+ }
+
+ def importValDef(tree: from.ValDef): ValDef = importTree(tree).asInstanceOf[ValDef]
+ def importTypeDef(tree: from.TypeDef): TypeDef = importTree(tree).asInstanceOf[TypeDef]
+ def importTemplate(tree: from.Template): Template = importTree(tree).asInstanceOf[Template]
+ def importRefTree(tree: from.RefTree): RefTree = importTree(tree).asInstanceOf[RefTree]
+ def importIdent(tree: from.Ident): Ident = importTree(tree).asInstanceOf[Ident]
+ def importCaseDef(tree: from.CaseDef): CaseDef = importTree(tree).asInstanceOf[CaseDef]
+ def importConstant(constant: from.Constant): Constant = new Constant(constant.tag match {
+ case ClazzTag => importType(constant.value.asInstanceOf[from.Type])
+ case EnumTag => importSymbol(constant.value.asInstanceOf[from.Symbol])
+ case _ => constant.value
+ })
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/InfoTransformers.scala b/src/reflect/scala/reflect/internal/InfoTransformers.scala
new file mode 100644
index 0000000000..e53f714c0c
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/InfoTransformers.scala
@@ -0,0 +1,51 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+trait InfoTransformers {
+ self: SymbolTable =>
+
+ /* Syncnote: This should not need to be protected, as reflection does not run in multiple phases.
+ */
+ abstract class InfoTransformer {
+ var prev: InfoTransformer = this
+ var next: InfoTransformer = this
+
+ val pid: Phase#Id
+ val changesBaseClasses: Boolean
+ def transform(sym: Symbol, tpe: Type): Type
+
+ def insert(that: InfoTransformer) {
+ assert(this.pid != that.pid, this.pid)
+
+ if (that.pid < this.pid) {
+ prev insert that
+ } else if (next.pid <= that.pid && next.pid != NoPhase.id) {
+ next insert that
+ } else {
+ log("Inserting info transformer %s following %s".format(phaseOf(that.pid), phaseOf(this.pid)))
+ that.next = next
+ that.prev = this
+ next.prev = that
+ this.next = that
+ }
+ }
+
+ /** The InfoTransformer whose (pid == from).
+ * If no such exists, the InfoTransformer with the next
+ * higher pid.
+ */
+ def nextFrom(from: Phase#Id): InfoTransformer =
+ if (from == this.pid) this
+ else if (from < this.pid)
+ if (prev.pid < from) this
+ else prev.nextFrom(from);
+ else if (next.pid == NoPhase.id) next
+ else next.nextFrom(from)
+ }
+}
+
diff --git a/src/reflect/scala/reflect/internal/Kinds.scala b/src/reflect/scala/reflect/internal/Kinds.scala
new file mode 100644
index 0000000000..b736a9192f
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Kinds.scala
@@ -0,0 +1,232 @@
+/* NSC -- new scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable }
+import scala.reflect.internal.util.StringOps.{ countAsString, countElementsAsString }
+
+trait Kinds {
+ self: SymbolTable =>
+
+ import definitions._
+
+ private type SymPair = ((Symbol, Symbol)) // ((Argument, Parameter))
+
+ case class KindErrors(
+ arity: List[SymPair] = Nil,
+ variance: List[SymPair] = Nil,
+ strictness: List[SymPair] = Nil
+ ) {
+ def isEmpty = arity.isEmpty && variance.isEmpty && strictness.isEmpty
+
+ def arityError(syms: SymPair) = copy(arity = arity :+ syms)
+ def varianceError(syms: SymPair) = copy(variance = variance :+ syms)
+ def strictnessError(syms: SymPair) = copy(strictness = strictness :+ syms)
+
+ def ++(errs: KindErrors) = KindErrors(
+ arity ++ errs.arity,
+ variance ++ errs.variance,
+ strictness ++ errs.strictness
+ )
+ // @M TODO this method is duplicated all over the place (varianceString)
+ private def varStr(s: Symbol): String =
+ if (s.isCovariant) "covariant"
+ else if (s.isContravariant) "contravariant"
+ else "invariant";
+
+ private def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else {
+ if((a0 eq b0) || (a0.owner eq b0.owner)) ""
+ else {
+ var a = a0; var b = b0
+ while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner}
+ if (a.locationString ne "") " (" + a.locationString.trim + ")" else ""
+ }
+ }
+ private def kindMessage(a: Symbol, p: Symbol)(f: (String, String) => String): String =
+ f(a+qualify(a,p), p+qualify(p,a))
+
+ // Normally it's nicer to print nothing rather than '>: Nothing <: Any' all over
+ // the place, but here we need it for the message to make sense.
+ private def strictnessMessage(a: Symbol, p: Symbol) =
+ kindMessage(a, p)("%s's bounds%s are stricter than %s's declared bounds%s".format(
+ _, a.info, _, p.info match {
+ case tb @ TypeBounds(_, _) if tb.isEmptyBounds => " >: Nothing <: Any"
+ case tb => "" + tb
+ })
+ )
+
+ private def varianceMessage(a: Symbol, p: Symbol) =
+ kindMessage(a, p)("%s is %s, but %s is declared %s".format(_, varStr(a), _, varStr(p)))
+
+ private def arityMessage(a: Symbol, p: Symbol) =
+ kindMessage(a, p)("%s has %s, but %s has %s".format(
+ _, countElementsAsString(a.typeParams.length, "type parameter"),
+ _, countAsString(p.typeParams.length))
+ )
+
+ private def buildMessage(xs: List[SymPair], f: (Symbol, Symbol) => String) = (
+ if (xs.isEmpty) ""
+ else xs map f.tupled mkString ("\n", ", ", "")
+ )
+
+ def errorMessage(targ: Type, tparam: Symbol): String = (
+ (targ+"'s type parameters do not match "+tparam+"'s expected parameters:")
+ + buildMessage(arity, arityMessage)
+ + buildMessage(variance, varianceMessage)
+ + buildMessage(strictness, strictnessMessage)
+ )
+ }
+ val NoKindErrors = KindErrors(Nil, Nil, Nil)
+
+ // TODO: this desperately needs to be cleaned up
+ // plan: split into kind inference and subkinding
+ // every Type has a (cached) Kind
+ def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean =
+ checkKindBounds0(tparams, targs, pre, owner, false).isEmpty
+
+ /** Check whether `sym1`'s variance conforms to `sym2`'s variance.
+ *
+ * If `sym2` is invariant, `sym1`'s variance is irrelevant. Otherwise they must be equal.
+ */
+ private def variancesMatch(sym1: Symbol, sym2: Symbol) = (
+ sym2.variance==0
+ || sym1.variance==sym2.variance
+ )
+
+ /** Check well-kindedness of type application (assumes arities are already checked) -- @M
+ *
+ * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1
+ * (checked one type member at a time -- in that case, prefix is the name of the type alias)
+ *
+ * Type application is just like value application: it's "contravariant" in the sense that
+ * the type parameters of the supplied type arguments must conform to the type parameters of
+ * the required type parameters:
+ * - their bounds must be less strict
+ * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters)
+ * - @M TODO: are these conditions correct,sufficient&necessary?
+ *
+ * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since
+ * List's type parameter is also covariant and its bounds are weaker than <: Int
+ */
+ def checkKindBounds0(
+ tparams: List[Symbol],
+ targs: List[Type],
+ pre: Type,
+ owner: Symbol,
+ explainErrors: Boolean
+ ): List[(Type, Symbol, KindErrors)] = {
+
+ // instantiate type params that come from outside the abstract type we're currently checking
+ def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz)
+
+ // check that the type parameters hkargs to a higher-kinded type conform to the
+ // expected params hkparams
+ def checkKindBoundsHK(
+ hkargs: List[Symbol],
+ arg: Symbol,
+ param: Symbol,
+ paramowner: Symbol,
+ underHKParams: List[Symbol],
+ withHKArgs: List[Symbol]
+ ): KindErrors = {
+
+ var kindErrors: KindErrors = NoKindErrors
+ def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs)
+ // @M sometimes hkargs != arg.typeParams, the symbol and the type may
+ // have very different type parameters
+ val hkparams = param.typeParams
+
+ def kindCheck(cond: Boolean, f: KindErrors => KindErrors) {
+ if (!cond)
+ kindErrors = f(kindErrors)
+ }
+
+ if (settings.debug.value) {
+ log("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner)
+ log("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner)
+ log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs)
+ }
+
+ if (!sameLength(hkargs, hkparams)) {
+ // Any and Nothing are kind-overloaded
+ if (arg == AnyClass || arg == NothingClass) NoKindErrors
+ // shortcut: always set error, whether explainTypesOrNot
+ else return kindErrors.arityError(arg -> param)
+ }
+ else foreach2(hkargs, hkparams) { (hkarg, hkparam) =>
+ if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind *
+ kindCheck(variancesMatch(hkarg, hkparam), _ varianceError (hkarg -> hkparam))
+ // instantiateTypeParams(tparams, targs)
+ // higher-order bounds, may contain references to type arguments
+ // substSym(hkparams, hkargs)
+ // these types are going to be compared as types of kind *
+ //
+ // Their arguments use different symbols, but are
+ // conceptually the same. Could also replace the types by
+ // polytypes, but can't just strip the symbols, as ordering
+ // is lost then.
+ val declaredBounds = transform(hkparam.info.instantiateTypeParams(tparams, targs).bounds, paramowner)
+ val declaredBoundsInst = transform(bindHKParams(declaredBounds), owner)
+ val argumentBounds = transform(hkarg.info.bounds, owner)
+
+ kindCheck(declaredBoundsInst <:< argumentBounds, _ strictnessError (hkarg -> hkparam))
+
+ debuglog(
+ "checkKindBoundsHK base case: " + hkparam +
+ " declared bounds: " + declaredBounds +
+ " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" +
+ "checkKindBoundsHK base case: "+ hkarg +
+ " has bounds: " + argumentBounds
+ )
+ }
+ else {
+ debuglog("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg)
+ kindErrors ++= checkKindBoundsHK(
+ hkarg.typeParams,
+ hkarg,
+ hkparam,
+ paramowner,
+ underHKParams ++ hkparam.typeParams,
+ withHKArgs ++ hkarg.typeParams
+ )
+ }
+ if (!explainErrors && !kindErrors.isEmpty)
+ return kindErrors
+ }
+ if (explainErrors) kindErrors
+ else NoKindErrors
+ }
+
+ if (settings.debug.value && (tparams.nonEmpty || targs.nonEmpty)) log(
+ "checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", "
+ + owner + ", " + explainErrors + ")"
+ )
+
+ flatMap2(tparams, targs) { (tparam, targ) =>
+ // Prevent WildcardType from causing kind errors, as typevars may be higher-order
+ if (targ == WildcardType) Nil else {
+ // force symbol load for #4205
+ targ.typeSymbolDirect.info
+ // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!!
+ val tparamsHO = targ.typeParams
+ if (targ.isHigherKinded || tparam.typeParams.nonEmpty) {
+ // NOTE: *not* targ.typeSymbol, which normalizes
+ val kindErrors = checkKindBoundsHK(
+ tparamsHO, targ.typeSymbolDirect, tparam,
+ tparam.owner, tparam.typeParams, tparamsHO
+ )
+ if (kindErrors.isEmpty) Nil else {
+ if (explainErrors) List((targ, tparam, kindErrors))
+ // Return as soon as an error is seen if there's nothing to explain.
+ else return List((NoType, NoSymbol, NoKindErrors))
+ }
+ }
+ else Nil
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
new file mode 100644
index 0000000000..e3680b14d5
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -0,0 +1,243 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import Flags._
+
+trait Mirrors extends api.Mirrors {
+ self: SymbolTable =>
+
+ override type Mirror >: Null <: RootsBase
+
+ abstract class RootsBase(rootOwner: Symbol) extends MirrorOf[Mirrors.this.type] { thisMirror =>
+
+ protected[scala] def rootLoader: LazyType
+
+ val RootClass: ClassSymbol
+ val RootPackage: ModuleSymbol
+ val EmptyPackageClass: ClassSymbol
+ val EmptyPackage: ModuleSymbol
+
+ def findMemberFromRoot(fullName: Name): Symbol = {
+ val segs = nme.segments(fullName.toString, fullName.isTermName)
+ if (segs.isEmpty) NoSymbol
+ else definitions.findNamedMember(segs.tail, RootClass.info member segs.head)
+ }
+
+ /** Todo: organize similar to mkStatic in reflect.Base */
+ private def getModuleOrClass(path: Name, len: Int): Symbol = {
+ val point = path lastPos('.', len - 1)
+ val owner =
+ if (point > 0) getModuleOrClass(path.toTermName, point)
+ else RootClass
+ val name = path subName (point + 1, len)
+ val sym = owner.info member name
+ val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym
+ if (result != NoSymbol) result
+ else {
+ if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug
+ mirrorMissingHook(owner, name) orElse symbolTableMissingHook(owner, name) orElse {
+ MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path+" in "+thisMirror)
+ }
+ }
+ }
+
+ protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol
+
+ protected def symbolTableMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name)
+
+ /** If you're looking for a class, pass a type name.
+ * If a module, a term name.
+ */
+ private def getModuleOrClass(path: Name): Symbol = getModuleOrClass(path, path.length)
+
+ override def staticClass(fullName: String): ClassSymbol = getRequiredClass(fullName)
+
+ // todo: get rid of most creation methods and keep just staticClass/Module/Package
+
+ def getClassByName(fullname: Name): ClassSymbol = {
+ var result = getModuleOrClass(fullname.toTypeName)
+ while (result.isAliasType) result = result.info.typeSymbol
+ result match {
+ case x: ClassSymbol => x
+ case _ => MissingRequirementError.notFound("class " + fullname)
+ }
+ }
+
+ override def staticModule(fullName: String): ModuleSymbol = getRequiredModule(fullName)
+
+ def getModule(fullname: Name): ModuleSymbol =
+ // [Eugene++] should be a ClassCastException instead?
+ getModuleOrClass(fullname.toTermName) match {
+ case x: ModuleSymbol => x
+ case _ => MissingRequirementError.notFound("object " + fullname)
+ }
+
+ def getPackage(fullname: Name): ModuleSymbol = getModule(fullname)
+
+ def getRequiredPackage(fullname: String): ModuleSymbol =
+ getPackage(newTermNameCached(fullname))
+
+ @deprecated("Use getClassByName", "2.10.0")
+ def getClass(fullname: Name): ClassSymbol = getClassByName(fullname)
+
+ def getRequiredClass(fullname: String): ClassSymbol =
+ getClassByName(newTypeNameCached(fullname)) match {
+ case x: ClassSymbol => x
+ case _ => MissingRequirementError.notFound("class " + fullname)
+ }
+
+ def getRequiredModule(fullname: String): ModuleSymbol =
+ getModule(newTermNameCached(fullname))
+
+ def erasureName[T: ClassTag] : String = {
+ /** We'd like the String representation to be a valid
+ * scala type, so we have to decode the jvm's secret language.
+ */
+ def erasureString(clazz: Class[_]): String = {
+ if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]"
+ else clazz.getName
+ }
+ erasureString(classTag[T].runtimeClass)
+ }
+
+ def requiredClass[T: ClassTag] : ClassSymbol =
+ getRequiredClass(erasureName[T])
+
+ // TODO: What syntax do we think should work here? Say you have an object
+ // like scala.Predef. You can't say requiredModule[scala.Predef] since there's
+ // no accompanying Predef class, and if you say requiredModule[scala.Predef.type]
+ // the name found via the erasure is scala.Predef$. For now I am
+ // removing the trailing $, but I think that classTag should have
+ // a method which returns a usable name, one which doesn't expose this
+ // detail of the backend.
+ def requiredModule[T: ClassTag] : ModuleSymbol =
+ getRequiredModule(erasureName[T] stripSuffix "$")
+
+ def getClassIfDefined(fullname: String): Symbol =
+ getClassIfDefined(newTypeName(fullname))
+
+ def getClassIfDefined(fullname: Name): Symbol =
+ wrapMissing(getClassByName(fullname.toTypeName))
+
+ def getModuleIfDefined(fullname: String): Symbol =
+ getModuleIfDefined(newTermName(fullname))
+
+ def getModuleIfDefined(fullname: Name): Symbol =
+ wrapMissing(getModule(fullname.toTermName))
+
+ def getPackageObject(fullname: String): ModuleSymbol =
+ (getModule(newTermName(fullname)).info member nme.PACKAGE) match {
+ case x: ModuleSymbol => x
+ case _ => MissingRequirementError.notFound("package object " + fullname)
+ }
+
+ def getPackageObjectIfDefined(fullname: String): Symbol = {
+ val module = getModuleIfDefined(newTermName(fullname))
+ if (module == NoSymbol) NoSymbol
+ else {
+ val packageObject = module.info member nme.PACKAGE
+ packageObject match {
+ case x: ModuleSymbol => x
+ case _ => NoSymbol
+ }
+ }
+ }
+
+ @inline private def wrapMissing(body: => Symbol): Symbol =
+ try body
+ catch { case _: MissingRequirementError => NoSymbol }
+
+ /** getModule2/getClass2 aren't needed at present but may be again,
+ * so for now they're mothballed.
+ */
+ // def getModule2(name1: Name, name2: Name) = {
+ // try getModuleOrClass(name1.toTermName)
+ // catch { case ex1: FatalError =>
+ // try getModuleOrClass(name2.toTermName)
+ // catch { case ex2: FatalError => throw ex1 }
+ // }
+ // }
+ // def getClass2(name1: Name, name2: Name) = {
+ // try {
+ // val result = getModuleOrClass(name1.toTypeName)
+ // if (result.isAliasType) getClass(name2) else result
+ // }
+ // catch { case ex1: FatalError =>
+ // try getModuleOrClass(name2.toTypeName)
+ // catch { case ex2: FatalError => throw ex1 }
+ // }
+ // }
+
+ def init() {
+ // Still fiddling with whether it's cleaner to do some of this setup here
+ // or from constructors. The latter approach tends to invite init order issues.
+
+ EmptyPackageClass setInfo ClassInfoType(Nil, newPackageScope(EmptyPackageClass), EmptyPackageClass)
+ EmptyPackage setInfo EmptyPackageClass.tpe
+
+ connectModuleToClass(EmptyPackage, EmptyPackageClass)
+ connectModuleToClass(RootPackage, RootClass)
+
+ RootClass.info.decls enter EmptyPackage
+ RootClass.info.decls enter RootPackage
+ }
+ }
+
+ abstract class Roots(rootOwner: Symbol) extends RootsBase(rootOwner) { thisMirror =>
+
+ // TODO - having these as objects means they elude the attempt to
+ // add synchronization in SynchronizedSymbols. But we should either
+ // flip on object overrides or find some other accomodation, because
+ // lazy vals are unnecessarily expensive relative to objects and it
+ // is very beneficial for a handful of bootstrap symbols to have
+ // first class identities
+ sealed trait WellKnownSymbol extends Symbol {
+ this initFlags TopLevelCreationFlags
+ }
+ // Features common to RootClass and RootPackage, the roots of all
+ // type and term symbols respectively.
+ sealed trait RootSymbol extends WellKnownSymbol {
+ final override def isRootSymbol = true
+ override def owner = rootOwner
+ override def typeOfThis = thisSym.tpe
+ }
+
+ // 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 {
+ this setInfo NullaryMethodType(RootClass.tpe)
+ RootClass.sourceModule = this
+
+ override def isRootPackage = true
+ }
+ // 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
+
+ override def isRoot = true
+ override def isEffectiveRoot = true
+ override def isStatic = true
+ override def isNestedClass = false
+ override def ownerOfNewSymbols = EmptyPackageClass
+ }
+ // 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 {
+ override def isEmptyPackage = true
+ }
+ final object EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
+ override def isEffectiveRoot = true
+ override def isEmptyPackageClass = true
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/MissingRequirementError.scala b/src/reflect/scala/reflect/internal/MissingRequirementError.scala
new file mode 100644
index 0000000000..fbbbcc1928
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/MissingRequirementError.scala
@@ -0,0 +1,24 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+class MissingRequirementError private (msg: String) extends FatalError(msg) {
+ import MissingRequirementError.suffix
+ def req: String = if (msg endsWith suffix) msg dropRight suffix.length else msg
+}
+
+object MissingRequirementError {
+ private val suffix = " not found."
+ def signal(msg: String): Nothing = throw new MissingRequirementError(msg)
+ def notFound(req: String): Nothing = signal(req + suffix)
+ def unapply(x: Throwable): Option[String] = x match {
+ case x: MissingRequirementError => Some(x.req)
+ case _ => None
+ }
+}
+
+
diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala
new file mode 100644
index 0000000000..18671871ae
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Names.scala
@@ -0,0 +1,527 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import scala.io.Codec
+import java.security.MessageDigest
+import language.implicitConversions
+
+/** The class Names ...
+ *
+ * @author Martin Odersky
+ * @version 1.0, 05/02/2005
+ */
+trait Names extends api.Names {
+ implicit def promoteTermNamesAsNecessary(name: Name): TermName = name.toTermName
+
+// Operations -------------------------------------------------------------
+
+ private final val HASH_SIZE = 0x8000
+ private final val HASH_MASK = 0x7FFF
+ private final val NAME_SIZE = 0x20000
+
+ final val nameDebug = false
+
+ /** Memory to store all names sequentially. */
+ var chrs: Array[Char] = new Array[Char](NAME_SIZE)
+ private var nc = 0
+
+ /** Hashtable for finding term names quickly. */
+ private val termHashtable = new Array[TermName](HASH_SIZE)
+
+ /** Hashtable for finding type names quickly. */
+ private val typeHashtable = new Array[TypeName](HASH_SIZE)
+
+ /** The hashcode of a name. */
+ private def hashValue(cs: Array[Char], offset: Int, len: Int): Int =
+ if (len > 0)
+ (len * (41 * 41 * 41) +
+ cs(offset) * (41 * 41) +
+ cs(offset + len - 1) * 41 +
+ cs(offset + (len >> 1)))
+ else 0;
+
+ /** Is (the ASCII representation of) name at given index equal to
+ * cs[offset..offset+len-1]?
+ */
+ private def equals(index: Int, cs: Array[Char], offset: Int, len: Int): Boolean = {
+ var i = 0
+ while ((i < len) && (chrs(index + i) == cs(offset + i)))
+ i += 1;
+ i == len
+ }
+
+ /** Enter characters into chrs array. */
+ private def enterChars(cs: Array[Char], offset: Int, len: Int) {
+ var i = 0
+ while (i < len) {
+ if (nc + i == chrs.length) {
+ val newchrs = new Array[Char](chrs.length * 2)
+ compat.Platform.arraycopy(chrs, 0, newchrs, 0, chrs.length)
+ chrs = newchrs
+ }
+ chrs(nc + i) = cs(offset + i)
+ i += 1
+ }
+ if (len == 0) nc += 1
+ else nc = nc + len
+ }
+
+ /** Create a term name from the characters in cs[offset..offset+len-1]. */
+ def newTermName(cs: Array[Char], offset: Int, len: Int): TermName =
+ newTermName(cs, offset, len, cachedString = null)
+
+ def newTermName(cs: Array[Char]): TermName = newTermName(cs, 0, cs.length)
+ def newTypeName(cs: Array[Char]): TypeName = newTypeName(cs, 0, cs.length)
+
+ /** Create a term name from the characters in cs[offset..offset+len-1].
+ * TODO - have a mode where name validation is performed at creation time
+ * (e.g. if a name has the string "$class" in it, then fail if that
+ * string is not at the very end.)
+ */
+ protected def newTermName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TermName = {
+ val h = hashValue(cs, offset, len) & HASH_MASK
+ var n = termHashtable(h)
+ while ((n ne null) && (n.length != len || !equals(n.start, cs, offset, len)))
+ n = n.next
+
+ if (n ne null) n
+ else {
+ // The logic order here is future-proofing against the possibility
+ // that name.toString will become an eager val, in which case the call
+ // to enterChars cannot follow the construction of the TermName.
+ val ncStart = nc
+ enterChars(cs, offset, len)
+ if (cachedString ne null) new TermName_S(ncStart, len, h, cachedString)
+ else new TermName_R(ncStart, len, h)
+ }
+ }
+ protected def newTypeName(cs: Array[Char], offset: Int, len: Int, cachedString: String): TypeName =
+ newTermName(cs, offset, len, cachedString).toTypeName
+
+ /** Create a term name from string. */
+ def newTermName(s: String): TermName = newTermName(s.toCharArray(), 0, s.length(), null)
+
+ /** Create a type name from string. */
+ def newTypeName(s: String): TypeName = newTermName(s).toTypeName
+
+ /** Create a term name from the UTF8 encoded bytes in bs[offset..offset+len-1]. */
+ def newTermName(bs: Array[Byte], offset: Int, len: Int): TermName = {
+ val chars = Codec.fromUTF8(bs, offset, len)
+ newTermName(chars, 0, chars.length)
+ }
+
+ def newTermNameCached(s: String): TermName =
+ newTermName(s.toCharArray(), 0, s.length(), cachedString = s)
+
+ def newTypeNameCached(s: String): TypeName =
+ newTypeName(s.toCharArray(), 0, s.length(), cachedString = s)
+
+ /** Create a type name from the characters in cs[offset..offset+len-1]. */
+ def newTypeName(cs: Array[Char], offset: Int, len: Int): TypeName =
+ newTermName(cs, offset, len, cachedString = null).toTypeName
+
+ /** Create a type name from the UTF8 encoded bytes in bs[offset..offset+len-1]. */
+ def newTypeName(bs: Array[Byte], offset: Int, len: Int): TypeName =
+ newTermName(bs, offset, len).toTypeName
+
+ def nameChars: Array[Char] = chrs
+ @deprecated("", "2.9.0") def view(s: String): TermName = newTermName(s)
+
+// Classes ----------------------------------------------------------------------
+
+ /** The name class.
+ * TODO - resolve schizophrenia regarding whether to treat Names as Strings
+ * or Strings as Names. Give names the key functions the absence of which
+ * make people want Strings all the time.
+ */
+ sealed abstract class Name(protected val index: Int, protected val len: Int) extends NameApi with Function1[Int, Char] {
+ type ThisNameType >: Null <: Name
+ protected[this] def thisName: ThisNameType
+
+ /** Index into name table */
+ def start: Int = index
+
+ /** The next name in the same hash bucket. */
+ def next: ThisNameType
+
+ /** The length of this name. */
+ final def length: Int = len
+ final def isEmpty = length == 0
+ final def nonEmpty = !isEmpty
+
+ def nameKind: String
+ def isTermName: Boolean
+ def isTypeName: Boolean
+ def toTermName: TermName
+ def toTypeName: TypeName
+ def companionName: Name
+ def bothNames: List[Name] = List(toTermName, toTypeName)
+
+ /** Return the subname with characters from from to to-1. */
+ def subName(from: Int, to: Int): ThisNameType
+
+ /** Return a new name of the same variety. */
+ def newName(str: String): ThisNameType
+
+ /** Return a new name based on string transformation. */
+ def mapName(f: String => String): ThisNameType = newName(f(toString))
+
+ /** Copy bytes of this name to buffer cs, starting at position `offset`. */
+ final def copyChars(cs: Array[Char], offset: Int) =
+ compat.Platform.arraycopy(chrs, index, cs, offset, len)
+
+ /** @return the ascii representation of this name */
+ final def toChars: Array[Char] = {
+ val cs = new Array[Char](len)
+ copyChars(cs, 0)
+ cs
+ }
+
+ /** Write to UTF8 representation of this name to given character array.
+ * Start copying to index `to`. Return index of next free byte in array.
+ * Array must have enough remaining space for all bytes
+ * (i.e. maximally 3*length bytes).
+ */
+ final def copyUTF8(bs: Array[Byte], offset: Int): Int = {
+ val bytes = Codec.toUTF8(chrs, index, len)
+ compat.Platform.arraycopy(bytes, 0, bs, offset, bytes.length)
+ offset + bytes.length
+ }
+
+ /** @return the hash value of this name */
+ final override def hashCode(): Int = index
+
+ // Presently disabled.
+ // override def equals(other: Any) = paranoidEquals(other)
+ private def paranoidEquals(other: Any): Boolean = {
+ val cmp = this eq other.asInstanceOf[AnyRef]
+ if (cmp || !nameDebug)
+ return cmp
+
+ other match {
+ case x: String =>
+ Console.println("Compared " + debugString + " and String '" + x + "'")
+ case x: Name =>
+ if (this.isTermName != x.isTermName) {
+ val panic = this.toTermName == x.toTermName
+ Console.println("Compared '%s' and '%s', one term, one type.%s".format(this, x,
+ if (panic) " And they contain the same name string!"
+ else ""
+ ))
+ }
+ case _ =>
+ }
+ false
+ }
+
+ /** @return the i'th Char of this name */
+ final def apply(i: Int): Char = chrs(index + i)
+
+ /** @return the index of first occurrence of char c in this name, length if not found */
+ final def pos(c: Char): Int = pos(c, 0)
+
+ /** @return the index of first occurrence of char c in this name, length if not found */
+ final def pos(s: String): Int = pos(s, 0)
+
+ /** Returns the index of the first occurrence of character c in
+ * this name from start, length if not found.
+ *
+ * @param c the character
+ * @param start ...
+ * @return the index of the first occurrence of c
+ */
+ final def pos(c: Char, start: Int): Int = {
+ var i = start
+ while (i < len && chrs(index + i) != c) i += 1
+ i
+ }
+
+ /** Returns the index of the first occurrence of nonempty string s
+ * in this name from start, length if not found.
+ *
+ * @param s the string
+ * @param start ...
+ * @return the index of the first occurrence of s
+ */
+ final def pos(s: String, start: Int): Int = {
+ var i = pos(s.charAt(0), start)
+ while (i + s.length() <= len) {
+ var j = 1
+ while (s.charAt(j) == chrs(index + i + j)) {
+ j += 1
+ if (j == s.length()) return i
+ }
+ i = pos(s.charAt(0), i + 1)
+ }
+ len
+ }
+
+ /** Returns the index of last occurrence of char c in this
+ * name, -1 if not found.
+ *
+ * @param c the character
+ * @return the index of the last occurrence of c
+ */
+ final def lastPos(c: Char): Int = lastPos(c, len - 1)
+
+ final def lastPos(s: String): Int = lastPos(s, len - s.length)
+
+ /** Returns the index of the last occurrence of char c in this
+ * name from start, -1 if not found.
+ *
+ * @param c the character
+ * @param start ...
+ * @return the index of the last occurrence of c
+ */
+ final def lastPos(c: Char, start: Int): Int = {
+ var i = start
+ while (i >= 0 && chrs(index + i) != c) i -= 1
+ i
+ }
+
+ /** Returns the index of the last occurrence of string s in this
+ * name from start, -1 if not found.
+ *
+ * @param s the string
+ * @param start ...
+ * @return the index of the last occurrence of s
+ */
+ final def lastPos(s: String, start: Int): Int = {
+ var i = lastPos(s.charAt(0), start)
+ while (i >= 0) {
+ var j = 1;
+ while (s.charAt(j) == chrs(index + i + j)) {
+ j += 1
+ if (j == s.length()) return i;
+ }
+ i = lastPos(s.charAt(0), i - 1)
+ }
+ -s.length()
+ }
+
+ /** Does this name start with prefix? */
+ final def startsWith(prefix: Name): Boolean = startsWith(prefix, 0)
+
+ /** Does this name start with prefix at given start index? */
+ final def startsWith(prefix: Name, start: Int): Boolean = {
+ var i = 0
+ while (i < prefix.length && start + i < len &&
+ chrs(index + start + i) == chrs(prefix.start + i))
+ i += 1;
+ i == prefix.length
+ }
+
+ /** Does this name end with suffix? */
+ final def endsWith(suffix: Name): Boolean = endsWith(suffix, len)
+
+ /** Does this name end with suffix just before given end index? */
+ final def endsWith(suffix: Name, end: Int): Boolean = {
+ var i = 1
+ while (i <= suffix.length && i <= end &&
+ chrs(index + end - i) == chrs(suffix.start + suffix.length - i))
+ i += 1;
+ i > suffix.length
+ }
+
+ final def containsName(subname: String): Boolean = containsName(newTermName(subname))
+ final def containsName(subname: Name): Boolean = {
+ var start = 0
+ val last = len - subname.length
+ while (start <= last && !startsWith(subname, start)) start += 1
+ start <= last
+ }
+ final def containsChar(ch: Char): Boolean = {
+ var i = index
+ val max = index + len
+ while (i < max) {
+ if (chrs(i) == ch)
+ return true
+ i += 1
+ }
+ false
+ }
+
+ /** Some thoroughly self-explanatory convenience functions. They
+ * assume that what they're being asked to do is known to be valid.
+ */
+ final def startChar: Char = apply(0)
+ final def endChar: Char = apply(len - 1)
+ final def startsWith(char: Char): Boolean = len > 0 && startChar == char
+ final def startsWith(name: String): Boolean = startsWith(newTermName(name))
+ final def endsWith(char: Char): Boolean = len > 0 && endChar == char
+ final def endsWith(name: String): Boolean = endsWith(newTermName(name))
+
+ def dropRight(n: Int): ThisNameType = subName(0, len - n)
+ def drop(n: Int): ThisNameType = subName(n, len)
+ def stripSuffix(suffix: Name): ThisNameType =
+ if (this endsWith suffix) dropRight(suffix.length) else thisName
+
+ def indexOf(ch: Char) = {
+ val idx = pos(ch)
+ if (idx == length) -1 else idx
+ }
+ def indexOf(ch: Char, fromIndex: Int) = {
+ val idx = pos(ch, fromIndex)
+ if (idx == length) -1 else idx
+ }
+ def lastIndexOf(ch: Char) = lastPos(ch)
+ def lastIndexOf(ch: Char, fromIndex: Int) = lastPos(ch, fromIndex)
+
+ /** Replace all occurrences of `from` by `to` in
+ * name; result is always a term name.
+ */
+ def replace(from: Char, to: Char): Name = {
+ val cs = new Array[Char](len)
+ var i = 0
+ while (i < len) {
+ val ch = this(i)
+ cs(i) = if (ch == from) to else ch
+ i += 1
+ }
+ newTermName(cs, 0, len)
+ }
+
+ /** TODO - reconcile/fix that encode returns a Name but
+ * decode returns a String.
+ */
+
+ /** !!! Duplicative but consistently named.
+ */
+ def decoded: String = decode
+ def encoded: String = "" + encode
+ // def decodedName: ThisNameType = newName(decoded)
+ def encodedName: ThisNameType = encode
+
+ /** Replace operator symbols by corresponding \$op_name. */
+ def encode: ThisNameType = {
+ val str = toString
+ val res = NameTransformer.encode(str)
+ if (res == str) thisName else newName(res)
+ }
+
+ /** Replace \$op_name by corresponding operator symbol. */
+ def decode: String = {
+ if (this containsChar '$') {
+ val str = toString
+ val res = NameTransformer.decode(str)
+ if (res == str) str
+ else res
+ }
+ else toString
+ }
+
+ /** TODO - find some efficiency. */
+ def append(ch: Char) = newName("" + this + ch)
+ def append(suffix: String) = newName("" + this + suffix)
+ def append(suffix: Name) = newName("" + this + suffix)
+ def prepend(ch: Char) = newName("" + ch + this)
+ def prepend(prefix: String) = newName("" + prefix + this)
+ def prepend(prefix: Name) = newName("" + prefix + this)
+
+ def decodedName: ThisNameType = newName(decode)
+ def isOperatorName: Boolean = decode != toString
+ def longString: String = nameKind + " " + decode
+ def debugString = { val s = decode ; if (isTypeName) s + "!" else s }
+ }
+
+ implicit val NameTag = ClassTag[Name](classOf[Name])
+
+ /** A name that contains no operator chars nor dollar signs.
+ * TODO - see if it's any faster to do something along these lines.
+ * Cute: now that exhaustivity kind of works, the mere presence of
+ * this trait causes TermName and TypeName to stop being exhaustive.
+ * Commented out.
+ */
+ // trait AlphaNumName extends Name {
+ // final override def encode = thisName
+ // final override def decodedName = thisName
+ // final override def decode = toString
+ // final override def isOperatorName = false
+ // }
+
+ /** TermName_S and TypeName_S have fields containing the string version of the name.
+ * TermName_R and TypeName_R recreate it each time toString is called.
+ */
+ private class TermName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TermName(index0, len0, hash) {
+ protected def createCompanionName(h: Int): TypeName = new TypeName_S(index, len, h, toString)
+ override def newName(str: String): TermName = newTermNameCached(str)
+ }
+ private class TypeName_S(index0: Int, len0: Int, hash: Int, override val toString: String) extends TypeName(index0, len0, hash) {
+ protected def createCompanionName(h: Int): TermName = new TermName_S(index, len, h, toString)
+ override def newName(str: String): TypeName = newTypeNameCached(str)
+ }
+
+ private class TermName_R(index0: Int, len0: Int, hash: Int) extends TermName(index0, len0, hash) {
+ protected def createCompanionName(h: Int): TypeName = new TypeName_R(index, len, h)
+ override def toString = new String(chrs, index, len)
+ }
+
+ private class TypeName_R(index0: Int, len0: Int, hash: Int) extends TypeName(index0, len0, hash) {
+ protected def createCompanionName(h: Int): TermName = new TermName_R(index, len, h)
+ override def toString = new String(chrs, index, len)
+ }
+
+ sealed abstract class TermName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) {
+ type ThisNameType = TermName
+ protected[this] def thisName: TermName = this
+
+ var next: TermName = termHashtable(hash)
+ termHashtable(hash) = this
+ def isTermName: Boolean = true
+ def isTypeName: Boolean = false
+ def toTermName: TermName = this
+ def toTypeName: TypeName = {
+ val h = hashValue(chrs, index, len) & HASH_MASK
+ var n = typeHashtable(h)
+ while ((n ne null) && n.start != index)
+ n = n.next
+
+ if (n ne null) n
+ else createCompanionName(h)
+ }
+ def newName(str: String): TermName = newTermName(str)
+ def companionName: TypeName = toTypeName
+ def subName(from: Int, to: Int): TermName =
+ newTermName(chrs, start + from, to - from)
+
+ def nameKind = "term"
+ protected def createCompanionName(h: Int): TypeName
+ }
+
+ implicit val TermNameTag = ClassTag[TermName](classOf[TermName])
+
+ sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) {
+ type ThisNameType = TypeName
+ protected[this] def thisName: TypeName = this
+
+ var next: TypeName = typeHashtable(hash)
+ typeHashtable(hash) = this
+ def isTermName: Boolean = false
+ def isTypeName: Boolean = true
+ def toTermName: TermName = {
+ val h = hashValue(chrs, index, len) & HASH_MASK
+ var n = termHashtable(h)
+ while ((n ne null) && n.start != index)
+ n = n.next
+
+ if (n ne null) n
+ else createCompanionName(h)
+ }
+ def toTypeName: TypeName = this
+ def newName(str: String): TypeName = newTypeName(str)
+ def companionName: TermName = toTermName
+ def subName(from: Int, to: Int): TypeName =
+ newTypeName(chrs, start + from, to - from)
+
+ def nameKind = "type"
+ override def decode = if (nameDebug) super.decode + "!" else super.decode
+ protected def createCompanionName(h: Int): TermName
+ }
+
+ implicit val TypeNameTag = ClassTag[TypeName](classOf[TypeName])
+}
diff --git a/src/reflect/scala/reflect/internal/Phase.scala b/src/reflect/scala/reflect/internal/Phase.scala
new file mode 100644
index 0000000000..68dc5ce783
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Phase.scala
@@ -0,0 +1,66 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+abstract class Phase(val prev: Phase) {
+ if ((prev ne null) && (prev ne NoPhase))
+ prev.nx = this
+
+ type Id = Int
+ val id: Id = if (prev eq null) 0 else prev.id + 1
+
+ /** New flags visible after this phase has completed */
+ def nextFlags: Long = 0l
+
+ /** New flags visible once this phase has started */
+ def newFlags: Long = 0l
+
+ val fmask = (
+ if (prev eq null) Flags.InitialFlags
+ else prev.flagMask | prev.nextFlags | newFlags
+ )
+ def flagMask: Long = fmask
+
+ private var nx: Phase = this
+
+ def next: Phase = nx
+ def hasNext = next != this
+ def iterator = Iterator.iterate(this)(_.next) takeWhile (p => p.next != p)
+
+ def name: String
+ def description: String = name
+ // Will running with -Ycheck:name work?
+ def checkable: Boolean = true
+ def specialized: Boolean = false
+ def erasedTypes: Boolean = false
+ def flatClasses: Boolean = false
+ def refChecked: Boolean = false
+
+ /** This is used only in unsafeTypeParams, and at this writing is
+ * overridden to false in parser, namer, typer, and erasure. (And NoPhase.)
+ */
+ def keepsTypeParams = true
+ def run(): Unit
+
+ override def toString() = name
+ override def hashCode = id.## + name.##
+ override def equals(other: Any) = other match {
+ case x: Phase => id == x.id && name == x.name
+ case _ => false
+ }
+}
+
+object NoPhase extends Phase(null) {
+ def name = "<no phase>"
+ override def keepsTypeParams = false
+ def run() { throw new Error("NoPhase.run") }
+}
+
+object SomePhase extends Phase(NoPhase) {
+ def name = "<some phase>"
+ def run() { throw new Error("SomePhase.run") }
+}
diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala
new file mode 100644
index 0000000000..6ae9b40fcb
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Positions.scala
@@ -0,0 +1,63 @@
+package scala.reflect
+package internal
+
+trait Positions extends api.Positions { self: SymbolTable =>
+
+ type Position = scala.reflect.internal.util.Position
+ val NoPosition = scala.reflect.internal.util.NoPosition
+ implicit val PositionTag = ClassTag[Position](classOf[Position])
+
+ /** A position that wraps a set of trees.
+ * The point of the wrapping position is the point of the default position.
+ * If some of the trees are ranges, returns a range position enclosing all ranges
+ * Otherwise returns default position.
+ */
+ def wrappingPos(default: Position, trees: List[Tree]): Position = default
+
+ /** A position that wraps the non-empty set of trees.
+ * The point of the wrapping position is the point of the first trees' position.
+ * If all some the trees are non-synthetic, returns a range position enclosing the non-synthetic trees
+ * Otherwise returns a synthetic offset position to point.
+ */
+ def wrappingPos(trees: List[Tree]): Position = trees.head.pos
+
+ /** Ensure that given tree has no positions that overlap with
+ * any of the positions of `others`. This is done by
+ * shortening the range or assigning TransparentPositions
+ * to some of the nodes in `tree`.
+ */
+ def ensureNonOverlapping(tree: Tree, others: List[Tree]) {}
+
+ trait PosAssigner extends Traverser {
+ var pos: Position
+ }
+ protected[this] lazy val posAssigner: PosAssigner = new DefaultPosAssigner
+
+ protected class DefaultPosAssigner extends PosAssigner {
+ var pos: Position = _
+ override def traverse(t: Tree) {
+ if (t eq EmptyTree) ()
+ else if (t.pos == NoPosition) {
+ t.setPos(pos)
+ super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if?
+ // @PP: it's pruning whenever it encounters a node with a
+ // position, which I interpret to mean that (in the author's
+ // mind at least) either the children of a positioned node will
+ // already be positioned, or the children of a positioned node
+ // do not merit positioning.
+ //
+ // Whatever the author's rationale, it does seem like a bad idea
+ // to press on through a positioned node to find unpositioned
+ // children beneath it and then to assign whatever happens to
+ // be in `pos` to such nodes. There are supposed to be some
+ // position invariants which I can't imagine surviving that.
+ }
+ }
+ }
+
+ def atPos[T <: Tree](pos: Position)(tree: T): T = {
+ posAssigner.pos = pos
+ posAssigner.traverse(tree)
+ tree
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/Required.scala b/src/reflect/scala/reflect/internal/Required.scala
new file mode 100644
index 0000000000..abbe8fbfb7
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Required.scala
@@ -0,0 +1,17 @@
+package scala.reflect
+package internal
+
+import settings.MutableSettings
+
+trait Required { self: SymbolTable =>
+
+ type AbstractFileType >: Null <: AbstractFileApi
+
+ def picklerPhase: Phase
+
+ def settings: MutableSettings
+
+ def forInteractive: Boolean
+
+ def forScaladoc: Boolean
+}
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
new file mode 100644
index 0000000000..ceacd2afb0
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -0,0 +1,359 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+trait Scopes extends api.Scopes { self: SymbolTable =>
+
+ class ScopeEntry(val sym: Symbol, val owner: Scope) {
+ /** the next entry in the hash bucket
+ */
+ var tail: ScopeEntry = null
+
+ /** the next entry in this scope
+ */
+ var next: ScopeEntry = null
+
+ override def hashCode(): Int = sym.name.start
+ override def toString(): String = sym.toString()
+ }
+
+ /**
+ * @param sym ...
+ * @param owner ...
+ * @return ...
+ */
+ private def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = {
+ val e = new ScopeEntry(sym, owner)
+ e.next = owner.elems
+ owner.elems = e
+ e
+ }
+
+ object Scope {
+ def unapplySeq(decls: Scope): Some[Seq[Symbol]] = Some(decls.toList)
+ }
+
+ /** Note: constructor is protected to force everyone to use the factory methods newScope or newNestedScope instead.
+ * This is necessary because when run from reflection every scope needs to have a
+ * SynchronizedScope as mixin.
+ */
+ class Scope protected[Scopes] (initElems: ScopeEntry = null) extends Iterable[Symbol] {
+
+ protected[Scopes] def this(base: Scope) = {
+ this(base.elems)
+ nestinglevel = base.nestinglevel + 1
+ }
+
+ private[scala] var elems: ScopeEntry = initElems
+
+ /** The number of times this scope is nested in another
+ */
+ private var nestinglevel = 0
+
+ /** the hash table
+ */
+ private var hashtable: Array[ScopeEntry] = null
+
+ /** a cache for all elements, to be used by symbol iterator.
+ */
+ private var elemsCache: List[Symbol] = null
+
+ /** size and mask of hash tables
+ * todo: make hashtables grow?
+ */
+ private val HASHSIZE = 0x80
+ private val HASHMASK = 0x7f
+
+ /** the threshold number of entries from which a hashtable is constructed.
+ */
+ private val MIN_HASH = 8
+
+ if (size >= MIN_HASH) createHash()
+
+ /** Returns a new scope with the same content as this one. */
+ def cloneScope: Scope = newScopeWith(this.toList: _*)
+
+ /** is the scope empty? */
+ override def isEmpty: Boolean = elems eq null
+
+ /** the number of entries in this scope */
+ override def size: Int = {
+ var s = 0
+ var e = elems
+ while (e ne null) {
+ s += 1
+ e = e.next
+ }
+ s
+ }
+
+ /** enter a scope entry
+ *
+ * @param e ...
+ */
+ protected def enter(e: ScopeEntry) {
+ elemsCache = null
+ if (hashtable ne null)
+ enterInHash(e)
+ else if (size >= MIN_HASH)
+ createHash()
+ }
+
+ private def enterInHash(e: ScopeEntry): Unit = {
+ val i = e.sym.name.start & HASHMASK
+ e.tail = hashtable(i)
+ hashtable(i) = e
+ }
+
+ /** enter a symbol
+ *
+ * @param sym ...
+ */
+ def enter[T <: Symbol](sym: T): T = { enter(newScopeEntry(sym, this)); sym }
+
+ /** enter a symbol, asserting that no symbol with same name exists in scope
+ *
+ * @param sym ...
+ */
+ def enterUnique(sym: Symbol) {
+ assert(lookup(sym.name) == NoSymbol, (sym.fullLocationString, lookup(sym.name).fullLocationString))
+ enter(sym)
+ }
+
+ private def createHash() {
+ hashtable = new Array[ScopeEntry](HASHSIZE)
+ enterAllInHash(elems)
+ }
+
+ private def enterAllInHash(e: ScopeEntry, n: Int = 0) {
+ if (e ne null) {
+ if (n < maxRecursions) {
+ enterAllInHash(e.next, n + 1)
+ enterInHash(e)
+ } else {
+ var entries: List[ScopeEntry] = List()
+ var ee = e
+ while (ee ne null) {
+ entries = ee :: entries
+ ee = ee.next
+ }
+ entries foreach enterInHash
+ }
+ }
+ }
+
+ def rehash(sym: Symbol, newname: Name) {
+ if (hashtable ne null) {
+ val index = sym.name.start & HASHMASK
+ var e1 = hashtable(index)
+ var e: ScopeEntry = null
+ if (e1 != null) {
+ if (e1.sym == sym) {
+ hashtable(index) = e1.tail
+ e = e1
+ } else {
+ while (e1.tail != null && e1.tail.sym != sym) e1 = e1.tail
+ if (e1.tail != null) {
+ e = e1.tail
+ e1.tail = e.tail
+ }
+ }
+ }
+ if (e != null) {
+ val newindex = newname.start & HASHMASK
+ e.tail = hashtable(newindex)
+ hashtable(newindex) = e
+ }
+ }
+ }
+
+ /** remove entry
+ *
+ * @param e ...
+ */
+ def unlink(e: ScopeEntry) {
+ if (elems == e) {
+ elems = e.next
+ } else {
+ var e1 = elems
+ while (e1.next != e) e1 = e1.next
+ e1.next = e.next
+ }
+ if (hashtable ne null) {
+ val index = e.sym.name.start & HASHMASK
+ var e1 = hashtable(index)
+ if (e1 == e) {
+ hashtable(index) = e.tail
+ } else {
+ while (e1.tail != e) e1 = e1.tail;
+ e1.tail = e.tail
+ }
+ }
+ elemsCache = null
+ }
+
+ /** remove symbol */
+ def unlink(sym: Symbol) {
+ var e = lookupEntry(sym.name)
+ while (e ne null) {
+ if (e.sym == sym) unlink(e);
+ e = lookupNextEntry(e)
+ }
+ }
+
+ /** lookup a symbol
+ *
+ * @param name ...
+ * @return ...
+ */
+ def lookup(name: Name): Symbol = {
+ val e = lookupEntry(name)
+ if (e eq null) NoSymbol else e.sym
+ }
+
+ /** Returns an iterator yielding every symbol with given name in this scope.
+ */
+ def lookupAll(name: Name): Iterator[Symbol] = new Iterator[Symbol] {
+ var e = lookupEntry(name)
+ def hasNext: Boolean = e ne null
+ def next(): Symbol = { val r = e.sym; e = lookupNextEntry(e); r }
+ }
+
+ /** lookup a symbol entry matching given name.
+ * @note from Martin: I believe this is a hotspot or will be one
+ * in future versions of the type system. I have reverted the previous
+ * change to use iterators as too costly.
+ */
+ def lookupEntry(name: Name): ScopeEntry = {
+ var e: ScopeEntry = null
+ if (hashtable ne null) {
+ e = hashtable(name.start & HASHMASK)
+ while ((e ne null) && e.sym.name != name) {
+ e = e.tail
+ }
+ } else {
+ e = elems
+ while ((e ne null) && e.sym.name != name) {
+ e = e.next
+ }
+ }
+ e
+ }
+
+ /** lookup next entry with same name as this one
+ * @note from Martin: I believe this is a hotspot or will be one
+ * in future versions of the type system. I have reverted the previous
+ * change to use iterators as too costly.
+ */
+ def lookupNextEntry(entry: ScopeEntry): ScopeEntry = {
+ var e = entry
+ if (hashtable ne null)
+ do { e = e.tail } while ((e ne null) && e.sym.name != entry.sym.name)
+ else
+ do { e = e.next } while ((e ne null) && e.sym.name != entry.sym.name);
+ e
+ }
+
+ /** Return all symbols as a list in the order they were entered in this scope.
+ */
+ override def toList: List[Symbol] = {
+ if (elemsCache eq null) {
+ elemsCache = Nil
+ var e = elems
+ while ((e ne null) && e.owner == this) {
+ elemsCache = e.sym :: elemsCache
+ e = e.next
+ }
+ }
+ elemsCache
+ }
+
+ /** Return the nesting level of this scope, i.e. the number of times this scope
+ * was nested in another */
+ def nestingLevel = nestinglevel
+
+ /** Return all symbols as an iterator in the order they were entered in this scope.
+ */
+ def iterator: Iterator[Symbol] = toList.iterator
+
+/*
+ /** Does this scope contain an entry for `sym`?
+ */
+ def contains(sym: Symbol): Boolean = lookupAll(sym.name) contains sym
+
+ /** A scope that contains all symbols of this scope and that also contains `sym`.
+ */
+ def +(sym: Symbol): Scope =
+ if (contains(sym)) this
+ else {
+ val result = cloneScope
+ result enter sym
+ result
+ }
+
+ /** A scope that contains all symbols of this scope except `sym`.
+ */
+ def -(sym: Symbol): Scope =
+ if (!contains(sym)) this
+ else {
+ val result = cloneScope
+ result unlink sym
+ result
+ }
+*/
+ override def foreach[U](p: Symbol => U): Unit = toList foreach p
+
+ override def filter(p: Symbol => Boolean): Scope =
+ if (!(toList forall p)) newScopeWith(toList filter p: _*) else this
+
+ override def mkString(start: String, sep: String, end: String) =
+ toList.map(_.defString).mkString(start, sep, end)
+
+ override def toString(): String = mkString("Scope{\n ", ";\n ", "\n}")
+
+ }
+
+ implicit val ScopeTag = ClassTag[Scope](classOf[Scope])
+
+ /** Create a new scope */
+ def newScope: Scope = new Scope()
+
+ /** Create a new scope nested in another one with which it shares its elements */
+ def newNestedScope(outer: Scope): Scope = new Scope(outer)
+
+ /** Create a new scope with given initial elements */
+ def newScopeWith(elems: Symbol*): Scope = {
+ val scope = newScope
+ elems foreach scope.enter
+ scope
+ }
+
+ /** Create new scope for the members of package `pkg` */
+ def newPackageScope(pkgClass: Symbol): Scope = newScope
+
+ /** Transform scope of members of `owner` using operation `op`
+ * This is overridden by the reflective compiler to avoid creating new scopes for packages
+ */
+ def scopeTransform(owner: Symbol)(op: => Scope): Scope = op
+
+
+ /** The empty scope (immutable).
+ */
+ object EmptyScope extends Scope {
+ override def enter(e: ScopeEntry) {
+ abort("EmptyScope.enter")
+ }
+ }
+
+ /** The error scope.
+ */
+ class ErrorScope(owner: Symbol) extends Scope
+
+ private final val maxRecursions = 1000
+
+}
+
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
new file mode 100644
index 0000000000..4ea9b27da9
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -0,0 +1,12 @@
+package scala.reflect
+package internal
+
+trait StdAttachments {
+ self: SymbolTable =>
+
+ case object BackquotedIdentifierAttachment
+
+ case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree])
+
+ case class MacroExpansionAttachment(original: Tree)
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/StdCreators.scala b/src/reflect/scala/reflect/internal/StdCreators.scala
new file mode 100644
index 0000000000..3e6b7c1ab4
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/StdCreators.scala
@@ -0,0 +1,21 @@
+package scala.reflect
+package internal
+
+import scala.reflect.base.{TreeCreator, TypeCreator}
+import scala.reflect.base.{Universe => BaseUniverse}
+
+trait StdCreators {
+ self: SymbolTable =>
+
+ case class FixedMirrorTreeCreator(mirror: MirrorOf[StdCreators.this.type], tree: Tree) extends TreeCreator {
+ def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Tree =
+ if (m eq mirror) tree.asInstanceOf[U # Tree]
+ else throw new IllegalArgumentException(s"Expr defined in $mirror cannot be migrated to other mirrors.")
+ }
+
+ case class FixedMirrorTypeCreator(mirror: MirrorOf[StdCreators.this.type], tpe: Type) extends TypeCreator {
+ def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type =
+ if (m eq mirror) tpe.asInstanceOf[U # Type]
+ else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
new file mode 100644
index 0000000000..6f68b8f63a
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -0,0 +1,1218 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import java.security.MessageDigest
+import Chars.isOperatorPart
+import annotation.switch
+import language.implicitConversions
+import scala.collection.immutable
+import scala.io.Codec
+
+trait StdNames {
+ self: SymbolTable =>
+
+ def encode(str: String): TermName = newTermNameCached(NameTransformer.encode(str))
+
+ implicit def lowerTermNames(n: TermName): String = n.toString
+
+ /** Tensions: would like the keywords to be the very first names entered into the names
+ * storage so their ids count from 0, which simplifies the parser. Switched to abstract
+ * classes to avoid all the indirection which is generated with implementation-containing
+ * traits. Since all these classes use eager vals, that means the constructor with the
+ * keywords must run first. If it's the top in the superclass chain, then CommonNames
+ * must inherit from it, which means TypeNames would inherit keywords as well.
+ *
+ * Solution: Keywords extends CommonNames and uses early defs to beat the
+ * CommonNames constructor out of the starting gate. This is its builder.
+ */
+ private class KeywordSetBuilder {
+ private var kws: Set[TermName] = Set()
+ def apply(s: String): TermName = {
+ val result = newTermNameCached(s)
+ kws = kws + result
+ result
+ }
+ def result: Set[TermName] = {
+ val result = kws
+ kws = null
+ result
+ }
+ }
+
+ private final object compactify extends (String => String) {
+ val md5 = MessageDigest.getInstance("MD5")
+
+ /**
+ * COMPACTIFY
+ *
+ * The hashed name has the form (prefix + marker + md5 + marker + suffix), where
+ * - prefix/suffix.length = MaxNameLength / 4
+ * - md5.length = 32
+ *
+ * We obtain the formula:
+ *
+ * FileNameLength = 2*(MaxNameLength / 4) + 2.marker.length + 32 + 6
+ *
+ * (+6 for ".class"). MaxNameLength can therefore be computed as follows:
+ */
+ val marker = "$$$$"
+ val MaxNameLength = math.min(
+ settings.maxClassfileName.value - 6,
+ 2 * (settings.maxClassfileName.value - 6 - 2*marker.length - 32)
+ )
+ def toMD5(s: String, edge: Int): String = {
+ val prefix = s take edge
+ val suffix = s takeRight edge
+
+ val cs = s.toArray
+ val bytes = Codec toUTF8 cs
+ md5 update bytes
+ val md5chars = (md5.digest() map (b => (b & 0xFF).toHexString)).mkString
+
+ prefix + marker + md5chars + marker + suffix
+ }
+ def apply(s: String): String = (
+ if (s.length <= MaxNameLength) s
+ else toMD5(s, MaxNameLength / 4)
+ )
+ }
+
+ abstract class CommonNames extends NamesApi {
+ type NameType >: Null <: Name
+ protected implicit def createNameType(name: String): NameType
+
+ def flattenedName(segments: Name*): NameType =
+ compactify(segments mkString NAME_JOIN_STRING)
+
+ val MODULE_SUFFIX_STRING: String = NameTransformer.MODULE_SUFFIX_STRING
+ val NAME_JOIN_STRING: String = NameTransformer.NAME_JOIN_STRING
+ val SINGLETON_SUFFIX: String = ".type"
+
+ val ANON_CLASS_NAME: NameType = "$anon"
+ val ANON_FUN_NAME: NameType = "$anonfun"
+ val EMPTY: NameType = ""
+ val EMPTY_PACKAGE_NAME: NameType = "<empty>"
+ val IMPL_CLASS_SUFFIX = "$class"
+ val IMPORT: NameType = "<import>"
+ val MODULE_SUFFIX_NAME: NameType = MODULE_SUFFIX_STRING
+ val MODULE_VAR_SUFFIX: NameType = "$module"
+ val NAME_JOIN_NAME: NameType = NAME_JOIN_STRING
+ val PACKAGE: NameType = "package"
+ val ROOT: NameType = "<root>"
+ val SPECIALIZED_SUFFIX: NameType = "$sp"
+
+ // value types (and AnyRef) are all used as terms as well
+ // as (at least) arguments to the @specialize annotation.
+ final val Boolean: NameType = "Boolean"
+ final val Byte: NameType = "Byte"
+ final val Char: NameType = "Char"
+ final val Double: NameType = "Double"
+ final val Float: NameType = "Float"
+ final val Int: NameType = "Int"
+ final val Long: NameType = "Long"
+ final val Short: NameType = "Short"
+ final val Unit: NameType = "Unit"
+
+ final val ScalaValueNames: scala.List[NameType] =
+ scala.List(Byte, Char, Short, Int, Long, Float, Double, Boolean, Unit)
+
+ // some types whose companions we utilize
+ final val AnyRef: NameType = "AnyRef"
+ final val Array: NameType = "Array"
+ final val List: NameType = "List"
+ final val Seq: NameType = "Seq"
+ final val Symbol: NameType = "Symbol"
+ final val ClassTag: NameType = "ClassTag"
+ final val TypeTag : NameType = "TypeTag"
+ final val ConcreteTypeTag: NameType = "ConcreteTypeTag"
+ final val Expr: NameType = "Expr"
+ final val String: NameType = "String"
+
+ // fictions we use as both types and terms
+ final val ERROR: NameType = "<error>"
+ final val NO_NAME: NameType = "<none>" // formerly NOSYMBOL
+ final val WILDCARD: NameType = "_"
+ }
+
+ /** This should be the first trait in the linearization. */
+ // abstract class Keywords extends CommonNames {
+ abstract class Keywords extends {
+ private val kw = new KeywordSetBuilder
+
+ final val ABSTRACTkw: TermName = kw("abstract")
+ final val CASEkw: TermName = kw("case")
+ final val CLASSkw: TermName = kw("class")
+ final val CATCHkw: TermName = kw("catch")
+ final val DEFkw: TermName = kw("def")
+ final val DOkw: TermName = kw("do")
+ final val ELSEkw: TermName = kw("else")
+ final val EXTENDSkw: TermName = kw("extends")
+ final val FALSEkw: TermName = kw("false")
+ final val FINALkw: TermName = kw("final")
+ final val FINALLYkw: TermName = kw("finally")
+ final val FORkw: TermName = kw("for")
+ final val FORSOMEkw: TermName = kw("forSome")
+ final val IFkw: TermName = kw("if")
+ final val IMPLICITkw: TermName = kw("implicit")
+ final val IMPORTkw: TermName = kw("import")
+ final val LAZYkw: TermName = kw("lazy")
+ final val MACROkw: TermName = kw("macro")
+ final val MATCHkw: TermName = kw("match")
+ final val NEWkw: TermName = kw("new")
+ final val NULLkw: TermName = kw("null")
+ final val OBJECTkw: TermName = kw("object")
+ final val OVERRIDEkw: TermName = kw("override")
+ final val PACKAGEkw: TermName = kw("package")
+ final val PRIVATEkw: TermName = kw("private")
+ final val PROTECTEDkw: TermName = kw("protected")
+ final val RETURNkw: TermName = kw("return")
+ final val SEALEDkw: TermName = kw("sealed")
+ final val SUPERkw: TermName = kw("super")
+ final val THENkw: TermName = kw("then")
+ final val THISkw: TermName = kw("this")
+ final val THROWkw: TermName = kw("throw")
+ final val TRAITkw: TermName = kw("trait")
+ final val TRUEkw: TermName = kw("true")
+ final val TRYkw: TermName = kw("try")
+ final val TYPEkw: TermName = kw("type")
+ final val VALkw: TermName = kw("val")
+ final val VARkw: TermName = kw("var")
+ final val WITHkw: TermName = kw("with")
+ final val WHILEkw: TermName = kw("while")
+ final val YIELDkw: TermName = kw("yield")
+ final val DOTkw: TermName = kw(".")
+ final val USCOREkw: TermName = kw("_")
+ final val COLONkw: TermName = kw(":")
+ final val EQUALSkw: TermName = kw("=")
+ final val ARROWkw: TermName = kw("=>")
+ final val LARROWkw: TermName = kw("<-")
+ final val SUBTYPEkw: TermName = kw("<:")
+ final val VIEWBOUNDkw: TermName = kw("<%")
+ final val SUPERTYPEkw: TermName = kw(">:")
+ final val HASHkw: TermName = kw("#")
+ final val ATkw: TermName = kw("@")
+
+ final val keywords = kw.result
+ } with CommonNames {
+ final val javaKeywords = new JavaKeywords()
+ }
+
+ abstract class TypeNames extends Keywords with TypeNamesApi {
+ type NameType = TypeName
+ protected implicit def createNameType(name: String): TypeName = newTypeNameCached(name)
+
+ final val BYNAME_PARAM_CLASS_NAME: NameType = "<byname>"
+ final val EQUALS_PATTERN_NAME: NameType = "<equals>"
+ final val JAVA_REPEATED_PARAM_CLASS_NAME: NameType = "<repeated...>"
+ final val LOCAL_CHILD: NameType = "<local child>"
+ final val REFINE_CLASS_NAME: NameType = "<refinement>"
+ final val REPEATED_PARAM_CLASS_NAME: NameType = "<repeated>"
+ final val WILDCARD_STAR: NameType = "_*"
+ final val REIFY_TREECREATOR_PREFIX: NameType = "$treecreator"
+ final val REIFY_TYPECREATOR_PREFIX: NameType = "$typecreator"
+
+ final val Any: NameType = "Any"
+ final val AnyVal: NameType = "AnyVal"
+ final val ExprApi: NameType = "ExprApi"
+ final val Mirror: NameType = "Mirror"
+ final val Nothing: NameType = "Nothing"
+ final val Null: NameType = "Null"
+ final val Object: NameType = "Object"
+ final val PartialFunction: NameType = "PartialFunction"
+ final val PrefixType: NameType = "PrefixType"
+ final val Product: NameType = "Product"
+ final val Serializable: NameType = "Serializable"
+ final val Singleton: NameType = "Singleton"
+ final val Throwable: NameType = "Throwable"
+
+ final val Annotation: NameType = "Annotation"
+ final val ClassfileAnnotation: NameType = "ClassfileAnnotation"
+ final val Enum: NameType = "Enum"
+ final val Group: NameType = "Group"
+ final val Tree: NameType = "Tree"
+ final val Type : NameType = "Type"
+ final val TypeTree: NameType = "TypeTree"
+
+ // Annotation simple names, used in Namer
+ final val BeanPropertyAnnot: NameType = "BeanProperty"
+ final val BooleanBeanPropertyAnnot: NameType = "BooleanBeanProperty"
+ final val bridgeAnnot: NameType = "bridge"
+
+ // Classfile Attributes
+ final val AnnotationDefaultATTR: NameType = "AnnotationDefault"
+ final val BridgeATTR: NameType = "Bridge"
+ final val ClassfileAnnotationATTR: NameType = "RuntimeInvisibleAnnotations" // RetentionPolicy.CLASS. Currently not used (Apr 2009).
+ final val CodeATTR: NameType = "Code"
+ final val ConstantValueATTR: NameType = "ConstantValue"
+ final val DeprecatedATTR: NameType = "Deprecated"
+ final val ExceptionsATTR: NameType = "Exceptions"
+ final val InnerClassesATTR: NameType = "InnerClasses"
+ final val LineNumberTableATTR: NameType = "LineNumberTable"
+ final val LocalVariableTableATTR: NameType = "LocalVariableTable"
+ final val RuntimeAnnotationATTR: NameType = "RuntimeVisibleAnnotations" // RetentionPolicy.RUNTIME
+ final val RuntimeParamAnnotationATTR: NameType = "RuntimeVisibleParameterAnnotations" // RetentionPolicy.RUNTIME (annotations on parameters)
+ final val ScalaATTR: NameType = "Scala"
+ final val ScalaSignatureATTR: NameType = "ScalaSig"
+ final val SignatureATTR: NameType = "Signature"
+ final val SourceFileATTR: NameType = "SourceFile"
+ final val SyntheticATTR: NameType = "Synthetic"
+
+ 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
+ def interfaceName(implname: Name): TypeName = (implname dropRight IMPL_CLASS_SUFFIX.length).toTypeName
+ }
+
+ abstract class TermNames extends Keywords with TermNamesApi {
+ type NameType = TermName
+ protected implicit def createNameType(name: String): TermName = newTermNameCached(name)
+
+ /** Base strings from which synthetic names are derived. */
+ val BITMAP_PREFIX = "bitmap$"
+ val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$"
+ val DEFAULT_GETTER_STRING = "$default$"
+ val DEFAULT_GETTER_INIT_STRING = "$lessinit$greater" // CONSTRUCTOR.encoded, less is more
+ val DO_WHILE_PREFIX = "doWhile$"
+ val EVIDENCE_PARAM_PREFIX = "evidence$"
+ val EXCEPTION_RESULT_PREFIX = "exceptionResult"
+ val EXPAND_SEPARATOR_STRING = "$$"
+ val INTERPRETER_IMPORT_WRAPPER = "$iw"
+ val INTERPRETER_LINE_PREFIX = "line"
+ val INTERPRETER_VAR_PREFIX = "res"
+ val INTERPRETER_WRAPPER_SUFFIX = "$object"
+ val LOCALDUMMY_PREFIX = "<local " // owner of local blocks
+ val PROTECTED_PREFIX = "protected$"
+ val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set"
+ val SUPER_PREFIX_STRING = "super$"
+ val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$"
+ val WHILE_PREFIX = "while$"
+
+ // Compiler internal names
+ val ANYNAME: NameType = "<anyname>"
+ val CONSTRUCTOR: NameType = "<init>"
+ val EQEQ_LOCAL_VAR: NameType = "eqEqTemp$"
+ val FAKE_LOCAL_THIS: NameType = "this$"
+ val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something?
+ val LAZY_LOCAL: NameType = "$lzy"
+ val LAZY_SLOW_SUFFIX: NameType = "$lzycompute"
+ val LOCAL_SUFFIX_STRING = " "
+ val UNIVERSE_BUILD_PREFIX: NameType = "$u.build."
+ val UNIVERSE_BUILD: NameType = "$u.build"
+ val UNIVERSE_PREFIX: NameType = "$u."
+ val UNIVERSE_SHORT: NameType = "$u"
+ val MIRROR_PREFIX: NameType = "$m."
+ val MIRROR_SHORT: NameType = "$m"
+ val MIRROR_UNTYPED: NameType = "$m$untyped"
+ val REIFY_FREE_PREFIX: NameType = "free$"
+ val REIFY_FREE_THIS_SUFFIX: NameType = "$this"
+ val REIFY_FREE_VALUE_SUFFIX: NameType = "$value"
+ val REIFY_SYMDEF_PREFIX: NameType = "symdef$"
+ val MIXIN_CONSTRUCTOR: NameType = "$init$"
+ val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
+ val OUTER: NameType = "$outer"
+ val OUTER_LOCAL: NameType = OUTER + LOCAL_SUFFIX_STRING // "$outer ", note the space
+ val OUTER_SYNTH: NameType = "<outer>" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter
+ val ROOTPKG: NameType = "_root_"
+ val SELECTOR_DUMMY: NameType = "<unapply-selector>"
+ val SELF: NameType = "$this"
+ val SETTER_SUFFIX: NameType = encode("_=")
+ val SPECIALIZED_INSTANCE: NameType = "specInstance$"
+ val STAR: NameType = "*"
+ val THIS: NameType = "_$this"
+
+ @deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
+ def SPECIALIZED_SUFFIX_STRING = SPECIALIZED_SUFFIX.toString
+ @deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
+ def SPECIALIZED_SUFFIX_NAME: TermName = SPECIALIZED_SUFFIX.toTermName
+
+ def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR
+ def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX
+ def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX
+ def isLocalDummyName(name: Name) = name startsWith LOCALDUMMY_PREFIX
+ def isLocalName(name: Name) = name endsWith LOCAL_SUFFIX_STRING
+ def isLoopHeaderLabel(name: Name) = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX)
+ def isProtectedAccessorName(name: Name) = name startsWith PROTECTED_PREFIX
+ def isSuperAccessorName(name: Name) = name startsWith SUPER_PREFIX_STRING
+ def isReplWrapperName(name: Name) = name containsName INTERPRETER_IMPORT_WRAPPER
+ def isSetterName(name: Name) = name endsWith SETTER_SUFFIX
+ def isTraitSetterName(name: Name) = isSetterName(name) && (name containsName TRAIT_SETTER_SEPARATOR_STRING)
+ def isSingletonName(name: Name) = name endsWith SINGLETON_SUFFIX
+ def isModuleName(name: Name) = name endsWith MODULE_SUFFIX_NAME
+
+ def isDeprecatedIdentifierName(name: Name) = name.toTermName match {
+ case nme.`then` | nme.`macro` => true
+ case _ => false
+ }
+
+ def isOpAssignmentName(name: Name) = name match {
+ case raw.NE | raw.LE | raw.GE | EMPTY => false
+ case _ =>
+ name.endChar == '=' && name.startChar != '=' && isOperatorPart(name.startChar)
+ }
+
+ /** The expanded name of `name` relative to this class `base` with given `separator`
+ */
+ def expandedName(name: TermName, base: Symbol, separator: String = EXPAND_SEPARATOR_STRING): TermName =
+ newTermNameCached(base.fullName('$') + separator + name)
+
+ /** The expanded setter name of `name` relative to this class `base`
+ */
+ def expandedSetterName(name: TermName, base: Symbol): TermName =
+ expandedName(name, base, separator = TRAIT_SETTER_SEPARATOR_STRING)
+
+ /** If `name` is an expandedName name, the original name.
+ * Otherwise `name` itself.
+ */
+ def originalName(name: Name): Name = {
+ var i = name.length
+ while (i >= 2 && !(name(i - 1) == '$' && name(i - 2) == '$')) i -= 1
+ if (i >= 2) {
+ while (i >= 3 && name(i - 3) == '$') i -= 1
+ name.subName(i, name.length)
+ } else name
+ }
+
+ def unspecializedName(name: Name): Name = (
+ if (name endsWith SPECIALIZED_SUFFIX)
+ name.subName(0, name.lastIndexOf('m') - 1)
+ else name
+ )
+
+ /*
+ def anonNumberSuffix(name: Name): Name = {
+ ("" + name) lastIndexOf '$' match {
+ case -1 => nme.EMPTY
+ case idx =>
+ val s = name drop idx
+ if (s.toString forall (_.isDigit)) s
+ else nme.EMPTY
+ }
+ }
+ */
+
+ /** Return the original name and the types on which this name
+ * is specialized. For example,
+ * {{{
+ * splitSpecializedName("foo$mIcD$sp") == ('foo', "I", "D")
+ * }}}
+ * `foo$mIcD$sp` is the name of a method specialized on two type
+ * parameters, the first one belonging to the method itself, on Int,
+ * and another one belonging to the enclosing class, on Double.
+ */
+ def splitSpecializedName(name: Name): (Name, String, String) =
+ if (name endsWith SPECIALIZED_SUFFIX) {
+ val name1 = name dropRight SPECIALIZED_SUFFIX.length
+ val idxC = name1 lastIndexOf 'c'
+ val idxM = name1 lastIndexOf 'm'
+
+ (name1.subName(0, idxM - 1),
+ name1.subName(idxC + 1, name1.length).toString,
+ name1.subName(idxM + 1, idxC).toString)
+ } else
+ (name, "", "")
+
+ def getterName(name: TermName): TermName = if (isLocalName(name)) localToGetter(name) else name
+ def getterToLocal(name: TermName): TermName = name append LOCAL_SUFFIX_STRING
+ def getterToSetter(name: TermName): TermName = name append SETTER_SUFFIX
+ def localToGetter(name: TermName): TermName = name dropRight LOCAL_SUFFIX_STRING.length
+
+ def dropLocalSuffix(name: Name): Name = if (name endsWith ' ') name dropRight 1 else name
+
+ def setterToGetter(name: TermName): TermName = {
+ val p = name.pos(TRAIT_SETTER_SEPARATOR_STRING)
+ if (p < name.length)
+ setterToGetter(name drop (p + TRAIT_SETTER_SEPARATOR_STRING.length))
+ else
+ name.subName(0, name.length - SETTER_SUFFIX.length)
+ }
+
+ // Nominally, name$default$N, encoded for <init>
+ def defaultGetterName(name: Name, pos: Int): TermName = {
+ val prefix = if (isConstructorName(name)) DEFAULT_GETTER_INIT_STRING else name
+ newTermName(prefix + DEFAULT_GETTER_STRING + pos)
+ }
+ // Nominally, name from name$default$N, CONSTRUCTOR for <init>
+ def defaultGetterToMethod(name: Name): TermName = {
+ val p = name.pos(DEFAULT_GETTER_STRING)
+ if (p < name.length) {
+ val q = name.toTermName.subName(0, p)
+ // i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q
+ if (q.toString == DEFAULT_GETTER_INIT_STRING) CONSTRUCTOR else q
+ } else name.toTermName
+ }
+
+ // If the name ends with $nn where nn are
+ // all digits, strip the $ and the digits.
+ // Otherwise return the argument.
+ def stripAnonNumberSuffix(name: Name): Name = {
+ var pos = name.length
+ while (pos > 0 && name(pos - 1).isDigit)
+ pos -= 1
+
+ if (pos <= 0 || pos == name.length || name(pos - 1) != '$') name
+ else name.subName(0, pos - 1)
+ }
+
+ def stripModuleSuffix(name: Name): Name = (
+ if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name
+ )
+ def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">")
+ def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name)
+
+ /** The name of an accessor for protected symbols. */
+ def protName(name: Name): TermName = newTermName(PROTECTED_PREFIX + name)
+
+ /** The name of a setter for protected symbols. Used for inherited Java fields. */
+ def protSetterName(name: Name): TermName = newTermName(PROTECTED_SET_PREFIX + name)
+
+ final val Nil: NameType = "Nil"
+ final val Predef: NameType = "Predef"
+ final val ScalaRunTime: NameType = "ScalaRunTime"
+ final val Some: NameType = "Some"
+
+ val _1 : NameType = "_1"
+ val _2 : NameType = "_2"
+ val _3 : NameType = "_3"
+ val _4 : NameType = "_4"
+ val _5 : NameType = "_5"
+ val _6 : NameType = "_6"
+ val _7 : NameType = "_7"
+ val _8 : NameType = "_8"
+ val _9 : NameType = "_9"
+ val _10 : NameType = "_10"
+ val _11 : NameType = "_11"
+ val _12 : NameType = "_12"
+ val _13 : NameType = "_13"
+ val _14 : NameType = "_14"
+ val _15 : NameType = "_15"
+ val _16 : NameType = "_16"
+ val _17 : NameType = "_17"
+ val _18 : NameType = "_18"
+ val _19 : NameType = "_19"
+ val _20 : NameType = "_20"
+ val _21 : NameType = "_21"
+ val _22 : NameType = "_22"
+
+ val x_0 : NameType = "x$0"
+ val x_1 : NameType = "x$1"
+ val x_2 : NameType = "x$2"
+ val x_3 : NameType = "x$3"
+ val x_4 : NameType = "x$4"
+ val x_5 : NameType = "x$5"
+ val x_6 : NameType = "x$6"
+ val x_7 : NameType = "x$7"
+ val x_8 : NameType = "x$8"
+ val x_9 : NameType = "x$9"
+
+ @switch def syntheticParamName(i: Int): TermName = i match {
+ case 0 => nme.x_0
+ case 1 => nme.x_1
+ case 2 => nme.x_2
+ case 3 => nme.x_3
+ case 4 => nme.x_4
+ case 5 => nme.x_5
+ case 6 => nme.x_6
+ case 7 => nme.x_7
+ case 8 => nme.x_8
+ case 9 => nme.x_9
+ case _ => newTermName("x$" + i)
+ }
+
+ @switch def productAccessorName(j: Int): TermName = j match {
+ case 1 => nme._1
+ case 2 => nme._2
+ case 3 => nme._3
+ case 4 => nme._4
+ case 5 => nme._5
+ case 6 => nme._6
+ case 7 => nme._7
+ case 8 => nme._8
+ case 9 => nme._9
+ case 10 => nme._10
+ case 11 => nme._11
+ case 12 => nme._12
+ case 13 => nme._13
+ case 14 => nme._14
+ case 15 => nme._15
+ case 16 => nme._16
+ case 17 => nme._17
+ case 18 => nme._18
+ case 19 => nme._19
+ case 20 => nme._20
+ case 21 => nme._21
+ case 22 => nme._22
+ case _ => newTermName("_" + j)
+ }
+
+ val ??? = encode("???")
+
+ val wrapRefArray: NameType = "wrapRefArray"
+ val wrapByteArray: NameType = "wrapByteArray"
+ val wrapShortArray: NameType = "wrapShortArray"
+ val wrapCharArray: NameType = "wrapCharArray"
+ val wrapIntArray: NameType = "wrapIntArray"
+ val wrapLongArray: NameType = "wrapLongArray"
+ val wrapFloatArray: NameType = "wrapFloatArray"
+ val wrapDoubleArray: NameType = "wrapDoubleArray"
+ val wrapBooleanArray: NameType = "wrapBooleanArray"
+ val wrapUnitArray: NameType = "wrapUnitArray"
+ val genericWrapArray: NameType = "genericWrapArray"
+
+ // Compiler utilized names
+
+ val AnnotatedType: NameType = "AnnotatedType"
+ val AnnotationInfo: NameType = "AnnotationInfo"
+ val Any: NameType = "Any"
+ val AnyVal: NameType = "AnyVal"
+ val AppliedTypeTree: NameType = "AppliedTypeTree"
+ val Apply: NameType = "Apply"
+ val ArrayAnnotArg: NameType = "ArrayAnnotArg"
+ val Constant: NameType = "Constant"
+ val ConstantType: NameType = "ConstantType"
+ val EmptyPackage: NameType = "EmptyPackage"
+ val EmptyPackageClass: NameType = "EmptyPackageClass"
+ val ExistentialTypeTree: NameType = "ExistentialTypeTree"
+ val Flag : NameType = "Flag"
+ val Ident: NameType = "Ident"
+ val Import: NameType = "Import"
+ val Literal: NameType = "Literal"
+ val LiteralAnnotArg: NameType = "LiteralAnnotArg"
+ val Modifiers: NameType = "Modifiers"
+ val NestedAnnotArg: NameType = "NestedAnnotArg"
+ val NoFlags: NameType = "NoFlags"
+ val NoPrefix: NameType = "NoPrefix"
+ val NoSymbol: NameType = "NoSymbol"
+ val Nothing: NameType = "Nothing"
+ val NoType: NameType = "NoType"
+ val Null: NameType = "Null"
+ val Object: NameType = "Object"
+ val RootPackage: NameType = "RootPackage"
+ val RootClass: NameType = "RootClass"
+ val Select: NameType = "Select"
+ val StringContext: NameType = "StringContext"
+ val This: NameType = "This"
+ val ThisType: NameType = "ThisType"
+ val Tree : NameType = "Tree"
+ val Tuple2: NameType = "Tuple2"
+ val TYPE_ : NameType = "TYPE"
+ val TypeApply: NameType = "TypeApply"
+ val TypeRef: NameType = "TypeRef"
+ val TypeTree: NameType = "TypeTree"
+ val UNIT : NameType = "UNIT"
+ val add_ : NameType = "add"
+ val annotation: NameType = "annotation"
+ val anyValClass: NameType = "anyValClass"
+ val append: NameType = "append"
+ val apply: NameType = "apply"
+ val applyDynamic: NameType = "applyDynamic"
+ val applyDynamicNamed: NameType = "applyDynamicNamed"
+ val applyImpl: NameType = "applyImpl"
+ val applyOrElse: NameType = "applyOrElse"
+ val args : NameType = "args"
+ val argv : NameType = "argv"
+ val arrayClass: NameType = "arrayClass"
+ val arrayElementClass: NameType = "arrayElementClass"
+ val arrayTagToClassManifest: NameType = "arrayTagToClassManifest"
+ val arrayValue: NameType = "arrayValue"
+ val array_apply : NameType = "array_apply"
+ val array_clone : NameType = "array_clone"
+ val array_length : NameType = "array_length"
+ val array_update : NameType = "array_update"
+ val arraycopy: NameType = "arraycopy"
+ val asTermSymbol: NameType = "asTermSymbol"
+ val asModuleSymbol: NameType = "asModuleSymbol"
+ val asMethodSymbol: NameType = "asMethodSymbol"
+ val asTypeSymbol: NameType = "asTypeSymbol"
+ val asClassSymbol: NameType = "asClassSymbol"
+ val asInstanceOf_ : NameType = "asInstanceOf"
+ val asInstanceOf_Ob : NameType = "$asInstanceOf"
+ val asTypeConstructor: NameType = "asTypeConstructor"
+ val assert_ : NameType = "assert"
+ val assume_ : NameType = "assume"
+ val basis : NameType = "basis"
+ val box: NameType = "box"
+ val build : NameType = "build"
+ val bytes: NameType = "bytes"
+ val canEqual_ : NameType = "canEqual"
+ val checkInitialized: NameType = "checkInitialized"
+ val classOf: NameType = "classOf"
+ val clone_ : NameType = if (forMSIL) "MemberwiseClone" else "clone" // sn.OClone causes checkinit failure
+ val concreteTypeTagToManifest: NameType = "concreteTypeTagToManifest"
+ val conforms: NameType = "conforms"
+ val copy: NameType = "copy"
+ val currentMirror: NameType = "currentMirror"
+ val definitions: NameType = "definitions"
+ val delayedInit: NameType = "delayedInit"
+ val delayedInitArg: NameType = "delayedInit$body"
+ val drop: NameType = "drop"
+ val elem: NameType = "elem"
+ val emptyValDef: NameType = "emptyValDef"
+ val ensureAccessible : NameType = "ensureAccessible"
+ val eq: NameType = "eq"
+ val equalsNumChar : NameType = "equalsNumChar"
+ val equalsNumNum : NameType = "equalsNumNum"
+ val equalsNumObject : NameType = "equalsNumObject"
+ val equals_ : NameType = if (forMSIL) "Equals" else "equals"
+ val error: NameType = "error"
+ val eval: NameType = "eval"
+ val ex: NameType = "ex"
+ val experimental: NameType = "experimental"
+ val false_ : NameType = "false"
+ val filter: NameType = "filter"
+ val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize"
+ val find_ : NameType = "find"
+ val flagsFromBits : NameType = "flagsFromBits"
+ val flatMap: NameType = "flatMap"
+ val foreach: NameType = "foreach"
+ val genericArrayOps: NameType = "genericArrayOps"
+ val get: NameType = "get"
+ val getOrElse: NameType = "getOrElse"
+ val hasNext: NameType = "hasNext"
+ val hashCode_ : NameType = if (forMSIL) "GetHashCode" else "hashCode"
+ val hash_ : NameType = "hash"
+ val head: NameType = "head"
+ val identity: NameType = "identity"
+ val implicitly: NameType = "implicitly"
+ val in: NameType = "in"
+ val info: NameType = "info"
+ val inlinedEquals: NameType = "inlinedEquals"
+ val isArray: NameType = "isArray"
+ val isDefinedAt: NameType = "isDefinedAt"
+ val isEmpty: NameType = "isEmpty"
+ val isInstanceOf_ : NameType = "isInstanceOf"
+ val isInstanceOf_Ob : NameType = "$isInstanceOf"
+ val java: NameType = "java"
+ val key: NameType = "key"
+ val lang: NameType = "lang"
+ val length: NameType = "length"
+ val lengthCompare: NameType = "lengthCompare"
+ val liftedTree: NameType = "liftedTree"
+ val `macro` : NameType = "macro"
+ val macroThis : NameType = "_this"
+ val macroContext : NameType = "c"
+ val main: NameType = "main"
+ val manifest: NameType = "manifest"
+ val manifestToConcreteTypeTag: NameType = "manifestToConcreteTypeTag"
+ val map: NameType = "map"
+ val materializeArrayTag: NameType = "materializeArrayTag"
+ val materializeClassTag: NameType = "materializeClassTag"
+ val materializeConcreteTypeTag: NameType = "materializeConcreteTypeTag"
+ val materializeTypeTag: NameType = "materializeTypeTag"
+ val mirror : NameType = "mirror"
+ val moduleClass : NameType = "moduleClass"
+ val name: NameType = "name"
+ val ne: NameType = "ne"
+ val newArray: NameType = "newArray"
+ val newFreeExistential: NameType = "newFreeExistential"
+ val newFreeTerm: NameType = "newFreeTerm"
+ val newFreeType: NameType = "newFreeType"
+ val newNestedSymbol: NameType = "newNestedSymbol"
+ val newScopeWith: NameType = "newScopeWith"
+ val next: NameType = "next"
+ val nmeNewTermName: NameType = "newTermName"
+ val nmeNewTypeName: NameType = "newTypeName"
+ val normalize: NameType = "normalize"
+ val notifyAll_ : NameType = "notifyAll"
+ val notify_ : NameType = "notify"
+ val null_ : NameType = "null"
+ val ofDim: NameType = "ofDim"
+ val origin: NameType = "origin"
+ val prefix : NameType = "prefix"
+ val productArity: NameType = "productArity"
+ val productElement: NameType = "productElement"
+ val productIterator: NameType = "productIterator"
+ val productPrefix: NameType = "productPrefix"
+ val readResolve: NameType = "readResolve"
+ val reflect : NameType = "reflect"
+ val reify : NameType = "reify"
+ val rootMirror : NameType = "rootMirror"
+ val runOrElse: NameType = "runOrElse"
+ val runtime: NameType = "runtime"
+ val runtimeClass: NameType = "runtimeClass"
+ val runtimeMirror: NameType = "runtimeMirror"
+ val sameElements: NameType = "sameElements"
+ val scala_ : NameType = "scala"
+ val selectDynamic: NameType = "selectDynamic"
+ val selectOverloadedMethod: NameType = "selectOverloadedMethod"
+ val selectTerm: NameType = "selectTerm"
+ val selectType: NameType = "selectType"
+ val self: NameType = "self"
+ val setAccessible: NameType = "setAccessible"
+ val setAnnotations: NameType = "setAnnotations"
+ val setSymbol: NameType = "setSymbol"
+ val setType: NameType = "setType"
+ val setTypeSignature: NameType = "setTypeSignature"
+ val splice: NameType = "splice"
+ val staticClass : NameType = "staticClass"
+ val staticModule : NameType = "staticModule"
+ val synchronized_ : NameType = "synchronized"
+ val tail: NameType = "tail"
+ val `then` : NameType = "then"
+ val this_ : NameType = "this"
+ val thisPrefix : NameType = "thisPrefix"
+ val throw_ : NameType = "throw"
+ val toArray: NameType = "toArray"
+ val toList: NameType = "toList"
+ val toObjectArray : NameType = "toObjectArray"
+ val toSeq: NameType = "toSeq"
+ val toString_ : NameType = if (forMSIL) "ToString" else "toString"
+ val tpe : NameType = "tpe"
+ val tree : NameType = "tree"
+ val true_ : NameType = "true"
+ val typedProductIterator: NameType = "typedProductIterator"
+ val unapply: NameType = "unapply"
+ val unapplySeq: NameType = "unapplySeq"
+ val unbox: NameType = "unbox"
+ val universe: NameType = "universe"
+ val update: NameType = "update"
+ val updateDynamic: NameType = "updateDynamic"
+ val value: NameType = "value"
+ val valueOf : NameType = "valueOf"
+ val values : NameType = "values"
+ val view_ : NameType = "view"
+ val wait_ : NameType = "wait"
+ val withFilter: NameType = "withFilter"
+ val wrap: NameType = "wrap"
+ val zip: NameType = "zip"
+
+ val synthSwitch: NameType = "$synthSwitch"
+
+ // unencoded operators
+ object raw {
+ final val AMP : NameType = "&"
+ final val BANG : NameType = "!"
+ final val BAR : NameType = "|"
+ final val DOLLAR: NameType = "$"
+ final val GE: NameType = ">="
+ final val LE: NameType = "<="
+ final val MINUS: NameType = "-"
+ final val NE: NameType = "!="
+ final val PLUS : NameType = "+"
+ final val SLASH: NameType = "/"
+ final val STAR : NameType = "*"
+ final val TILDE: NameType = "~"
+
+ final val isUnary: Set[Name] = Set(MINUS, PLUS, TILDE, BANG)
+ }
+
+ // value-conversion methods
+ val toByte: NameType = "toByte"
+ val toShort: NameType = "toShort"
+ val toChar: NameType = "toChar"
+ val toInt: NameType = "toInt"
+ val toLong: NameType = "toLong"
+ val toFloat: NameType = "toFloat"
+ val toDouble: NameType = "toDouble"
+
+ // primitive operation methods for structual types mostly
+ // overlap with the above, but not for these two.
+ val toCharacter: NameType = "toCharacter"
+ val toInteger: NameType = "toInteger"
+
+ def newLazyValSlowComputeName(lzyValName: Name) = lzyValName append LAZY_SLOW_SUFFIX
+
+ // ASCII names for operators
+ val ADD = encode("+")
+ val AND = encode("&")
+ val ASR = encode(">>")
+ val DIV = encode("/")
+ val EQ = encode("==")
+ val EQL = encode("=")
+ val GE = encode(">=")
+ val GT = encode(">")
+ val HASHHASH = encode("##")
+ val LE = encode("<=")
+ val LSL = encode("<<")
+ val LSR = encode(">>>")
+ val LT = encode("<")
+ val MINUS = encode("-")
+ val MOD = encode("%")
+ val MUL = encode("*")
+ val NE = encode("!=")
+ val OR = encode("|")
+ val PLUS = ADD // technically redundant, but ADD looks funny with MINUS
+ val SUB = MINUS // ... as does SUB with PLUS
+ val XOR = encode("^")
+ val ZAND = encode("&&")
+ val ZOR = encode("||")
+
+ // unary operators
+ val UNARY_~ = encode("unary_~")
+ val UNARY_+ = encode("unary_+")
+ val UNARY_- = encode("unary_-")
+ val UNARY_! = encode("unary_!")
+
+ // Grouped here so Cleanup knows what tests to perform.
+ val CommonOpNames = Set[Name](OR, XOR, AND, EQ, NE)
+ val ConversionNames = Set[Name](toByte, toChar, toDouble, toFloat, toInt, toLong, toShort)
+ val BooleanOpNames = Set[Name](ZOR, ZAND, UNARY_!) ++ CommonOpNames
+ val NumberOpNames = (
+ Set[Name](ADD, SUB, MUL, DIV, MOD, LSL, LSR, ASR, LT, LE, GE, GT)
+ ++ Set(UNARY_+, UNARY_-, UNARY_!)
+ ++ ConversionNames
+ ++ CommonOpNames
+ )
+
+ val add: NameType = "add"
+ val complement: NameType = "complement"
+ val divide: NameType = "divide"
+ val multiply: NameType = "multiply"
+ val negate: NameType = "negate"
+ val positive: NameType = "positive"
+ val shiftLogicalRight: NameType = "shiftLogicalRight"
+ val shiftSignedLeft: NameType = "shiftSignedLeft"
+ val shiftSignedRight: NameType = "shiftSignedRight"
+ val subtract: NameType = "subtract"
+ val takeAnd: NameType = "takeAnd"
+ val takeConditionalAnd: NameType = "takeConditionalAnd"
+ val takeConditionalOr: NameType = "takeConditionalOr"
+ val takeModulo: NameType = "takeModulo"
+ val takeNot: NameType = "takeNot"
+ val takeOr: NameType = "takeOr"
+ val takeXor: NameType = "takeXor"
+ val testEqual: NameType = "testEqual"
+ val testGreaterOrEqualThan: NameType = "testGreaterOrEqualThan"
+ val testGreaterThan: NameType = "testGreaterThan"
+ val testLessOrEqualThan: NameType = "testLessOrEqualThan"
+ val testLessThan: NameType = "testLessThan"
+ val testNotEqual: NameType = "testNotEqual"
+
+ def toUnaryName(name: TermName): TermName = name match {
+ case raw.MINUS => UNARY_-
+ case raw.PLUS => UNARY_+
+ case raw.TILDE => UNARY_~
+ case raw.BANG => UNARY_!
+ case _ => name
+ }
+ /** The name of a method which stands in for a primitive operation
+ * during structural type dispatch.
+ */
+ def primitiveInfixMethodName(name: Name): TermName = name match {
+ case OR => takeOr
+ case XOR => takeXor
+ case AND => takeAnd
+ case EQ => testEqual
+ case NE => testNotEqual
+ case ADD => add
+ case SUB => subtract
+ case MUL => multiply
+ case DIV => divide
+ case MOD => takeModulo
+ case LSL => shiftSignedLeft
+ case LSR => shiftLogicalRight
+ case ASR => shiftSignedRight
+ case LT => testLessThan
+ case LE => testLessOrEqualThan
+ case GE => testGreaterOrEqualThan
+ case GT => testGreaterThan
+ case ZOR => takeConditionalOr
+ case ZAND => takeConditionalAnd
+ case _ => NO_NAME
+ }
+ /** Postfix/prefix, really.
+ */
+ def primitivePostfixMethodName(name: Name): TermName = name match {
+ case UNARY_! => takeNot
+ case UNARY_+ => positive
+ case UNARY_- => negate
+ case UNARY_~ => complement
+ case `toByte` => toByte
+ case `toShort` => toShort
+ case `toChar` => toCharacter
+ case `toInt` => toInteger
+ case `toLong` => toLong
+ case `toFloat` => toFloat
+ case `toDouble` => toDouble
+ case _ => NO_NAME
+ }
+
+ /** Translate a String into a list of simple TypeNames and TermNames.
+ * In all segments before the last, type/term is determined by whether
+ * the following separator char is '.' or '#'. In the last segment,
+ * the argument "assumeTerm" determines it. Examples:
+ *
+ * package foo {
+ * object Lorax { object Wog ; class Wog }
+ * class Lorax { object Zax ; class Zax }
+ * }
+ *
+ * f("foo.Lorax", true) == List("foo": Term, "Lorax": Term) // object Lorax
+ * f("foo.Lorax", false) == List("foo": Term, "Lorax": Type) // class Lorax
+ * f("Lorax.Wog", true) == List("Lorax": Term, "Wog": Term) // object Wog
+ * f("Lorax.Wog", false) == List("Lorax": Term, "Wog": Type) // class Wog
+ * f("Lorax#Zax", true) == List("Lorax": Type, "Zax": Term) // object Zax
+ * f("Lorax#Zax", false) == List("Lorax": Type, "Zax": Type) // class Zax
+ *
+ * Note that in actual scala syntax you cannot refer to object Zax without an
+ * instance of Lorax, so Lorax#Zax could only mean the type. One might think
+ * that Lorax#Zax.type would work, but this is not accepted by the parser.
+ * For the purposes of referencing that object, the syntax is allowed.
+ */
+ def segments(name: String, assumeTerm: Boolean): List[Name] = {
+ def mkName(str: String, term: Boolean): Name =
+ if (term) newTermName(str) else newTypeName(str)
+
+ name.indexWhere(ch => ch == '.' || ch == '#') match {
+ // it's the last segment: the parameter tells us whether type or term
+ case -1 => if (name == "") scala.Nil else scala.List(mkName(name, assumeTerm))
+ // otherwise, we can tell based on whether '#' or '.' is the following char.
+ case idx =>
+ val (simple, div, rest) = (name take idx, name charAt idx, newTermName(name) drop (idx + 1))
+ mkName(simple, div == '.') :: segments(rest, assumeTerm)
+ }
+ }
+
+ def newBitmapName(bitmapPrefix: Name, n: Int) = bitmapPrefix append ("" + n)
+
+ val BITMAP_NORMAL: NameType = BITMAP_PREFIX + "" // initialization bitmap for public/protected lazy vals
+ val BITMAP_TRANSIENT: NameType = BITMAP_PREFIX + "trans$" // initialization bitmap for transient lazy vals
+ val BITMAP_CHECKINIT: NameType = BITMAP_PREFIX + "init$" // initialization bitmap for checkinit values
+ val BITMAP_CHECKINIT_TRANSIENT: NameType = BITMAP_PREFIX + "inittrans$" // initialization bitmap for transient checkinit values
+ }
+
+ object tpnme extends TypeNames { }
+
+ /** For fully qualified type names.
+ */
+ object fulltpnme extends TypeNames {
+ val RuntimeNothing: NameType = "scala.runtime.Nothing$"
+ val RuntimeNull: NameType = "scala.runtime.Null$"
+ val JavaLangEnum: NameType = "java.lang.Enum"
+ }
+
+ /** Java binary names, like scala/runtime/Nothing$.
+ */
+ object binarynme {
+ def toBinary(name: Name) = name mapName (_.replace('.', '/'))
+
+ val RuntimeNothing = toBinary(fulltpnme.RuntimeNothing).toTypeName
+ val RuntimeNull = toBinary(fulltpnme.RuntimeNull).toTypeName
+ }
+
+ val javanme = nme.javaKeywords
+
+ // [Eugene++ to Martin] had to move a lot of stuff from here to TermNames to satisfy the contract
+ // why do we even have stuff in object nme? cf. object tpnme
+ object nme extends TermNames {
+
+ def isModuleVarName(name: Name): Boolean =
+ stripAnonNumberSuffix(name) endsWith MODULE_VAR_SUFFIX
+
+ def moduleVarName(name: TermName): TermName =
+ newTermNameCached("" + name + MODULE_VAR_SUFFIX)
+
+ def getCause = sn.GetCause
+ def getClass_ = sn.GetClass
+ def getComponentType = sn.GetComponentType
+ def getMethod_ = sn.GetMethod
+ def invoke_ = sn.Invoke
+
+ val isBoxedNumberOrBoolean: NameType = "isBoxedNumberOrBoolean"
+ val isBoxedNumber: NameType = "isBoxedNumber"
+
+ val reflPolyCacheName: NameType = "reflPoly$Cache"
+ val reflClassCacheName: NameType = "reflClass$Cache"
+ val reflParamsCacheName: NameType = "reflParams$Cache"
+ val reflMethodCacheName: NameType = "reflMethod$Cache"
+ val reflMethodName: NameType = "reflMethod$Method"
+
+ private val reflectionCacheNames = Set[NameType](
+ reflPolyCacheName,
+ reflClassCacheName,
+ reflParamsCacheName,
+ reflMethodCacheName,
+ reflMethodName
+ )
+ def isReflectionCacheName(name: Name) = reflectionCacheNames exists (name startsWith _)
+
+ @deprecated("Use a method in tpnme", "2.10.0") def dropSingletonName(name: Name): TypeName = tpnme.dropSingletonName(name)
+ @deprecated("Use a method in tpnme", "2.10.0") def singletonName(name: Name): TypeName = tpnme.singletonName(name)
+ @deprecated("Use a method in tpnme", "2.10.0") def implClassName(name: Name): TypeName = tpnme.implClassName(name)
+ @deprecated("Use a method in tpnme", "2.10.0") def interfaceName(implname: Name): TypeName = tpnme.interfaceName(implname)
+ }
+
+ abstract class SymbolNames {
+ protected implicit def createNameType(s: String): TypeName = newTypeNameCached(s)
+
+ val BeanProperty : TypeName
+ val BooleanBeanProperty : TypeName
+ val BoxedBoolean : TypeName
+ val BoxedCharacter : TypeName
+ val BoxedNumber : TypeName
+ val Class : TypeName
+ val Delegate : TypeName
+ val IOOBException : TypeName // IndexOutOfBoundsException
+ val InvTargetException : TypeName // InvocationTargetException
+ val JavaSerializable : TypeName
+ val MethodAsObject : TypeName
+ val NPException : TypeName // NullPointerException
+ val Object : TypeName
+ val String : TypeName
+ val Throwable : TypeName
+ val ValueType : TypeName
+
+ val ForName : TermName
+ val GetCause : TermName
+ val GetClass : TermName
+ val GetClassLoader : TermName
+ val GetComponentType : TermName
+ val GetMethod : TermName
+ val Invoke : TermName
+ val JavaLang : TermName
+
+ val Boxed: immutable.Map[TypeName, TypeName]
+ }
+
+ class JavaKeywords {
+ private val kw = new KeywordSetBuilder
+
+ final val ABSTRACTkw: TermName = kw("abstract")
+ final val ASSERTkw: TermName = kw("assert")
+ final val BOOLEANkw: TermName = kw("boolean")
+ final val BREAKkw: TermName = kw("break")
+ final val BYTEkw: TermName = kw("byte")
+ final val CASEkw: TermName = kw("case")
+ final val CATCHkw: TermName = kw("catch")
+ final val CHARkw: TermName = kw("char")
+ final val CLASSkw: TermName = kw("class")
+ final val CONSTkw: TermName = kw("const")
+ final val CONTINUEkw: TermName = kw("continue")
+ final val DEFAULTkw: TermName = kw("default")
+ final val DOkw: TermName = kw("do")
+ final val DOUBLEkw: TermName = kw("double")
+ final val ELSEkw: TermName = kw("else")
+ final val ENUMkw: TermName = kw("enum")
+ final val EXTENDSkw: TermName = kw("extends")
+ final val FINALkw: TermName = kw("final")
+ final val FINALLYkw: TermName = kw("finally")
+ final val FLOATkw: TermName = kw("float")
+ final val FORkw: TermName = kw("for")
+ final val IFkw: TermName = kw("if")
+ final val GOTOkw: TermName = kw("goto")
+ final val IMPLEMENTSkw: TermName = kw("implements")
+ final val IMPORTkw: TermName = kw("import")
+ final val INSTANCEOFkw: TermName = kw("instanceof")
+ final val INTkw: TermName = kw("int")
+ final val INTERFACEkw: TermName = kw("interface")
+ final val LONGkw: TermName = kw("long")
+ final val NATIVEkw: TermName = kw("native")
+ final val NEWkw: TermName = kw("new")
+ final val PACKAGEkw: TermName = kw("package")
+ final val PRIVATEkw: TermName = kw("private")
+ final val PROTECTEDkw: TermName = kw("protected")
+ final val PUBLICkw: TermName = kw("public")
+ final val RETURNkw: TermName = kw("return")
+ final val SHORTkw: TermName = kw("short")
+ final val STATICkw: TermName = kw("static")
+ final val STRICTFPkw: TermName = kw("strictfp")
+ final val SUPERkw: TermName = kw("super")
+ final val SWITCHkw: TermName = kw("switch")
+ final val SYNCHRONIZEDkw: TermName = kw("synchronized")
+ final val THISkw: TermName = kw("this")
+ final val THROWkw: TermName = kw("throw")
+ final val THROWSkw: TermName = kw("throws")
+ final val TRANSIENTkw: TermName = kw("transient")
+ final val TRYkw: TermName = kw("try")
+ final val VOIDkw: TermName = kw("void")
+ final val VOLATILEkw: TermName = kw("volatile")
+ final val WHILEkw: TermName = kw("while")
+
+ final val keywords = kw.result
+ }
+
+ private abstract class JavaNames extends SymbolNames {
+ final val BoxedBoolean: TypeName = "java.lang.Boolean"
+ final val BoxedByte: TypeName = "java.lang.Byte"
+ final val BoxedCharacter: TypeName = "java.lang.Character"
+ final val BoxedDouble: TypeName = "java.lang.Double"
+ final val BoxedFloat: TypeName = "java.lang.Float"
+ final val BoxedInteger: TypeName = "java.lang.Integer"
+ final val BoxedLong: TypeName = "java.lang.Long"
+ final val BoxedNumber: TypeName = "java.lang.Number"
+ final val BoxedShort: TypeName = "java.lang.Short"
+ final val Class: TypeName = "java.lang.Class"
+ final val Delegate: TypeName = tpnme.NO_NAME
+ final val IOOBException: TypeName = "java.lang.IndexOutOfBoundsException"
+ final val InvTargetException: TypeName = "java.lang.reflect.InvocationTargetException"
+ final val MethodAsObject: TypeName = "java.lang.reflect.Method"
+ final val NPException: TypeName = "java.lang.NullPointerException"
+ final val Object: TypeName = "java.lang.Object"
+ final val String: TypeName = "java.lang.String"
+ final val Throwable: TypeName = "java.lang.Throwable"
+ final val ValueType: TypeName = tpnme.NO_NAME
+
+ final val ForName: TermName = newTermName("forName")
+ final val GetCause: TermName = newTermName("getCause")
+ final val GetClass: TermName = newTermName("getClass")
+ final val GetClassLoader: TermName = newTermName("getClassLoader")
+ final val GetComponentType: TermName = newTermName("getComponentType")
+ final val GetMethod: TermName = newTermName("getMethod")
+ final val Invoke: TermName = newTermName("invoke")
+ final val JavaLang: TermName = newTermName("java.lang")
+
+ val Boxed = immutable.Map[TypeName, TypeName](
+ tpnme.Boolean -> BoxedBoolean,
+ tpnme.Byte -> BoxedByte,
+ tpnme.Char -> BoxedCharacter,
+ tpnme.Short -> BoxedShort,
+ tpnme.Int -> BoxedInteger,
+ tpnme.Long -> BoxedLong,
+ tpnme.Float -> BoxedFloat,
+ tpnme.Double -> BoxedDouble
+ )
+ }
+
+ private class MSILNames extends SymbolNames {
+ final val BeanProperty: TypeName = tpnme.NO_NAME
+ final val BooleanBeanProperty: TypeName = tpnme.NO_NAME
+ final val BoxedBoolean: TypeName = "System.IConvertible"
+ final val BoxedCharacter: TypeName = "System.IConvertible"
+ final val BoxedNumber: TypeName = "System.IConvertible"
+ final val Class: TypeName = "System.Type"
+ final val Delegate: TypeName = "System.MulticastDelegate"
+ final val IOOBException: TypeName = "System.IndexOutOfRangeException"
+ final val InvTargetException: TypeName = "System.Reflection.TargetInvocationException"
+ final val JavaSerializable: TypeName = tpnme.NO_NAME
+ final val MethodAsObject: TypeName = "System.Reflection.MethodInfo"
+ final val NPException: TypeName = "System.NullReferenceException"
+ final val Object: TypeName = "System.Object"
+ final val String: TypeName = "System.String"
+ final val Throwable: TypeName = "System.Exception"
+ final val ValueType: TypeName = "System.ValueType"
+
+ final val ForName: TermName = newTermName("GetType")
+ final val GetCause: TermName = newTermName("InnerException") /* System.Reflection.TargetInvocationException.InnerException */
+ final val GetClass: TermName = newTermName("GetType")
+ final lazy val GetClassLoader: TermName = throw new UnsupportedOperationException("Scala reflection is not supported on this platform");
+ final val GetComponentType: TermName = newTermName("GetElementType")
+ final val GetMethod: TermName = newTermName("GetMethod")
+ final val Invoke: TermName = newTermName("Invoke")
+ final val JavaLang: TermName = newTermName("System")
+
+ val Boxed = immutable.Map[TypeName, TypeName](
+ tpnme.Boolean -> "System.Boolean",
+ tpnme.Byte -> "System.SByte", // a scala.Byte is signed and a System.SByte too (unlike a System.Byte)
+ tpnme.Char -> "System.Char",
+ tpnme.Short -> "System.Int16",
+ tpnme.Int -> "System.Int32",
+ tpnme.Long -> "System.Int64",
+ tpnme.Float -> "System.Single",
+ tpnme.Double -> "System.Double"
+ )
+ }
+
+ private class J2SENames extends JavaNames {
+ final val BeanProperty: TypeName = "scala.beans.BeanProperty"
+ final val BooleanBeanProperty: TypeName = "scala.beans.BooleanBeanProperty"
+ final val JavaSerializable: TypeName = "java.io.Serializable"
+ }
+
+ lazy val sn: SymbolNames =
+ if (forMSIL) new MSILNames
+ else new J2SENames
+}
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
new file mode 100644
index 0000000000..cadd76b1ba
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -0,0 +1,332 @@
+/* NSC -- new scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable }
+import util._
+
+abstract class SymbolTable extends makro.Universe
+ with Collections
+ with Names
+ with Symbols
+ with Types
+ with Kinds
+ with ExistentialsAndSkolems
+ with FlagSets
+ with Scopes
+ with Mirrors
+ with Definitions
+ with Constants
+ with BaseTypeSeqs
+ with InfoTransformers
+ with transform.Transforms
+ with StdNames
+ with AnnotationInfos
+ with AnnotationCheckers
+ with Trees
+ with TreePrinters
+ with Positions
+ with TypeDebugging
+ with Importers
+ with Required
+ with CapturedVariables
+ with StdAttachments
+ with StdCreators
+ with BuildUtils
+{
+
+ val gen = new TreeGen { val global: SymbolTable.this.type = SymbolTable.this }
+ val treeBuild = gen
+
+ def log(msg: => AnyRef): Unit
+ def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg))
+
+ @deprecated("Give us a reason", "2.10.0")
+ def abort(): Nothing = abort("unknown error")
+
+ /** Override with final implementation for inlining. */
+ def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg)
+ def debugwarn(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg)
+ def throwableAsString(t: Throwable): String = "" + t
+
+ /** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */
+ def debugStack(t: Throwable): Unit = debugwarn(throwableAsString(t))
+
+ /** Overridden when we know more about what was happening during a failure. */
+ def supplementErrorMessage(msg: String): String = msg
+
+ private[scala] def printCaller[T](msg: String)(result: T) = {
+ Console.err.println("%s: %s\nCalled from: %s".format(msg, result,
+ (new Throwable).getStackTrace.drop(2).take(15).mkString("\n")))
+
+ result
+ }
+
+ private[scala] def printResult[T](msg: String)(result: T) = {
+ Console.err.println(msg + ": " + result)
+ result
+ }
+ private[scala] def logResult[T](msg: String)(result: T): T = {
+ log(msg + ": " + result)
+ result
+ }
+ private[scala] def logResultIf[T](msg: String, cond: T => Boolean)(result: T): T = {
+ if (cond(result))
+ log(msg + ": " + result)
+
+ result
+ }
+
+ // 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.
+ implicit def lowPriorityNameOrdering[T <: Names#Name]: Ordering[T] =
+ SimpleNameOrdering.asInstanceOf[Ordering[T]]
+
+ private object SimpleNameOrdering extends Ordering[Names#Name] {
+ def compare(n1: Names#Name, n2: Names#Name) = (
+ if (n1 eq n2) 0
+ else n1.toString compareTo n2.toString
+ )
+ }
+
+ /** Dump each symbol to stdout after shutdown.
+ */
+ final val traceSymbolActivity = sys.props contains "scalac.debug.syms"
+ object traceSymbols extends {
+ val global: SymbolTable.this.type = SymbolTable.this
+ } with util.TraceSymbolActivity
+
+ /** Are we compiling for Java SE? */
+ // def forJVM: Boolean
+
+ /** Are we compiling for .NET? */
+ def forMSIL: Boolean = false
+
+ /** A last effort if symbol in a select <owner>.<name> is not found.
+ * This is overridden by the reflection compiler to make up a package
+ * when it makes sense (i.e. <owner> is a package and <name> is a term name).
+ */
+ def missingHook(owner: Symbol, name: Name): Symbol = NoSymbol
+
+ /** Returns the mirror that loaded given symbol */
+ def mirrorThatLoaded(sym: Symbol): Mirror
+
+ /** A period is an ordinal number for a phase in a run.
+ * Phases in later runs have higher periods than phases in earlier runs.
+ * Later phases have higher periods than earlier phases in the same run.
+ */
+ type Period = Int
+ final val NoPeriod = 0
+
+ /** An ordinal number for compiler runs. First run has number 1. */
+ type RunId = Int
+ final val NoRunId = 0
+
+ // sigh, this has to be public or atPhase doesn't inline.
+ var phStack: List[Phase] = Nil
+ private var ph: Phase = NoPhase
+ private var per = NoPeriod
+
+ final def atPhaseStack: List[Phase] = phStack
+ final def phase: Phase = ph
+
+ def atPhaseStackMessage = atPhaseStack match {
+ case Nil => ""
+ case ps => ps.reverseMap("->" + _).mkString("(", " ", ")")
+ }
+
+ final def phase_=(p: Phase) {
+ //System.out.println("setting phase to " + p)
+ assert((p ne null) && p != NoPhase, p)
+ ph = p
+ per = period(currentRunId, p.id)
+ }
+ final def pushPhase(ph: Phase): Phase = {
+ val current = phase
+ phase = ph
+ phStack ::= ph
+ current
+ }
+ final def popPhase(ph: Phase) {
+ phStack = phStack.tail
+ phase = ph
+ }
+
+ /** The current compiler run identifier. */
+ def currentRunId: RunId
+
+ /** The run identifier of the given period. */
+ final def runId(period: Period): RunId = period >> 8
+
+ /** The phase identifier of the given period. */
+ final def phaseId(period: Period): Phase#Id = period & 0xFF
+
+ /** The period at the start of run that includes `period`. */
+ final def startRun(period: Period): Period = period & 0xFFFFFF00
+
+ /** The current period. */
+ final def currentPeriod: Period = {
+ //assert(per == (currentRunId << 8) + phase.id)
+ per
+ }
+
+ /** The phase associated with given period. */
+ final def phaseOf(period: Period): Phase = phaseWithId(phaseId(period))
+
+ final def period(rid: RunId, pid: Phase#Id): Period =
+ (rid << 8) + pid
+
+ /** Are we later than given phase in compilation? */
+ final def isAtPhaseAfter(p: Phase) =
+ p != NoPhase && phase.id > p.id
+
+ /** Perform given operation at given phase. */
+ @inline final def atPhase[T](ph: Phase)(op: => T): T = {
+ val saved = pushPhase(ph)
+ try op
+ finally popPhase(saved)
+ }
+
+
+ /** Since when it is to be "at" a phase is inherently ambiguous,
+ * a couple unambiguously named methods.
+ */
+ @inline final def beforePhase[T](ph: Phase)(op: => T): T = atPhase(ph)(op)
+ @inline final def afterPhase[T](ph: Phase)(op: => T): T = atPhase(ph.next)(op)
+ @inline final def afterCurrentPhase[T](op: => T): T = atPhase(phase.next)(op)
+ @inline final def beforePrevPhase[T](op: => T): T = atPhase(phase.prev)(op)
+
+ @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T =
+ if (isAtPhaseAfter(target)) atPhase(target)(op) else op
+
+ final def isValid(period: Period): Boolean =
+ period != 0 && runId(period) == currentRunId && {
+ val pid = phaseId(period)
+ if (phase.id > pid) infoTransformers.nextFrom(pid).pid >= phase.id
+ else infoTransformers.nextFrom(phase.id).pid >= pid
+ }
+
+ final def isValidForBaseClasses(period: Period): Boolean = {
+ def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): Boolean = (
+ it.pid >= limit ||
+ !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit)
+ );
+ period != 0 && runId(period) == currentRunId && {
+ val pid = phaseId(period)
+ if (phase.id > pid) noChangeInBaseClasses(infoTransformers.nextFrom(pid), phase.id)
+ else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid)
+ }
+ }
+
+ def openPackageModule(container: Symbol, dest: Symbol) {
+ // unlink existing symbols in the package
+ for (member <- container.info.decls.iterator) {
+ if (!member.isPrivate && !member.isConstructor) {
+ // todo: handle overlapping definitions in some way: mark as errors
+ // or treat as abstractions. For now the symbol in the package module takes precedence.
+ for (existing <- dest.info.decl(member.name).alternatives)
+ dest.info.decls.unlink(existing)
+ }
+ }
+ // enter non-private decls the class
+ for (member <- container.info.decls.iterator) {
+ if (!member.isPrivate && !member.isConstructor) {
+ dest.info.decls.enter(member)
+ }
+ }
+ // enter decls of parent classes
+ for (p <- container.parentSymbols) {
+ if (p != definitions.ObjectClass) {
+ openPackageModule(p, dest)
+ }
+ }
+ }
+
+ /** Convert array parameters denoting a repeated parameter of a Java method
+ * to `JavaRepeatedParamClass` types.
+ */
+ def arrayToRepeated(tp: Type): Type = tp match {
+ case MethodType(params, rtpe) =>
+ val formals = tp.paramTypes
+ assert(formals.last.typeSymbol == definitions.ArrayClass, formals)
+ val method = params.last.owner
+ val elemtp = formals.last.typeArgs.head match {
+ case RefinedType(List(t1, t2), _) if (t1.typeSymbol.isAbstractType && t2.typeSymbol == definitions.ObjectClass) =>
+ t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them.
+ case t =>
+ t
+ }
+ val newParams = method.newSyntheticValueParams(formals.init :+ definitions.javaRepeatedType(elemtp))
+ MethodType(newParams, rtpe)
+ case PolyType(tparams, rtpe) =>
+ PolyType(tparams, arrayToRepeated(rtpe))
+ }
+
+ abstract class SymLoader extends LazyType {
+ def fromSource = false
+ }
+
+ /** if there's a `package` member object in `pkgClass`, enter its members into it. */
+ def openPackageModule(pkgClass: Symbol) {
+
+ val pkgModule = pkgClass.info.decl(nme.PACKAGEkw)
+ def fromSource = pkgModule.rawInfo match {
+ case ltp: SymLoader => ltp.fromSource
+ case _ => false
+ }
+ if (pkgModule.isModule && !fromSource) {
+ // println("open "+pkgModule)//DEBUG
+ openPackageModule(pkgModule, pkgClass)
+ }
+ }
+
+ object perRunCaches {
+ import java.lang.ref.WeakReference
+ import scala.runtime.ScalaRunTime.stringOf
+ import scala.collection.generic.Clearable
+
+ // Weak references so the garbage collector will take care of
+ // letting us know when a cache is really out of commission.
+ private val caches = mutable.HashSet[WeakReference[Clearable]]()
+
+ def recordCache[T <: Clearable](cache: T): T = {
+ caches += new WeakReference(cache)
+ cache
+ }
+
+ def clearAll() = {
+ debuglog("Clearing " + caches.size + " caches.")
+ caches foreach { ref =>
+ val cache = ref.get()
+ if (cache == null)
+ caches -= ref
+ else
+ cache.clear()
+ }
+ }
+
+ def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]())
+ def newMap[K, V]() = recordCache(mutable.HashMap[K, V]())
+ def newSet[K]() = recordCache(mutable.HashSet[K]())
+ def newWeakSet[K <: AnyRef]() = recordCache(new WeakHashSet[K]())
+ }
+
+ /** The set of all installed infotransformers. */
+ var infoTransformers = new InfoTransformer {
+ val pid = NoPhase.id
+ val changesBaseClasses = true
+ def transform(sym: Symbol, tpe: Type): Type = tpe
+ }
+
+ /** The phase which has given index as identifier. */
+ val phaseWithId: Array[Phase]
+
+ /** Is this symbol table a part of a compiler universe?
+ */
+ def isCompilerUniverse = false
+}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
new file mode 100644
index 0000000000..86693cf880
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -0,0 +1,3190 @@
+ /* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.ListBuffer
+import util.Statistics._
+import Flags._
+
+trait Symbols extends api.Symbols { self: SymbolTable =>
+ import definitions._
+
+ protected var ids = 0
+
+ val emptySymbolArray = new Array[Symbol](0)
+
+ def symbolCount = ids // statistics
+
+ protected def nextId() = { ids += 1; ids }
+
+ /** Used for deciding in the IDE whether we can interrupt the compiler */
+ //protected var activeLocks = 0
+
+ /** Used for debugging only */
+ //protected var lockedSyms = 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 nextexid = 0
+ protected def freshExistentialName(suffix: String) = {
+ nextexid += 1
+ newTypeName("_" + nextexid + suffix)
+ }
+
+ // Set the fields which point companions at one another. Returns the module.
+ def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = {
+ moduleClass.sourceModule = m
+ m setModuleClass moduleClass
+ m
+ }
+
+ /** Create a new free term. Its owner is NoSymbol.
+ */
+ def newFreeTermSymbol(name: TermName, info: Type, value: => Any, flags: Long = 0L, origin: String): FreeTermSymbol =
+ new FreeTermSymbol(name, value, origin) initFlags flags setInfo info
+
+ /** Create a new free type. Its owner is NoSymbol.
+ */
+ def newFreeTypeSymbol(name: TypeName, info: Type, value: => Any, flags: Long = 0L, origin: String): FreeTypeSymbol =
+ new FreeTypeSymbol(name, value, origin) initFlags flags setInfo info
+
+ /** The original owner of a class. Used by the backend to generate
+ * EnclosingMethod attributes.
+ */
+ val originalOwner = perRunCaches.newMap[Symbol, Symbol]()
+
+ abstract class SymbolContextApiImpl extends SymbolContextApi {
+ this: Symbol =>
+
+ def kind: String = kindString
+ def isExistential: Boolean = this.isExistentiallyBound
+
+ def newNestedSymbol(name: Name, pos: Position, newFlags: Long, isClass: Boolean): Symbol = name match {
+ case n: TermName => newTermSymbol(n, pos, newFlags)
+ case n: TypeName => if (isClass) newClassSymbol(n, pos, newFlags) else newNonClassSymbol(n, pos, newFlags)
+ }
+
+ def thisPrefix: Type = thisType
+ def selfType: Type = typeOfThis
+ def typeSignature: Type = info
+ def typeSignatureIn(site: Type): Type = site memberInfo this
+
+ def asType: Type = tpe
+ def asTypeIn(site: Type): Type = site.memberType(this)
+ def asTypeConstructor: Type = typeConstructor
+ def setInternalFlags(flag: Long): this.type = { setFlag(flag); this }
+ def setTypeSignature(tpe: Type): this.type = { setInfo(tpe); this }
+ def getAnnotations: List[AnnotationInfo] = { initialize; annotations }
+ def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this }
+
+ private def lastElemType(ts: Seq[Type]): Type = ts.last.normalize.typeArgs.head
+
+ private def formalTypes(formals: List[Type], nargs: Int): List[Type] = {
+ val formals1 = formals mapConserve {
+ case TypeRef(_, ByNameParamClass, List(arg)) => arg
+ case formal => formal
+ }
+ if (isVarArgTypes(formals1)) {
+ val ft = lastElemType(formals)
+ formals1.init ::: List.fill(nargs - (formals1.length - 1))(ft)
+ } else formals1
+ }
+
+ def resolveOverloaded(pre: Type, targs: Seq[Type], actuals: Seq[Type]): Symbol = {
+ def firstParams(tpe: Type): (List[Symbol], List[Type]) = tpe match {
+ case PolyType(tparams, restpe) =>
+ val (Nil, formals) = firstParams(restpe)
+ (tparams, formals)
+ case MethodType(params, _) =>
+ (Nil, params map (_.tpe))
+ case _ =>
+ (Nil, Nil)
+ }
+ def isApplicable(alt: Symbol, targs: List[Type], actuals: Seq[Type]) = {
+ def isApplicableType(tparams: List[Symbol], tpe: Type): Boolean = {
+ val (tparams, formals) = firstParams(pre memberType alt)
+ val formals1 = formalTypes(formals, actuals.length)
+ val actuals1 =
+ if (isVarArgTypes(actuals)) {
+ if (!isVarArgTypes(formals)) return false
+ actuals.init :+ lastElemType(actuals)
+ } else actuals
+ if (formals1.length != actuals1.length) return false
+
+ if (tparams.isEmpty) return (actuals1 corresponds formals1)(_ <:< _)
+
+ if (targs.length == tparams.length)
+ isApplicableType(List(), tpe.instantiateTypeParams(tparams, targs))
+ else if (targs.nonEmpty)
+ false
+ else {
+ val tvars = tparams map (TypeVar(_))
+ (actuals1 corresponds formals1) { (actual, formal) =>
+ val tp1 = actual.deconst.instantiateTypeParams(tparams, tvars)
+ val pt1 = actual.instantiateTypeParams(tparams, tvars)
+ tp1 <:< pt1
+ } &&
+ solve(tvars, tparams, List.fill(tparams.length)(COVARIANT), upper = false)
+ }
+ }
+ isApplicableType(List(), pre.memberType(alt))
+ }
+ def isAsGood(alt1: Symbol, alt2: Symbol): Boolean = {
+ alt1 == alt2 ||
+ alt2 == NoSymbol || {
+ val (tparams, formals) = firstParams(pre memberType alt1)
+ isApplicable(alt2, tparams map (_.tpe), formals)
+ }
+ }
+ assert(isOverloaded)
+ val applicables = alternatives filter (isApplicable(_, targs.toList, actuals))
+ def winner(alts: List[Symbol]) =
+ ((NoSymbol: Symbol) /: alts)((best, alt) => if (isAsGood(alt, best)) alt else best)
+ val best = winner(applicables)
+ if (best == winner(applicables.reverse)) best else NoSymbol
+ }
+ }
+
+ /** The class for all symbols */
+ abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name)
+ extends SymbolContextApiImpl
+ with HasFlags
+ with Annotatable[Symbol] {
+
+ type AccessBoundaryType = Symbol
+ type AnnotationType = AnnotationInfo
+
+ // TODO - don't allow names to be renamed in this unstructured a fashion.
+ // Rename as little as possible. Enforce invariants on all renames.
+ type TypeOfClonedSymbol >: Null <: Symbol { type NameType = Symbol.this.NameType }
+
+ // Abstract here so TypeSymbol and TermSymbol can have a private[this] field
+ // with the proper specific type.
+ def rawname: NameType
+ def name: NameType
+ def name_=(n: Name): Unit
+ def asNameType(n: Name): NameType
+
+ private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api
+ private[this] var _rawflags: Long = _
+
+ def rawowner = _rawowner
+ def rawflags = _rawflags
+
+ private var rawpos = initPos
+
+ val id = nextId() // identity displayed when -uniqid
+ //assert(id != 3390, initName)
+
+ private[this] var _validTo: Period = NoPeriod
+
+ if (traceSymbolActivity)
+ traceSymbols.recordNewSymbol(this)
+
+ def validTo = _validTo
+ def validTo_=(x: Period) { _validTo = x}
+
+ def pos = rawpos
+ def setPos(pos: Position): this.type = { this.rawpos = pos; this }
+ def setName(name: Name): this.type = { this.name = asNameType(name) ; this }
+
+ // Update the surrounding scopes
+ protected[this] def changeNameInOwners(name: Name) {
+ if (owner.isClass) {
+ var ifs = owner.infos
+ while (ifs != null) {
+ ifs.info.decls.rehash(this, name)
+ ifs = ifs.prev
+ }
+ }
+ }
+
+ def rawFlagString(mask: Long): String = calculateFlagString(rawflags & mask)
+ def rawFlagString: String = rawFlagString(flagMask)
+ def debugFlagString: String = flagString(AllFlags)
+
+ /** String representation of symbol's variance */
+ def varianceString: String =
+ if (variance == 1) "+"
+ else if (variance == -1) "-"
+ else ""
+
+ override def flagMask =
+ if (settings.debug.value && !isAbstractType) AllFlags
+ else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE
+ else ExplicitFlags
+
+ // make the error message more googlable
+ def flagsExplanationString =
+ if (isGADTSkolem) " (this is a GADT skolem)"
+ else ""
+
+ def shortSymbolClass = getClass.getName.split('.').last.stripPrefix("Symbols$")
+ def symbolCreationString: String = (
+ "%s%25s | %-40s | %s".format(
+ if (settings.uniqid.value) "%06d | ".format(id) else "",
+ shortSymbolClass,
+ name.decode + " in " + owner,
+ rawFlagString
+ )
+ )
+
+// ------ creators -------------------------------------------------------------------
+
+ final def newValue(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol =
+ newTermSymbol(name, pos, newFlags)
+ final def newVariable(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol =
+ newTermSymbol(name, pos, MUTABLE | newFlags)
+ final def newValueParameter(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol =
+ newTermSymbol(name, pos, PARAM | newFlags)
+
+ /** Create local dummy for template (owner of local blocks) */
+ final def newLocalDummy(pos: Position): TermSymbol =
+ newTermSymbol(nme.localDummyName(this), pos) setInfo NoType
+ final def newMethod(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol =
+ createMethodSymbol(name, pos, METHOD | newFlags)
+ final def newMethodSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): MethodSymbol =
+ createMethodSymbol(name, pos, METHOD | newFlags)
+ final def newLabel(name: TermName, pos: Position = NoPosition): MethodSymbol =
+ newMethod(name, pos, LABEL)
+
+ /** Propagates ConstrFlags (JAVA, specifically) from owner to constructor. */
+ final def newConstructor(pos: Position, newFlags: Long = 0L): MethodSymbol =
+ newMethod(nme.CONSTRUCTOR, pos, getFlag(ConstrFlags) | newFlags)
+
+ /** Static constructor with info set. */
+ def newStaticConstructor(pos: Position): MethodSymbol =
+ newConstructor(pos, STATIC) setInfo UnitClass.tpe
+
+ /** Instance constructor with info set. */
+ def newClassConstructor(pos: Position): MethodSymbol =
+ newConstructor(pos) setInfo MethodType(Nil, this.tpe)
+
+ def newLinkedModule(clazz: Symbol, newFlags: Long = 0L): ModuleSymbol = {
+ val m = newModuleSymbol(clazz.name.toTermName, clazz.pos, MODULE | newFlags)
+ connectModuleToClass(m, clazz.asInstanceOf[ClassSymbol])
+ }
+ final def newModule(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = {
+ val m = newModuleSymbol(name, pos, newFlags | MODULE)
+ val clazz = newModuleClass(name.toTypeName, pos, m getFlag ModuleToClassFlags)
+ connectModuleToClass(m, clazz)
+ }
+
+ final def newPackage(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol = {
+ assert(name == nme.ROOT || isPackageClass, this)
+ newModule(name, pos, PackageFlags | newFlags)
+ }
+
+ final def newThisSym(name: TermName = nme.this_, pos: Position = NoPosition): TermSymbol =
+ newTermSymbol(name, pos, SYNTHETIC)
+
+ final def newImport(pos: Position): TermSymbol =
+ newTermSymbol(nme.IMPORT, pos)
+
+ final def newModuleSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol =
+ newTermSymbol(name, pos, newFlags).asInstanceOf[ModuleSymbol]
+
+ final def newModuleAndClassSymbol(name: Name, pos: Position, flags: FlagSet): (ModuleSymbol, ClassSymbol) = {
+ val m = newModuleSymbol(name, pos, flags | MODULE)
+ val c = newModuleClass(name.toTypeName, pos, m getFlag ModuleToClassFlags)
+ connectModuleToClass(m, c)
+ (m, c)
+ }
+
+ final def newPackageSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleSymbol =
+ newTermSymbol(name, pos, newFlags).asInstanceOf[ModuleSymbol]
+
+ final def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol =
+ newClassSymbol(name, pos, newFlags).asInstanceOf[ModuleClassSymbol]
+
+ final def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem =
+ createTypeSkolemSymbol(name, origin, pos, newFlags)
+
+ /** @param pre type relative to which alternatives are seen.
+ * for instance:
+ * class C[T] {
+ * def m(x: T): T
+ * def m'(): T
+ * }
+ * val v: C[Int]
+ *
+ * Then v.m has symbol TermSymbol(flags = {OVERLOADED},
+ * tpe = OverloadedType(C[Int], List(m, m')))
+ * You recover the type of m doing a
+ *
+ * m.tpe.asSeenFrom(pre, C) (generally, owner of m, which is C here).
+ *
+ * or:
+ *
+ * pre.memberType(m)
+ */
+ final def newOverloaded(pre: Type, alternatives: List[Symbol]): TermSymbol = (
+ newTermSymbol(alternatives.head.name.toTermName, alternatives.head.pos, OVERLOADED)
+ setInfo OverloadedType(pre, alternatives)
+ )
+
+ final def newErrorValue(name: TermName): TermSymbol =
+ newTermSymbol(name, pos, SYNTHETIC | IS_ERROR) setInfo ErrorType
+
+ /** Symbol of a type definition type T = ...
+ */
+ final def newAliasType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol =
+ createAliasTypeSymbol(name, pos, newFlags)
+
+ /** Symbol of an abstract type type T >: ... <: ...
+ */
+ final def newAbstractType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol =
+ createAbstractTypeSymbol(name, pos, DEFERRED | newFlags)
+
+ /** Symbol of a type parameter
+ */
+ final def newTypeParameter(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol =
+ newAbstractType(name, pos, PARAM | newFlags)
+
+// is defined in SymbolCreations
+// final def newTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol =
+// (if ((newFlags & DEFERRED) != 0) new AbstractTypeSymbol(this, pos, name)
+// else new AbstractTypeSymbol(this, pos, name)) setFlag newFlags
+
+ /** Symbol of an existential type T forSome { ... }
+ */
+ final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol =
+ newAbstractType(name, pos, EXISTENTIAL | newFlags)
+
+ /** Synthetic value parameters when parameter symbols are not available
+ */
+ final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[TermSymbol]] = {
+ var cnt = 0
+ def freshName() = { cnt += 1; nme.syntheticParamName(cnt) }
+ mmap(argtypess)(tp => newValueParameter(freshName(), owner.pos.focus, SYNTHETIC) setInfo tp)
+ }
+
+ def newSyntheticTypeParam(): TypeSymbol = newSyntheticTypeParam("T0", 0L)
+ def newSyntheticTypeParam(name: String, newFlags: Long): TypeSymbol = newTypeParameter(newTypeName(name), NoPosition, newFlags) setInfo TypeBounds.empty
+ def newSyntheticTypeParams(num: Int): List[TypeSymbol] = (0 until num).toList map (n => newSyntheticTypeParam("T" + n, 0L))
+
+ /** Create a new existential type skolem with this symbol its owner,
+ * based on the given symbol and origin.
+ */
+ def newExistentialSkolem(basis: Symbol, origin: AnyRef): TypeSkolem = {
+ val skolem = newTypeSkolemSymbol(basis.name.toTypeName, origin, basis.pos, (basis.flags | EXISTENTIAL) & ~PARAM)
+ skolem setInfo (basis.info cloneInfo skolem)
+ }
+
+ // flags set up to maintain TypeSkolem's invariant: origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
+ // CASEACCESSOR | SYNTHETIC used to single this symbol out in deskolemizeGADT
+ def newGADTSkolem(name: TypeName, origin: Symbol, info: Type): TypeSkolem =
+ newTypeSkolemSymbol(name, origin, origin.pos, origin.flags & ~(EXISTENTIAL | PARAM) | CASEACCESSOR | SYNTHETIC) setInfo info
+
+ final def freshExistential(suffix: String): TypeSymbol =
+ newExistential(freshExistentialName(suffix), pos)
+
+ /** Synthetic value parameters when parameter symbols are not available.
+ * Calling this method multiple times will re-use the same parameter names.
+ */
+ final def newSyntheticValueParams(argtypes: List[Type]): List[TermSymbol] =
+ newSyntheticValueParamss(List(argtypes)).head
+
+ /** Synthetic value parameter when parameter symbol is not available.
+ * Calling this method multiple times will re-use the same parameter name.
+ */
+ final def newSyntheticValueParam(argtype: Type): Symbol =
+ newSyntheticValueParams(List(argtype)).head
+
+ /** Type skolems are type parameters ''seen from the inside''
+ * Assuming a polymorphic method m[T], its type is a PolyType which has a TypeParameter
+ * with name `T` in its typeParams list. While type checking the parameters, result type and
+ * body of the method, there's a local copy of `T` which is a TypeSkolem.
+ */
+ final def newTypeSkolem: TypeSkolem =
+ owner.newTypeSkolemSymbol(name.toTypeName, this, pos, flags)
+
+ final def newClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol =
+ newClassSymbol(name, pos, newFlags)
+
+ /** A new class with its info set to a ClassInfoType with given scope and parents. */
+ def newClassWithInfo(name: TypeName, parents: List[Type], scope: Scope, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = {
+ val clazz = newClass(name, pos, newFlags)
+ clazz setInfo ClassInfoType(parents, scope, clazz)
+ }
+ final def newErrorClass(name: TypeName): ClassSymbol =
+ newClassWithInfo(name, Nil, new ErrorScope(this), pos, SYNTHETIC | IS_ERROR)
+
+ final def newModuleClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol =
+ newModuleClassSymbol(name, pos, newFlags | MODULE)
+
+ final def newAnonymousFunctionClass(pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol =
+ newClassSymbol(tpnme.ANON_FUN_NAME, pos, FINAL | SYNTHETIC | newFlags)
+
+ final def newAnonymousFunctionValue(pos: Position, newFlags: Long = 0L): TermSymbol =
+ newTermSymbol(nme.ANON_FUN_NAME, pos, SYNTHETIC | newFlags) setInfo NoType
+
+ def newImplClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = {
+ newClassSymbol(name, pos, newFlags | IMPLCLASS)
+ }
+
+ /** Refinement types P { val x: String; type T <: Number }
+ * also have symbols, they are refinementClasses
+ */
+ final def newRefinementClass(pos: Position): RefinementClassSymbol =
+ createRefinementClassSymbol(pos, 0L)
+
+ /** Create a new getter for current symbol (which must be a field)
+ */
+ final def newGetter: MethodSymbol = (
+ owner.newMethod(nme.getterName(name.toTermName), NoPosition, getterFlags(flags))
+ setPrivateWithin privateWithin
+ setInfo MethodType(Nil, tpe)
+ )
+
+ final def newErrorSymbol(name: Name): Symbol = name match {
+ case x: TypeName => newErrorClass(x)
+ case x: TermName => newErrorValue(x)
+ }
+
+ @deprecated("Use the other signature", "2.10.0")
+ def newClass(pos: Position, name: TypeName): Symbol = newClass(name, pos)
+ @deprecated("Use the other signature", "2.10.0")
+ def newModuleClass(pos: Position, name: TypeName): Symbol = newModuleClass(name, pos)
+ @deprecated("Use the other signature", "2.10.0")
+ def newLabel(pos: Position, name: TermName): MethodSymbol = newLabel(name, pos)
+ @deprecated("Use the other signature", "2.10.0")
+ def newValue(pos: Position, name: TermName): TermSymbol = newTermSymbol(name, pos)
+ @deprecated("Use the other signature", "2.10.0")
+ def newAliasType(pos: Position, name: TypeName): Symbol = newAliasType(name, pos)
+ @deprecated("Use the other signature", "2.10.0")
+ def newAbstractType(pos: Position, name: TypeName): Symbol = newAbstractType(name, pos)
+ @deprecated("Use the other signature", "2.10.0")
+ def newExistential(pos: Position, name: TypeName): Symbol = newExistential(name, pos)
+ @deprecated("Use the other signature", "2.10.0")
+ def newMethod(pos: Position, name: TermName): MethodSymbol = newMethod(name, pos)
+
+// ----- locking and unlocking ------------------------------------------------------
+
+ // True if the symbol is unlocked.
+ // True if the symbol is locked but still below the allowed recursion depth.
+ // False otherwise
+ private[scala] def lockOK: Boolean = {
+ ((_rawflags & LOCKED) == 0L) ||
+ ((settings.Yrecursion.value != 0) &&
+ (recursionTable get this match {
+ case Some(n) => (n <= settings.Yrecursion.value)
+ case None => true }))
+ }
+
+ // Lock a symbol, using the handler if the recursion depth becomes too great.
+ private[scala] def lock(handler: => Unit): Boolean = {
+ if ((_rawflags & LOCKED) != 0L) {
+ if (settings.Yrecursion.value != 0) {
+ recursionTable get this match {
+ case Some(n) =>
+ if (n > settings.Yrecursion.value) {
+ handler
+ false
+ } else {
+ recursionTable += (this -> (n + 1))
+ true
+ }
+ case None =>
+ recursionTable += (this -> 1)
+ true
+ }
+ } else { handler; false }
+ } else {
+ _rawflags |= LOCKED
+ true
+// activeLocks += 1
+// lockedSyms += this
+ }
+ }
+
+ // Unlock a symbol
+ private[scala] def unlock() = {
+ if ((_rawflags & LOCKED) != 0L) {
+// activeLocks -= 1
+// lockedSyms -= this
+ _rawflags &= ~LOCKED
+ if (settings.Yrecursion.value != 0)
+ recursionTable -= this
+ }
+ }
+
+// ----- tests ----------------------------------------------------------------------
+
+ def isAliasType = false
+ def isAbstractType = false
+ def isSkolem = false
+
+ /** A Type, but not a Class. */
+ def isNonClassType = false
+
+ /** The bottom classes are Nothing and Null, found in Definitions. */
+ def isBottomClass = false
+ def isSpecialized = this hasFlag SPECIALIZED
+
+ /** These are all tests for varieties of ClassSymbol, which has these subclasses:
+ * - ModuleClassSymbol
+ * - RefinementClassSymbol
+ * - PackageClassSymbol (extends ModuleClassSymbol)
+ */
+ def isAbstractClass = false
+ def isAnonOrRefinementClass = false
+ def isAnonymousClass = false
+ def isCaseClass = false
+ def isConcreteClass = false
+ def isImplClass = false // the implementation class of a trait
+ def isJavaInterface = false
+ def isModuleClass = false
+ def isNumericValueClass = false
+ def isPrimitiveValueClass = false
+ def isRefinementClass = false
+ override def isTrait = false
+
+ /** Qualities of Types, always false for TermSymbols.
+ */
+ def isContravariant = false
+ def isCovariant = false
+ def isExistentialQuantified = false
+ def isExistentialSkolem = false
+ def isExistentiallyBound = false
+ def isGADTSkolem = false
+ def isTypeParameter = false
+ def isTypeParameterOrSkolem = false
+ def isTypeSkolem = false
+ def isTypeMacro = false
+
+ /** Qualities of Terms, always false for TypeSymbols.
+ */
+ def isAccessor = false
+ def isBridge = false
+ def isCapturedVariable = false
+ def isClassConstructor = false
+ def isConstructor = false
+ def isEarlyInitialized = false
+ def isGetter = false
+ def isLocalDummy = false
+ def isMixinConstructor = false
+ def isOverloaded = false
+ def isSetter = false
+ def isSetterParameter = false
+ def isValue = false
+ def isValueParameter = false
+ def isVariable = false
+ override def hasDefault = false
+ def isTermMacro = false
+
+ /** Qualities of MethodSymbols, always false for TypeSymbols
+ * and other TermSymbols.
+ */
+ def isCaseAccessorMethod = false
+ def isLiftedMethod = false
+ def isSourceMethod = false
+ def isVarargsMethod = false
+ override def isLabel = false
+
+ /** Package/package object tests */
+ def isPackageClass = false
+ def isPackageObject = false
+ def isPackageObjectClass = false
+ def isPackageObjectOrClass = isPackageObject || isPackageObjectClass
+ def isModuleOrModuleClass = isModule || isModuleClass
+
+ /** Overridden in custom objects in Definitions */
+ def isRoot = false
+ def isRootPackage = false
+ def isRootSymbol = false // RootPackage and RootClass. TODO: also NoSymbol.
+ def isEmptyPackage = false
+ def isEmptyPackageClass = false
+
+ /** Is this symbol an effective root for fullname string?
+ */
+ def isEffectiveRoot = false
+
+ /** For RootClass, this is EmptyPackageClass. For all other symbols,
+ * the symbol itself.
+ */
+ def ownerOfNewSymbols = this
+
+ final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol
+ final def isOverridableMember = !(isClass || isEffectivelyFinal) && (this ne NoSymbol) && owner.isClass
+
+ /** Does this symbol denote a wrapper created by the repl? */
+ final def isInterpreterWrapper = (
+ (this hasFlag MODULE)
+ && owner.isPackageClass
+ && nme.isReplWrapperName(name)
+ )
+ @inline final def getFlag(mask: Long): Long = flags & mask
+ /** Does symbol have ANY flag in `mask` set? */
+ @inline final def hasFlag(mask: Long): Boolean = (flags & mask) != 0
+ /** Does symbol have ALL the flags in `mask` set? */
+ @inline final def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask
+
+ def setFlag(mask: Long): this.type = { _rawflags |= mask ; this }
+ def resetFlag(mask: Long): this.type = { _rawflags &= ~mask ; this }
+ def resetFlags() { rawflags &= TopLevelCreationFlags }
+
+ /** Default implementation calls the generic string function, which
+ * will print overloaded flags as <flag1/flag2/flag3>. Subclasses
+ * of Symbol refine.
+ */
+ override def resolveOverloadedFlag(flag: Long): String = Flags.flagToString(flag)
+
+ /** Set the symbol's flags to the given value, asserting
+ * that the previous value was 0.
+ */
+ def initFlags(mask: Long): this.type = {
+ assert(rawflags == 0L, symbolCreationString)
+ _rawflags = mask
+ this
+ }
+
+ final def flags: Long = {
+ val fs = _rawflags & phase.flagMask
+ (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift)
+ }
+ def flags_=(fs: Long) = _rawflags = fs
+ def rawflags_=(x: Long) { _rawflags = x }
+
+ final def hasGetter = isTerm && nme.isLocalName(name)
+
+ final def isInitializedToDefault = !isType && hasAllFlags(DEFAULTINIT | ACCESSOR)
+ final def isStaticModule = isModule && isStatic && !isMethod
+ final def isThisSym = isTerm && owner.thisSym == this
+ final def isError = hasFlag(IS_ERROR)
+ final def isErroneous = isError || isInitialized && tpe.isErroneous
+
+ def isHigherOrderTypeParameter = owner.isTypeParameterOrSkolem
+
+ // class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor
+ def isClassLocalToConstructor = false
+
+ final def isDerivedValueClass =
+ isClass && info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass
+
+ final def isMethodWithExtension =
+ isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR)
+
+ final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
+ final def isDefinedInPackage = effectiveOwner.isPackageClass
+ final def needsFlatClasses = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass
+
+ /** change name by appending $$<fully-qualified-name-of-class `base`>
+ * Do the same for any accessed symbols or setters/getters.
+ * Implementation in TermSymbol.
+ */
+ def expandName(base: Symbol) { }
+
+ // In java.lang, Predef, or scala package/package object
+ def isInDefaultNamespace = UnqualifiedOwners(effectiveOwner)
+
+ /** The owner, skipping package objects.
+ */
+ def effectiveOwner = owner.skipPackageObject
+
+ /** If this is a package object or its implementing class, its owner: otherwise this.
+ */
+ def skipPackageObject: Symbol = this
+
+ /** If this is a constructor, its owner: otherwise this.
+ */
+ final def skipConstructor: Symbol = if (isConstructor) owner else this
+
+ /** Conditions where we omit the prefix when printing a symbol, to avoid
+ * unpleasantries like Predef.String, $iw.$iw.Foo and <empty>.Bippy.
+ */
+ final def isOmittablePrefix = /*!settings.debug.value &&*/ (
+ UnqualifiedOwners(skipPackageObject)
+ || isEmptyPrefix
+ )
+ def isEmptyPrefix = (
+ isEffectiveRoot // has no prefix for real, <empty> or <root>
+ || isAnonOrRefinementClass // has uninteresting <anon> or <refinement> prefix
+ || nme.isReplWrapperName(name) // has ugly $iw. prefix (doesn't call isInterpreterWrapper due to nesting)
+ )
+ def isFBounded = info match {
+ case TypeBounds(_, _) => info.baseTypeSeq exists (_ contains this)
+ case _ => false
+ }
+
+ /** Is symbol a monomorphic type?
+ * assumption: if a type starts out as monomorphic, it will not acquire
+ * type parameters in later phases.
+ */
+ final def isMonomorphicType =
+ isType && {
+ val info = originalInfo
+ info.isComplete && !info.isHigherKinded
+ }
+
+ def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr)
+ def isSerializable = (
+ info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass)
+ || hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated
+ )
+ def hasBridgeAnnotation = hasAnnotation(BridgeClass)
+ def isDeprecated = hasAnnotation(DeprecatedAttr)
+ def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0)
+ def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1)
+ def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0)
+
+ // !!! when annotation arguments are not literal strings, but any sort of
+ // assembly of strings, there is a fair chance they will turn up here not as
+ // Literal(const) but some arbitrary AST. However nothing in the compiler
+ // prevents someone from writing a @migration annotation with a calculated
+ // string. So this needs attention. For now the fact that migration is
+ // private[scala] ought to provide enough protection.
+ def hasMigrationAnnotation = hasAnnotation(MigrationAnnotationClass)
+ def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(0) }
+ def migrationVersion = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(1) }
+ def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) }
+ def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) }
+
+ /** Is this symbol an accessor method for outer? */
+ final def isOuterAccessor = {
+ hasFlag(STABLE | SYNTHETIC) &&
+ originalName == nme.OUTER
+ }
+
+ /** Is this symbol an accessor method for outer? */
+ final def isOuterField = {
+ hasFlag(SYNTHETIC) &&
+ originalName == nme.OUTER_LOCAL
+ }
+
+ /** Does this symbol denote a stable value? */
+ def isStable = false
+
+ /** Does this symbol denote the primary constructor of its enclosing class? */
+ final def isPrimaryConstructor =
+ isConstructor && owner.primaryConstructor == this
+
+ /** Does this symbol denote an auxiliary constructor of its enclosing class? */
+ final def isAuxiliaryConstructor =
+ isConstructor && !isPrimaryConstructor
+
+ /** Is this symbol a synthetic apply or unapply method in a companion object of a case class? */
+ final def isCaseApplyOrUnapply =
+ isMethod && isCase && isSynthetic
+
+ /** Is this symbol a trait which needs an implementation class? */
+ final def needsImplClass = (
+ isTrait
+ && (!isInterface || hasFlag(lateINTERFACE))
+ && !isImplClass
+ )
+
+ /** Is this a symbol which exists only in the implementation class, not in its trait? */
+ final def isImplOnly = isPrivate || (
+ (owner.isTrait || owner.isImplClass) && (
+ hasAllFlags(LIFTED | MODULE | METHOD)
+ || isConstructor
+ || hasFlag(notPRIVATE | LIFTED) && !hasFlag(ACCESSOR | SUPERACCESSOR | MODULE)
+ )
+ )
+ final def isModuleVar = hasFlag(MODULEVAR)
+
+ /** Is this symbol static (i.e. with no outer instance)?
+ * Q: When exactly is a sym marked as STATIC?
+ * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep.
+ * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
+ */
+ def isStatic = (this hasFlag STATIC) || owner.isStaticOwner
+
+ /** Is this symbol a static constructor? */
+ final def isStaticConstructor: Boolean =
+ isStaticMember && isClassConstructor
+
+ /** Is this symbol a static member of its class? (i.e. needs to be implemented as a Java static?) */
+ final def isStaticMember: Boolean =
+ hasFlag(STATIC) || owner.isImplClass
+
+ /** Does this symbol denote a class that defines static symbols? */
+ final def isStaticOwner: Boolean =
+ isPackageClass || isModuleClass && isStatic
+
+ def isTopLevelModule = hasFlag(MODULE) && owner.isPackageClass
+
+ /** Is this symbol effectively final? I.e, it cannot be overridden */
+ final def isEffectivelyFinal: Boolean = (
+ (this hasFlag FINAL | PACKAGE)
+ || isModuleOrModuleClass && (owner.isPackageClass || !settings.overrideObjects.value)
+ || isTerm && (
+ isPrivate
+ || isLocal
+ || owner.isClass && owner.isEffectivelyFinal
+ )
+ )
+
+ /** Is this symbol locally defined? I.e. not accessed from outside `this` instance */
+ final def isLocal: Boolean = owner.isTerm
+
+ /** Is this symbol a constant? */
+ final def isConstant: Boolean = isStable && isConstantType(tpe.resultType)
+
+ /** Is this class nested in another class or module (not a package)? */
+ def isNestedClass = false
+
+ /** Is this class locally defined?
+ * A class is local, if
+ * - it is anonymous, or
+ * - its owner is a value
+ * - it is defined within a local class
+ */
+ def isLocalClass = false
+
+ def isStableClass = false
+
+/* code for fixing nested objects
+ override final def isModuleClass: Boolean =
+ super.isModuleClass && !isExpandedModuleClass
+*/
+ /** Is this class or type defined as a structural refinement type?
+ */
+ final def isStructuralRefinement: Boolean =
+ (isClass || isType || isModule) && info.normalize/*.underlying*/.isStructuralRefinement
+
+ /** Is this a term symbol only defined in a refinement (so that it needs
+ * to be accessed by reflection)?
+ */
+ def isOnlyRefinementMember: Boolean =
+ isTerm && // type members are not affected
+ owner.isRefinementClass && // owner must be a refinement class
+ (owner.info decl name) == this && // symbol must be explicitly declared in the refinement (not synthesized from glb)
+ allOverriddenSymbols.isEmpty && // symbol must not override a symbol in a base class
+ !isConstant // symbol must not be a constant. Question: Can we exclude @inline methods as well?
+
+ final def isStructuralRefinementMember = owner.isStructuralRefinement && isPossibleInRefinement && isPublic
+ final def isPossibleInRefinement = !isConstructor && !isOverridingSymbol
+
+ /** Is this symbol a member of class `clazz`? */
+ def isMemberOf(clazz: Symbol) =
+ clazz.info.member(name).alternatives contains this
+
+ /** A a member of class `base` is incomplete if
+ * (1) it is declared deferred or
+ * (2) it is abstract override and its super symbol in `base` is
+ * nonexistent or incomplete.
+ *
+ * @param base ...
+ * @return ...
+ */
+ final def isIncompleteIn(base: Symbol): Boolean =
+ this.isDeferred ||
+ (this hasFlag ABSOVERRIDE) && {
+ val supersym = superSymbol(base)
+ supersym == NoSymbol || supersym.isIncompleteIn(base)
+ }
+
+ // Does not always work if the rawInfo is a SourcefileLoader, see comment
+ // in "def coreClassesFirst" in Global.
+ def exists = !owner.isPackageClass || { rawInfo.load(this); rawInfo != NoType }
+
+ final def isInitialized: Boolean =
+ validTo != NoPeriod
+
+ // [Eugene] todo. needs to be reviewed and [only then] rewritten without explicit returns
+ /** Determines whether this symbol can be loaded by subsequent reflective compilation */
+ final def isLocatable: Boolean = {
+ if (this == NoSymbol) return false
+ if (isRoot || isRootPackage) return true
+
+ if (!owner.isLocatable) return false
+ if (owner.isTerm) return false
+ if (isLocalDummy) return false
+
+ if (isType && isNonClassType) return false
+ if (isRefinementClass) return false
+ return true
+ }
+
+ // [Eugene] is it a good idea to add ``dealias'' to Symbol?
+ /** Expands type aliases */
+ def dealias: Symbol = this
+
+ /** The variance of this symbol as an integer */
+ final def variance: Int =
+ if (isCovariant) 1
+ else if (isContravariant) -1
+ else 0
+
+ /** The sequence number of this parameter symbol among all type
+ * and value parameters of symbol's owner. -1 if symbol does not
+ * appear among the parameters of its owner.
+ */
+ def paramPos: Int = {
+ def searchIn(tpe: Type, base: Int): Int = {
+ def searchList(params: List[Symbol], fallback: Type): Int = {
+ val idx = params indexOf this
+ if (idx >= 0) idx + base
+ else searchIn(fallback, base + params.length)
+ }
+ tpe match {
+ case PolyType(tparams, res) => searchList(tparams, res)
+ case MethodType(params, res) => searchList(params, res)
+ case _ => -1
+ }
+ }
+ searchIn(owner.info, 0)
+ }
+
+// ------ owner attribute --------------------------------------------------------------
+
+ def owner: Symbol = rawowner
+ // TODO - don't allow the owner to be changed without checking invariants, at least
+ // when under some flag. Define per-phase invariants for owner/owned relationships,
+ // e.g. after flatten all classes are owned by package classes, there are lots and
+ // lots of these to be declared (or more realistically, discovered.)
+ def owner_=(owner: Symbol) {
+ // don't keep the original owner in presentation compiler runs
+ // (the map will grow indefinitely, and the only use case is the
+ // backend).
+ if (!forInteractive) {
+ if (originalOwner contains this) ()
+ else originalOwner(this) = rawowner
+ }
+ assert(isCompilerUniverse, "owner_= is not thread-safe; cannot be run in reflexive code")
+ if (traceSymbolActivity)
+ traceSymbols.recordNewSymbolOwner(this, owner)
+ _rawowner = owner
+ }
+
+ def ownerChain: List[Symbol] = this :: owner.ownerChain
+ def originalOwnerChain: List[Symbol] = this :: originalOwner.getOrElse(this, rawowner).originalOwnerChain
+
+ // Non-classes skip self and return rest of owner chain; overridden in ClassSymbol.
+ def enclClassChain: List[Symbol] = owner.enclClassChain
+
+ def ownersIterator: Iterator[Symbol] = new Iterator[Symbol] {
+ private var current = Symbol.this
+ def hasNext = current ne NoSymbol
+ def next = { val r = current; current = current.owner; r }
+ }
+
+ /** Same as `ownerChain contains sym` but more efficient, and
+ * with a twist for refinement classes (see RefinementClassSymbol.)
+ */
+ def hasTransOwner(sym: Symbol): Boolean = {
+ var o = this
+ while ((o ne sym) && (o ne NoSymbol)) o = o.owner
+ (o eq sym)
+ }
+
+// ------ name attribute --------------------------------------------------------------
+
+ /** If this symbol has an expanded name, its original name, otherwise its name itself.
+ * @see expandName
+ */
+ def originalName: Name = nme.originalName(name)
+
+ /** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`.
+ */
+ def encodedName: String = name.toString
+
+ /** The decoded name of the symbol, e.g. `==` instead of `\$eq\$eq`.
+ */
+ def decodedName: String = nme.dropLocalSuffix(name).decode
+
+ private def addModuleSuffix(n: Name): Name =
+ if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n
+
+ def moduleSuffix: String = (
+ if (needsModuleSuffix) nme.MODULE_SUFFIX_STRING
+ else ""
+ )
+ /** Whether this symbol needs nme.MODULE_SUFFIX_STRING (aka $) appended on the java platform.
+ */
+ def needsModuleSuffix = (
+ hasModuleFlag
+ && !isMethod
+ && !isImplClass
+ && !isJavaDefined
+ )
+ /** These should be moved somewhere like JavaPlatform.
+ */
+ def javaSimpleName: Name = addModuleSuffix(nme.dropLocalSuffix(simpleName))
+ def javaBinaryName: Name = addModuleSuffix(fullNameInternal('/'))
+ def javaClassName: String = addModuleSuffix(fullNameInternal('.')).toString
+
+ /** The encoded full path name of this symbol, where outer names and inner names
+ * are separated by `separator` characters.
+ * Never translates expansions of operators back to operator symbol.
+ * Never adds id.
+ * Drops package objects.
+ */
+ final def fullName(separator: Char): String = fullNameAsName(separator).toString
+
+ /** Doesn't drop package objects, for those situations (e.g. classloading)
+ * where the true path is needed.
+ */
+ private def fullNameInternal(separator: Char): Name = (
+ if (isRoot || isRootPackage || this == NoSymbol) name
+ else if (owner.isEffectiveRoot) name
+ else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name
+ )
+
+ def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator))
+
+ /** The encoded full path name of this symbol, where outer names and inner names
+ * are separated by periods.
+ */
+ final def fullName: String = fullName('.')
+
+ /**
+ * Symbol creation implementations.
+ */
+
+ protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol =
+ new AbstractTypeSymbol(this, pos, name) initFlags newFlags
+
+ protected def createAliasTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AliasTypeSymbol =
+ new AliasTypeSymbol(this, pos, name) initFlags newFlags
+
+ protected def createTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position, newFlags: Long): TypeSkolem =
+ new TypeSkolem(this, pos, name, origin) initFlags newFlags
+
+ protected def createClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
+ new ClassSymbol(this, pos, name) initFlags newFlags
+
+ protected def createModuleClassSymbol(name: TypeName, pos: Position, newFlags: Long): ModuleClassSymbol =
+ new ModuleClassSymbol(this, pos, name) initFlags newFlags
+
+ protected def createPackageClassSymbol(name: TypeName, pos: Position, newFlags: Long): PackageClassSymbol =
+ new PackageClassSymbol(this, pos, name) initFlags newFlags
+
+ protected def createRefinementClassSymbol(pos: Position, newFlags: Long): RefinementClassSymbol =
+ new RefinementClassSymbol(this, pos) initFlags newFlags
+
+ protected def createPackageObjectClassSymbol(pos: Position, newFlags: Long): PackageObjectClassSymbol =
+ new PackageObjectClassSymbol(this, pos) initFlags newFlags
+
+ protected def createImplClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
+ new ClassSymbol(this, pos, name) with ImplClassSymbol initFlags newFlags
+
+ protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) initFlags newFlags
+
+ protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol =
+ new MethodSymbol(this, pos, name) initFlags newFlags
+
+ protected def createModuleSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
+ new ModuleSymbol(this, pos, name) initFlags newFlags
+
+ protected def createPackageSymbol(name: TermName, pos: Position, newFlags: Long): ModuleSymbol =
+ new ModuleSymbol(this, pos, name) initFlags newFlags
+
+ protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) initFlags newFlags
+
+ protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) initFlags newFlags
+
+ final def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = {
+ if ((newFlags & METHOD) != 0)
+ createMethodSymbol(name, pos, newFlags)
+ else if ((newFlags & PACKAGE) != 0)
+ createPackageSymbol(name, pos, newFlags | PackageFlags)
+ else if ((newFlags & MODULE) != 0)
+ createModuleSymbol(name, pos, newFlags)
+ else if ((newFlags & PARAM) != 0)
+ createValueParameterSymbol(name, pos, newFlags)
+ else
+ createValueMemberSymbol(name, pos, newFlags)
+ }
+
+ final def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = {
+ if (name == tpnme.REFINE_CLASS_NAME)
+ createRefinementClassSymbol(pos, newFlags)
+ else if ((newFlags & PACKAGE) != 0)
+ createPackageClassSymbol(name, pos, newFlags | PackageFlags)
+ else if (name == tpnme.PACKAGE)
+ createPackageObjectClassSymbol(pos, newFlags)
+ else if ((newFlags & MODULE) != 0)
+ createModuleClassSymbol(name, pos, newFlags)
+ else if ((newFlags & IMPLCLASS) != 0)
+ createImplClassSymbol(name, pos, newFlags)
+ else
+ createClassSymbol(name, pos, newFlags)
+ }
+
+ final def newNonClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol = {
+ if ((newFlags & DEFERRED) != 0)
+ createAbstractTypeSymbol(name, pos, newFlags)
+ else
+ createAliasTypeSymbol(name, pos, newFlags)
+ }
+
+ def newTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol =
+ newNonClassSymbol(name, pos, newFlags)
+
+ /** The class or term up to which this symbol is accessible,
+ * or RootClass if it is public. As java protected statics are
+ * otherwise completely inaccessible in scala, they are treated
+ * as public.
+ */
+ def accessBoundary(base: Symbol): Symbol = {
+ if (hasFlag(PRIVATE) || isLocal) owner
+ else if (hasAllFlags(PROTECTED | STATIC | JAVA)) enclosingRootClass
+ else if (hasAccessBoundary && !phase.erasedTypes) privateWithin
+ else if (hasFlag(PROTECTED)) base
+ else enclosingRootClass
+ }
+
+ def isLessAccessibleThan(other: Symbol): Boolean = {
+ val tb = this.accessBoundary(owner)
+ val ob1 = other.accessBoundary(owner)
+ val ob2 = ob1.linkedClassOfClass
+ var o = tb
+ while (o != NoSymbol && o != ob1 && o != ob2) {
+ o = o.owner
+ }
+ o != NoSymbol && o != tb
+ }
+
+ /** See comment in HasFlags for how privateWithin combines with flags.
+ */
+ private[this] var _privateWithin: Symbol = _
+ def privateWithin = _privateWithin
+ def privateWithin_=(sym: Symbol) { _privateWithin = sym }
+ def setPrivateWithin(sym: Symbol): this.type = { privateWithin_=(sym) ; this }
+
+ /** Does symbol have a private or protected qualifier set? */
+ final def hasAccessBoundary = (privateWithin != null) && (privateWithin != NoSymbol)
+
+// ------ info and type -------------------------------------------------------------------
+
+ private[Symbols] var infos: TypeHistory = null
+ def originalInfo = {
+ if (infos eq null) null
+ else {
+ var is = infos
+ while (is.prev ne null) { is = is.prev }
+ is.info
+ }
+ }
+
+ /** Get type. The type of a symbol is:
+ * for a type symbol, the type corresponding to the symbol itself,
+ * @M you should use tpeHK for a type symbol with type parameters if
+ * the kind of the type need not be *, as tpe introduces dummy arguments
+ * to generate a type of kind *
+ * for a term symbol, its usual type.
+ * See the tpe/tpeHK overrides in TypeSymbol for more.
+ */
+ def tpe: Type = info
+ def tpeHK: Type = tpe
+
+ /** Get type info associated with symbol at current phase, after
+ * ensuring that symbol is initialized (i.e. type is completed).
+ */
+ def info: Type = try {
+ var cnt = 0
+ while (validTo == NoPeriod) {
+ //if (settings.debug.value) System.out.println("completing " + this);//DEBUG
+ assert(infos ne null, this.name)
+ assert(infos.prev eq null, this.name)
+ val tp = infos.info
+ //if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug
+
+ if ((_rawflags & LOCKED) != 0L) { // rolled out once for performance
+ lock {
+ setInfo(ErrorType)
+ throw CyclicReference(this, tp)
+ }
+ } else {
+ _rawflags |= LOCKED
+// activeLocks += 1
+ // lockedSyms += this
+ }
+ val current = phase
+ try {
+ phase = phaseOf(infos.validFrom)
+ tp.complete(this)
+ } finally {
+ unlock()
+ phase = current
+ }
+ cnt += 1
+ // allow for two completions:
+ // one: sourceCompleter to LazyType, two: LazyType to completed type
+ if (cnt == 3) abort("no progress in completing " + this + ":" + tp)
+ }
+ rawInfo
+ }
+ catch {
+ case ex: CyclicReference =>
+ debugwarn("... hit cycle trying to complete " + this.fullLocationString)
+ throw ex
+ }
+
+ def info_=(info: Type) {
+ assert(info ne null)
+ infos = TypeHistory(currentPeriod, info, null)
+ unlock()
+ _validTo = if (info.isComplete) currentPeriod else NoPeriod
+ }
+
+ /** Set initial info. */
+ def setInfo(info: Type): this.type = { info_=(info); this }
+ /** Modifies this symbol's info in place. */
+ def modifyInfo(f: Type => Type): this.type = setInfo(f(info))
+ /** Substitute second list of symbols for first in current info. */
+ def substInfo(syms0: List[Symbol], syms1: List[Symbol]): this.type =
+ if (syms0.isEmpty) this
+ else modifyInfo(_.substSym(syms0, syms1))
+
+ def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info atOwner this)
+
+ /** Set the info and enter this symbol into the owner's scope. */
+ def setInfoAndEnter(info: Type): this.type = {
+ setInfo(info)
+ owner.info.decls enter this
+ this
+ }
+
+ /** Set new info valid from start of this phase. */
+ def updateInfo(info: Type): Symbol = {
+ val pid = phaseId(infos.validFrom)
+ assert(pid <= phase.id, (pid, phase.id))
+ if (pid == phase.id) infos = infos.prev
+ infos = TypeHistory(currentPeriod, info, infos)
+ _validTo = if (info.isComplete) currentPeriod else NoPeriod
+ this
+ }
+
+ def hasRawInfo: Boolean = infos ne null
+ def hasCompleteInfo = hasRawInfo && rawInfo.isComplete
+
+ /** Return info without checking for initialization or completing */
+ def rawInfo: Type = {
+ var infos = this.infos
+ assert(infos != null)
+ val curPeriod = currentPeriod
+ val curPid = phaseId(curPeriod)
+
+ if (validTo != NoPeriod) {
+ // skip any infos that concern later phases
+ while (curPid < phaseId(infos.validFrom) && infos.prev != null)
+ infos = infos.prev
+
+ if (validTo < curPeriod) {
+ // adapt any infos that come from previous runs
+ val current = phase
+ try {
+ infos = adaptInfos(infos)
+
+ //assert(runId(validTo) == currentRunId, name)
+ //assert(runId(infos.validFrom) == currentRunId, name)
+
+ if (validTo < curPeriod) {
+ var itr = infoTransformers.nextFrom(phaseId(validTo))
+ infoTransformers = itr; // caching optimization
+ while (itr.pid != NoPhase.id && itr.pid < current.id) {
+ phase = phaseWithId(itr.pid)
+ val info1 = itr.transform(this, infos.info)
+ if (info1 ne infos.info) {
+ infos = TypeHistory(currentPeriod + 1, info1, infos)
+ this.infos = infos
+ }
+ _validTo = currentPeriod + 1 // to enable reads from same symbol during info-transform
+ itr = itr.next
+ }
+ _validTo = if (itr.pid == NoPhase.id) curPeriod
+ else period(currentRunId, itr.pid)
+ }
+ } finally {
+ phase = current
+ }
+ }
+ }
+ infos.info
+ }
+
+ // adapt to new run in fsc.
+ private def adaptInfos(infos: TypeHistory): TypeHistory = {
+ assert(isCompilerUniverse)
+ if (infos == null || runId(infos.validFrom) == currentRunId) {
+ infos
+ } else {
+ val prev1 = adaptInfos(infos.prev)
+ if (prev1 ne infos.prev) prev1
+ else {
+ val pid = phaseId(infos.validFrom)
+
+ _validTo = period(currentRunId, pid)
+ phase = phaseWithId(pid)
+
+ val info1 = (
+ if (isPackageClass) infos.info
+ else adaptToNewRunMap(infos.info)
+ )
+ if (info1 eq infos.info) {
+ infos.validFrom = validTo
+ infos
+ } else {
+ this.infos = TypeHistory(validTo, info1, prev1)
+ this.infos
+ }
+ }
+ }
+ }
+
+ /** Initialize the symbol */
+ final def initialize: this.type = {
+ if (!isInitialized) info
+ this
+ }
+
+ /** Was symbol's type updated during given phase? */
+ final def isUpdatedAt(pid: Phase#Id): Boolean = {
+ assert(isCompilerUniverse)
+ var infos = this.infos
+ while ((infos ne null) && phaseId(infos.validFrom) != pid + 1) infos = infos.prev
+ infos ne null
+ }
+
+ /** Was symbol's type updated during given phase? */
+ final def hasTypeAt(pid: Phase#Id): Boolean = {
+ assert(isCompilerUniverse)
+ var infos = this.infos
+ while ((infos ne null) && phaseId(infos.validFrom) > pid) infos = infos.prev
+ infos ne null
+ }
+
+ /** Modify term symbol's type so that a raw type C is converted to an existential C[_]
+ *
+ * This is done in checkAccessible and overriding checks in refchecks
+ * We can't do this on class loading because it would result in infinite cycles.
+ */
+ final def cookJavaRawInfo() {
+ if (hasFlag(TRIEDCOOKING)) return else setFlag(TRIEDCOOKING) // only try once...
+ val oldInfo = info
+ doCookJavaRawInfo()
+ }
+
+ protected def doCookJavaRawInfo(): Unit
+
+ /** The type constructor of a symbol is:
+ * For a type symbol, the type corresponding to the symbol itself,
+ * excluding parameters.
+ * Not applicable for term symbols.
+ */
+ def typeConstructor: Type =
+ abort("typeConstructor inapplicable for " + this)
+
+ /** The logic approximately boils down to finding the most recent phase
+ * which immediately follows any of parser, namer, typer, or erasure.
+ * In effect that means this will return one of:
+ *
+ * - packageobjects (follows namer)
+ * - superaccessors (follows typer)
+ * - lazyvals (follows erasure)
+ * - null
+ */
+ private def unsafeTypeParamPhase = {
+ var ph = phase
+ while (ph.prev.keepsTypeParams)
+ ph = ph.prev
+
+ ph
+ }
+ /** The type parameters of this symbol, without ensuring type completion.
+ * assumption: if a type starts out as monomorphic, it will not acquire
+ * type parameters later.
+ */
+ def unsafeTypeParams: List[Symbol] =
+ if (isMonomorphicType) Nil
+ else atPhase(unsafeTypeParamPhase)(rawInfo.typeParams)
+
+ /** The type parameters of this symbol.
+ * assumption: if a type starts out as monomorphic, it will not acquire
+ * type parameters later.
+ */
+ def typeParams: List[Symbol] =
+ 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)
+ atPhase(phaseOf(infos.validFrom))(rawInfo load this)
+ if (validTo == NoPeriod)
+ atPhase(phaseOf(infos.validFrom))(rawInfo load this)
+
+ rawInfo.typeParams
+ }
+
+ /** The value parameter sections of this symbol.
+ */
+ def paramss: List[List[Symbol]] = info.paramss
+ def hasParamWhich(cond: Symbol => Boolean) = mexists(paramss)(cond)
+
+ /** The least proper supertype of a class; includes all parent types
+ * and refinement where needed. You need to compute that in a situation like this:
+ * {
+ * class C extends P { ... }
+ * new C
+ * }
+ */
+ def classBound: Type = {
+ val tp = refinedType(info.parents, owner)
+ val thistp = tp.typeSymbol.thisType
+ val oldsymbuf = new ListBuffer[Symbol]
+ val newsymbuf = new ListBuffer[Symbol]
+ for (sym <- info.decls) {
+ // todo: what about public references to private symbols?
+ if (sym.isPublic && !sym.isConstructor) {
+ oldsymbuf += sym
+ newsymbuf += (
+ if (sym.isClass)
+ tp.typeSymbol.newAbstractType(sym.name.toTypeName, sym.pos).setInfo(sym.existentialBound)
+ else
+ sym.cloneSymbol(tp.typeSymbol))
+ }
+ }
+ val oldsyms = oldsymbuf.toList
+ val newsyms = newsymbuf.toList
+ for (sym <- newsyms) {
+ addMember(thistp, tp, sym modifyInfo (_ substThisAndSym(this, thistp, oldsyms, newsyms)))
+ }
+ tp
+ }
+
+ /** If we quantify existentially over this symbol,
+ * the bound of the type variable that stands for it
+ * pre: symbol is a term, a class, or an abstract type (no alias type allowed)
+ */
+ def existentialBound: Type
+
+ /** Reset symbol to initial state
+ */
+ def reset(completer: Type): this.type = {
+ resetFlags()
+ infos = null
+ _validTo = NoPeriod
+ //limit = NoPhase.id
+ setInfo(completer)
+ }
+
+ /**
+ * Adds the interface scala.Serializable to the parents of a ClassInfoType.
+ * Note that the tree also has to be updated accordingly.
+ */
+ def makeSerializable() {
+ info match {
+ case ci @ ClassInfoType(_, _, _) =>
+ updateInfo(ci.copy(parents = ci.parents :+ SerializableClass.tpe))
+ case i =>
+ abort("Only ClassInfoTypes can be made serializable: "+ i)
+ }
+ }
+
+// ----- setters implemented in selected subclasses -------------------------------------
+
+ def typeOfThis_=(tp: Type) { throw new UnsupportedOperationException("typeOfThis_= inapplicable for " + this) }
+ def sourceModule_=(sym: Symbol) { throw new UnsupportedOperationException("sourceModule_= inapplicable for " + this) }
+ def addChild(sym: Symbol) { throw new UnsupportedOperationException("addChild inapplicable for " + this) }
+
+// ----- annotations ------------------------------------------------------------
+
+ // null is a marker that they still need to be obtained.
+ private[this] var _annotations: List[AnnotationInfo] = Nil
+
+ def annotationsString = if (annotations.isEmpty) "" else annotations.mkString("(", ", ", ")")
+
+ /** After the typer phase (before, look at the definition's Modifiers), contains
+ * the annotations attached to member a definition (class, method, type, field).
+ */
+ def annotations: List[AnnotationInfo] =
+ _annotations
+
+ def setAnnotations(annots: List[AnnotationInfo]): this.type = {
+ _annotations = annots
+ this
+ }
+
+ def withAnnotations(annots: List[AnnotationInfo]): this.type =
+ setAnnotations(annots ::: annotations)
+
+ def withoutAnnotations: this.type =
+ setAnnotations(Nil)
+
+ def filterAnnotations(p: AnnotationInfo => Boolean): this.type =
+ setAnnotations(annotations filter p)
+
+ def addAnnotation(annot: AnnotationInfo): this.type =
+ setAnnotations(annot :: annotations)
+
+ // Convenience for the overwhelmingly common case
+ def addAnnotation(sym: Symbol, args: Tree*): this.type =
+ addAnnotation(AnnotationInfo(sym.tpe, args.toList, Nil))
+
+// ------ comparisons ----------------------------------------------------------------
+
+ /** A total ordering between symbols that refines the class
+ * inheritance graph (i.e. subclass.isLess(superclass) always holds).
+ * the ordering is given by: (_.isType, -_.baseTypeSeq.length) for type symbols, followed by `id`.
+ */
+ final def isLess(that: Symbol): Boolean = {
+ def baseTypeSeqLength(sym: Symbol) =
+ if (sym.isAbstractType) 1 + sym.info.bounds.hi.baseTypeSeq.length
+ else sym.info.baseTypeSeq.length
+ if (this.isType)
+ (that.isType &&
+ { val diff = baseTypeSeqLength(this) - baseTypeSeqLength(that)
+ diff > 0 || diff == 0 && this.id < that.id })
+ else
+ that.isType || this.id < that.id
+ }
+
+ /** A partial ordering between symbols.
+ * (this isNestedIn that) holds iff this symbol is defined within
+ * a class or method defining that symbol
+ */
+ final def isNestedIn(that: Symbol): Boolean =
+ owner == that || owner != NoSymbol && (owner isNestedIn that)
+
+ /** Is this class symbol a subclass of that symbol,
+ * and is this class symbol also different from Null or Nothing? */
+ def isNonBottomSubClass(that: Symbol): Boolean = false
+
+ /** Overridden in NullClass and NothingClass for custom behavior.
+ */
+ def isSubClass(that: Symbol) = isNonBottomSubClass(that)
+
+ final def isNumericSubClass(that: Symbol): Boolean =
+ definitions.isNumericSubClass(this, that)
+
+ final def isWeakSubClass(that: Symbol) =
+ isSubClass(that) || isNumericSubClass(that)
+
+// ------ overloaded alternatives ------------------------------------------------------
+
+ def alternatives: List[Symbol] =
+ if (isOverloaded) info.asInstanceOf[OverloadedType].alternatives
+ else List(this)
+
+ def filter(cond: Symbol => Boolean): Symbol =
+ if (isOverloaded) {
+ val alts = alternatives
+ val alts1 = alts filter cond
+ if (alts1 eq alts) this
+ else if (alts1.isEmpty) NoSymbol
+ else if (alts1.tail.isEmpty) alts1.head
+ else owner.newOverloaded(info.prefix, alts1)
+ }
+ else if (cond(this)) this
+ else NoSymbol
+
+ def suchThat(cond: Symbol => Boolean): Symbol = {
+ val result = filter(cond)
+ assert(!result.isOverloaded, result.alternatives)
+ result
+ }
+
+ @inline final def map(f: Symbol => Symbol): Symbol = if (this eq NoSymbol) this else f(this)
+
+// ------ cloneing -------------------------------------------------------------------
+
+ /** A clone of this symbol. */
+ final def cloneSymbol: TypeOfClonedSymbol =
+ cloneSymbol(owner)
+
+ /** A clone of this symbol, but with given owner. */
+ final def cloneSymbol(newOwner: Symbol): TypeOfClonedSymbol =
+ cloneSymbol(newOwner, _rawflags)
+ final def cloneSymbol(newOwner: Symbol, newFlags: Long): TypeOfClonedSymbol =
+ cloneSymbol(newOwner, newFlags, null)
+ final def cloneSymbol(newOwner: Symbol, newFlags: Long, newName: Name): TypeOfClonedSymbol = {
+ val clone = cloneSymbolImpl(newOwner, newFlags)
+ ( clone
+ setPrivateWithin privateWithin
+ setInfo (this.info cloneInfo clone)
+ setAnnotations this.annotations
+ )
+ if (clone.thisSym != clone)
+ clone.typeOfThis = (clone.typeOfThis cloneInfo clone)
+
+ if (newName ne null)
+ clone setName asNameType(newName)
+
+ clone
+ }
+
+ /** Internal method to clone a symbol's implementation with the given flags and no info. */
+ def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeOfClonedSymbol
+
+// ------ access to related symbols --------------------------------------------------
+
+ /** The next enclosing class. */
+ def enclClass: Symbol = if (isClass) this else owner.enclClass
+
+ /** The next enclosing method. */
+ def enclMethod: Symbol = if (isSourceMethod) this else owner.enclMethod
+
+ /** The primary constructor of a class. */
+ def primaryConstructor: Symbol = NoSymbol
+
+ /** The self symbol (a TermSymbol) of a class with explicit self type, or else the
+ * symbol itself (a TypeSymbol).
+ *
+ * WARNING: you're probably better off using typeOfThis, as it's more uniform across classes with and without self variables.
+ *
+ * Example by Paul:
+ * scala> trait Foo1 { }
+ * scala> trait Foo2 { self => }
+ * scala> intp("Foo1").thisSym
+ * res0: $r.intp.global.Symbol = trait Foo1
+ *
+ * scala> intp("Foo2").thisSym
+ * res1: $r.intp.global.Symbol = value self
+ *
+ * Martin says: The reason `thisSym' is `this' is so that thisType can be this.thisSym.tpe.
+ * It's a trick to shave some cycles off.
+ *
+ * Morale: DO: if (clazz.typeOfThis.typeConstructor ne clazz.typeConstructor) ...
+ * DON'T: if (clazz.thisSym ne clazz) ...
+ *
+ */
+ def thisSym: Symbol = this
+
+ /** The type of `this` in a class, or else the type of the symbol itself. */
+ def typeOfThis = thisSym.tpe
+
+ /** If symbol is a class, the type <code>this.type</code> in this class,
+ * otherwise <code>NoPrefix</code>.
+ * We always have: thisType <:< typeOfThis
+ */
+ def thisType: Type = NoPrefix
+
+ /** For a case class, the symbols of the accessor methods, one for each
+ * argument in the first parameter list of the primary constructor.
+ * The empty list for all other classes.
+ */
+ final def caseFieldAccessors: List[Symbol] =
+ (info.decls filter (_.isCaseAccessorMethod)).toList
+
+ final def constrParamAccessors: List[Symbol] =
+ info.decls.toList filter (sym => !sym.isMethod && sym.isParamAccessor)
+
+ /** The symbol accessed by this accessor (getter or setter) function. */
+ final def accessed: Symbol = accessed(owner.info)
+
+ /** The symbol accessed by this accessor function, but with given owner type. */
+ final def accessed(ownerTp: Type): Symbol = {
+ assert(hasAccessorFlag, this)
+ ownerTp decl nme.getterToLocal(getterName.toTermName)
+ }
+
+ /** The module corresponding to this module class (note that this
+ * is not updated when a module is cloned), or NoSymbol if this is not a ModuleClass.
+ */
+ def sourceModule: Symbol = NoSymbol
+
+ /** The implementation class of a trait. If available it will be the
+ * symbol with the same owner, and the name of this symbol with $class
+ * appended to it.
+ */
+ final def implClass: Symbol = owner.info.decl(tpnme.implClassName(name))
+
+ /** The class that is logically an outer class of given `clazz`.
+ * This is the enclosing class, except for classes defined locally to constructors,
+ * where it is the outer class of the enclosing class.
+ */
+ final def outerClass: Symbol =
+ if (owner.isClass) owner
+ else if (isClassLocalToConstructor) owner.enclClass.outerClass
+ else owner.outerClass
+
+ /** For a paramaccessor: a superclass paramaccessor for which this symbol
+ * is an alias, NoSymbol for all others.
+ */
+ def alias: Symbol = NoSymbol
+
+ /** For a lazy value, its lazy accessor. NoSymbol for all others. */
+ def lazyAccessor: Symbol = NoSymbol
+
+ /** If this is a lazy value, the lazy accessor; otherwise this symbol. */
+ def lazyAccessorOrSelf: Symbol = if (isLazy) lazyAccessor else this
+
+ /** If this is an accessor, the accessed symbol. Otherwise, this symbol. */
+ def accessedOrSelf: Symbol = if (hasAccessorFlag) accessed else this
+
+ /** For an outer accessor: The class from which the outer originates.
+ * For all other symbols: NoSymbol
+ */
+ def outerSource: Symbol = NoSymbol
+
+ /** The superclass of this class. */
+ def superClass: Symbol = if (info.parents.isEmpty) NoSymbol else info.parents.head.typeSymbol
+ def parentSymbols: List[Symbol] = info.parents map (_.typeSymbol)
+
+ /** The directly or indirectly inherited mixins of this class
+ * except for mixin classes inherited by the superclass. Mixin classes appear
+ * in linearization order.
+ */
+ def mixinClasses: List[Symbol] = {
+ val sc = superClass
+ ancestors takeWhile (sc ne _)
+ }
+
+ /** All directly or indirectly inherited classes. */
+ def ancestors: List[Symbol] = info.baseClasses drop 1
+
+ @inline final def enclosingSuchThat(p: Symbol => Boolean): Symbol = {
+ var sym = this
+ while (sym != NoSymbol && !p(sym))
+ sym = sym.owner
+ sym
+ }
+
+ /** The package class containing this symbol, or NoSymbol if there
+ * is not one.
+ * TODO: formulate as enclosingSuchThat, after making sure
+ * we can start with current symbol rather than onwner.
+ * TODO: Also harmonize with enclClass, enclMethod etc.
+ */
+ def enclosingPackageClass: Symbol = {
+ var sym = this.owner
+ while (sym != NoSymbol && !sym.isPackageClass)
+ sym = sym.owner
+ sym
+ }
+
+ /** The package class containing this symbol, or NoSymbol if there
+ * is not one. */
+ def enclosingRootClass: Symbol = enclosingSuchThat(_.isRoot)
+
+ /** The package containing this symbol, or NoSymbol if there
+ * is not one. */
+ def enclosingPackage: Symbol = enclosingPackageClass.companionModule
+
+ /** Return the original enclosing method of this symbol. It should return
+ * the same thing as enclMethod when called before lambda lift,
+ * but it preserves the original nesting when called afterwards.
+ *
+ * @note This method is NOT available in the presentation compiler run. The
+ * originalOwner map is not populated for memory considerations (the symbol
+ * may hang on to lazy types and in turn to whole (outdated) compilation units.
+ */
+ def originalEnclosingMethod: Symbol = {
+ assert(!forInteractive, "originalOwner is not kept in presentation compiler runs.")
+ if (isMethod) this
+ else {
+ val owner = originalOwner.getOrElse(this, rawowner)
+ if (isLocalDummy) owner.enclClass.primaryConstructor
+ else owner.originalEnclosingMethod
+ }
+ }
+
+ /** The method or class which logically encloses the current symbol.
+ * If the symbol is defined in the initialization part of a template
+ * this is the template's primary constructor, otherwise it is
+ * the physically enclosing method or class.
+ *
+ * Example 1:
+ *
+ * def f() { val x = { def g() = ...; g() } }
+ *
+ * In this case the owner chain of `g` is `x`, followed by `f` and
+ * `g.logicallyEnclosingMember == f`.
+ *
+ * Example 2:
+ *
+ * class C {
+ * def <init> = { ... }
+ * val x = { def g() = ...; g() } }
+ * }
+ *
+ * In this case the owner chain of `g` is `x`, followed by `C` but
+ * g.logicallyEnclosingMember is the primary constructor symbol `<init>`
+ * (or, for traits: `$init`) of `C`.
+ *
+ */
+ def logicallyEnclosingMember: Symbol =
+ if (isLocalDummy) enclClass.primaryConstructor
+ else if (isMethod || isClass) this
+ else owner.logicallyEnclosingMember
+
+ /** Kept for source compatibility with 2.9. Scala IDE for Eclipse relies on this. */
+ @deprecated("Use enclosingTopLevelClass", "2.10.0")
+ def toplevelClass: Symbol = enclosingTopLevelClass
+
+ /** The top-level class containing this symbol. */
+ def enclosingTopLevelClass: Symbol =
+ if (owner.isPackageClass) {
+ if (isClass) this else moduleClass
+ } else owner.enclosingTopLevelClass
+
+ /** Is this symbol defined in the same scope and compilation unit as `that` symbol? */
+ def isCoDefinedWith(that: Symbol) = {
+ import language.reflectiveCalls
+ (this.rawInfo ne NoType) &&
+ (this.effectiveOwner == that.effectiveOwner) && {
+ !this.effectiveOwner.isPackageClass ||
+ (this.sourceFile eq null) ||
+ (that.sourceFile eq null) ||
+ (this.sourceFile == that.sourceFile) || {
+ // recognize companion object in separate file and fail, else compilation
+ // appears to succeed but highly opaque errors come later: see bug #1286
+ if (this.sourceFile.path != that.sourceFile.path) {
+ // The cheaper check can be wrong: do the expensive normalization
+ // before failing.
+ if (this.sourceFile.canonicalPath != that.sourceFile.canonicalPath)
+ throw InvalidCompanions(this, that)
+ }
+
+ false
+ }
+ }
+ }
+
+ /** The internal representation of classes and objects:
+ *
+ * class Foo is "the class" or sometimes "the plain class"
+ * object Foo is "the module"
+ * class Foo$ is "the module class" (invisible to the user: it implements object Foo)
+ *
+ * class Foo <
+ * ^ ^ (2) \
+ * | | | \
+ * | (5) | (3)
+ * | | | \
+ * (1) v v \
+ * object Foo (4)-> > class Foo$
+ *
+ * (1) companionClass
+ * (2) companionModule
+ * (3) linkedClassOfClass
+ * (4) moduleClass
+ * (5) companionSymbol
+ */
+
+ /** For a module: the class with the same name in the same package.
+ * For all others: NoSymbol
+ * Note: does not work for classes owned by methods, see Namers.companionClassOf
+ *
+ * object Foo . companionClass --> class Foo
+ *
+ * !!! linkedClassOfClass depends on companionClass on the module class getting
+ * to the class. As presently implemented this potentially returns class for
+ * any symbol except NoSymbol.
+ */
+ def companionClass: Symbol = flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this)
+
+ /** For a class: the module or case class factory with the same name in the same package.
+ * For all others: NoSymbol
+ * Note: does not work for modules owned by methods, see Namers.companionModuleOf
+ *
+ * class Foo . companionModule --> object Foo
+ */
+ def companionModule: Symbol = NoSymbol
+
+ /** For a module: its linked class
+ * For a plain class: its linked module or case factory.
+ * Note: does not work for modules owned by methods, see Namers.companionSymbolOf
+ *
+ * class Foo <-- companionSymbol --> object Foo
+ */
+ def companionSymbol: Symbol = NoSymbol
+
+ /** For a module class: its linked class
+ * For a plain class: the module class of its linked module.
+ *
+ * class Foo <-- linkedClassOfClass --> class Foo$
+ */
+ def linkedClassOfClass: Symbol = NoSymbol
+
+ /**
+ * Returns the rawInfo of the owner. If the current phase has flat classes,
+ * it first applies all pending type maps to this symbol.
+ *
+ * assume this is the ModuleSymbol for B in the following definition:
+ * package p { class A { object B { val x = 1 } } }
+ *
+ * The owner after flatten is "package p" (see "def owner"). The flatten type map enters
+ * symbol B in the decls of p. So to find a linked symbol ("object B" or "class B")
+ * we need to apply flatten to B first. Fixes #2470.
+ */
+ protected final def flatOwnerInfo: Type = {
+ if (needsFlatClasses)
+ info
+ owner.rawInfo
+ }
+
+ /** If this symbol is an implementation class, its interface, otherwise the symbol itself
+ * The method follows two strategies to determine the interface.
+ * - during or after erasure, it takes the last parent of the implementation class
+ * (which is always the interface, by convention)
+ * - before erasure, it looks up the interface name in the scope of the owner of the class.
+ * This only works for implementation classes owned by other classes or traits.
+ * !!! Why?
+ */
+ def toInterface: Symbol = this
+
+ /** The module class corresponding to this module.
+ */
+ def moduleClass: Symbol = NoSymbol
+
+ /** The non-private symbol whose type matches the type of this symbol
+ * in in given class.
+ *
+ * @param ofclazz The class containing the symbol's definition
+ * @param site The base type from which member types are computed
+ */
+ final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol =
+ ofclazz.info.nonPrivateDecl(name).filter(sym =>
+ !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
+
+ /** The non-private member of `site` whose type and name match the type of this symbol. */
+ final def matchingSymbol(site: Type, admit: Long = 0L): Symbol =
+ site.nonPrivateMemberAdmitting(name, admit).filter(sym =>
+ !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
+
+ /** The symbol, in class `ofclazz`, that is overridden by this symbol.
+ *
+ * @param ofclazz is a base class of this symbol's owner.
+ */
+ final def overriddenSymbol(ofclazz: Symbol): Symbol =
+ if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, owner.thisType)
+
+ /** The symbol overriding this symbol in given subclass `ofclazz`.
+ *
+ * @param ofclazz is a subclass of this symbol's owner
+ */
+ final def overridingSymbol(ofclazz: Symbol): Symbol =
+ if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, ofclazz.thisType)
+
+ /** Returns all symbols overriden by this symbol. */
+ final def allOverriddenSymbols: List[Symbol] =
+ if (!owner.isClass) Nil
+ else owner.ancestors map overriddenSymbol filter (_ != NoSymbol)
+
+ /** Equivalent to allOverriddenSymbols.nonEmpty, but more efficient. */
+ // !!! When if ever will this answer differ from .isOverride?
+ // How/where is the OVERRIDE flag managed, as compared to how checks
+ // based on type membership will evaluate?
+ def isOverridingSymbol = owner.isClass && (
+ owner.ancestors exists (cls => matchingSymbol(cls, owner.thisType) != NoSymbol)
+ )
+ /** Equivalent to allOverriddenSymbols.head (or NoSymbol if no overrides) but more efficient. */
+ def nextOverriddenSymbol: Symbol = {
+ if (owner.isClass) owner.ancestors foreach { base =>
+ val sym = overriddenSymbol(base)
+ if (sym != NoSymbol)
+ return sym
+ }
+ NoSymbol
+ }
+
+ /** Returns all symbols overridden by this symbol, plus all matching symbols
+ * defined in parents of the selftype.
+ */
+ final def extendedOverriddenSymbols: List[Symbol] =
+ if (!owner.isClass) Nil
+ else owner.thisSym.ancestors map overriddenSymbol filter (_ != NoSymbol)
+
+ /** The symbol accessed by a super in the definition of this symbol when
+ * seen from class `base`. This symbol is always concrete.
+ * pre: `this.owner` is in the base class sequence of `base`.
+ */
+ final def superSymbol(base: Symbol): Symbol = {
+ var bcs = base.info.baseClasses.dropWhile(owner != _).tail
+ var sym: Symbol = NoSymbol
+ while (!bcs.isEmpty && sym == NoSymbol) {
+ if (!bcs.head.isImplClass)
+ sym = matchingSymbol(bcs.head, base.thisType).suchThat(!_.isDeferred)
+ bcs = bcs.tail
+ }
+ sym
+ }
+
+ /** The getter of this value or setter definition in class `base`, or NoSymbol if
+ * none exists.
+ */
+ final def getter(base: Symbol): Symbol = base.info.decl(getterName) filter (_.hasAccessorFlag)
+
+ def getterName: TermName = (
+ if (isSetter) nme.setterToGetter(name.toTermName)
+ else if (nme.isLocalName(name)) nme.localToGetter(name.toTermName)
+ else name.toTermName
+ )
+
+ /** The setter of this value or getter definition, or NoSymbol if none exists */
+ final def setter(base: Symbol): Symbol = setter(base, false)
+
+ final def setter(base: Symbol, hasExpandedName: Boolean): Symbol = {
+ var sname = nme.getterToSetter(nme.getterName(name.toTermName))
+ if (hasExpandedName) sname = nme.expandedSetterName(sname, base)
+ base.info.decl(sname) filter (_.hasAccessorFlag)
+ }
+
+ /** Return the accessor method of the first parameter of this class.
+ * or NoSymbol if it does not exist.
+ */
+ def firstParamAccessor: Symbol = NoSymbol
+
+ /** The case module corresponding to this case class
+ * @pre case class is a member of some other class or package
+ */
+ final def caseModule: Symbol = {
+ var modname = name.toTermName
+ if (privateWithin.isClass && !privateWithin.isModuleClass && !hasFlag(EXPANDEDNAME))
+ modname = nme.expandedName(modname, privateWithin)
+ initialize.owner.info.decl(modname).suchThat(_.isModule)
+ }
+
+ /** If this symbol is a type parameter skolem (not an existential skolem!)
+ * its corresponding type parameter, otherwise this */
+ def deSkolemize: Symbol = this
+
+ /** If this symbol is an existential skolem the location (a Tree or null)
+ * where it was unpacked. Resulttype is AnyRef because trees are not visible here. */
+ def unpackLocation: AnyRef = null
+
+ /** Remove private modifier from symbol `sym`s definition. If `sym` is a
+ * is not a constructor nor a static module rename it by expanding its name to avoid name clashes
+ * @param base the fully qualified name of this class will be appended if name expansion is needed
+ */
+ final def makeNotPrivate(base: Symbol) {
+ if (this.isPrivate) {
+ setFlag(notPRIVATE)
+ // Marking these methods final causes problems for proxies which use subclassing. If people
+ // write their code with no usage of final, we probably shouldn't introduce it ourselves
+ // unless we know it is safe. ... Unfortunately if they aren't marked final the inliner
+ // thinks it can't inline them. So once again marking lateFINAL, and in genjvm we no longer
+ // generate ACC_FINAL on "final" methods which are actually lateFINAL.
+ if (isMethod && !isDeferred)
+ setFlag(lateFINAL)
+ if (!isStaticModule && !isClassConstructor) {
+ expandName(base)
+ if (isModule) moduleClass.makeNotPrivate(base)
+ }
+ }
+ }
+
+ /** Remove any access boundary and clear flags PROTECTED | PRIVATE.
+ */
+ def makePublic = this setPrivateWithin NoSymbol resetFlag AccessFlags
+
+ /** The first parameter to the first argument list of this method,
+ * or NoSymbol if inapplicable.
+ */
+ def firstParam = info.params match {
+ case p :: _ => p
+ case _ => NoSymbol
+ }
+/* code for fixing nested objects
+ def expandModuleClassName() {
+ name = newTypeName(name.toString + "$")
+ }
+
+ def isExpandedModuleClass: Boolean = name(name.length - 1) == '$'
+*/
+
+ /** Desire to re-use the field in ClassSymbol which stores the source
+ * file to also store the classfile, but without changing the behavior
+ * of sourceFile (which is expected at least in the IDE only to
+ * return actual source code.) So sourceFile has classfiles filtered out.
+ */
+ private def sourceFileOnly(file: AbstractFileType): AbstractFileType =
+ if ((file eq null) || (file.path endsWith ".class")) null else file
+
+ private def binaryFileOnly(file: AbstractFileType): AbstractFileType =
+ if ((file eq null) || !(file.path endsWith ".class")) null else file
+
+ final def binaryFile: AbstractFileType = binaryFileOnly(associatedFile)
+ final def sourceFile: AbstractFileType = sourceFileOnly(associatedFile)
+
+ /** Overridden in ModuleSymbols to delegate to the module class. */
+ def associatedFile: AbstractFileType = enclosingTopLevelClass.associatedFile
+ def associatedFile_=(f: AbstractFileType) { abort("associatedFile_= inapplicable for " + this) }
+
+ @deprecated("Use associatedFile_= instead", "2.10.0")
+ def sourceFile_=(f: AbstractFileType): Unit = associatedFile_=(f)
+
+ /** If this is a sealed class, its known direct subclasses.
+ * Otherwise, the empty set.
+ */
+ def children: Set[Symbol] = Set()
+
+ /** Recursively assemble all children of this symbol.
+ */
+ def sealedDescendants: Set[Symbol] = children.flatMap(_.sealedDescendants) + this
+
+ @inline final def orElse(alt: => Symbol): Symbol = if (this ne NoSymbol) this else alt
+ @inline final def andAlso(f: Symbol => Unit): Symbol = { if (this ne NoSymbol) f(this) ; this }
+
+// ------ toString -------------------------------------------------------------------
+
+ /** A tag which (in the ideal case) uniquely identifies class symbols */
+ final def tag: Int = fullName.##
+
+ /** The simple name of this Symbol */
+ final def simpleName: Name = name
+
+ /** The String used to order otherwise identical sealed symbols.
+ * This uses data which is stable across runs and variable classpaths
+ * (the initial Name) before falling back on id, which varies depending
+ * on exactly when a symbol is loaded.
+ */
+ final def sealedSortName: String = initName + "#" + id
+
+ /** String representation of symbol's definition key word */
+ final def keyString: String =
+ if (isJavaInterface) "interface"
+ else if (isTrait && !isImplClass) "trait"
+ else if (isClass) "class"
+ else if (isType && !isParameter) "type"
+ else if (isVariable) "var"
+ else if (isPackage) "package"
+ else if (isModule) "object"
+ else if (isSourceMethod) "def"
+ 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) ("macro method", "macro method", "MAC")
+ else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE")
+ else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY")
+ else if (isPackage) ("package", "package", "PK")
+ else if (isPackageClass) ("package class", "package", "PKC")
+ else if (isPackageObject) ("package object", "package", "PKO")
+ else if (isPackageObjectClass) ("package object class", "package", "PKOC")
+ else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC")
+ else if (isRefinementClass) ("refinement class", "", "RC")
+ else if (isModule) ("module", "object", "MOD")
+ else if (isModuleClass) ("module class", "object", "MODC")
+ else if (isGetter) ("getter", if (isSourceMethod) "method" else "value", "GET")
+ else if (isSetter) ("setter", if (isSourceMethod) "method" else "value", "SET")
+ else if (isTerm && isLazy) ("lazy value", "lazy value", "LAZ")
+ else if (isVariable) ("field", "variable", "VAR")
+ else if (isImplClass) ("implementation class", "class", "IMPL")
+ else if (isTrait) ("trait", "trait", "TRT")
+ else if (isClass) ("class", "class", "CLS")
+ else if (isType) ("type", "type", "TPE")
+ else if (isClassConstructor && isPrimaryConstructor) ("primary constructor", "constructor", "PCTOR")
+ else if (isClassConstructor) ("constructor", "constructor", "CTOR")
+ else if (isSourceMethod) ("method", "method", "METH")
+ else if (isTerm) ("value", "value", "VAL")
+ else ("", "", "???")
+ if (isSkolem) kind = (kind._1, kind._2, kind._3 + "#SKO")
+ SymbolKind(kind._1, kind._2, kind._3)
+ }
+
+ /** Accurate string representation of symbols' kind, suitable for developers. */
+ final def accurateKindString: String =
+ symbolKind.accurate
+
+ /** String representation of symbol's kind, suitable for the masses. */
+ private def sanitizedKindString: String =
+ symbolKind.sanitized
+
+ /** String representation of symbol's kind, suitable for the masses. */
+ protected[scala] def abbreviatedKindString: String =
+ symbolKind.abbreviation
+
+ final def kindString: String =
+ if (settings.debug.value) accurateKindString
+ else sanitizedKindString
+
+ /** If the name of the symbol's owner should be used when you care about
+ * seeing an interesting name: in such cases this symbol is e.g. a method
+ * parameter with a synthetic name, a constructor named "this", an object
+ * "package", etc. The kind string, if non-empty, will be phrased relative
+ * to the name of the owner.
+ */
+ def hasMeaninglessName = (
+ isSetterParameter // x$1
+ || isClassConstructor // this
+ || isRefinementClass // <refinement>
+ || (name == nme.PACKAGE) // package
+ )
+
+ /** String representation of symbol's simple name.
+ * If !settings.debug translates expansions of operators back to operator symbol.
+ * E.g. $eq => =.
+ * If settings.uniqid, adds id.
+ * If settings.Yshowsymkinds, adds abbreviated symbol kind.
+ */
+ def nameString: String = (
+ if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + decodedName
+ else if (settings.uniqid.value && !settings.Yshowsymkinds.value) decodedName + "#" + id
+ else if (!settings.uniqid.value && settings.Yshowsymkinds.value) decodedName + "#" + abbreviatedKindString
+ else decodedName + "#" + id + "#" + abbreviatedKindString
+ )
+
+ def fullNameString: String = {
+ def recur(sym: Symbol): String = {
+ if (sym.isRootSymbol || sym == NoSymbol) sym.nameString
+ else if (sym.owner.isEffectiveRoot) sym.nameString
+ else recur(sym.effectiveOwner.enclClass) + "." + sym.nameString
+ }
+
+ recur(this)
+ }
+
+ /** If settings.uniqid is set, the symbol's id, else "" */
+ final def idString = if (settings.uniqid.value) "#"+id else ""
+
+ /** String representation, including symbol's kind e.g., "class Foo", "method Bar".
+ * If hasMeaninglessName is true, uses the owner's name to disambiguate identity.
+ */
+ override def toString: String = compose(
+ kindString,
+ if (hasMeaninglessName) owner.decodedName + idString else nameString
+ )
+
+ /** String representation of location.
+ */
+ def ownsString: String = {
+ val owns = effectiveOwner
+ if (owns.isClass && !owns.isEmptyPrefix) "" + owns else ""
+ }
+
+ /** String representation of location, plus a preposition. Doesn't do much,
+ * for backward compatibility reasons.
+ */
+ def locationString: String = ownsString match {
+ case "" => ""
+ case s => " in " + s
+ }
+ def fullLocationString: String = toString + locationString
+ def signatureString: String = if (hasRawInfo) infoString(rawInfo) else "<_>"
+
+ /** String representation of symbol's definition following its name */
+ final def infoString(tp: Type): String = {
+ def parents = (
+ if (settings.debug.value) parentsString(tp.parents)
+ else briefParentsString(tp.parents)
+ )
+ if (isType) typeParamsString(tp) + (
+ if (isClass) " extends " + parents
+ else if (isAliasType) " = " + tp.resultType
+ else tp.resultType match {
+ case rt @ TypeBounds(_, _) => "" + rt
+ case rt => " <: " + rt
+ }
+ )
+ else if (isModule) "" // avoid "object X of type X.type"
+ else tp match {
+ case PolyType(tparams, res) => typeParamsString(tp) + infoString(res)
+ case NullaryMethodType(res) => infoString(res)
+ case MethodType(params, res) => valueParamsString(tp) + infoString(res)
+ case _ => ": " + tp
+ }
+ }
+
+ def infosString = infos.toString
+ def debugLocationString = fullLocationString + " (flags: " + debugFlagString + ")"
+
+ private def defStringCompose(infoString: String) = compose(
+ flagString,
+ keyString,
+ varianceString + nameString + infoString + flagsExplanationString
+ )
+ /** String representation of symbol's definition. It uses the
+ * symbol's raw info to avoid forcing types.
+ */
+ def defString = defStringCompose(signatureString)
+
+ /** String representation of symbol's definition, using the supplied
+ * info rather than the symbol's.
+ */
+ def defStringSeenAs(info: Type) = defStringCompose(infoString(info))
+
+ /** Concatenate strings separated by spaces */
+ private def compose(ss: String*) = ss filter (_ != "") mkString " "
+
+ def isSingletonExistential =
+ nme.isSingletonName(name) && (info.bounds.hi.typeSymbol isSubClass SingletonClass)
+
+ /** String representation of existentially bound variable */
+ def existentialToString =
+ if (isSingletonExistential && !settings.debug.value)
+ "val " + tpnme.dropSingletonName(name) + ": " + dropSingletonType(info.bounds.hi)
+ else defString
+ }
+ implicit val SymbolTag = ClassTag[Symbol](classOf[Symbol])
+
+ /** A class for term symbols */
+ class TermSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
+ extends Symbol(initOwner, initPos, initName) with TermSymbolApi {
+ private[this] var _referenced: Symbol = NoSymbol
+ privateWithin = NoSymbol
+
+ type TypeOfClonedSymbol = TermSymbol
+
+ private[this] var _rawname: TermName = initName
+ def rawname = _rawname
+ def name = _rawname
+ def name_=(name: Name) {
+ if (name != rawname) {
+ log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name))
+ changeNameInOwners(name)
+ _rawname = name.toTermName
+ }
+ }
+ final def asNameType(n: Name) = n.toTermName
+
+ /** Term symbols with the exception of static parts of Java classes and packages.
+ */
+ override def isValue = !(isModule && hasFlag(PACKAGE | JAVA))
+ override def isVariable = isMutable && !isMethod
+ override def isTermMacro = hasFlag(MACRO)
+
+ // interesting only for lambda lift. Captured variables are accessed from inner lambdas.
+ override def isCapturedVariable = hasAllFlags(MUTABLE | CAPTURED) && !hasFlag(METHOD)
+
+ override def companionSymbol: Symbol = companionClass
+ override def moduleClass = if (isModule) referenced else NoSymbol
+
+ override def hasDefault = this hasFlag DEFAULTPARAM // overloaded with TRAIT
+ override def isBridge = this hasFlag BRIDGE
+ override def isEarlyInitialized = this hasFlag PRESUPER
+ override def isMethod = this hasFlag METHOD
+ override def isModule = this hasFlag MODULE
+ override def isOverloaded = this hasFlag OVERLOADED
+ override def isPackage = this hasFlag PACKAGE
+ override def isValueParameter = this hasFlag PARAM
+
+ override def isSetterParameter = isValueParameter && owner.isSetter
+ override def isAccessor = this hasFlag ACCESSOR
+ override def isGetter = isAccessor && !isSetter
+ override def isSetter = isAccessor && nme.isSetterName(name) // todo: make independent of name, as this can be forged.
+ override def isLocalDummy = nme.isLocalDummyName(name)
+ override def isClassConstructor = name == nme.CONSTRUCTOR
+ override def isMixinConstructor = name == nme.MIXIN_CONSTRUCTOR
+ override def isConstructor = nme.isConstructorName(name)
+
+ override def isPackageObject = isModule && (name == nme.PACKAGE)
+ override def isStable = !isUnstable
+ private def isUnstable = (
+ isMutable
+ || (hasFlag(METHOD | BYNAMEPARAM) && !hasFlag(STABLE))
+ || (tpe.isVolatile && !hasAnnotation(uncheckedStableClass))
+ )
+
+ // The name in comments is what it is being disambiguated from.
+ // TODO - rescue CAPTURED from BYNAMEPARAM so we can see all the names.
+ override def resolveOverloadedFlag(flag: Long) = flag match {
+ case DEFAULTPARAM => "<defaultparam>" // TRAIT
+ case MIXEDIN => "<mixedin>" // EXISTENTIAL
+ case LABEL => "<label>" // CONTRAVARIANT / INCONSTRUCTOR
+ case PRESUPER => "<presuper>" // IMPLCLASS
+ case BYNAMEPARAM => if (this.isValueParameter) "<bynameparam>" else "<captured>" // COVARIANT
+ case _ => super.resolveOverloadedFlag(flag)
+ }
+
+ def referenced: Symbol = _referenced
+ def referenced_=(x: Symbol) { _referenced = x }
+
+ def existentialBound = singletonBounds(this.tpe)
+
+ def cloneSymbolImpl(owner: Symbol, newFlags: Long): TermSymbol =
+ owner.newTermSymbol(name, pos, newFlags).copyAttrsFrom(this)
+
+ def copyAttrsFrom(original: TermSymbol): this.type = {
+ referenced = original.referenced
+ this
+ }
+
+ private val validAliasFlags = SUPERACCESSOR | PARAMACCESSOR | MIXEDIN | SPECIALIZED
+
+ override def alias: Symbol =
+ if (hasFlag(validAliasFlags)) initialize.referenced
+ else NoSymbol
+
+ def setAlias(alias: Symbol): TermSymbol = {
+ assert(alias != NoSymbol, this)
+ assert(!alias.isOverloaded, alias)
+ assert(hasFlag(validAliasFlags), this)
+
+ referenced = alias
+ this
+ }
+
+ override def outerSource: Symbol =
+ if (originalName == nme.OUTER) initialize.referenced
+ else NoSymbol
+
+ def setModuleClass(clazz: Symbol): TermSymbol = {
+ assert(isModule, this)
+ referenced = clazz
+ this
+ }
+
+ def setLazyAccessor(sym: Symbol): TermSymbol = {
+ assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, debugFlagString, referenced, sym))
+ referenced = sym
+ this
+ }
+
+ override def lazyAccessor: Symbol = {
+ assert(isLazy, this)
+ referenced
+ }
+
+ /** change name by appending $$<fully-qualified-name-of-class `base`>
+ * Do the same for any accessed symbols or setters/getters
+ */
+ override def expandName(base: Symbol) {
+ if (!hasFlag(EXPANDEDNAME)) {
+ setFlag(EXPANDEDNAME)
+ if (hasAccessorFlag && !isDeferred) {
+ accessed.expandName(base)
+ }
+ else if (hasGetter) {
+ getter(owner).expandName(base)
+ setter(owner).expandName(base)
+ }
+ name = nme.expandedName(name.toTermName, base)
+ }
+ }
+
+ protected def doCookJavaRawInfo() {
+ def cook(sym: Symbol) {
+ require(sym.isJavaDefined, sym)
+ // @M: I think this is more desirable, but Martin prefers to leave raw-types as-is as much as possible
+ // object rawToExistentialInJava extends TypeMap {
+ // def apply(tp: Type): Type = tp match {
+ // // any symbol that occurs in a java sig, not just java symbols
+ // // see http://lampsvn.epfl.ch/trac/scala/ticket/2454#comment:14
+ // case TypeRef(pre, sym, List()) if !sym.typeParams.isEmpty =>
+ // val eparams = typeParamsToExistentials(sym, sym.typeParams)
+ // existentialAbstraction(eparams, TypeRef(pre, sym, eparams map (_.tpe)))
+ // case _ =>
+ // mapOver(tp)
+ // }
+ // }
+ val tpe1 = rawToExistential(sym.tpe)
+ // println("cooking: "+ sym +": "+ sym.tpe +" to "+ tpe1)
+ if (tpe1 ne sym.tpe) {
+ sym.setInfo(tpe1)
+ }
+ }
+
+ if (isJavaDefined)
+ cook(this)
+ else if (isOverloaded)
+ for (sym2 <- alternatives)
+ if (sym2.isJavaDefined)
+ cook(sym2)
+ }
+ }
+ implicit val TermSymbolTag = ClassTag[TermSymbol](classOf[TermSymbol])
+
+ /** A class for module symbols */
+ class ModuleSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
+ extends TermSymbol(initOwner, initPos, initName) with ModuleSymbolApi {
+ private var flatname: TermName = null
+
+ override def associatedFile = moduleClass.associatedFile
+ override def associatedFile_=(f: AbstractFileType) { moduleClass.associatedFile = f }
+
+ override def moduleClass = referenced
+ override def companionClass =
+ flatOwnerInfo.decl(name.toTypeName).suchThat(_ isCoDefinedWith this)
+
+ override def owner = (
+ if (!isMethod && needsFlatClasses) rawowner.owner
+ else rawowner
+ )
+ override def name: TermName = (
+ if (!isMethod && needsFlatClasses) {
+ if (flatname eq null)
+ flatname = nme.flattenedName(rawowner.name, rawname)
+
+ flatname
+ }
+ else rawname
+ )
+ }
+ implicit val ModuleSymbolTag = ClassTag[ModuleSymbol](classOf[ModuleSymbol])
+
+ /** A class for method symbols */
+ class MethodSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TermName)
+ extends TermSymbol(initOwner, initPos, initName) with MethodSymbolApi {
+ private[this] var mtpePeriod = NoPeriod
+ private[this] var mtpePre: Type = _
+ private[this] var mtpeResult: Type = _
+ private[this] var mtpeInfo: Type = _
+
+ override def isLabel = this hasFlag LABEL
+ override def isVarargsMethod = this hasFlag VARARGS
+ override def isLiftedMethod = this hasFlag LIFTED
+
+ // TODO - this seems a strange definition for "isSourceMethod", given that
+ // it does not make any specific effort to exclude synthetics. Figure out what
+ // this method is really for and what logic makes sense.
+ override def isSourceMethod = !(this hasFlag STABLE) // exclude all accessors
+ // unfortunately having the CASEACCESSOR flag does not actually mean you
+ // are a case accessor (you can also be a field.)
+ override def isCaseAccessorMethod = isCaseAccessor
+
+ def typeAsMemberOf(pre: Type): Type = {
+ if (mtpePeriod == currentPeriod) {
+ if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult
+ } else if (isValid(mtpePeriod)) {
+ mtpePeriod = currentPeriod
+ if ((mtpePre eq pre) && (mtpeInfo eq info)) return mtpeResult
+ }
+ val res = pre.computeMemberType(this)
+ mtpePeriod = currentPeriod
+ mtpePre = pre
+ mtpeInfo = info
+ mtpeResult = res
+ res
+ }
+ }
+ implicit val MethodSymbolTag = ClassTag[MethodSymbol](classOf[MethodSymbol])
+
+ class AliasTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
+ extends TypeSymbol(initOwner, initPos, initName) {
+ type TypeOfClonedSymbol = TypeSymbol
+ final override def isAliasType = true
+ final override def dealias = info.typeSymbol.dealias
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeSymbol =
+ owner.newNonClassSymbol(name, pos, newFlags)
+ }
+
+ class AbstractTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
+ extends TypeSymbol(initOwner, initPos, initName) {
+ type TypeOfClonedSymbol = TypeSymbol
+ final override def isAbstractType = true
+ override def existentialBound = this.info
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeSymbol =
+ owner.newNonClassSymbol(name, pos, newFlags)
+ }
+
+ /** A class of type symbols. Alias and abstract types are direct instances
+ * of this class. Classes are instances of a subclass.
+ */
+ abstract class TypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
+ extends Symbol(initOwner, initPos, initName) with TypeSymbolApi {
+ privateWithin = NoSymbol
+ private[this] var _rawname: TypeName = initName
+
+ type TypeOfClonedSymbol >: Null <: TypeSymbol
+ // cloneSymbolImpl still abstract in TypeSymbol.
+
+ def rawname = _rawname
+ def name = _rawname
+ final def asNameType(n: Name) = n.toTypeName
+
+ override def isNonClassType = true
+ override def isTypeMacro = hasFlag(MACRO)
+
+ override def resolveOverloadedFlag(flag: Long) = flag match {
+ case TRAIT => "<trait>" // DEFAULTPARAM
+ case EXISTENTIAL => "<existential>" // MIXEDIN
+ case COVARIANT => "<covariant>" // BYNAMEPARAM / CAPTURED
+ case CONTRAVARIANT => "<contravariant>" // LABEL / INCONSTRUCTOR (overridden again in ClassSymbol)
+ case _ => super.resolveOverloadedFlag(flag)
+ }
+
+ private var tyconCache: Type = null
+ private var tyconRunId = NoRunId
+ private var tpeCache: Type = _
+ private var tpePeriod = NoPeriod
+
+ override def isAbstractType = this hasFlag DEFERRED
+ override def isContravariant = this hasFlag CONTRAVARIANT
+ override def isCovariant = this hasFlag COVARIANT
+ override def isExistentialQuantified = isExistentiallyBound && !isSkolem
+ override def isExistentiallyBound = this hasFlag EXISTENTIAL
+ override def isTypeParameter = isTypeParameterOrSkolem && !isSkolem
+ override def isTypeParameterOrSkolem = this hasFlag PARAM
+
+ /** Overridden in subclasses for which it makes sense.
+ */
+ def existentialBound: Type = abort("unexpected type: "+this.getClass+ " "+debugLocationString)
+
+ // TODO - don't allow names to be renamed in this unstructured a fashion.
+ // Rename as little as possible. Enforce invariants on all renames.
+ def name_=(name: Name) {
+ if (name != rawname) {
+ log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name))
+ changeNameInOwners(name)
+ _rawname = name.toTypeName
+ }
+ }
+
+ private def newPrefix = if (this hasFlag EXISTENTIAL | PARAM) NoPrefix else owner.thisType
+ private def newTypeRef(targs: List[Type]) = typeRef(newPrefix, this, targs)
+
+ /** Let's say you have a type definition
+ *
+ * {{{
+ * type T <: Number
+ * }}}
+ *
+ * and tsym is the symbol corresponding to T. Then
+ *
+ * {{{
+ * tsym.info = TypeBounds(Nothing, Number)
+ * tsym.tpe = TypeRef(NoPrefix, T, List())
+ * }}}
+ */
+ override def tpe: Type = {
+ if (tpeCache eq NoType) throw CyclicReference(this, typeConstructor)
+ if (tpePeriod != currentPeriod) {
+ if (isValid(tpePeriod)) {
+ tpePeriod = currentPeriod
+ } else {
+ if (isInitialized) tpePeriod = currentPeriod
+ tpeCache = NoType
+ val targs =
+ if (phase.erasedTypes && this != ArrayClass) List()
+ else unsafeTypeParams map (_.typeConstructor)
+ //@M! use typeConstructor to generate dummy type arguments,
+ // sym.tpe should not be called on a symbol that's supposed to be a higher-kinded type
+ // memberType should be used instead, that's why it uses tpeHK and not tpe
+ tpeCache = newTypeRef(targs)
+ }
+ }
+ assert(tpeCache ne null/*, "" + this + " " + phase*/)//debug
+ tpeCache
+ }
+
+ /** @M -- tpe vs tpeHK:
+ *
+ * tpe: creates a TypeRef with dummy type arguments and kind *
+ * tpeHK: creates a TypeRef with no type arguments but with type parameters
+ *
+ * If typeParams is nonEmpty, calling tpe may hide errors or
+ * introduce spurious ones. (For example, when deriving a type from
+ * the symbol of a type argument that may be higher-kinded.) As far
+ * as I can tell, it only makes sense to call tpe in conjunction
+ * with a substitution that replaces the generated dummy type
+ * arguments by their actual types.
+ *
+ * TODO: the above conditions desperately need to be enforced by code.
+ */
+ override def tpeHK = typeConstructor // @M! used in memberType
+
+ override def typeConstructor: Type = {
+ if ((tyconCache eq null) || tyconRunId != currentRunId) {
+ tyconCache = newTypeRef(Nil)
+ tyconRunId = currentRunId
+ }
+ assert(tyconCache ne null)
+ tyconCache
+ }
+
+ override def info_=(tp: Type) {
+ tpePeriod = NoPeriod
+ tyconCache = null
+ super.info_=(tp)
+ }
+
+ final override def isNonBottomSubClass(that: Symbol): Boolean = (
+ (this eq that) || this.isError || that.isError ||
+ info.baseTypeIndex(that) >= 0
+ )
+
+ override def reset(completer: Type): this.type = {
+ super.reset(completer)
+ tpePeriod = NoPeriod
+ tyconRunId = NoRunId
+ this
+ }
+
+ /*** example:
+ * public class Test3<T> {}
+ * public class Test1<T extends Test3> {}
+ * info for T in Test1 should be >: Nothing <: Test3[_]
+ */
+ protected def doCookJavaRawInfo() {
+ if (isJavaDefined || owner.isJavaDefined) {
+ val tpe1 = rawToExistential(info)
+ // println("cooking type: "+ this +": "+ info +" to "+ tpe1)
+ if (tpe1 ne info) {
+ setInfo(tpe1)
+ }
+ }
+ }
+
+ incCounter(typeSymbolCount)
+ }
+ implicit val TypeSymbolTag = ClassTag[TypeSymbol](classOf[TypeSymbol])
+
+ /** A class for type parameters viewed from inside their scopes
+ *
+ * @param origin Can be either a tree, or a symbol, or null.
+ * If skolem got created from newTypeSkolem (called in Namers), origin denotes
+ * the type parameter from which the skolem was created. If it got created from
+ * skolemizeExistential, origin is either null or a Tree. If it is a Tree, it indicates
+ * where the skolem was introduced (this is important for knowing when to pack it
+ * again into ab Existential). origin is `null` only in skolemizeExistentials called
+ * from <:< or isAsSpecific, because here its value does not matter.
+ * I believe the following invariant holds:
+ *
+ * origin.isInstanceOf[Symbol] == !hasFlag(EXISTENTIAL)
+ */
+ class TypeSkolem protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName, origin: AnyRef)
+ extends TypeSymbol(initOwner, initPos, initName) {
+ type TypeOfClonedSymbol = TypeSkolem
+ /** The skolemization level in place when the skolem was constructed */
+ val level = skolemizationLevel
+
+ final override def isSkolem = true
+
+ // a type symbol bound by an existential type, for instance the T in
+ // List[T] forSome { type T }
+ override def isExistentialSkolem = this hasFlag EXISTENTIAL
+ override def isGADTSkolem = this hasFlag CASEACCESSOR | SYNTHETIC
+ override def isTypeSkolem = this hasFlag PARAM
+ override def isAbstractType = this hasFlag DEFERRED
+
+ override def isExistentialQuantified = false
+ override def existentialBound = if (isAbstractType) this.info else super.existentialBound
+
+ /** If typeskolem comes from a type parameter, that parameter, otherwise skolem itself */
+ override def deSkolemize = origin match {
+ case s: Symbol => s
+ case _ => this
+ }
+
+ /** If type skolem comes from an existential, the tree where it was created */
+ override def unpackLocation = origin
+
+ //@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo
+ override def typeParams = info.typeParams
+
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): TypeSkolem =
+ owner.newTypeSkolemSymbol(name, origin, pos, newFlags)
+
+ override def nameString: String =
+ if (settings.debug.value) (super.nameString + "&" + level)
+ else super.nameString
+ }
+
+ /** A class for class symbols */
+ class ClassSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName)
+ extends TypeSymbol(initOwner, initPos, initName) with ClassSymbolApi {
+ type TypeOfClonedSymbol = ClassSymbol
+
+ private[this] var flatname: TypeName = _
+ private[this] var _associatedFile: AbstractFileType = _
+ private[this] var thissym: Symbol = this
+
+ private[this] var thisTypeCache: Type = _
+ private[this] var thisTypePeriod = NoPeriod
+
+ override def resolveOverloadedFlag(flag: Long) = flag match {
+ case INCONSTRUCTOR => "<inconstructor>" // INCONSTRUCTOR / CONTRAVARIANT / LABEL
+ case EXISTENTIAL => "<existential>" // EXISTENTIAL / MIXEDIN
+ case IMPLCLASS => "<implclass>" // IMPLCLASS / PRESUPER
+ case _ => super.resolveOverloadedFlag(flag)
+ }
+
+ final override def isNonClassType = false
+ final override def isAbstractType = false
+ final override def isAliasType = false
+
+ override def isAbstractClass = this hasFlag ABSTRACT
+ override def isCaseClass = this hasFlag CASE
+ override def isClassLocalToConstructor = this hasFlag INCONSTRUCTOR
+ override def isImplClass = this hasFlag IMPLCLASS
+ override def isModuleClass = this hasFlag MODULE
+ override def isPackageClass = this hasFlag PACKAGE
+ override def isTrait = this hasFlag TRAIT
+
+ override def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass
+ override def isAnonymousClass = name containsName tpnme.ANON_CLASS_NAME
+ override def isConcreteClass = !(this hasFlag ABSTRACT | TRAIT)
+ override def isJavaInterface = hasAllFlags(JAVA | TRAIT)
+ override def isNestedClass = !owner.isPackageClass
+ override def isNumericValueClass = definitions.isNumericValueClass(this)
+ override def isPackageObjectClass = isModuleClass && (name == tpnme.PACKAGE)
+ override def isPrimitiveValueClass = definitions.isPrimitiveValueClass(this)
+
+ // The corresponding interface is the last parent by convention.
+ private def lastParent = if (tpe.parents.isEmpty) NoSymbol else tpe.parents.last.typeSymbol
+ override def toInterface: Symbol = (
+ if (isImplClass) {
+ if (phase.next.erasedTypes) lastParent
+ else owner.info.decl(tpnme.interfaceName(name))
+ }
+ else super.toInterface
+ )
+
+ /** Is this class locally defined?
+ * A class is local, if
+ * - it is anonymous, or
+ * - its owner is a value
+ * - it is defined within a local class
+ */
+ override def isLocalClass = (
+ isAnonOrRefinementClass
+ || isLocal
+ || !owner.isPackageClass && owner.isLocalClass
+ )
+ override def isStableClass = (this hasFlag STABLE) || checkStable()
+
+ private def checkStable() = {
+ def hasNoAbstractTypeMember(clazz: Symbol): Boolean =
+ (clazz hasFlag STABLE) || {
+ var e = clazz.info.decls.elems
+ while ((e ne null) && !(e.sym.isAbstractType && info.member(e.sym.name) == e.sym))
+ e = e.next
+ e == null
+ }
+ (info.baseClasses forall hasNoAbstractTypeMember) && {
+ setFlag(STABLE)
+ true
+ }
+ }
+
+ override def enclClassChain = this :: owner.enclClassChain
+
+ /** A helper method that factors the common code used the discover a
+ * companion module of a class. If a companion module exists, its symbol is
+ * returned, otherwise, `NoSymbol` is returned.
+ */
+ protected final def companionModule0: Symbol =
+ flatOwnerInfo.decl(name.toTermName).suchThat(
+ sym => sym.hasFlag(MODULE) && (sym isCoDefinedWith this) && !sym.isMethod)
+
+ override def companionModule = companionModule0
+ override def companionSymbol = companionModule0
+ override def linkedClassOfClass = companionModule.moduleClass
+
+ override def sourceModule = if (isModuleClass) companionModule else NoSymbol
+
+ override def existentialBound = GenPolyType(this.typeParams, TypeBounds.upper(this.classBound))
+
+ def primaryConstructorName = if (this hasFlag TRAIT | IMPLCLASS) nme.MIXIN_CONSTRUCTOR else nme.CONSTRUCTOR
+
+ override def primaryConstructor = {
+ val c = info decl primaryConstructorName
+ if (c.isOverloaded) c.alternatives.head else c
+ }
+
+ override def associatedFile = if (owner.isPackageClass) _associatedFile else super.associatedFile
+ override def associatedFile_=(f: AbstractFileType) { _associatedFile = f }
+
+ override def reset(completer: Type): this.type = {
+ super.reset(completer)
+ thissym = this
+ this
+ }
+
+ /** the type this.type in this class */
+ override def thisType: Type = {
+ val period = thisTypePeriod
+ if (period != currentPeriod) {
+ thisTypePeriod = currentPeriod
+ if (!isValid(period)) thisTypeCache = ThisType(this)
+ }
+ thisTypeCache
+ }
+
+ override def owner: Symbol =
+ if (needsFlatClasses) rawowner.owner else rawowner
+
+ override def name: TypeName = (
+ if (needsFlatClasses) {
+ if (flatname eq null)
+ flatname = nme.flattenedName(rawowner.name, rawname).toTypeName
+
+ flatname
+ }
+ else rawname
+ )
+
+ /** A symbol carrying the self type of the class as its type */
+ override def thisSym: Symbol = thissym
+
+ /** Sets the self type of the class */
+ override def typeOfThis_=(tp: Type) {
+ thissym = newThisSym(nme.this_, pos).setInfo(tp)
+ }
+
+ override def cloneSymbolImpl(owner: Symbol, newFlags: Long): ClassSymbol = {
+ val clone = owner.newClassSymbol(name, pos, newFlags)
+ if (thisSym != this) {
+ clone.typeOfThis = typeOfThis
+ clone.thisSym setName thisSym.name
+ }
+ if (_associatedFile ne null)
+ clone.associatedFile = _associatedFile
+
+ clone
+ }
+
+ override def firstParamAccessor =
+ info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse NoSymbol
+
+ private[this] var childSet: Set[Symbol] = Set()
+ override def children = childSet
+ override def addChild(sym: Symbol) { childSet = childSet + sym }
+
+ incCounter(classSymbolCount)
+ }
+ implicit val ClassSymbolTag = ClassTag[ClassSymbol](classOf[ClassSymbol])
+
+ /** A class for module class symbols
+ * Note: Not all module classes are of this type; when unpickled, we get
+ * plain class symbols!
+ */
+ class ModuleClassSymbol protected[Symbols] (owner: Symbol, pos: Position, name: TypeName)
+ extends ClassSymbol(owner, pos, name) {
+ private[this] var module: Symbol = _
+ private[this] var typeOfThisCache: Type = _
+ private[this] var typeOfThisPeriod = NoPeriod
+
+ private var implicitMembersCacheValue: List[Symbol] = Nil
+ private var implicitMembersCacheKey1: Type = NoType
+ private var implicitMembersCacheKey2: ScopeEntry = null
+
+ override def isModuleClass = true
+ override def linkedClassOfClass = companionClass
+
+ /** the self type of an object foo is foo.type, not class<foo>.this.type
+ */
+ override def typeOfThis = {
+ val period = typeOfThisPeriod
+ if (period != currentPeriod) {
+ typeOfThisPeriod = currentPeriod
+ if (!isValid(period))
+ typeOfThisCache = singleType(owner.thisType, sourceModule)
+ }
+ typeOfThisCache
+ }
+
+ def implicitMembers: List[Symbol] = {
+ val tp = info
+ if ((implicitMembersCacheKey1 ne tp) || (implicitMembersCacheKey2 ne tp.decls.elems)) {
+ // 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) {
+ implicitMembersCacheKey1 = tp
+ implicitMembersCacheKey2 = tp.decls.elems
+ implicitMembersCacheValue = tp.implicitMembers
+ }
+ }
+ implicitMembersCacheValue
+ }
+ // The null check seems to be necessary for the reifier.
+ override def sourceModule = if (module ne null) module else companionModule
+ override def sourceModule_=(module: Symbol) { this.module = module }
+ }
+
+ class PackageObjectClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position)
+ extends ModuleClassSymbol(owner0, pos0, tpnme.PACKAGE) {
+ final override def isPackageObjectClass = true
+ final override def isPackageObjectOrClass = true
+ final override def skipPackageObject = owner
+ final override def setName(name: Name): this.type = {
+ abort("Can't rename a package object to " + name)
+ }
+ }
+
+ trait ImplClassSymbol extends ClassSymbol {
+ override def sourceModule = companionModule
+ // override def isImplClass = true
+ override def typeOfThis = thisSym.tpe // don't use the ModuleClassSymbol typeOfThisCache.
+ }
+
+ class PackageClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position, name0: TypeName)
+ extends ModuleClassSymbol(owner0, pos0, name0) {
+ override def sourceModule = companionModule
+ override def enclClassChain = Nil
+ override def isPackageClass = true
+ }
+
+ class RefinementClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position)
+ extends ClassSymbol(owner0, pos0, tpnme.REFINE_CLASS_NAME) {
+ override def name_=(name: Name) {
+ assert(false, "Cannot set name of RefinementClassSymbol to " + name)
+ super.name_=(name)
+ }
+ override def isRefinementClass = true
+ override def isAnonOrRefinementClass = true
+ override def isLocalClass = true
+ override def hasMeaninglessName = true
+ override def companionModule: Symbol = NoSymbol
+
+ /** The mentioned twist. A refinement class has transowner X
+ * if any of its parents has transowner X.
+ */
+ override def hasTransOwner(sym: Symbol) = (
+ super.hasTransOwner(sym)
+ || info.parents.exists(_.typeSymbol hasTransOwner sym)
+ )
+ }
+
+ trait FreeSymbol extends Symbol {
+ def origin: String
+ }
+ class FreeTermSymbol(name0: TermName, value0: => Any, val origin: String) extends TermSymbol(NoSymbol, NoPosition, name0) with FreeSymbol with FreeTermSymbolApi {
+ def value = value0
+ }
+ implicit val FreeTermSymbolTag = ClassTag[FreeTermSymbol](classOf[FreeTermSymbol])
+
+ class FreeTypeSymbol(name0: TypeName, value0: => Any, val origin: String) extends TypeSkolem(NoSymbol, NoPosition, name0, NoSymbol) with FreeSymbol with FreeTypeSymbolApi {
+ def value = value0
+ }
+ implicit val FreeTypeSymbolTag = ClassTag[FreeTypeSymbol](classOf[FreeTypeSymbol])
+
+ /** An object representing a missing symbol */
+ class NoSymbol protected[Symbols]() extends Symbol(null, NoPosition, nme.NO_NAME) {
+ final type NameType = TermName
+ type TypeOfClonedSymbol = NoSymbol
+
+ def asNameType(n: Name) = n.toTermName
+ def rawname = nme.NO_NAME
+ def name = nme.NO_NAME
+ def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n)
+
+ synchronized {
+ setInfo(NoType)
+ privateWithin = this
+ }
+ override def info_=(info: Type) = {
+ infos = TypeHistory(1, NoType, null)
+ unlock()
+ validTo = currentPeriod
+ }
+ override def flagMask = AllFlags
+ override def exists = false
+ override def isHigherOrderTypeParameter = false
+ override def companionClass = NoSymbol
+ override def companionModule = NoSymbol
+ override def companionSymbol = NoSymbol
+ override def isSubClass(that: Symbol) = false
+ override def filter(cond: Symbol => Boolean) = this
+ override def defString: String = toString
+ override def locationString: String = ""
+ override def enclClassChain = Nil
+ override def enclClass: Symbol = this
+ override def enclosingTopLevelClass: Symbol = this
+ override def enclosingPackageClass: Symbol = this
+ override def enclMethod: Symbol = this
+ override def associatedFile = null
+ override def ownerChain: List[Symbol] = List()
+ override def ownersIterator: Iterator[Symbol] = Iterator.empty
+ override def alternatives: List[Symbol] = List()
+ override def reset(completer: Type): this.type = this
+ override def info: Type = NoType
+ override def existentialBound: Type = NoType
+ override def rawInfo: Type = NoType
+ protected def doCookJavaRawInfo() {}
+ override def accessBoundary(base: Symbol): Symbol = enclosingRootClass
+ def cloneSymbolImpl(owner: Symbol, newFlags: Long) = abort("NoSymbol.clone()")
+ override def originalEnclosingMethod = this
+
+ override def owner: Symbol =
+ abort("no-symbol does not have an owner")
+ override def typeConstructor: Type =
+ abort("no-symbol does not have a type constructor (this may indicate scalac cannot find fundamental classes)")
+ }
+
+ protected def makeNoSymbol: NoSymbol = new NoSymbol
+
+ lazy val NoSymbol: NoSymbol = makeNoSymbol
+
+ /** Derives a new list of symbols from the given list by mapping the given
+ * list across the given function. Then fixes the info of all the new symbols
+ * by substituting the new symbols for the original symbols.
+ *
+ * @param syms the prototypical symbols
+ * @param symFn the function to create new symbols
+ * @return the new list of info-adjusted symbols
+ */
+ def deriveSymbols(syms: List[Symbol], symFn: Symbol => Symbol): List[Symbol] = {
+ val syms1 = syms map symFn
+ syms1 map (_ substInfo (syms, syms1))
+ }
+
+ /** Derives a new Type by first deriving new symbols as in deriveSymbols,
+ * then performing the same oldSyms => newSyms substitution on `tpe` as is
+ * performed on the symbol infos in deriveSymbols.
+ *
+ * @param syms the prototypical symbols
+ * @param symFn the function to create new symbols
+ * @param tpe the prototypical type
+ * @return the new symbol-subsituted type
+ */
+ def deriveType(syms: List[Symbol], symFn: Symbol => Symbol)(tpe: Type): Type = {
+ val syms1 = deriveSymbols(syms, symFn)
+ tpe.substSym(syms, syms1)
+ }
+ /** Derives a new Type by instantiating the given list of symbols as
+ * WildcardTypes.
+ *
+ * @param syms the symbols to replace
+ * @return the new type with WildcardType replacing those syms
+ */
+ def deriveTypeWithWildcards(syms: List[Symbol])(tpe: Type): Type = {
+ if (syms.isEmpty) tpe
+ else tpe.instantiateTypeParams(syms, syms map (_ => WildcardType))
+ }
+ /** Convenience functions which derive symbols by cloning.
+ */
+ def cloneSymbols(syms: List[Symbol]): List[Symbol] =
+ deriveSymbols(syms, _.cloneSymbol)
+ def cloneSymbolsAtOwner(syms: List[Symbol], owner: Symbol): List[Symbol] =
+ deriveSymbols(syms, _ cloneSymbol owner)
+
+ /** Clone symbols and apply the given function to each new symbol's info.
+ *
+ * @param syms the prototypical symbols
+ * @param infoFn the function to apply to the infos
+ * @return the newly created, info-adjusted symbols
+ */
+ def cloneSymbolsAndModify(syms: List[Symbol], infoFn: Type => Type): List[Symbol] =
+ cloneSymbols(syms) map (_ modifyInfo infoFn)
+ def cloneSymbolsAtOwnerAndModify(syms: List[Symbol], owner: Symbol, infoFn: Type => Type): List[Symbol] =
+ cloneSymbolsAtOwner(syms, owner) map (_ modifyInfo infoFn)
+
+ /** Functions which perform the standard clone/substituting on the given symbols and type,
+ * then call the creator function with the new symbols and type as arguments.
+ */
+ def createFromClonedSymbols[T](syms: List[Symbol], tpe: Type)(creator: (List[Symbol], Type) => T): T = {
+ val syms1 = cloneSymbols(syms)
+ creator(syms1, tpe.substSym(syms, syms1))
+ }
+ def createFromClonedSymbolsAtOwner[T](syms: List[Symbol], owner: Symbol, tpe: Type)(creator: (List[Symbol], Type) => T): T = {
+ val syms1 = cloneSymbolsAtOwner(syms, owner)
+ creator(syms1, tpe.substSym(syms, syms1))
+ }
+
+ /** A deep map on a symbol's paramss.
+ */
+ def mapParamss[T](sym: Symbol)(f: Symbol => T): List[List[T]] = mmap(sym.info.paramss)(f)
+
+ /** An exception for cyclic references of symbol definitions */
+ case class CyclicReference(sym: Symbol, info: Type)
+ extends TypeError("illegal cyclic reference involving " + sym) {
+ if (settings.debug.value) printStackTrace()
+ }
+
+ case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable({
+ import language.reflectiveCalls
+ "Companions '" + sym1 + "' and '" + sym2 + "' must be defined in same file:\n" +
+ " Found in " + sym1.sourceFile.canonicalPath + " and " + sym2.sourceFile.canonicalPath
+ }) {
+ override def toString = getMessage
+ }
+
+ /** A class for type histories */
+ private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) {
+ assert((prev eq null) || phaseId(validFrom) > phaseId(prev.validFrom), this)
+ assert(validFrom != NoPeriod, this)
+
+ override def toString() =
+ "TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")"
+
+ def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
new file mode 100644
index 0000000000..c3a6fce164
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -0,0 +1,280 @@
+package scala.reflect
+package internal
+
+abstract class TreeGen extends makro.TreeBuilder {
+ val global: SymbolTable
+
+ import global._
+ import definitions._
+
+ def rootId(name: Name) = Select(Ident(nme.ROOTPKG), name)
+ def rootScalaDot(name: Name) = Select(rootId(nme.scala_) setSymbol ScalaPackage, name)
+ def scalaDot(name: Name) = Select(Ident(nme.scala_) setSymbol ScalaPackage, name)
+ def scalaAnnotationDot(name: Name) = Select(scalaDot(nme.annotation), name)
+ def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) setSymbol AnyRefClass
+ def scalaUnitConstr = scalaDot(tpnme.Unit) setSymbol UnitClass
+ def productConstr = scalaDot(tpnme.Product) setSymbol ProductRootClass
+ def serializableConstr = scalaDot(tpnme.Serializable) setSymbol SerializableClass
+
+ def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree, abstractFun: Boolean = false): Tree = {
+ val cls = if (abstractFun)
+ mkAttributedRef(AbstractFunctionClass(argtpes.length))
+ else
+ mkAttributedRef(FunctionClass(argtpes.length))
+ AppliedTypeTree(cls, argtpes :+ restpe)
+ }
+
+ /** A creator for method calls, e.g. fn[T1, T2, ...](v1, v2, ...)
+ * There are a number of variations.
+ *
+ * @param receiver symbol of the method receiver
+ * @param methodName name of the method to call
+ * @param targs type arguments (if Nil, no TypeApply node will be generated)
+ * @param args value arguments
+ * @return the newly created trees.
+ */
+ def mkMethodCall(receiver: Symbol, methodName: Name, targs: List[Type], args: List[Tree]): Tree =
+ mkMethodCall(Select(mkAttributedRef(receiver), methodName), targs, args)
+ def mkMethodCall(method: Symbol, targs: List[Type], args: List[Tree]): Tree =
+ mkMethodCall(mkAttributedRef(method), targs, args)
+ def mkMethodCall(method: Symbol, args: List[Tree]): Tree =
+ mkMethodCall(method, Nil, args)
+ def mkMethodCall(target: Tree, args: List[Tree]): Tree =
+ mkMethodCall(target, Nil, args)
+ def mkMethodCall(receiver: Symbol, methodName: Name, args: List[Tree]): Tree =
+ mkMethodCall(receiver, methodName, Nil, args)
+ def mkMethodCall(receiver: Tree, method: Symbol, targs: List[Type], args: List[Tree]): Tree =
+ mkMethodCall(Select(receiver, method), targs, args)
+
+ def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree =
+ Apply(mkTypeApply(target, targs map TypeTree), args)
+
+ def mkNullaryCall(method: Symbol, targs: List[Type]): Tree =
+ mkTypeApply(mkAttributedRef(method), targs map TypeTree)
+
+ /** Builds a reference to value whose type is given stable prefix.
+ * The type must be suitable for this. For example, it
+ * must not be a TypeRef pointing to an abstract type variable.
+ */
+ def mkAttributedQualifier(tpe: Type): Tree =
+ mkAttributedQualifier(tpe, NoSymbol)
+
+ /** Builds a reference to value whose type is given stable prefix.
+ * If the type is unsuitable, e.g. it is a TypeRef for an
+ * abstract type variable, then an Ident will be made using
+ * termSym as the Ident's symbol. In that case, termSym must
+ * not be NoSymbol.
+ */
+ def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = {
+ def failMessage = "mkAttributedQualifier(" + tpe + ", " + termSym + ")"
+ tpe match {
+ case NoPrefix =>
+ EmptyTree
+ case ThisType(clazz) =>
+ if (clazz.isEffectiveRoot) EmptyTree
+ else mkAttributedThis(clazz)
+ case SingleType(pre, sym) =>
+ mkApplyIfNeeded(mkAttributedStableRef(pre, sym))
+ case TypeRef(pre, sym, args) =>
+ if (sym.isRoot) {
+ mkAttributedThis(sym)
+ } else if (sym.isModuleClass) {
+ mkApplyIfNeeded(mkAttributedRef(pre, sym.sourceModule))
+ } else if (sym.isModule || sym.isClass) {
+ assert(phase.erasedTypes, failMessage)
+ mkAttributedThis(sym)
+ } else if (sym.isType) {
+ assert(termSym != NoSymbol, failMessage)
+ mkAttributedIdent(termSym) setType tpe
+ } else {
+ mkAttributedRef(pre, sym)
+ }
+
+ case ConstantType(value) =>
+ Literal(value) setType tpe
+
+ case AnnotatedType(_, atp, _) =>
+ mkAttributedQualifier(atp)
+
+ case RefinedType(parents, _) =>
+ // I am unclear whether this is reachable, but
+ // the following implementation looks logical -Lex
+ val firstStable = parents.find(_.isStable)
+ assert(!firstStable.isEmpty, failMessage + " parents = " + parents)
+ mkAttributedQualifier(firstStable.get)
+
+ case _ =>
+ abort("bad qualifier received: " + failMessage)
+ }
+ }
+ /** If this is a reference to a method with an empty
+ * parameter list, wrap it in an apply.
+ */
+ def mkApplyIfNeeded(qual: Tree) = qual.tpe match {
+ case MethodType(Nil, restpe) => atPos(qual.pos)(Apply(qual, Nil) setType restpe)
+ case _ => qual
+ }
+
+ /** Builds a reference to given symbol with given stable prefix. */
+ def mkAttributedRef(pre: Type, sym: Symbol): Tree = {
+ val qual = mkAttributedQualifier(pre)
+ qual match {
+ case EmptyTree => mkAttributedIdent(sym)
+ case This(clazz) if qual.symbol.isEffectiveRoot => mkAttributedIdent(sym)
+ case _ => mkAttributedSelect(qual, sym)
+ }
+ }
+
+ /** Builds a reference to given symbol. */
+ def mkAttributedRef(sym: Symbol): Tree =
+ if (sym.owner.isClass) mkAttributedRef(sym.owner.thisType, sym)
+ else mkAttributedIdent(sym)
+
+ /** Builds an untyped reference to given symbol. */
+ def mkUnattributedRef(sym: Symbol): Tree =
+ if (sym.owner.isClass) Select(This(sym.owner), sym)
+ else Ident(sym)
+
+ /** Replaces tree type with a stable type if possible */
+ def stabilize(tree: Tree): Tree = {
+ for(tp <- stableTypeFor(tree)) tree.tpe = tp
+ tree
+ }
+
+ /** Computes stable type for a tree if possible */
+ def stableTypeFor(tree: Tree): Option[Type] = tree match {
+ case Ident(_) if tree.symbol.isStable =>
+ Some(singleType(tree.symbol.owner.thisType, tree.symbol))
+ case Select(qual, _) if ((tree.symbol ne null) && (qual.tpe ne null)) && // turned assert into guard for #4064
+ tree.symbol.isStable && qual.tpe.isStable =>
+ Some(singleType(qual.tpe, tree.symbol))
+ case _ =>
+ None
+ }
+
+ /** Builds a reference with stable type to given symbol */
+ def mkAttributedStableRef(pre: Type, sym: Symbol): Tree =
+ stabilize(mkAttributedRef(pre, sym))
+
+ def mkAttributedStableRef(sym: Symbol): Tree =
+ stabilize(mkAttributedRef(sym))
+
+ def mkAttributedThis(sym: Symbol): Tree =
+ This(sym.name.toTypeName) setSymbol sym setType sym.thisType
+
+ def mkAttributedIdent(sym: Symbol): Tree =
+ Ident(sym.name) setSymbol sym setType sym.tpe
+
+ def mkAttributedSelect(qual: Tree, sym: Symbol): Tree = {
+ // Tests involving the repl fail without the .isEmptyPackage condition.
+ if (qual.symbol != null && (qual.symbol.isEffectiveRoot || qual.symbol.isEmptyPackage))
+ mkAttributedIdent(sym)
+ else {
+ val pkgQualifier =
+ if (sym != null && sym.owner.isPackageObjectClass && sym.effectiveOwner == qual.tpe.typeSymbol) {
+ val obj = sym.owner.sourceModule
+ Select(qual, nme.PACKAGE) setSymbol obj setType singleType(qual.tpe, obj)
+ }
+ else qual
+
+ val tree = Select(pkgQualifier, sym)
+ if (pkgQualifier.tpe == null) tree
+ else tree setType (qual.tpe memberType sym)
+ }
+ }
+
+ /** Builds a type application node if args.nonEmpty, returns fun otherwise. */
+ def mkTypeApply(fun: Tree, targs: List[Tree]): Tree =
+ if (targs.isEmpty) fun else TypeApply(fun, targs)
+ def mkTypeApply(target: Tree, method: Symbol, targs: List[Type]): Tree =
+ mkTypeApply(Select(target, method), targs map TypeTree)
+ def mkAttributedTypeApply(target: Tree, method: Symbol, targs: List[Type]): Tree =
+ mkTypeApply(mkAttributedSelect(target, method), targs map TypeTree)
+
+ private def mkSingleTypeApply(value: Tree, tpe: Type, what: Symbol, wrapInApply: Boolean) = {
+ val tapp = mkAttributedTypeApply(value, what, List(tpe.normalize))
+ if (wrapInApply) Apply(tapp, Nil) else tapp
+ }
+ private def typeTestSymbol(any: Boolean) = if (any) Any_isInstanceOf else Object_isInstanceOf
+ private def typeCastSymbol(any: Boolean) = if (any) Any_asInstanceOf else Object_asInstanceOf
+
+ /** Builds an instance test with given value and type. */
+ def mkIsInstanceOf(value: Tree, tpe: Type, any: Boolean = true, wrapInApply: Boolean = true): Tree =
+ mkSingleTypeApply(value, tpe, typeTestSymbol(any), wrapInApply)
+
+ /** Builds a cast with given value and type. */
+ def mkAsInstanceOf(value: Tree, tpe: Type, any: Boolean = true, wrapInApply: Boolean = true): Tree =
+ mkSingleTypeApply(value, tpe, typeCastSymbol(any), wrapInApply)
+
+ /** Cast `tree` to `pt`, unless tpe is a subtype of pt, or pt is Unit. */
+ def maybeMkAsInstanceOf(tree: Tree, pt: Type, tpe: Type, beforeRefChecks: Boolean = false): Tree =
+ if ((pt == UnitClass.tpe) || (tpe <:< pt)) tree
+ else atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = true, wrapInApply = !beforeRefChecks))
+
+ /** Apparently we smuggle a Type around as a Literal(Constant(tp))
+ * and the implementation of Constant#tpe is such that x.tpe becomes
+ * ClassType(value.asInstanceOf[Type]), i.e. java.lang.Class[Type].
+ * Can't find any docs on how/why it's done this way. See ticket
+ * SI-490 for some interesting comments from lauri alanko suggesting
+ * that the type given by classOf[T] is too strong and should be
+ * weakened so as not to suggest that classOf[List[String]] is any
+ * different from classOf[List[Int]].
+ *
+ * !!! See deconstMap in Erasure for one bug this encoding has induced:
+ * I would be very surprised if there aren't more.
+ */
+ def mkClassOf(tp: Type): Tree =
+ Literal(Constant(tp)) setType ConstantType(Constant(tp))
+
+ /** Builds a list with given head and tail. */
+ def mkNewCons(head: Tree, tail: Tree): Tree =
+ New(Apply(mkAttributedRef(ConsClass), List(head, tail)))
+
+ /** Builds a list with given head and tail. */
+ def mkNil: Tree = mkAttributedRef(NilModule)
+
+ /** Builds a tree representing an undefined local, as in
+ * var x: T = _
+ * which is appropriate to the given Type.
+ */
+ def mkZero(tp: Type): Tree = tp.typeSymbol match {
+ case NothingClass => mkMethodCall(Predef_???, Nil) setType NothingClass.tpe
+ case _ => Literal(mkConstantZero(tp)) setType tp
+ }
+
+ def mkConstantZero(tp: Type): Constant = tp.typeSymbol match {
+ case UnitClass => Constant(())
+ case BooleanClass => Constant(false)
+ case FloatClass => Constant(0.0f)
+ case DoubleClass => Constant(0.0d)
+ case ByteClass => Constant(0.toByte)
+ case ShortClass => Constant(0.toShort)
+ case IntClass => Constant(0)
+ case LongClass => Constant(0L)
+ case CharClass => Constant(0.toChar)
+ case _ => Constant(null)
+ }
+
+ /** Builds a tuple */
+ def mkTuple(elems: List[Tree]): Tree =
+ if (elems.isEmpty) Literal(Constant())
+ else Apply(
+ Select(mkAttributedRef(TupleClass(elems.length).caseModule), nme.apply),
+ elems)
+
+ // tree1 AND tree2
+ def mkAnd(tree1: Tree, tree2: Tree): Tree =
+ Apply(Select(tree1, Boolean_and), List(tree2))
+
+ // tree1 OR tree2
+ def mkOr(tree1: Tree, tree2: Tree): Tree =
+ Apply(Select(tree1, Boolean_or), List(tree2))
+
+ def mkBasisUniverseRef: Tree =
+ mkAttributedRef(ReflectBasis) setType singleType(ReflectBasis.owner.thisPrefix, ReflectBasis)
+
+ def mkRuntimeUniverseRef: Tree = {
+ assert(ReflectRuntimeUniverse != NoSymbol)
+ mkAttributedRef(ReflectRuntimeUniverse) setType singleType(ReflectRuntimeUniverse.owner.thisPrefix, ReflectRuntimeUniverse)
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
new file mode 100644
index 0000000000..4b2105876d
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -0,0 +1,571 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import Flags._
+
+/** This class ...
+ *
+ * @author Martin Odersky
+ * @version 1.0
+ */
+abstract class TreeInfo {
+ val global: SymbolTable
+
+ import global._
+ import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass, TupleClass }
+
+ /* Does not seem to be used. Not sure what it does anyway.
+ def isOwnerDefinition(tree: Tree): Boolean = tree match {
+ case PackageDef(_, _)
+ | ClassDef(_, _, _, _)
+ | ModuleDef(_, _, _)
+ | DefDef(_, _, _, _, _, _)
+ | Import(_, _) => true
+ case _ => false
+ }
+*/
+
+ // def isDefinition(tree: Tree): Boolean = tree.isDef
+
+ /** Is tree a declaration or type definition?
+ */
+ def isDeclarationOrTypeDef(tree: Tree): Boolean = tree match {
+ case x: ValOrDefDef => x.rhs eq EmptyTree
+ case _ => tree.isInstanceOf[TypeDef]
+ }
+
+ /** Is tree legal as a member definition of an interface?
+ */
+ def isInterfaceMember(tree: Tree): Boolean = tree match {
+ case EmptyTree => true
+ case Import(_, _) => true
+ case TypeDef(_, _, _, _) => true
+ case DefDef(mods, _, _, _, _, __) => mods.isDeferred
+ case ValDef(mods, _, _, _) => mods.isDeferred
+ case _ => false
+ }
+
+ /** Is tree a pure (i.e. non-side-effecting) definition?
+ */
+ def isPureDef(tree: Tree): Boolean = tree match {
+ case EmptyTree
+ | ClassDef(_, _, _, _)
+ | TypeDef(_, _, _, _)
+ | Import(_, _)
+ | DefDef(_, _, _, _, _, _) =>
+ true
+ case ValDef(mods, _, _, rhs) =>
+ !mods.isMutable && isExprSafeToInline(rhs)
+ case _ =>
+ false
+ }
+
+ /** Is tree an expression which can be inlined without affecting program semantics?
+ *
+ * Note that this is not called "isExprSafeToInline" since purity (lack of side-effects)
+ * is not the litmus test. References to modules and lazy vals are side-effecting,
+ * both because side-effecting code may be executed and because the first reference
+ * takes a different code path than all to follow; but they are safe to inline
+ * because the expression result from evaluating them is always the same.
+ */
+ def isExprSafeToInline(tree: Tree): Boolean = tree match {
+ case EmptyTree
+ | This(_)
+ | Super(_, _)
+ | Literal(_) =>
+ true
+ case Ident(_) =>
+ tree.symbol.isStable
+ // this case is mostly to allow expressions like -5 and +7, but any
+ // member of an anyval should be safely pure
+ case Select(Literal(const), name) =>
+ const.isAnyVal && (const.tpe.member(name) != NoSymbol)
+ case Select(qual, _) =>
+ tree.symbol.isStable && isExprSafeToInline(qual)
+ case TypeApply(fn, _) =>
+ isExprSafeToInline(fn)
+ case Apply(fn, List()) =>
+ /* Note: After uncurry, field accesses are represented as Apply(getter, Nil),
+ * so an Apply can also be pure.
+ * However, before typing, applications of nullary functional values are also
+ * Apply(function, Nil) trees. To prevent them from being treated as pure,
+ * we check that the callee is a method. */
+ fn.symbol.isMethod && !fn.symbol.isLazy && isExprSafeToInline(fn)
+ case Typed(expr, _) =>
+ isExprSafeToInline(expr)
+ case Block(stats, expr) =>
+ (stats forall isPureDef) && isExprSafeToInline(expr)
+ case _ =>
+ false
+ }
+
+ @deprecated("Use isExprSafeToInline instead", "2.10.0")
+ def isPureExpr(tree: Tree) = isExprSafeToInline(tree)
+
+ def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] =
+ mapMethodParamsAndArgs(params, args)((param, arg) => ((param, arg)))
+
+ def mapMethodParamsAndArgs[R](params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => R): List[R] = {
+ val b = List.newBuilder[R]
+ foreachMethodParamAndArg(params, args)((param, arg) => b += f(param, arg))
+ b.result
+ }
+ def foreachMethodParamAndArg(params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => Unit): Boolean = {
+ val plen = params.length
+ val alen = args.length
+ def fail() = {
+ global.debugwarn(
+ "Mismatch trying to zip method parameters and argument list:\n" +
+ " params = " + params + "\n" +
+ " args = " + args + "\n"
+ )
+ false
+ }
+
+ if (plen == alen) foreach2(params, args)(f)
+ else if (params.isEmpty) return fail
+ else if (isVarArgsList(params)) {
+ val plenInit = plen - 1
+ if (alen == plenInit) {
+ if (alen == 0) Nil // avoid calling mismatched zip
+ else foreach2(params.init, args)(f)
+ }
+ else if (alen < plenInit) return fail
+ else {
+ foreach2(params.init, args take plenInit)(f)
+ val remainingArgs = args drop plenInit
+ foreach2(List.fill(remainingArgs.size)(params.last), remainingArgs)(f)
+ }
+ }
+ else return fail
+
+ true
+ }
+
+ /**
+ * Selects the correct parameter list when there are nested applications.
+ * Given Apply(fn, args), args might correspond to any of fn.symbol's parameter
+ * lists. To choose the correct one before uncurry, we have to unwrap any
+ * applies: for instance Apply(fn @ Apply(Apply(_, _), _), args) implies args
+ * correspond to the third parameter list.
+ *
+ * The argument fn is the function part of the apply node being considered.
+ *
+ * Also accounts for varargs.
+ */
+ private def applyMethodParameters(fn: Tree): List[Symbol] = {
+ val depth = applyDepth(fn)
+ // There could be applies which go beyond the parameter list(s),
+ // being applied to the result of the method call.
+ // !!! Note that this still doesn't seem correct, although it should
+ // be closer than what it replaced.
+ if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth)
+ else if (fn.symbol.paramss.isEmpty) Nil
+ else fn.symbol.paramss.last
+ }
+
+ def zipMethodParamsAndArgs(t: Tree): List[(Symbol, Tree)] = t match {
+ case Apply(fn, args) => zipMethodParamsAndArgs(applyMethodParameters(fn), args)
+ case _ => Nil
+ }
+ def foreachMethodParamAndArg(t: Tree)(f: (Symbol, Tree) => Unit): Unit = t match {
+ case Apply(fn, args) => foreachMethodParamAndArg(applyMethodParameters(fn), args)(f)
+ case _ =>
+ }
+
+ /** Is symbol potentially a getter of a variable?
+ */
+ def mayBeVarGetter(sym: Symbol): Boolean = sym.info match {
+ case NullaryMethodType(_) => sym.owner.isClass && !sym.isStable
+ case PolyType(_, NullaryMethodType(_)) => sym.owner.isClass && !sym.isStable
+ case mt @ MethodType(_, _) => mt.isImplicit && sym.owner.isClass && !sym.isStable
+ case _ => false
+ }
+
+ /** Is tree a mutable variable, or the getter of a mutable field?
+ */
+ def isVariableOrGetter(tree: Tree) = {
+ def sym = tree.symbol
+ def isVar = sym.isVariable
+ def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name.toTermName)) != NoSymbol
+
+ tree match {
+ case Ident(_) => isVar
+ case Select(_, _) => isVar || isGetter
+ case _ =>
+ methPart(tree) match {
+ case Select(qual, nme.apply) => qual.tpe.member(nme.update) != NoSymbol
+ case _ => false
+ }
+ }
+ }
+
+ /** Is tree a self constructor call this(...)? I.e. a call to a constructor of the
+ * same object?
+ */
+ def isSelfConstrCall(tree: Tree): Boolean = methPart(tree) match {
+ case Ident(nme.CONSTRUCTOR)
+ | Select(This(_), nme.CONSTRUCTOR) => true
+ case _ => false
+ }
+
+ /** Is tree a super constructor call?
+ */
+ def isSuperConstrCall(tree: Tree): Boolean = methPart(tree) match {
+ case Select(Super(_, _), nme.CONSTRUCTOR) => true
+ case _ => false
+ }
+
+ /**
+ * Named arguments can transform a constructor call into a block, e.g.
+ * <init>(b = foo, a = bar)
+ * is transformed to
+ * { val x$1 = foo
+ * val x$2 = bar
+ * <init>(x$2, x$1)
+ * }
+ */
+ def stripNamedApplyBlock(tree: Tree) = tree match {
+ case Block(stats, expr) if stats.forall(_.isInstanceOf[ValDef]) =>
+ expr
+ case _ =>
+ tree
+ }
+
+ /** Is tree a self or super constructor call? */
+ def isSelfOrSuperConstrCall(tree: Tree) = {
+ // stripNamedApply for SI-3584: adaptToImplicitMethod in Typers creates a special context
+ // for implicit search in constructor calls, adaptToImplicitMethod(isSelfOrConstrCall)
+ val tree1 = stripNamedApplyBlock(tree)
+ isSelfConstrCall(tree1) || isSuperConstrCall(tree1)
+ }
+
+ /** Is tree a variable pattern? */
+ def isVarPattern(pat: Tree): Boolean = pat match {
+ case x: Ident => !x.isBackquoted && isVariableName(x.name)
+ case _ => false
+ }
+ def isDeprecatedIdentifier(tree: Tree): Boolean = tree match {
+ case x: Ident => !x.isBackquoted && nme.isDeprecatedIdentifierName(x.name)
+ case _ => false
+ }
+
+ /** The first constructor definitions in `stats` */
+ def firstConstructor(stats: List[Tree]): Tree = stats find {
+ case x: DefDef => nme.isConstructorName(x.name)
+ case _ => false
+ } getOrElse EmptyTree
+
+ /** The arguments to the first constructor in `stats`. */
+ def firstConstructorArgs(stats: List[Tree]): List[Tree] = firstConstructor(stats) match {
+ case DefDef(_, _, _, args :: _, _, _) => args
+ case _ => Nil
+ }
+
+ /** The value definitions marked PRESUPER in this statement sequence */
+ def preSuperFields(stats: List[Tree]): List[ValDef] =
+ stats collect { case vd: ValDef if isEarlyValDef(vd) => vd }
+
+ def isEarlyDef(tree: Tree) = tree match {
+ case TypeDef(mods, _, _, _) => mods hasFlag PRESUPER
+ case ValDef(mods, _, _, _) => mods hasFlag PRESUPER
+ case _ => false
+ }
+
+ def isEarlyValDef(tree: Tree) = tree match {
+ case ValDef(mods, _, _, _) => mods hasFlag PRESUPER
+ case _ => false
+ }
+
+ def isEarlyTypeDef(tree: Tree) = tree match {
+ case TypeDef(mods, _, _, _) => mods hasFlag PRESUPER
+ case _ => false
+ }
+
+ /** Is tpt a vararg type of the form T* ? */
+ def isRepeatedParamType(tpt: Tree) = tpt match {
+ case TypeTree() => definitions.isRepeatedParamType(tpt.tpe)
+ case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS_NAME), _) => true
+ case AppliedTypeTree(Select(_, tpnme.JAVA_REPEATED_PARAM_CLASS_NAME), _) => true
+ case _ => false
+ }
+
+ /** The parameter ValDefs of a method definition that have vararg types of the form T*
+ */
+ def repeatedParams(tree: Tree): List[ValDef] = tree match {
+ case DefDef(_, _, _, vparamss, _, _) => vparamss.flatten filter (vd => isRepeatedParamType(vd.tpt))
+ case _ => Nil
+ }
+
+ /** Is tpt a by-name parameter type of the form => T? */
+ def isByNameParamType(tpt: Tree) = tpt match {
+ case TypeTree() => definitions.isByNameParamType(tpt.tpe)
+ case AppliedTypeTree(Select(_, tpnme.BYNAME_PARAM_CLASS_NAME), _) => true
+ case _ => false
+ }
+
+ /** Is name a left-associative operator? */
+ def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.endChar != ':')
+
+ private val reserved = Set[Name](nme.false_, nme.true_, nme.null_)
+
+ /** Is name a variable name? */
+ def isVariableName(name: Name): Boolean = {
+ val first = name(0)
+ ((first.isLower && first.isLetter) || first == '_') && !reserved(name)
+ }
+
+ /** Is tree a `this` node which belongs to `enclClass`? */
+ def isSelf(tree: Tree, enclClass: Symbol): Boolean = tree match {
+ case This(_) => tree.symbol == enclClass
+ case _ => false
+ }
+
+ /** can this type be a type pattern */
+ def mayBeTypePat(tree: Tree): Boolean = tree match {
+ case CompoundTypeTree(Template(tps, _, Nil)) => tps exists mayBeTypePat
+ case Annotated(_, tp) => mayBeTypePat(tp)
+ case AppliedTypeTree(constr, args) => mayBeTypePat(constr) || args.exists(_.isInstanceOf[Bind])
+ case SelectFromTypeTree(tp, _) => mayBeTypePat(tp)
+ case _ => false
+ }
+
+ /** Is this tree comprised of nothing but identifiers,
+ * but possibly in bindings or tuples? For instance
+ *
+ * foo @ (bar, (baz, quux))
+ *
+ * is a variable pattern; if the structure matches,
+ * then the remainder is inevitable.
+ */
+ def isVariablePattern(tree: Tree): Boolean = tree match {
+ case Bind(name, pat) => isVariablePattern(pat)
+ case Ident(name) => true
+ case Apply(sel, args) =>
+ ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName)
+ && (args forall isVariablePattern)
+ )
+ case _ => false
+ }
+
+ /** Is this argument node of the form <expr> : _* ?
+ */
+ def isWildcardStarArg(tree: Tree): Boolean = tree match {
+ case Typed(_, Ident(tpnme.WILDCARD_STAR)) => true
+ case _ => false
+ }
+
+ /** If this tree represents a type application (after unwrapping
+ * any applies) the first type argument. Otherwise, EmptyTree.
+ */
+ def firstTypeArg(tree: Tree): Tree = tree match {
+ case Apply(fn, _) => firstTypeArg(fn)
+ case TypeApply(_, targ :: _) => targ
+ case _ => EmptyTree
+ }
+
+ /** If this tree has type parameters, those. Otherwise Nil.
+ */
+ def typeParameters(tree: Tree): List[TypeDef] = tree match {
+ case DefDef(_, _, tparams, _, _, _) => tparams
+ case ClassDef(_, _, tparams, _) => tparams
+ case TypeDef(_, _, tparams, _) => tparams
+ case _ => Nil
+ }
+
+ /** Does this argument list end with an argument of the form <expr> : _* ? */
+ def isWildcardStarArgList(trees: List[Tree]) =
+ trees.nonEmpty && isWildcardStarArg(trees.last)
+
+ /** Is the argument a wildcard argument of the form `_` or `x @ _`?
+ */
+ def isWildcardArg(tree: Tree): Boolean = unbind(tree) match {
+ case Ident(nme.WILDCARD) => true
+ case _ => false
+ }
+
+ /** Is this pattern node a catch-all (wildcard or variable) pattern? */
+ def isDefaultCase(cdef: CaseDef) = cdef match {
+ case CaseDef(pat, EmptyTree, _) => isWildcardArg(pat)
+ case _ => false
+ }
+
+ /** Does this CaseDef catch Throwable? */
+ def catchesThrowable(cdef: CaseDef) = catchesAllOf(cdef, ThrowableClass.tpe)
+
+ /** Does this CaseDef catch everything of a certain Type? */
+ def catchesAllOf(cdef: CaseDef, threshold: Type) =
+ isDefaultCase(cdef) || (cdef.guard.isEmpty && (unbind(cdef.pat) match {
+ case Typed(Ident(nme.WILDCARD), tpt) => (tpt.tpe != null) && (threshold <:< tpt.tpe)
+ case _ => false
+ }))
+
+ /** Is this pattern node a catch-all or type-test pattern? */
+ def isCatchCase(cdef: CaseDef) = cdef match {
+ case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree, _) =>
+ isSimpleThrowable(tpt.tpe)
+ case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree, _) =>
+ isSimpleThrowable(tpt.tpe)
+ case _ =>
+ isDefaultCase(cdef)
+ }
+
+ private def isSimpleThrowable(tp: Type): Boolean = tp match {
+ case TypeRef(pre, sym, args) =>
+ (pre == NoPrefix || pre.widen.typeSymbol.isStatic) &&
+ (sym isNonBottomSubClass ThrowableClass) && /* bq */ !sym.isTrait
+ case _ =>
+ false
+ }
+
+ /* If we have run-time types, and these are used for pattern matching,
+ we should replace this by something like:
+
+ tp match {
+ case TypeRef(pre, sym, args) =>
+ args.isEmpty && (sym.owner.isPackageClass || isSimple(pre))
+ case NoPrefix =>
+ true
+ case _ =>
+ false
+ }
+*/
+
+ /** Is this pattern node a sequence-valued pattern? */
+ def isSequenceValued(tree: Tree): Boolean = unbind(tree) match {
+ case Alternative(ts) => ts exists isSequenceValued
+ case ArrayValue(_, _) | Star(_) => true
+ case _ => false
+ }
+
+ /** The underlying pattern ignoring any bindings */
+ def unbind(x: Tree): Tree = x match {
+ case Bind(_, y) => unbind(y)
+ case y => y
+ }
+
+ /** Is this tree a Star(_) after removing bindings? */
+ def isStar(x: Tree) = unbind(x) match {
+ case Star(_) => true
+ case _ => false
+ }
+
+ /** The method part of an application node
+ */
+ def methPart(tree: Tree): Tree = tree match {
+ case Apply(fn, _) => methPart(fn)
+ case TypeApply(fn, _) => methPart(fn)
+ case AppliedTypeTree(fn, _) => methPart(fn)
+ case _ => tree
+ }
+
+ /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _)
+ * has depth 3. Continues through type applications (without counting them.)
+ */
+ def applyDepth(tree: Tree): Int = tree match {
+ case Apply(fn, _) => 1 + applyDepth(fn)
+ case TypeApply(fn, _) => applyDepth(fn)
+ case AppliedTypeTree(fn, _) => applyDepth(fn)
+ case _ => 0
+ }
+ def firstArgument(tree: Tree): Tree = tree match {
+ case Apply(fn, args) =>
+ val f = firstArgument(fn)
+ if (f == EmptyTree && !args.isEmpty) args.head else f
+ case _ =>
+ EmptyTree
+ }
+
+ /** Does list of trees start with a definition of
+ * a class of module with given name (ignoring imports)
+ */
+ def firstDefinesClassOrObject(trees: List[Tree], name: Name): Boolean = trees match {
+ case Import(_, _) :: xs => firstDefinesClassOrObject(xs, name)
+ case Annotated(_, tree1) :: Nil => firstDefinesClassOrObject(List(tree1), name)
+ case ModuleDef(_, `name`, _) :: Nil => true
+ case ClassDef(_, `name`, _, _) :: Nil => true
+ case _ => false
+ }
+
+
+ /** Is this file the body of a compilation unit which should not
+ * have Predef imported?
+ */
+ def noPredefImportForUnit(body: Tree) = {
+ // Top-level definition whose leading imports include Predef.
+ def containsLeadingPredefImport(defs: List[Tree]): Boolean = defs match {
+ case PackageDef(_, defs1) :: _ => containsLeadingPredefImport(defs1)
+ case Import(expr, _) :: rest => isReferenceToPredef(expr) || containsLeadingPredefImport(rest)
+ case _ => false
+ }
+
+ // Compilation unit is class or object 'name' in package 'scala'
+ def isUnitInScala(tree: Tree, name: Name) = tree match {
+ case PackageDef(Ident(nme.scala_), defs) => firstDefinesClassOrObject(defs, name)
+ case _ => false
+ }
+
+ ( isUnitInScala(body, nme.Predef)
+ || containsLeadingPredefImport(List(body)))
+ }
+
+ def isAbsTypeDef(tree: Tree) = tree match {
+ case TypeDef(_, _, _, TypeBoundsTree(_, _)) => true
+ case TypeDef(_, _, _, rhs) => rhs.tpe.isInstanceOf[TypeBounds]
+ case _ => false
+ }
+
+ def isAliasTypeDef(tree: Tree) = tree match {
+ case TypeDef(_, _, _, _) => !isAbsTypeDef(tree)
+ case _ => false
+ }
+
+ /** Some handy extractors for spotting trees through the
+ * the haze of irrelevant braces: i.e. Block(Nil, SomeTree)
+ * should not keep us from seeing SomeTree.
+ */
+ abstract class SeeThroughBlocks[T] {
+ protected def unapplyImpl(x: Tree): T
+ def unapply(x: Tree): T = x match {
+ case Block(Nil, expr) => unapply(expr)
+ case _ => unapplyImpl(x)
+ }
+ }
+ object IsTrue extends SeeThroughBlocks[Boolean] {
+ protected def unapplyImpl(x: Tree): Boolean = x match {
+ case Literal(Constant(true)) => true
+ case _ => false
+ }
+ }
+ object IsFalse extends SeeThroughBlocks[Boolean] {
+ protected def unapplyImpl(x: Tree): Boolean = x match {
+ case Literal(Constant(false)) => true
+ case _ => false
+ }
+ }
+ object IsIf extends SeeThroughBlocks[Option[(Tree, Tree, Tree)]] {
+ protected def unapplyImpl(x: Tree) = x match {
+ case If(cond, thenp, elsep) => Some((cond, thenp, elsep))
+ case _ => None
+ }
+ }
+
+ def isApplyDynamicName(name: Name) = (name == nme.updateDynamic) || (name == nme.selectDynamic) || (name == nme.applyDynamic) || (name == nme.applyDynamicNamed)
+
+ class DynamicApplicationExtractor(nameTest: Name => Boolean) {
+ def unapply(tree: Tree) = tree match {
+ case Apply(TypeApply(Select(qual, oper), _), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name))
+ case Apply(Select(qual, oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((qual, name))
+ case Apply(Ident(oper), List(Literal(Constant(name)))) if nameTest(oper) => Some((EmptyTree, name))
+ case _ => None
+ }
+ }
+ object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic)
+ object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName)
+ object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed)
+}
diff --git a/src/reflect/scala/reflect/internal/TreePrinters.scala b/src/reflect/scala/reflect/internal/TreePrinters.scala
new file mode 100644
index 0000000000..6d035c8b9d
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/TreePrinters.scala
@@ -0,0 +1,478 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+// [Eugene++ to Martin] we need to unify this prettyprinter with NodePrinters
+
+package scala.reflect
+package internal
+
+import java.io.{ OutputStream, PrintWriter, StringWriter, Writer }
+import Flags._
+
+trait TreePrinters extends api.TreePrinters { self: SymbolTable =>
+
+ //nsc import treeInfo.{ IsTrue, IsFalse }
+
+ final val showOuterTests = false
+
+ /** Adds backticks if the name is a scala keyword. */
+ def quotedName(name: Name, decode: Boolean): String = {
+ val s = if (decode) name.decode else name.toString
+ val term = name.toTermName
+ if (nme.keywords(term) && term != nme.USCOREkw) "`%s`" format s
+ else s
+ }
+ def quotedName(name: Name): String = quotedName(name, false)
+ def quotedName(name: String): String = quotedName(newTermName(name), false)
+
+ private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = {
+ val sym = tree.symbol
+ if (sym.name.toString == nme.ERROR.toString) {
+ "<" + quotedName(name, decoded) + ": error>"
+ } else if (sym != null && sym != NoSymbol) {
+ val prefix = if (sym.isMixinConstructor) "/*%s*/".format(quotedName(sym.owner.name, decoded)) else ""
+ var suffix = ""
+ if (settings.uniqid.value) suffix += ("#" + sym.id)
+ if (settings.Yshowsymkinds.value) suffix += ("#" + sym.abbreviatedKindString)
+ prefix + quotedName(tree.symbol.decodedName) + suffix
+ } else {
+ quotedName(name, decoded)
+ }
+ }
+
+ def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, true)
+ def symName(tree: Tree, name: Name) = symNameInternal(tree, name, false)
+
+ /** Turns a path into a String, introducing backquotes
+ * as necessary.
+ */
+ def backquotedPath(t: Tree): String = {
+ t match {
+ case Select(qual, name) if name.isTermName => "%s.%s".format(backquotedPath(qual), symName(t, name))
+ case Select(qual, name) if name.isTypeName => "%s#%s".format(backquotedPath(qual), symName(t, name))
+ case Ident(name) => symName(t, name)
+ case _ => t.toString
+ }
+ }
+
+ class TreePrinter(out: PrintWriter) extends super.TreePrinter {
+ protected var indentMargin = 0
+ protected val indentStep = 2
+ protected var indentString = " " // 40
+
+ typesPrinted = settings.printtypes.value
+ uniqueIds = settings.uniqid.value
+ protected def doPrintPositions = settings.Xprintpos.value
+
+ def indent() = indentMargin += indentStep
+ def undent() = indentMargin -= indentStep
+
+ def printPosition(tree: Tree) = if (doPrintPositions) print(tree.pos.show)
+
+ def println() {
+ out.println()
+ while (indentMargin > indentString.length())
+ indentString += indentString
+ if (indentMargin > 0)
+ out.write(indentString, 0, indentMargin)
+ }
+
+ def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) {
+ ls match {
+ case List() =>
+ case List(x) => printelem(x)
+ case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep)
+ }
+ }
+
+ def printColumn(ts: List[Tree], start: String, sep: String, end: String) {
+ print(start); indent; println()
+ printSeq(ts){print(_)}{print(sep); println()}; undent; println(); print(end)
+ }
+
+ def printRow(ts: List[Tree], start: String, sep: String, end: String) {
+ print(start); printSeq(ts){print(_)}{print(sep)}; print(end)
+ }
+
+ def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") }
+
+ def printTypeParams(ts: List[TypeDef]) {
+ if (!ts.isEmpty) {
+ print("["); printSeq(ts){ t =>
+ printAnnotations(t)
+ printParam(t)
+ }{print(", ")}; print("]")
+ }
+ }
+
+ def printLabelParams(ps: List[Ident]) {
+ print("(")
+ printSeq(ps){printLabelParam}{print(", ")}
+ print(")")
+ }
+
+ def printLabelParam(p: Ident) {
+ print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe)
+ }
+
+ def printValueParams(ts: List[ValDef]) {
+ print("(")
+ if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "")
+ printSeq(ts){printParam}{print(", ")}
+ print(")")
+ }
+
+ def printParam(tree: Tree) {
+ tree match {
+ case ValDef(mods, name, tp, rhs) =>
+ printPosition(tree)
+ printAnnotations(tree)
+ print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs)
+ case TypeDef(mods, name, tparams, rhs) =>
+ printPosition(tree)
+ print(symName(tree, name))
+ printTypeParams(tparams); print(rhs)
+ }
+ }
+
+ def printBlock(tree: Tree) {
+ tree match {
+ case Block(_, _) =>
+ print(tree)
+ case _ =>
+ printColumn(List(tree), "{", ";", "}")
+ }
+ }
+
+ private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match {
+ case null | NoSymbol => orElse
+ case sym => f(sym)
+ }
+ private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false)
+
+ def printOpt(prefix: String, tree: Tree) {
+ if (!tree.isEmpty) { print(prefix, tree) }
+ }
+
+ def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags(
+ if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + (
+ if (tree.symbol == NoSymbol) mods.privateWithin
+ else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name
+ else ""
+ )
+ )
+
+ def printFlags(flags: Long, privateWithin: String) {
+ var mask: Long = if (settings.debug.value) -1L else PrintableFlags
+ val s = flagsToString(flags & mask, privateWithin)
+ if (s != "") print(s + " ")
+ }
+
+ def printAnnotations(tree: Tree) {
+ if (!isCompilerUniverse && tree.symbol != null && tree.symbol != NoSymbol)
+ // [Eugene++] todo. this is not 100% correct, but is necessary for sane printing
+ // the problem is that getting annotations doesn't automatically initialize the symbol
+ // so we might easily print something as if it doesn't have annotations, whereas it does
+ tree.symbol.initialize
+
+ val annots = tree.symbol.annotations match {
+ case Nil => tree.asInstanceOf[MemberDef].mods.annotations
+ case anns => anns
+ }
+ annots foreach (annot => print("@"+annot+" "))
+ }
+
+ private var currentOwner: Symbol = NoSymbol
+ private var selectorType: Type = NoType
+
+ def printTree(tree: Tree) {
+ tree match {
+ case EmptyTree =>
+ print("<empty>")
+
+ case ClassDef(mods, name, tparams, impl) =>
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ val word =
+ if (mods.isTrait) "trait"
+ else if (ifSym(tree, _.isModuleClass)) "object"
+ else "class"
+
+ print(word, " ", symName(tree, name))
+ printTypeParams(tparams)
+ print(if (mods.isDeferred) " <: " else " extends ", impl)
+
+ case PackageDef(packaged, stats) =>
+ printAnnotations(tree)
+ print("package ", packaged); printColumn(stats, " {", ";", "}")
+
+ case ModuleDef(mods, name, impl) =>
+ printAnnotations(tree)
+ printModifiers(tree, mods);
+ print("object " + symName(tree, name), " extends ", impl)
+
+ case ValDef(mods, name, tp, rhs) =>
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print(if (mods.isMutable) "var " else "val ", symName(tree, name))
+ printOpt(": ", tp)
+ if (!mods.isDeferred)
+ print(" = ", if (rhs.isEmpty) "_" else rhs)
+
+ case DefDef(mods, name, tparams, vparamss, tp, rhs) =>
+ printAnnotations(tree)
+ printModifiers(tree, mods)
+ print("def " + symName(tree, name))
+ printTypeParams(tparams); vparamss foreach printValueParams
+ printOpt(": ", tp); printOpt(" = ", rhs)
+
+ case TypeDef(mods, name, tparams, rhs) =>
+ if (mods hasFlag (PARAM | DEFERRED)) {
+ printAnnotations(tree)
+ printModifiers(tree, mods); print("type "); printParam(tree)
+ } else {
+ printAnnotations(tree)
+ printModifiers(tree, mods); print("type " + symName(tree, name))
+ printTypeParams(tparams); printOpt(" = ", rhs)
+ }
+
+ case LabelDef(name, params, rhs) =>
+ print(symName(tree, name)); printLabelParams(params); printBlock(rhs)
+
+ case Import(expr, selectors) =>
+ // Is this selector remapping a name (i.e, {name1 => name2})
+ def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename)
+ def selectorToString(s: ImportSelector): String = {
+ val from = quotedName(s.name)
+ if (isNotRemap(s)) from
+ else from + "=>" + quotedName(s.rename)
+ }
+ print("import ", backquotedPath(expr), ".")
+ selectors match {
+ case List(s) =>
+ // If there is just one selector and it is not remapping a name, no braces are needed
+ if (isNotRemap(s)) print(selectorToString(s))
+ else print("{", selectorToString(s), "}")
+ // If there is more than one selector braces are always needed
+ case many =>
+ print(many.map(selectorToString).mkString("{", ", ", "}"))
+ }
+
+ case Template(parents, self, body) =>
+ val currentOwner1 = currentOwner
+ if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner
+// if (parents exists isReferenceToAnyVal) {
+// print("AnyVal")
+// }
+// else {
+ printRow(parents, " with ")
+ if (!body.isEmpty) {
+ if (self.name != nme.WILDCARD) {
+ print(" { ", self.name); printOpt(": ", self.tpt); print(" => ")
+ } else if (!self.tpt.isEmpty) {
+ print(" { _ : ", self.tpt, " => ")
+ } else {
+ print(" {")
+ }
+ printColumn(body, "", ";", "}")
+ }
+// }
+ currentOwner = currentOwner1
+
+ case Block(stats, expr) =>
+ printColumn(stats ::: List(expr), "{", ";", "}")
+
+ case Match(selector, cases) =>
+ val selectorType1 = selectorType
+ selectorType = selector.tpe
+ print(selector); printColumn(cases, " match {", "", "}")
+ selectorType = selectorType1
+
+ case CaseDef(pat, guard, body) =>
+ print("case ")
+ def patConstr(pat: Tree): Tree = pat match {
+ case Apply(fn, args) => patConstr(fn)
+ case _ => pat
+ }
+ if (showOuterTests &&
+ needsOuterTest(
+ patConstr(pat).tpe.finalResultType, selectorType, currentOwner))
+ print("???")
+ print(pat); printOpt(" if ", guard)
+ print(" => ", body)
+
+ case Alternative(trees) =>
+ printRow(trees, "(", "| ", ")")
+
+ case Star(elem) =>
+ print("(", elem, ")*")
+
+ case Bind(name, t) =>
+ print("(", symName(tree, name), " @ ", t, ")")
+
+ case UnApply(fun, args) =>
+ print(fun, " <unapply> "); printRow(args, "(", ", ", ")")
+
+ case ArrayValue(elemtpt, trees) =>
+ print("Array[", elemtpt); printRow(trees, "]{", ", ", "}")
+
+ case Function(vparams, body) =>
+ print("("); printValueParams(vparams); print(" => ", body, ")")
+ if (uniqueIds && tree.symbol != null) print("#"+tree.symbol.id)
+
+ case Assign(lhs, rhs) =>
+ print(lhs, " = ", rhs)
+
+ case AssignOrNamedArg(lhs, rhs) =>
+ print(lhs, " = ", rhs)
+
+ case If(cond, thenp, elsep) =>
+ print("if (", cond, ")"); indent; println()
+ print(thenp); undent
+ if (!elsep.isEmpty) {
+ println(); print("else"); indent; println(); print(elsep); undent
+ }
+
+ case Return(expr) =>
+ print("return ", expr)
+
+ case Try(block, catches, finalizer) =>
+ print("try "); printBlock(block)
+ if (!catches.isEmpty) printColumn(catches, " catch {", "", "}")
+ printOpt(" finally ", finalizer)
+
+ case Throw(expr) =>
+ print("throw ", expr)
+
+ case New(tpe) =>
+ print("new ", tpe)
+
+ case Typed(expr, tp) =>
+ print("(", expr, ": ", tp, ")")
+
+ case TypeApply(fun, targs) =>
+ print(fun); printRow(targs, "[", ", ", "]")
+
+ case Apply(fun, vargs) =>
+ print(fun); printRow(vargs, "(", ", ", ")")
+
+ case ApplyDynamic(qual, vargs) =>
+ print("<apply-dynamic>(", qual, "#", tree.symbol.nameString)
+ printRow(vargs, ", (", ", ", "))")
+
+ case Super(This(qual), mix) =>
+ if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".")
+ print("super")
+ if (!mix.isEmpty)
+ print("[" + mix + "]")
+
+ case Super(qual, mix) =>
+ print(qual, ".super")
+ if (!mix.isEmpty)
+ print("[" + mix + "]")
+
+ case This(qual) =>
+ if (!qual.isEmpty) print(symName(tree, qual) + ".")
+ print("this")
+
+ case Select(qual @ New(tpe), name) if (!settings.debug.value) =>
+ print(qual)
+
+ case Select(qualifier, name) =>
+ print(backquotedPath(qualifier), ".", symName(tree, name))
+
+ case id @ Ident(name) =>
+ val str = symName(tree, name)
+ print( if (id.isBackquoted) "`" + str + "`" else str )
+
+ case Literal(x) =>
+ print(x.escapedStringValue)
+
+ case tt: TypeTree =>
+ if ((tree.tpe eq null) || (doPrintPositions && tt.original != null)) {
+ if (tt.original != null) print("<type: ", tt.original, ">")
+ else print("<type ?>")
+ } else if ((tree.tpe.typeSymbol ne null) && tree.tpe.typeSymbol.isAnonymousClass) {
+ print(tree.tpe.typeSymbol.toString)
+ } else {
+ print(tree.tpe.toString)
+ }
+
+ case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
+ def printAnnot() {
+ print("@", tpt)
+ if (!args.isEmpty)
+ printRow(args, "(", ",", ")")
+ }
+ print(tree, if (tree.isType) " " else ": ")
+ printAnnot()
+
+ case SingletonTypeTree(ref) =>
+ print(ref, ".type")
+
+ case SelectFromTypeTree(qualifier, selector) =>
+ print(qualifier, "#", symName(tree, selector))
+
+ case CompoundTypeTree(templ) =>
+ print(templ)
+
+ case AppliedTypeTree(tp, args) =>
+ print(tp); printRow(args, "[", ", ", "]")
+
+ case TypeBoundsTree(lo, hi) =>
+ printOpt(" >: ", lo); printOpt(" <: ", hi)
+
+ case ExistentialTypeTree(tpt, whereClauses) =>
+ print(tpt);
+ printColumn(whereClauses, " forSome { ", ";", "}")
+
+// SelectFromArray is no longer visible in reflect.internal.
+// eliminated until we figure out what we will do with both TreePrinters and
+// SelectFromArray.
+// case SelectFromArray(qualifier, name, _) =>
+// print(qualifier); print(".<arr>"); print(symName(tree, name))
+
+ case tree =>
+ xprintTree(this, tree)
+ }
+ if (typesPrinted && tree.isTerm && !tree.isEmpty) {
+ print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}")
+ }
+ }
+
+ def print(args: Any*): Unit = args foreach {
+ case tree: Tree =>
+ printPosition(tree)
+ printTree(tree)
+ case name: Name =>
+ print(quotedName(name))
+ case arg =>
+ out.print(if (arg == null) "null" else arg.toString)
+ }
+ }
+
+ /** Hook for extensions */
+ def xprintTree(treePrinter: TreePrinter, tree: Tree) =
+ treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")"))
+
+ def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
+ def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
+ def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter))
+
+ /** A writer that writes to the current Console and
+ * is sensitive to replacement of the Console's
+ * output stream.
+ */
+ object ConsoleWriter extends Writer {
+ override def write(str: String) { Console.print(str) }
+
+ def write(cbuf: Array[Char], off: Int, len: Int) {
+ write(new String(cbuf, off, len))
+ }
+
+ def close = { /* do nothing */ }
+ def flush = { /* do nothing */ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
new file mode 100644
index 0000000000..11d0790100
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -0,0 +1,1592 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import Flags._
+import base.Attachments
+import collection.mutable.{ListBuffer, LinkedHashSet}
+
+trait Trees extends api.Trees { self: SymbolTable =>
+
+ private[scala] var nodeCount = 0
+
+ abstract class Tree extends TreeContextApiImpl with Product {
+ val id = nodeCount // TODO: add to attachment?
+ nodeCount += 1
+
+ @inline final def pos: Position = rawatt.pos
+ def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos)
+ def setPos(newpos: Position): this.type = { pos = newpos; this }
+
+ private var rawatt: Attachments { type Pos = Position } = NoPosition
+ def attachments = rawatt
+ def addAttachment(attachment: Any): this.type = { rawatt = rawatt.add(attachment); this }
+ def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
+
+ private[this] var rawtpe: Type = _
+ @inline final def tpe = rawtpe
+ def tpe_=(t: Type) = rawtpe = t
+ def setType(tp: Type): this.type = { rawtpe = tp; this }
+ def defineType(tp: Type): this.type = setType(tp)
+
+ def symbol: Symbol = null
+ def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) }
+ def setSymbol(sym: Symbol): this.type = { symbol = sym; this }
+ def hasSymbol = false
+
+ def isDef = false
+
+ def isEmpty = false
+
+ /** The canonical way to test if a Tree represents a term.
+ */
+ def isTerm: Boolean = this match {
+ case _: TermTree => true
+ case Bind(name, _) => name.isTermName
+ case Select(_, name) => name.isTermName
+ case Ident(name) => name.isTermName
+ case Annotated(_, arg) => arg.isTerm
+ case _ => false
+ }
+
+ /** The canonical way to test if a Tree represents a type.
+ */
+ def isType: Boolean = this match {
+ case _: TypTree => true
+ case Bind(name, _) => name.isTypeName
+ case Select(_, name) => name.isTypeName
+ case Ident(name) => name.isTypeName
+ case Annotated(_, arg) => arg.isType
+ case _ => false
+ }
+
+ private[scala] def copyAttrs(tree: Tree): this.type = {
+ rawatt = tree.rawatt
+ tpe = tree.tpe
+ if (hasSymbol) symbol = tree.symbol
+ this
+ }
+
+ override def hashCode(): Int = System.identityHashCode(this)
+ override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
+
+ override def duplicate: this.type =
+ (duplicator transform this).asInstanceOf[this.type]
+ }
+
+ abstract class TreeContextApiImpl extends TreeContextApi { this: Tree =>
+
+ override def orElse(alt: => Tree) = if (!isEmpty) this else alt
+
+ override def foreach(f: Tree => Unit) { new ForeachTreeTraverser(f).traverse(this) }
+
+ override def withFilter(f: Tree => Boolean): List[Tree] = {
+ val ft = new FilterTreeTraverser(f)
+ ft.traverse(this)
+ ft.hits.toList
+ }
+
+ override def filter(f: Tree => Boolean): List[Tree] = withFilter(f)
+
+ override def collect[T](pf: PartialFunction[Tree, T]): List[T] = {
+ val ctt = new CollectTreeTraverser[T](pf)
+ ctt.traverse(this)
+ ctt.results.toList
+ }
+
+ override def find(p: Tree => Boolean): Option[Tree] = {
+ val ft = new FindTreeTraverser(p)
+ ft.traverse(this)
+ ft.result
+ }
+
+ override def exists(p: Tree => Boolean): Boolean = !find(p).isEmpty
+
+ override def forAll(p: Tree => Boolean): Boolean = find(!p(_)).isEmpty
+
+ override def equalsStructure(that : Tree) = correspondsStructure(that)(_ eq _)
+
+ def correspondsStructure(that: Tree)(f: (Tree,Tree) => Boolean): Boolean =
+ f(this, that) || ((productArity == that.productArity) && {
+ def equals0(this0: Any, that0: Any): Boolean = (this0, that0) match {
+ case (x: Tree, y: Tree) => f(x, y) || (x correspondsStructure y)(f)
+ case (xs: List[_], ys: List[_]) => (xs corresponds ys)(equals0)
+ case _ => this0 == that0
+ }
+ def compareOriginals() = (this, that) match {
+ case (x: TypeTree, y: TypeTree) if x.original != null && y.original != null =>
+ (x.original correspondsStructure y.original)(f)
+ case _ =>
+ true
+ }
+
+ (productIterator zip that.productIterator forall { case (x, y) => equals0(x, y) }) && compareOriginals()
+ })
+
+ override def children: List[Tree] = {
+ def subtrees(x: Any): List[Tree] = x match {
+ case EmptyTree => Nil
+ case t: Tree => List(t)
+ case xs: List[_] => xs flatMap subtrees
+ case _ => Nil
+ }
+ productIterator.toList flatMap subtrees
+ }
+
+ override def freeTerms: List[FreeTermSymbol] = freeSyms[FreeTermSymbol](_.isFreeTerm, _.termSymbol)
+ override def freeTypes: List[FreeTypeSymbol] = freeSyms[FreeTypeSymbol](_.isFreeType, _.typeSymbol)
+
+ private def freeSyms[S <: Symbol](isFree: Symbol => Boolean, symOfType: Type => Symbol): List[S] = {
+ val s = collection.mutable.LinkedHashSet[S]()
+ def addIfFree(sym: Symbol): Unit = if (sym != null && isFree(sym)) s += sym.asInstanceOf[S]
+ for (t <- this) {
+ addIfFree(t.symbol)
+ if (t.tpe != null) {
+ for (tp <- t.tpe) {
+ addIfFree(symOfType(tp))
+ }
+ }
+ }
+ s.toList
+ }
+
+ override def substituteSymbols(from: List[Symbol], to: List[Symbol]): Tree =
+ new TreeSymSubstituter(from, to)(this)
+
+ override def substituteTypes(from: List[Symbol], to: List[Type]): Tree =
+ new TreeTypeSubstituter(from, to)(this)
+
+ override def substituteThis(clazz: Symbol, to: Tree): Tree =
+ new ThisSubstituter(clazz, to) transform this
+
+ def hasSymbolWhich(f: Symbol => Boolean) =
+ hasSymbol && symbol != null && f(symbol)
+
+ def isErroneous = (tpe ne null) && tpe.isErroneous
+ def isTyped = (tpe ne null) && !tpe.isErroneous
+
+ /** Sets the tree's type to the result of the given function.
+ * If the type is null, it remains null - the function is not called.
+ */
+ def modifyType(f: Type => Type): Tree =
+ if (tpe eq null) this
+ else this setType f(tpe)
+
+ /** If `pf` is defined for a given subtree, call super.traverse(pf(tree)),
+ * otherwise super.traverse(tree).
+ */
+ def foreachPartial(pf: PartialFunction[Tree, Tree]) {
+ new ForeachPartialTreeTraverser(pf).traverse(this)
+ }
+
+ def changeOwner(pairs: (Symbol, Symbol)*): Tree = {
+ pairs.foldLeft(this) { case (t, (oldOwner, newOwner)) =>
+ new ChangeOwnerTraverser(oldOwner, newOwner) apply t
+ }
+ }
+
+ def shallowDuplicate: Tree = new ShallowDuplicator(this) transform this
+ def shortClass: String = (getClass.getName split "[.$]").last
+
+ def isErrorTyped = (tpe ne null) && tpe.isError
+
+ /** When you want to know a little more than the class, but a lot
+ * less than the whole tree.
+ */
+ def summaryString: String = this match {
+ case Literal(const) => "Literal(" + const + ")"
+ case Ident(name) => "Ident(%s)".format(name.decode)
+ case Select(qual, name) => "Select(%s, %s)".format(qual.summaryString, name.decode)
+ case t: NameTree => t.name.longString
+ case t =>
+ t.shortClass + (
+ if (t.symbol != null && t.symbol != NoSymbol) "(" + t.symbol + ")"
+ else ""
+ )
+ }
+ }
+
+ trait TermTree extends Tree with TermTreeApi
+
+ trait TypTree extends Tree with TypTreeApi
+
+ trait SymTree extends Tree with SymTreeContextApi {
+ override def hasSymbol = true
+ override var symbol: Symbol = NoSymbol
+ }
+
+ trait NameTree extends Tree with NameTreeApi {
+ def name: Name
+ }
+
+ trait RefTree extends SymTree with NameTree with RefTreeApi {
+ def qualifier: Tree // empty for Idents
+ def name: Name
+ }
+
+ abstract class DefTree extends SymTree with NameTree with DefTreeApi {
+ def name: Name
+ override def isDef = true
+ }
+
+ case object EmptyTree extends TermTree {
+ super.tpe_=(NoType)
+ override def tpe_=(t: Type) =
+ if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>")
+ override def isEmpty = true
+ }
+
+ abstract class MemberDef extends DefTree with MemberDefApi {
+ def mods: Modifiers
+ def keyword: String = this match {
+ case TypeDef(_, _, _, _) => "type"
+ case ClassDef(mods, _, _, _) => if (mods hasFlag TRAIT) "trait" else "class"
+ case DefDef(_, _, _, _, _, _) => "def"
+ case ModuleDef(_, _, _) => "object"
+ case PackageDef(_, _) => "package"
+ case ValDef(mods, _, _, _) => if (mods hasFlag MUTABLE) "var" else "val"
+ case _ => ""
+ }
+ }
+
+ case class PackageDef(pid: RefTree, stats: List[Tree])
+ extends MemberDef with PackageDefApi {
+ def name = pid.name
+ def mods = NoMods
+ }
+ object PackageDef extends PackageDefExtractor
+
+ abstract class ImplDef extends MemberDef with ImplDefApi {
+ def impl: Template
+ }
+
+ case class ClassDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], impl: Template)
+ extends ImplDef with ClassDefApi
+ object ClassDef extends ClassDefExtractor
+
+ case class ModuleDef(mods: Modifiers, name: TermName, impl: Template)
+ extends ImplDef with ModuleDefApi
+ object ModuleDef extends ModuleDefExtractor
+
+ abstract class ValOrDefDef extends MemberDef with ValOrDefDefApi {
+ def name: Name
+ def tpt: Tree
+ def rhs: Tree
+ }
+
+ case class ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) extends ValOrDefDef with ValDefApi
+ object ValDef extends ValDefExtractor
+
+ case class DefDef(mods: Modifiers, name: Name, tparams: List[TypeDef],
+ vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) extends ValOrDefDef with DefDefApi
+ object DefDef extends DefDefExtractor
+
+ case class TypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree)
+ extends MemberDef with TypeDefApi
+ object TypeDef extends TypeDefExtractor
+
+ case class LabelDef(name: TermName, params: List[Ident], rhs: Tree)
+ extends DefTree with TermTree with LabelDefApi
+ object LabelDef extends LabelDefExtractor
+
+ case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) extends ImportSelectorApi
+ object ImportSelector extends ImportSelectorExtractor
+
+ case class Import(expr: Tree, selectors: List[ImportSelector])
+ extends SymTree with ImportApi
+ object Import extends ImportExtractor
+
+ case class Template(parents: List[Tree], self: ValDef, body: List[Tree])
+ extends SymTree with TemplateApi
+ object Template extends TemplateExtractor
+
+ case class Block(stats: List[Tree], expr: Tree)
+ extends TermTree with BlockApi
+ object Block extends BlockExtractor
+
+ case class CaseDef(pat: Tree, guard: Tree, body: Tree)
+ extends Tree with CaseDefApi
+ object CaseDef extends CaseDefExtractor
+
+ case class Alternative(trees: List[Tree])
+ extends TermTree with AlternativeApi
+ object Alternative extends AlternativeExtractor
+
+ case class Star(elem: Tree)
+ extends TermTree with StarApi
+ object Star extends StarExtractor
+
+ case class Bind(name: Name, body: Tree)
+ extends DefTree with BindApi
+ object Bind extends BindExtractor
+
+ case class UnApply(fun: Tree, args: List[Tree])
+ extends TermTree with UnApplyApi
+ object UnApply extends UnApplyExtractor
+
+ case class ArrayValue(elemtpt: Tree, elems: List[Tree])
+ extends TermTree with ArrayValueApi
+ object ArrayValue extends ArrayValueExtractor
+
+ case class Function(vparams: List[ValDef], body: Tree)
+ extends TermTree with SymTree with FunctionApi
+ object Function extends FunctionExtractor
+
+ case class Assign(lhs: Tree, rhs: Tree)
+ extends TermTree with AssignApi
+ object Assign extends AssignExtractor
+
+ case class AssignOrNamedArg(lhs: Tree, rhs: Tree)
+ extends TermTree with AssignOrNamedArgApi
+ object AssignOrNamedArg extends AssignOrNamedArgExtractor
+
+ case class If(cond: Tree, thenp: Tree, elsep: Tree)
+ extends TermTree with IfApi
+ object If extends IfExtractor
+
+ case class Match(selector: Tree, cases: List[CaseDef])
+ extends TermTree with MatchApi
+ object Match extends MatchExtractor
+
+ case class Return(expr: Tree)
+ extends TermTree with SymTree with ReturnApi
+ object Return extends ReturnExtractor
+
+ case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree)
+ extends TermTree with TryApi
+ object Try extends TryExtractor
+
+ case class Throw(expr: Tree)
+ extends TermTree with ThrowApi
+ object Throw extends ThrowExtractor
+
+ case class New(tpt: Tree) extends TermTree with NewApi
+ object New extends NewExtractor
+
+ case class Typed(expr: Tree, tpt: Tree)
+ extends TermTree with TypedApi
+ object Typed extends TypedExtractor
+
+ abstract class GenericApply extends TermTree with GenericApplyApi {
+ val fun: Tree
+ val args: List[Tree]
+ }
+
+ case class TypeApply(fun: Tree, args: List[Tree])
+ extends GenericApply with TypeApplyApi {
+ override def symbol: Symbol = fun.symbol
+ override def symbol_=(sym: Symbol) { fun.symbol = sym }
+ }
+ object TypeApply extends TypeApplyExtractor
+
+ case class Apply(fun: Tree, args: List[Tree])
+ extends GenericApply with ApplyApi {
+ override def symbol: Symbol = fun.symbol
+ override def symbol_=(sym: Symbol) { fun.symbol = sym }
+ }
+ object Apply extends ApplyExtractor
+
+ // TODO remove this class, add a tree attachment to Apply to track whether implicits were involved
+ // copying trees will all too easily forget to distinguish subclasses
+ class ApplyToImplicitArgs(fun: Tree, args: List[Tree]) extends Apply(fun, args)
+
+ // TODO remove this class, add a tree attachment to Apply to track whether implicits were involved
+ // copying trees will all too easily forget to distinguish subclasses
+ class ApplyImplicitView(fun: Tree, args: List[Tree]) extends Apply(fun, args)
+
+ def ApplyConstructor(tpt: Tree, args: List[Tree]) = Apply(Select(New(tpt), nme.CONSTRUCTOR), args)
+
+ case class ApplyDynamic(qual: Tree, args: List[Tree])
+ extends TermTree with SymTree with ApplyDynamicApi
+ object ApplyDynamic extends ApplyDynamicExtractor
+
+ case class Super(qual: Tree, mix: TypeName) extends TermTree with SuperApi {
+ override def symbol: Symbol = qual.symbol
+ override def symbol_=(sym: Symbol) { qual.symbol = sym }
+ }
+ object Super extends SuperExtractor
+
+ case class This(qual: TypeName)
+ extends TermTree with SymTree with ThisApi
+ object This extends ThisExtractor
+
+ case class Select(qualifier: Tree, name: Name)
+ extends RefTree with SelectApi
+ object Select extends SelectExtractor
+
+ case class Ident(name: Name) extends RefTree with IdentContextApi {
+ def qualifier: Tree = EmptyTree
+ def isBackquoted = this.attachments.get[BackquotedIdentifierAttachment.type].isDefined
+ }
+ object Ident extends IdentExtractor
+
+ case class ReferenceToBoxed(ident: Ident) extends TermTree with ReferenceToBoxedApi {
+ override def symbol: Symbol = ident.symbol
+ override def symbol_=(sym: Symbol) { ident.symbol = sym }
+ }
+ object ReferenceToBoxed extends ReferenceToBoxedExtractor
+
+ case class Literal(value: Constant)
+ extends TermTree with LiteralApi {
+ assert(value ne null)
+ }
+ object Literal extends LiteralExtractor
+
+// @deprecated("will be removed and then be re-introduced with changed semantics, use Literal(Constant(x)) instead")
+// def Literal(x: Any) = new Literal(Constant(x))
+
+ case class Annotated(annot: Tree, arg: Tree) extends Tree with AnnotatedApi
+ object Annotated extends AnnotatedExtractor
+
+ case class SingletonTypeTree(ref: Tree)
+ extends TypTree with SingletonTypeTreeApi
+ object SingletonTypeTree extends SingletonTypeTreeExtractor
+
+ case class SelectFromTypeTree(qualifier: Tree, name: TypeName)
+ extends TypTree with RefTree with SelectFromTypeTreeApi
+ object SelectFromTypeTree extends SelectFromTypeTreeExtractor
+
+ case class CompoundTypeTree(templ: Template)
+ extends TypTree with CompoundTypeTreeApi
+ object CompoundTypeTree extends CompoundTypeTreeExtractor
+
+ case class AppliedTypeTree(tpt: Tree, args: List[Tree])
+ extends TypTree with AppliedTypeTreeApi {
+ override def symbol: Symbol = tpt.symbol
+ override def symbol_=(sym: Symbol) { tpt.symbol = sym }
+ }
+ object AppliedTypeTree extends AppliedTypeTreeExtractor
+
+ case class TypeBoundsTree(lo: Tree, hi: Tree)
+ extends TypTree with TypeBoundsTreeApi
+ object TypeBoundsTree extends TypeBoundsTreeExtractor
+
+ case class ExistentialTypeTree(tpt: Tree, whereClauses: List[Tree])
+ extends TypTree with ExistentialTypeTreeApi
+ object ExistentialTypeTree extends ExistentialTypeTreeExtractor
+
+ case class TypeTree() extends TypTree with TypeTreeContextApi {
+ private var orig: Tree = null
+ private[scala] var wasEmpty: Boolean = false
+
+ override def symbol = if (tpe == null) null else tpe.typeSymbol
+ override def isEmpty = (tpe eq null) || tpe == NoType
+
+ def original: Tree = orig
+ def setOriginal(tree: Tree): this.type = {
+ def followOriginal(t: Tree): Tree = t match {
+ case tt: TypeTree => followOriginal(tt.original)
+ case t => t
+ }
+
+ orig = followOriginal(tree); setPos(tree.pos);
+ this
+ }
+
+ override def defineType(tp: Type): this.type = {
+ wasEmpty = isEmpty
+ setType(tp)
+ }
+ }
+ object TypeTree extends TypeTreeExtractor
+
+ def TypeTree(tp: Type): TypeTree = TypeTree() setType tp
+
+ class StrictTreeCopier extends TreeCopierOps {
+ def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) =
+ new ClassDef(mods, name.toTypeName, tparams, impl).copyAttrs(tree)
+ def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]) =
+ new PackageDef(pid, stats).copyAttrs(tree)
+ def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) =
+ new ModuleDef(mods, name.toTermName, impl).copyAttrs(tree)
+ def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) =
+ new ValDef(mods, name.toTermName, tpt, rhs).copyAttrs(tree)
+ def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) =
+ new DefDef(mods, name.toTermName, tparams, vparamss, tpt, rhs).copyAttrs(tree)
+ def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) =
+ new TypeDef(mods, name.toTypeName, tparams, rhs).copyAttrs(tree)
+ def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) =
+ new LabelDef(name.toTermName, params, rhs).copyAttrs(tree)
+ def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]) =
+ new Import(expr, selectors).copyAttrs(tree)
+ def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) =
+ new Template(parents, self, body).copyAttrs(tree)
+ def Block(tree: Tree, stats: List[Tree], expr: Tree) =
+ new Block(stats, expr).copyAttrs(tree)
+ def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) =
+ new CaseDef(pat, guard, body).copyAttrs(tree)
+ def Alternative(tree: Tree, trees: List[Tree]) =
+ new Alternative(trees).copyAttrs(tree)
+ def Star(tree: Tree, elem: Tree) =
+ new Star(elem).copyAttrs(tree)
+ def Bind(tree: Tree, name: Name, body: Tree) =
+ new Bind(name, body).copyAttrs(tree)
+ def UnApply(tree: Tree, fun: Tree, args: List[Tree]) =
+ new UnApply(fun, args).copyAttrs(tree)
+ def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) =
+ new ArrayValue(elemtpt, trees).copyAttrs(tree)
+ def Function(tree: Tree, vparams: List[ValDef], body: Tree) =
+ new Function(vparams, body).copyAttrs(tree)
+ def Assign(tree: Tree, lhs: Tree, rhs: Tree) =
+ new Assign(lhs, rhs).copyAttrs(tree)
+ def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) =
+ new AssignOrNamedArg(lhs, rhs).copyAttrs(tree)
+ def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) =
+ new If(cond, thenp, elsep).copyAttrs(tree)
+ def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) =
+ new Match(selector, cases).copyAttrs(tree)
+ def Return(tree: Tree, expr: Tree) =
+ new Return(expr).copyAttrs(tree)
+ def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) =
+ new Try(block, catches, finalizer).copyAttrs(tree)
+ def Throw(tree: Tree, expr: Tree) =
+ new Throw(expr).copyAttrs(tree)
+ def New(tree: Tree, tpt: Tree) =
+ new New(tpt).copyAttrs(tree)
+ def Typed(tree: Tree, expr: Tree, tpt: Tree) =
+ new Typed(expr, tpt).copyAttrs(tree)
+ def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) =
+ new TypeApply(fun, args).copyAttrs(tree)
+ def Apply(tree: Tree, fun: Tree, args: List[Tree]) =
+ (tree match { // TODO: use a tree attachment to track whether this is an apply to implicit args or a view
+ case _: ApplyToImplicitArgs => new ApplyToImplicitArgs(fun, args)
+ case _: ApplyImplicitView => new ApplyImplicitView(fun, args)
+ // TODO: ApplyConstructor ???
+ case _ => new Apply(fun, args)
+ }).copyAttrs(tree)
+ def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) =
+ new ApplyDynamic(qual, args).copyAttrs(tree)
+ def Super(tree: Tree, qual: Tree, mix: TypeName) =
+ new Super(qual, mix).copyAttrs(tree)
+ def This(tree: Tree, qual: Name) =
+ new This(qual.toTypeName).copyAttrs(tree)
+ def Select(tree: Tree, qualifier: Tree, selector: Name) =
+ new Select(qualifier, selector).copyAttrs(tree)
+ def Ident(tree: Tree, name: Name) =
+ new Ident(name) copyAttrs tree
+ def ReferenceToBoxed(tree: Tree, idt: Ident) =
+ new ReferenceToBoxed(idt).copyAttrs(tree)
+ def Literal(tree: Tree, value: Constant) =
+ new Literal(value).copyAttrs(tree)
+ def TypeTree(tree: Tree) =
+ new TypeTree().copyAttrs(tree)
+ def Annotated(tree: Tree, annot: Tree, arg: Tree) =
+ new Annotated(annot, arg).copyAttrs(tree)
+ def SingletonTypeTree(tree: Tree, ref: Tree) =
+ new SingletonTypeTree(ref).copyAttrs(tree)
+ def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) =
+ new SelectFromTypeTree(qualifier, selector.toTypeName).copyAttrs(tree)
+ def CompoundTypeTree(tree: Tree, templ: Template) =
+ new CompoundTypeTree(templ).copyAttrs(tree)
+ def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) =
+ new AppliedTypeTree(tpt, args).copyAttrs(tree)
+ def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree) =
+ new TypeBoundsTree(lo, hi).copyAttrs(tree)
+ def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) =
+ new ExistentialTypeTree(tpt, whereClauses).copyAttrs(tree)
+ }
+
+ class LazyTreeCopier extends TreeCopierOps {
+ val treeCopy: TreeCopier = newStrictTreeCopier
+ def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) = tree match {
+ case t @ ClassDef(mods0, name0, tparams0, impl0)
+ if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (impl0 == impl) => t
+ case _ => treeCopy.ClassDef(tree, mods, name, tparams, impl)
+ }
+ def PackageDef(tree: Tree, pid: RefTree, stats: List[Tree]) = tree match {
+ case t @ PackageDef(pid0, stats0)
+ if (pid0 == pid) && (stats0 == stats) => t
+ case _ => treeCopy.PackageDef(tree, pid, stats)
+ }
+ def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) = tree match {
+ case t @ ModuleDef(mods0, name0, impl0)
+ if (mods0 == mods) && (name0 == name) && (impl0 == impl) => t
+ case _ => treeCopy.ModuleDef(tree, mods, name, impl)
+ }
+ def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) = tree match {
+ case t @ ValDef(mods0, name0, tpt0, rhs0)
+ if (mods0 == mods) && (name0 == name) && (tpt0 == tpt) && (rhs0 == rhs) => t
+ case _ => treeCopy.ValDef(tree, mods, name, tpt, rhs)
+ }
+ def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) = tree match {
+ case t @ DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0)
+ if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) &&
+ (vparamss0 == vparamss) && (tpt0 == tpt) && (rhs == rhs0) => t
+ case _ => treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs)
+ }
+ def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) = tree match {
+ case t @ TypeDef(mods0, name0, tparams0, rhs0)
+ if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (rhs0 == rhs) => t
+ case _ => treeCopy.TypeDef(tree, mods, name, tparams, rhs)
+ }
+ def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = tree match {
+ case t @ LabelDef(name0, params0, rhs0)
+ if (name0 == name) && (params0 == params) && (rhs0 == rhs) => t
+ case _ => treeCopy.LabelDef(tree, name, params, rhs)
+ }
+ def Import(tree: Tree, expr: Tree, selectors: List[ImportSelector]) = tree match {
+ case t @ Import(expr0, selectors0)
+ if (expr0 == expr) && (selectors0 == selectors) => t
+ case _ => treeCopy.Import(tree, expr, selectors)
+ }
+ def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) = tree match {
+ case t @ Template(parents0, self0, body0)
+ if (parents0 == parents) && (self0 == self) && (body0 == body) => t
+ case _ => treeCopy.Template(tree, parents, self, body)
+ }
+ def Block(tree: Tree, stats: List[Tree], expr: Tree) = tree match {
+ case t @ Block(stats0, expr0)
+ if ((stats0 == stats) && (expr0 == expr)) => t
+ case _ => treeCopy.Block(tree, stats, expr)
+ }
+ def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = tree match {
+ case t @ CaseDef(pat0, guard0, body0)
+ if (pat0 == pat) && (guard0 == guard) && (body0 == body) => t
+ case _ => treeCopy.CaseDef(tree, pat, guard, body)
+ }
+ def Alternative(tree: Tree, trees: List[Tree]) = tree match {
+ case t @ Alternative(trees0)
+ if trees0 == trees => t
+ case _ => treeCopy.Alternative(tree, trees)
+ }
+ def Star(tree: Tree, elem: Tree) = tree match {
+ case t @ Star(elem0)
+ if elem0 == elem => t
+ case _ => treeCopy.Star(tree, elem)
+ }
+ def Bind(tree: Tree, name: Name, body: Tree) = tree match {
+ case t @ Bind(name0, body0)
+ if (name0 == name) && (body0 == body) => t
+ case _ => treeCopy.Bind(tree, name, body)
+ }
+ def UnApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match {
+ case t @ UnApply(fun0, args0)
+ if (fun0 == fun) && (args0 == args) => t
+ case _ => treeCopy.UnApply(tree, fun, args)
+ }
+ def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) = tree match {
+ case t @ ArrayValue(elemtpt0, trees0)
+ if (elemtpt0 == elemtpt) && (trees0 == trees) => t
+ case _ => treeCopy.ArrayValue(tree, elemtpt, trees)
+ }
+ def Function(tree: Tree, vparams: List[ValDef], body: Tree) = tree match {
+ case t @ Function(vparams0, body0)
+ if (vparams0 == vparams) && (body0 == body) => t
+ case _ => treeCopy.Function(tree, vparams, body)
+ }
+ def Assign(tree: Tree, lhs: Tree, rhs: Tree) = tree match {
+ case t @ Assign(lhs0, rhs0)
+ if (lhs0 == lhs) && (rhs0 == rhs) => t
+ case _ => treeCopy.Assign(tree, lhs, rhs)
+ }
+ def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = tree match {
+ case t @ AssignOrNamedArg(lhs0, rhs0)
+ if (lhs0 == lhs) && (rhs0 == rhs) => t
+ case _ => treeCopy.AssignOrNamedArg(tree, lhs, rhs)
+ }
+ def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = tree match {
+ case t @ If(cond0, thenp0, elsep0)
+ if (cond0 == cond) && (thenp0 == thenp) && (elsep0 == elsep) => t
+ case _ => treeCopy.If(tree, cond, thenp, elsep)
+ }
+ def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = tree match {
+ case t @ Match(selector0, cases0)
+ if (selector0 == selector) && (cases0 == cases) => t
+ case _ => treeCopy.Match(tree, selector, cases)
+ }
+ def Return(tree: Tree, expr: Tree) = tree match {
+ case t @ Return(expr0)
+ if expr0 == expr => t
+ case _ => treeCopy.Return(tree, expr)
+ }
+ def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = tree match {
+ case t @ Try(block0, catches0, finalizer0)
+ if (block0 == block) && (catches0 == catches) && (finalizer0 == finalizer) => t
+ case _ => treeCopy.Try(tree, block, catches, finalizer)
+ }
+ def Throw(tree: Tree, expr: Tree) = tree match {
+ case t @ Throw(expr0)
+ if expr0 == expr => t
+ case _ => treeCopy.Throw(tree, expr)
+ }
+ def New(tree: Tree, tpt: Tree) = tree match {
+ case t @ New(tpt0)
+ if tpt0 == tpt => t
+ case _ => treeCopy.New(tree, tpt)
+ }
+ def Typed(tree: Tree, expr: Tree, tpt: Tree) = tree match {
+ case t @ Typed(expr0, tpt0)
+ if (expr0 == expr) && (tpt0 == tpt) => t
+ case _ => treeCopy.Typed(tree, expr, tpt)
+ }
+ def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match {
+ case t @ TypeApply(fun0, args0)
+ if (fun0 == fun) && (args0 == args) => t
+ case _ => treeCopy.TypeApply(tree, fun, args)
+ }
+ def Apply(tree: Tree, fun: Tree, args: List[Tree]) = tree match {
+ case t @ Apply(fun0, args0)
+ if (fun0 == fun) && (args0 == args) => t
+ case _ => treeCopy.Apply(tree, fun, args)
+ }
+ def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) = tree match {
+ case t @ ApplyDynamic(qual0, args0)
+ if (qual0 == qual) && (args0 == args) => t
+ case _ => treeCopy.ApplyDynamic(tree, qual, args)
+ }
+ def Super(tree: Tree, qual: Tree, mix: TypeName) = tree match {
+ case t @ Super(qual0, mix0)
+ if (qual0 == qual) && (mix0 == mix) => t
+ case _ => treeCopy.Super(tree, qual, mix)
+ }
+ def This(tree: Tree, qual: Name) = tree match {
+ case t @ This(qual0)
+ if qual0 == qual => t
+ case _ => treeCopy.This(tree, qual)
+ }
+ def Select(tree: Tree, qualifier: Tree, selector: Name) = tree match {
+ case t @ Select(qualifier0, selector0)
+ if (qualifier0 == qualifier) && (selector0 == selector) => t
+ case _ => treeCopy.Select(tree, qualifier, selector)
+ }
+ def Ident(tree: Tree, name: Name) = tree match {
+ case t @ Ident(name0)
+ if name0 == name => t
+ case _ => treeCopy.Ident(tree, name)
+ }
+ def ReferenceToBoxed(tree: Tree, idt: Ident) = tree match {
+ case t @ ReferenceToBoxed(idt0)
+ if (idt0 == idt) => t
+ case _ => this.treeCopy.ReferenceToBoxed(tree, idt)
+ }
+ def Literal(tree: Tree, value: Constant) = tree match {
+ case t @ Literal(value0)
+ if value0 == value => t
+ case _ => treeCopy.Literal(tree, value)
+ }
+ def TypeTree(tree: Tree) = tree match {
+ case t @ TypeTree() => t
+ case _ => treeCopy.TypeTree(tree)
+ }
+ def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match {
+ case t @ Annotated(annot0, arg0)
+ if (annot0==annot) => t
+ case _ => treeCopy.Annotated(tree, annot, arg)
+ }
+ def SingletonTypeTree(tree: Tree, ref: Tree) = tree match {
+ case t @ SingletonTypeTree(ref0)
+ if ref0 == ref => t
+ case _ => treeCopy.SingletonTypeTree(tree, ref)
+ }
+ def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = tree match {
+ case t @ SelectFromTypeTree(qualifier0, selector0)
+ if (qualifier0 == qualifier) && (selector0 == selector) => t
+ case _ => treeCopy.SelectFromTypeTree(tree, qualifier, selector)
+ }
+ def CompoundTypeTree(tree: Tree, templ: Template) = tree match {
+ case t @ CompoundTypeTree(templ0)
+ if templ0 == templ => t
+ case _ => treeCopy.CompoundTypeTree(tree, templ)
+ }
+ def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) = tree match {
+ case t @ AppliedTypeTree(tpt0, args0)
+ if (tpt0 == tpt) && (args0 == args) => t
+ case _ => treeCopy.AppliedTypeTree(tree, tpt, args)
+ }
+ def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree) = tree match {
+ case t @ TypeBoundsTree(lo0, hi0)
+ if (lo0 == lo) && (hi0 == hi) => t
+ case _ => treeCopy.TypeBoundsTree(tree, lo, hi)
+ }
+ def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = tree match {
+ case t @ ExistentialTypeTree(tpt0, whereClauses0)
+ if (tpt0 == tpt) && (whereClauses0 == whereClauses) => t
+ case _ => treeCopy.ExistentialTypeTree(tree, tpt, whereClauses)
+ }
+ }
+
+ // Belongs in TreeInfo but then I can't reach it from TreePrinters.
+ def isReferenceToScalaMember(t: Tree, Id: Name) = t match {
+ case Ident(Id) => true
+ case Select(Ident(nme.scala_), Id) => true
+ case Select(Select(Ident(nme.ROOTPKG), nme.scala_), Id) => true
+ case _ => false
+ }
+ /** Is the tree Predef, scala.Predef, or _root_.scala.Predef?
+ */
+ def isReferenceToPredef(t: Tree) = isReferenceToScalaMember(t, nme.Predef)
+ def isReferenceToAnyVal(t: Tree) = isReferenceToScalaMember(t, tpnme.AnyVal)
+
+ // --- modifiers implementation ---------------------------------------
+
+ /** @param privateWithin the qualifier for a private (a type name)
+ * or tpnme.EMPTY, if none is given.
+ * @param annotations the annotations for the definition.
+ * '''Note:''' the typechecker drops these annotations,
+ * use the AnnotationInfo's (Symbol.annotations) in later phases.
+ */
+ case class Modifiers(flags: Long,
+ privateWithin: Name,
+ annotations: List[Tree]) extends ModifiersApi with HasFlags {
+
+ var positions: Map[Long, Position] = Map()
+
+ def setPositions(poss: Map[Long, Position]): this.type = {
+ positions = poss; this
+ }
+
+ /* Abstract types from HasFlags. */
+ type AccessBoundaryType = Name
+ type AnnotationType = Tree
+
+ def hasAnnotationNamed(name: TypeName) = {
+ annotations exists {
+ case Apply(Select(New(Ident(`name`)), _), _) => true
+ case Apply(Select(New(Select(_, `name`)), _), _) => true
+ case _ => false
+ }
+ }
+
+ def hasAccessBoundary = privateWithin != tpnme.EMPTY
+ def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask
+ def hasFlag(flag: Long) = (flag & flags) != 0L
+
+ def & (flag: Long): Modifiers = {
+ val flags1 = flags & flag
+ if (flags1 == flags) this
+ else Modifiers(flags1, privateWithin, annotations) setPositions positions
+ }
+ def &~ (flag: Long): Modifiers = {
+ val flags1 = flags & (~flag)
+ if (flags1 == flags) this
+ else Modifiers(flags1, privateWithin, annotations) setPositions positions
+ }
+ def | (flag: Long): Modifiers = {
+ val flags1 = flags | flag
+ if (flags1 == flags) this
+ else Modifiers(flags1, privateWithin, annotations) setPositions positions
+ }
+ def withAnnotations(annots: List[Tree]) =
+ if (annots.isEmpty) this
+ else copy(annotations = annotations ::: annots) setPositions positions
+
+ def withPosition(flag: Long, position: Position) =
+ copy() setPositions positions + (flag -> position)
+
+ override def mapAnnotations(f: List[Tree] => List[Tree]): Modifiers =
+ Modifiers(flags, privateWithin, f(annotations)) setPositions positions
+
+ override def toString = "Modifiers(%s, %s, %s)".format(flagString, annotations mkString ", ", positions)
+ }
+
+ object Modifiers extends ModifiersCreator
+
+ implicit val ModifiersTag = ClassTag[Modifiers](classOf[Modifiers])
+
+ // ---- values and creators ---------------------------------------
+
+ /** @param sym the class symbol
+ * @return the implementation template
+ */
+ def ClassDef(sym: Symbol, impl: Template): ClassDef =
+ atPos(sym.pos) {
+ ClassDef(Modifiers(sym.flags),
+ sym.name.toTypeName,
+ sym.typeParams map TypeDef,
+ impl) setSymbol sym
+ }
+
+ /**
+ * @param sym the class symbol
+ * @param impl the implementation template
+ */
+ def ModuleDef(sym: Symbol, impl: Template): ModuleDef =
+ atPos(sym.pos) {
+ ModuleDef(Modifiers(sym.flags), sym.name.toTermName, impl) setSymbol sym
+ }
+
+ def ValDef(sym: Symbol, rhs: Tree): ValDef =
+ atPos(sym.pos) {
+ ValDef(Modifiers(sym.flags), sym.name.toTermName,
+ TypeTree(sym.tpe) setPos sym.pos.focus,
+ rhs) setSymbol sym
+ }
+
+ def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree)
+
+ object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) {
+ override def isEmpty = true
+ super.setPos(NoPosition)
+ override def setPos(pos: Position) = { assert(false); this }
+ }
+
+ def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef =
+ atPos(sym.pos) {
+ assert(sym != NoSymbol)
+ DefDef(mods,
+ sym.name.toTermName,
+ sym.typeParams map TypeDef,
+ vparamss,
+ TypeTree(sym.tpe.finalResultType) setPos sym.pos.focus,
+ rhs) setSymbol sym
+ }
+
+ def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef =
+ DefDef(sym, Modifiers(sym.flags), vparamss, rhs)
+
+ def DefDef(sym: Symbol, mods: Modifiers, rhs: Tree): DefDef =
+ DefDef(sym, mods, mapParamss(sym)(ValDef), rhs)
+
+ def DefDef(sym: Symbol, rhs: Tree): DefDef =
+ DefDef(sym, Modifiers(sym.flags), rhs)
+
+ def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef =
+ DefDef(sym, rhs(sym.info.paramss))
+
+ /** A TypeDef node which defines given `sym` with given tight hand side `rhs`. */
+ def TypeDef(sym: Symbol, rhs: Tree): TypeDef =
+ atPos(sym.pos) {
+ TypeDef(Modifiers(sym.flags), sym.name.toTypeName, sym.typeParams map TypeDef, rhs) setSymbol sym
+ }
+
+ /** A TypeDef node which defines abstract type or type parameter for given `sym` */
+ def TypeDef(sym: Symbol): TypeDef =
+ TypeDef(sym, TypeBoundsTree(TypeTree(sym.info.bounds.lo), TypeTree(sym.info.bounds.hi)))
+
+ def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef =
+ atPos(sym.pos) {
+ LabelDef(sym.name.toTermName, params map Ident, rhs) setSymbol sym
+ }
+
+ /** casedef shorthand */
+ def CaseDef(pat: Tree, body: Tree): CaseDef =
+ CaseDef(pat, EmptyTree, body)
+
+ def Bind(sym: Symbol, body: Tree): Bind =
+ Bind(sym.name, body) setSymbol sym
+
+ def Try(body: Tree, cases: (Tree, Tree)*): Try =
+ Try(body, cases.toList map { case (pat, rhs) => CaseDef(pat, EmptyTree, rhs) }, EmptyTree)
+
+ def Throw(tpe: Type, args: Tree*): Throw =
+ Throw(New(tpe, args: _*))
+
+ def Apply(sym: Symbol, args: Tree*): Tree =
+ Apply(Ident(sym), args.toList)
+
+ /** Factory method for object creation `new tpt(args_1)...(args_n)`
+ * A `New(t, as)` is expanded to: `(new t).<init>(as)`
+ */
+ def New(tpt: Tree, argss: List[List[Tree]]): Tree = argss match {
+ case Nil => ApplyConstructor(tpt, Nil)
+ case xs :: rest => {
+ def mkApply(fun: Tree, args: List[Tree]) = Apply(fun, args)
+ rest.foldLeft(ApplyConstructor(tpt, xs): Tree)(mkApply)
+ // [Eugene++] no longer compiles after I moved the `Apply` case class here
+ // rest.foldLeft(ApplyConstructor(tpt, xs): Tree)(Apply)
+ }
+ }
+
+ /** 0-1 argument list new, based on a type.
+ */
+ def New(tpe: Type, args: Tree*): Tree =
+ ApplyConstructor(TypeTree(tpe), args.toList)
+
+ def New(sym: Symbol, args: Tree*): Tree =
+ New(sym.tpe, args: _*)
+
+ def Super(sym: Symbol, mix: TypeName): Tree =
+ Super(This(sym), mix)
+
+ def This(sym: Symbol): Tree =
+ This(sym.name.toTypeName) setSymbol sym
+
+ def Select(qualifier: Tree, name: String): Select =
+ Select(qualifier, newTermName(name))
+
+ def Select(qualifier: Tree, sym: Symbol): Select =
+ Select(qualifier, sym.name) setSymbol sym
+
+ def Ident(name: String): Ident =
+ Ident(newTermName(name))
+
+ def Ident(sym: Symbol): Ident =
+ Ident(sym.name) setSymbol sym
+
+ /** Block factory that flattens directly nested blocks.
+ */
+ def Block(stats: Tree*): Block = {
+ if (stats.isEmpty) Block(Nil, Literal(Constant(())))
+ else stats match {
+ case Seq(b @ Block(_, _)) => b
+ case Seq(stat) => Block(stats.toList, Literal(Constant(())))
+ case Seq(_, rest @ _*) => Block(stats.init.toList, stats.last)
+ }
+ }
+
+ // --- generic traversers and transformers
+
+ 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)
+ }
+ case LabelDef(name, params, rhs) =>
+ traverseTrees(params); traverse(rhs)
+ case Import(expr, selectors) =>
+ traverse(expr)
+ case Annotated(annot, arg) =>
+ traverse(annot); traverse(arg)
+ case Template(parents, self, body) =>
+ traverseTrees(parents)
+ if (!self.isEmpty) traverse(self)
+ traverseStats(body, tree.symbol)
+ case Block(stats, expr) =>
+ traverseTrees(stats); traverse(expr)
+ case CaseDef(pat, guard, body) =>
+ traverse(pat); traverse(guard); traverse(body)
+ case Alternative(trees) =>
+ traverseTrees(trees)
+ case Star(elem) =>
+ traverse(elem)
+ case Bind(name, body) =>
+ traverse(body)
+ case UnApply(fun, args) =>
+ traverse(fun); traverseTrees(args)
+ case ArrayValue(elemtpt, trees) =>
+ traverse(elemtpt); traverseTrees(trees)
+ case Function(vparams, body) =>
+ atOwner(tree.symbol) {
+ traverseTrees(vparams); traverse(body)
+ }
+ case Assign(lhs, rhs) =>
+ traverse(lhs); traverse(rhs)
+ case AssignOrNamedArg(lhs, rhs) =>
+ traverse(lhs); traverse(rhs)
+ case If(cond, thenp, elsep) =>
+ traverse(cond); traverse(thenp); traverse(elsep)
+ case Match(selector, cases) =>
+ traverse(selector); traverseTrees(cases)
+ case Return(expr) =>
+ traverse(expr)
+ case Try(block, catches, finalizer) =>
+ traverse(block); traverseTrees(catches); traverse(finalizer)
+ case Throw(expr) =>
+ traverse(expr)
+ case New(tpt) =>
+ traverse(tpt)
+ case Typed(expr, tpt) =>
+ traverse(expr); traverse(tpt)
+ case TypeApply(fun, args) =>
+ traverse(fun); traverseTrees(args)
+ case Apply(fun, args) =>
+ traverse(fun); traverseTrees(args)
+ case ApplyDynamic(qual, args) =>
+ traverse(qual); traverseTrees(args)
+ case Super(qual, _) =>
+ traverse(qual)
+ case This(_) =>
+ ;
+ case Select(qualifier, selector) =>
+ traverse(qualifier)
+ case Ident(_) =>
+ ;
+ case ReferenceToBoxed(idt) =>
+ traverse(idt)
+ case Literal(_) =>
+ ;
+ case TypeTree() =>
+ ;
+ case SingletonTypeTree(ref) =>
+ traverse(ref)
+ case SelectFromTypeTree(qualifier, selector) =>
+ traverse(qualifier)
+ case CompoundTypeTree(templ) =>
+ traverse(templ)
+ case AppliedTypeTree(tpt, args) =>
+ traverse(tpt); traverseTrees(args)
+ case TypeBoundsTree(lo, hi) =>
+ traverse(lo); traverse(hi)
+ case ExistentialTypeTree(tpt, whereClauses) =>
+ traverse(tpt); traverseTrees(whereClauses)
+ case _ => xtraverse(traverser, tree)
+ }
+ }
+
+ override protected def itransform(transformer: Transformer, tree: Tree): Tree = {
+ import transformer._
+ val treeCopy = transformer.treeCopy
+ tree match {
+ case EmptyTree =>
+ tree
+ case PackageDef(pid, stats) =>
+ treeCopy.PackageDef(
+ tree, transform(pid).asInstanceOf[RefTree],
+ atOwner(mclass(tree.symbol)) {
+ transformStats(stats, currentOwner)
+ }
+ )
+ case ClassDef(mods, name, tparams, impl) =>
+ atOwner(tree.symbol) {
+ treeCopy.ClassDef(tree, transformModifiers(mods), name,
+ transformTypeDefs(tparams), transformTemplate(impl))
+ }
+ case ModuleDef(mods, name, impl) =>
+ atOwner(mclass(tree.symbol)) {
+ treeCopy.ModuleDef(tree, transformModifiers(mods),
+ name, transformTemplate(impl))
+ }
+ case ValDef(mods, name, tpt, rhs) =>
+ atOwner(tree.symbol) {
+ treeCopy.ValDef(tree, transformModifiers(mods),
+ name, transform(tpt), transform(rhs))
+ }
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ atOwner(tree.symbol) {
+ treeCopy.DefDef(tree, transformModifiers(mods), name,
+ transformTypeDefs(tparams), transformValDefss(vparamss),
+ transform(tpt), transform(rhs))
+ }
+ case TypeDef(mods, name, tparams, rhs) =>
+ atOwner(tree.symbol) {
+ treeCopy.TypeDef(tree, transformModifiers(mods), name,
+ transformTypeDefs(tparams), transform(rhs))
+ }
+ case LabelDef(name, params, rhs) =>
+ treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy'
+ case Import(expr, selectors) =>
+ treeCopy.Import(tree, transform(expr), selectors)
+ case Template(parents, self, body) =>
+ treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol))
+ case Block(stats, expr) =>
+ treeCopy.Block(tree, transformStats(stats, currentOwner), transform(expr))
+ case CaseDef(pat, guard, body) =>
+ treeCopy.CaseDef(tree, transform(pat), transform(guard), transform(body))
+ case Alternative(trees) =>
+ treeCopy.Alternative(tree, transformTrees(trees))
+ case Star(elem) =>
+ treeCopy.Star(tree, transform(elem))
+ case Bind(name, body) =>
+ treeCopy.Bind(tree, name, transform(body))
+ case UnApply(fun, args) =>
+ treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
+ case ArrayValue(elemtpt, trees) =>
+ treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
+ case Function(vparams, body) =>
+ atOwner(tree.symbol) {
+ treeCopy.Function(tree, transformValDefs(vparams), transform(body))
+ }
+ case Assign(lhs, rhs) =>
+ treeCopy.Assign(tree, transform(lhs), transform(rhs))
+ case AssignOrNamedArg(lhs, rhs) =>
+ treeCopy.AssignOrNamedArg(tree, transform(lhs), transform(rhs))
+ case If(cond, thenp, elsep) =>
+ treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep))
+ case Match(selector, cases) =>
+ treeCopy.Match(tree, transform(selector), transformCaseDefs(cases))
+ case Return(expr) =>
+ treeCopy.Return(tree, transform(expr))
+ case Try(block, catches, finalizer) =>
+ treeCopy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer))
+ case Throw(expr) =>
+ treeCopy.Throw(tree, transform(expr))
+ case New(tpt) =>
+ treeCopy.New(tree, transform(tpt))
+ case Typed(expr, tpt) =>
+ treeCopy.Typed(tree, transform(expr), transform(tpt))
+ case TypeApply(fun, args) =>
+ treeCopy.TypeApply(tree, transform(fun), transformTrees(args))
+ case Apply(fun, args) =>
+ treeCopy.Apply(tree, transform(fun), transformTrees(args))
+ case ApplyDynamic(qual, args) =>
+ treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args))
+ case Super(qual, mix) =>
+ treeCopy.Super(tree, transform(qual), mix)
+ case This(qual) =>
+ treeCopy.This(tree, qual)
+ case Select(qualifier, selector) =>
+ treeCopy.Select(tree, transform(qualifier), selector)
+ case Ident(name) =>
+ treeCopy.Ident(tree, name)
+ case ReferenceToBoxed(idt) =>
+ treeCopy.ReferenceToBoxed(tree, transform(idt) match { case idt1: Ident => idt1 })
+ case Literal(value) =>
+ treeCopy.Literal(tree, value)
+ case TypeTree() =>
+ treeCopy.TypeTree(tree)
+ case Annotated(annot, arg) =>
+ treeCopy.Annotated(tree, transform(annot), transform(arg))
+ case SingletonTypeTree(ref) =>
+ treeCopy.SingletonTypeTree(tree, transform(ref))
+ case SelectFromTypeTree(qualifier, selector) =>
+ treeCopy.SelectFromTypeTree(tree, transform(qualifier), selector)
+ case CompoundTypeTree(templ) =>
+ treeCopy.CompoundTypeTree(tree, transformTemplate(templ))
+ case AppliedTypeTree(tpt, args) =>
+ treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args))
+ case TypeBoundsTree(lo, hi) =>
+ treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi))
+ case ExistentialTypeTree(tpt, whereClauses) =>
+ treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses))
+ case _ =>
+ xtransform(transformer, tree)
+ }
+ }
+
+ private def mclass(sym: Symbol) = sym map (_.asModuleSymbol.moduleClass)
+
+ // --- specific traversers and transformers
+
+ class ForeachPartialTreeTraverser(pf: PartialFunction[Tree, Tree]) extends Traverser {
+ override def traverse(tree: Tree) {
+ val t = if (pf isDefinedAt tree) pf(tree) else tree
+ super.traverse(t)
+ }
+ }
+
+ class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser {
+ def changeOwner(tree: Tree) = tree match {
+ case Return(expr) =>
+ if (tree.symbol == oldowner) {
+ // SI-5612
+ if (newowner hasTransOwner oldowner)
+ log("NOT changing owner of %s because %s is nested in %s".format(tree, newowner, oldowner))
+ else {
+ log("changing owner of %s: %s => %s".format(tree, oldowner, newowner))
+ tree.symbol = newowner
+ }
+ }
+ case _: DefTree | _: Function =>
+ if (tree.symbol != NoSymbol && tree.symbol.owner == oldowner) {
+ tree.symbol.owner = newowner
+ }
+ case _ =>
+ }
+ override def traverse(tree: Tree) {
+ changeOwner(tree)
+ super.traverse(tree)
+ }
+ }
+
+ private class ShallowDuplicator(orig: Tree) extends Transformer {
+ override val treeCopy = newStrictTreeCopier
+ override def transform(tree: Tree) =
+ if (tree eq orig) super.transform(tree)
+ else tree
+ }
+ // Create a readable string describing a substitution.
+ private def substituterString(fromStr: String, toStr: String, from: List[Any], to: List[Any]): String = {
+ "subst[%s, %s](%s)".format(fromStr, toStr, (from, to).zipped map (_ + " -> " + _) mkString ", ")
+ }
+
+ // NOTE: calls shallowDuplicate on trees in `to` to avoid problems when symbols in `from`
+ // occur multiple times in the `tree` passed to `transform`,
+ // otherwise, the resulting Tree would be a graph, not a tree... this breaks all sorts of stuff,
+ // notably concerning the mutable aspects of Trees (such as setting their .tpe)
+ class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Ident(_) =>
+ def subst(from: List[Symbol], to: List[Tree]): Tree =
+ if (from.isEmpty) tree
+ else if (tree.symbol == from.head) to.head.shallowDuplicate // TODO: does it ever make sense *not* to perform a shallowDuplicate on `to.head`?
+ else subst(from.tail, to.tail);
+ subst(from, to)
+ case _ =>
+ super.transform(tree)
+ }
+ override def toString = substituterString("Symbol", "Tree", from, to)
+ }
+
+ /** Substitute clazz.this with `to`. `to` must be an attributed tree.
+ */
+ class ThisSubstituter(clazz: Symbol, to: => Tree) extends Transformer {
+ val newtpe = to.tpe
+ override def transform(tree: Tree) = {
+ if (tree.tpe ne null) tree.tpe = tree.tpe.substThis(clazz, newtpe)
+ tree match {
+ case This(_) if tree.symbol == clazz => to
+ case _ => super.transform(tree)
+ }
+ }
+ }
+
+ class TypeMapTreeSubstituter(val typeMap: TypeMap) extends Traverser {
+ override def traverse(tree: Tree) {
+ if (tree.tpe ne null)
+ tree.tpe = typeMap(tree.tpe)
+ if (tree.isDef)
+ tree.symbol modifyInfo typeMap
+
+ super.traverse(tree)
+ }
+ override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate)
+ }
+
+ class TreeTypeSubstituter(val from: List[Symbol], val to: List[Type]) extends TypeMapTreeSubstituter(new SubstTypeMap(from, to)) {
+ def isEmpty = from.isEmpty && to.isEmpty
+ override def toString() = "TreeTypeSubstituter("+from+","+to+")"
+ }
+
+ lazy val EmptyTreeTypeSubstituter = new TreeTypeSubstituter(List(), List())
+
+ class TreeSymSubstTraverser(val from: List[Symbol], val to: List[Symbol]) extends TypeMapTreeSubstituter(new SubstSymMap(from, to)) {
+ override def toString() = "TreeSymSubstTraverser/" + substituterString("Symbol", "Symbol", from, to)
+ }
+
+ /** Substitute symbols in `from` with symbols in `to`. Returns a new
+ * tree using the new symbols and whose Ident and Select nodes are
+ * name-consistent with the new symbols.
+ */
+ class TreeSymSubstituter(from: List[Symbol], to: List[Symbol]) extends Transformer {
+ val symSubst = new SubstSymMap(from, to)
+ override def transform(tree: Tree): Tree = {
+ def subst(from: List[Symbol], to: List[Symbol]) {
+ if (!from.isEmpty)
+ if (tree.symbol == from.head) tree setSymbol to.head
+ else subst(from.tail, to.tail)
+ }
+
+ if (tree.tpe ne null) tree.tpe = symSubst(tree.tpe)
+ if (tree.hasSymbol) {
+ subst(from, to)
+ tree match {
+ case Ident(name0) if tree.symbol != NoSymbol =>
+ treeCopy.Ident(tree, tree.symbol.name)
+ case Select(qual, name0) if tree.symbol != NoSymbol =>
+ treeCopy.Select(tree, transform(qual), tree.symbol.name)
+ case _ =>
+ super.transform(tree)
+ }
+ } else
+ super.transform(tree)
+ }
+ def apply[T <: Tree](tree: T): T = transform(tree).asInstanceOf[T]
+ override def toString() = "TreeSymSubstituter/" + substituterString("Symbol", "Symbol", from, to)
+ }
+
+
+ class ForeachTreeTraverser(f: Tree => Unit) extends Traverser {
+ override def traverse(t: Tree) {
+ f(t)
+ super.traverse(t)
+ }
+ }
+
+ class FilterTreeTraverser(p: Tree => Boolean) extends Traverser {
+ val hits = new ListBuffer[Tree]
+ override def traverse(t: Tree) {
+ if (p(t)) hits += t
+ super.traverse(t)
+ }
+ }
+
+ class CollectTreeTraverser[T](pf: PartialFunction[Tree, T]) extends Traverser {
+ val results = new ListBuffer[T]
+ override def traverse(t: Tree) {
+ if (pf.isDefinedAt(t)) results += pf(t)
+ super.traverse(t)
+ }
+ }
+
+ class FindTreeTraverser(p: Tree => Boolean) extends Traverser {
+ var result: Option[Tree] = None
+ override def traverse(t: Tree) {
+ if (result.isEmpty) {
+ if (p(t)) result = Some(t)
+ super.traverse(t)
+ }
+ }
+ }
+
+ private lazy val duplicator = new Transformer {
+ override val treeCopy = newStrictTreeCopier
+ override def transform(t: Tree) = {
+ val t1 = super.transform(t)
+ if ((t1 ne t) && t1.pos.isRange) t1 setPos t.pos.focus
+ t1
+ }
+ }
+
+ // ------ copiers -------------------------------------------
+
+ def copyDefDef(tree: Tree)(
+ mods: Modifiers = null,
+ name: Name = null,
+ tparams: List[TypeDef] = null,
+ vparamss: List[List[ValDef]] = null,
+ tpt: Tree = null,
+ rhs: Tree = null
+ ): DefDef = tree match {
+ case DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0) =>
+ treeCopy.DefDef(tree,
+ if (mods eq null) mods0 else mods,
+ if (name eq null) name0 else name,
+ if (tparams eq null) tparams0 else tparams,
+ if (vparamss eq null) vparamss0 else vparamss,
+ if (tpt eq null) tpt0 else tpt,
+ if (rhs eq null) rhs0 else rhs
+ )
+ case t =>
+ sys.error("Not a DefDef: " + t + "/" + t.getClass)
+ }
+ def copyValDef(tree: Tree)(
+ mods: Modifiers = null,
+ name: Name = null,
+ tpt: Tree = null,
+ rhs: Tree = null
+ ): ValDef = tree match {
+ case ValDef(mods0, name0, tpt0, rhs0) =>
+ treeCopy.ValDef(tree,
+ if (mods eq null) mods0 else mods,
+ if (name eq null) name0 else name,
+ if (tpt eq null) tpt0 else tpt,
+ if (rhs eq null) rhs0 else rhs
+ )
+ case t =>
+ sys.error("Not a ValDef: " + t + "/" + t.getClass)
+ }
+ def copyClassDef(tree: Tree)(
+ mods: Modifiers = null,
+ name: Name = null,
+ tparams: List[TypeDef] = null,
+ impl: Template = null
+ ): ClassDef = tree match {
+ case ClassDef(mods0, name0, tparams0, impl0) =>
+ treeCopy.ClassDef(tree,
+ if (mods eq null) mods0 else mods,
+ if (name eq null) name0 else name,
+ if (tparams eq null) tparams0 else tparams,
+ if (impl eq null) impl0 else impl
+ )
+ case t =>
+ sys.error("Not a ClassDef: " + t + "/" + t.getClass)
+ }
+
+ def deriveDefDef(ddef: Tree)(applyToRhs: Tree => Tree): DefDef = ddef match {
+ case DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0) =>
+ treeCopy.DefDef(ddef, mods0, name0, tparams0, vparamss0, tpt0, applyToRhs(rhs0))
+ case t =>
+ sys.error("Not a DefDef: " + t + "/" + t.getClass)
+ }
+ def deriveValDef(vdef: Tree)(applyToRhs: Tree => Tree): ValDef = vdef match {
+ case ValDef(mods0, name0, tpt0, rhs0) =>
+ treeCopy.ValDef(vdef, mods0, name0, tpt0, applyToRhs(rhs0))
+ case t =>
+ sys.error("Not a ValDef: " + t + "/" + t.getClass)
+ }
+ def deriveTemplate(templ: Tree)(applyToBody: List[Tree] => List[Tree]): Template = templ match {
+ case Template(parents0, self0, body0) =>
+ treeCopy.Template(templ, parents0, self0, applyToBody(body0))
+ case t =>
+ sys.error("Not a Template: " + t + "/" + t.getClass)
+ }
+ def deriveClassDef(cdef: Tree)(applyToImpl: Template => Template): ClassDef = cdef match {
+ case ClassDef(mods0, name0, tparams0, impl0) =>
+ treeCopy.ClassDef(cdef, mods0, name0, tparams0, applyToImpl(impl0))
+ case t =>
+ sys.error("Not a ClassDef: " + t + "/" + t.getClass)
+ }
+ def deriveModuleDef(mdef: Tree)(applyToImpl: Template => Template): ModuleDef = mdef match {
+ case ModuleDef(mods0, name0, impl0) =>
+ treeCopy.ModuleDef(mdef, mods0, name0, applyToImpl(impl0))
+ case t =>
+ sys.error("Not a ModuleDef: " + t + "/" + t.getClass)
+ }
+ def deriveCaseDef(cdef: Tree)(applyToBody: Tree => Tree): CaseDef = cdef match {
+ case CaseDef(pat0, guard0, body0) =>
+ treeCopy.CaseDef(cdef, pat0, guard0, applyToBody(body0))
+ case t =>
+ sys.error("Not a CaseDef: " + t + "/" + t.getClass)
+ }
+ def deriveLabelDef(ldef: Tree)(applyToRhs: Tree => Tree): LabelDef = ldef match {
+ case LabelDef(name0, params0, rhs0) =>
+ treeCopy.LabelDef(ldef, name0, params0, applyToRhs(rhs0))
+ case t =>
+ sys.error("Not a LabelDef: " + t + "/" + t.getClass)
+ }
+
+ implicit val TreeTag = ClassTag[Tree](classOf[Tree])
+ implicit val TermTreeTag = ClassTag[TermTree](classOf[TermTree])
+ implicit val TypTreeTag = ClassTag[TypTree](classOf[TypTree])
+ implicit val SymTreeTag = ClassTag[SymTree](classOf[SymTree])
+ implicit val NameTreeTag = ClassTag[NameTree](classOf[NameTree])
+ implicit val RefTreeTag = ClassTag[RefTree](classOf[RefTree])
+ implicit val DefTreeTag = ClassTag[DefTree](classOf[DefTree])
+ implicit val MemberDefTag = ClassTag[MemberDef](classOf[MemberDef])
+ implicit val PackageDefTag = ClassTag[PackageDef](classOf[PackageDef])
+ implicit val ImplDefTag = ClassTag[ImplDef](classOf[ImplDef])
+ implicit val ClassDefTag = ClassTag[ClassDef](classOf[ClassDef])
+ implicit val ModuleDefTag = ClassTag[ModuleDef](classOf[ModuleDef])
+ implicit val ValOrDefDefTag = ClassTag[ValOrDefDef](classOf[ValOrDefDef])
+ implicit val ValDefTag = ClassTag[ValDef](classOf[ValDef])
+ implicit val DefDefTag = ClassTag[DefDef](classOf[DefDef])
+ implicit val TypeDefTag = ClassTag[TypeDef](classOf[TypeDef])
+ implicit val LabelDefTag = ClassTag[LabelDef](classOf[LabelDef])
+ implicit val ImportSelectorTag = ClassTag[ImportSelector](classOf[ImportSelector])
+ implicit val ImportTag = ClassTag[Import](classOf[Import])
+ implicit val TemplateTag = ClassTag[Template](classOf[Template])
+ implicit val BlockTag = ClassTag[Block](classOf[Block])
+ implicit val CaseDefTag = ClassTag[CaseDef](classOf[CaseDef])
+ implicit val AlternativeTag = ClassTag[Alternative](classOf[Alternative])
+ implicit val StarTag = ClassTag[Star](classOf[Star])
+ implicit val BindTag = ClassTag[Bind](classOf[Bind])
+ implicit val UnApplyTag = ClassTag[UnApply](classOf[UnApply])
+ implicit val ArrayValueTag = ClassTag[ArrayValue](classOf[ArrayValue])
+ implicit val FunctionTag = ClassTag[Function](classOf[Function])
+ implicit val AssignTag = ClassTag[Assign](classOf[Assign])
+ implicit val AssignOrNamedArgTag = ClassTag[AssignOrNamedArg](classOf[AssignOrNamedArg])
+ implicit val IfTag = ClassTag[If](classOf[If])
+ implicit val MatchTag = ClassTag[Match](classOf[Match])
+ implicit val ReturnTag = ClassTag[Return](classOf[Return])
+ implicit val TryTag = ClassTag[Try](classOf[Try])
+ implicit val ThrowTag = ClassTag[Throw](classOf[Throw])
+ implicit val NewTag = ClassTag[New](classOf[New])
+ implicit val TypedTag = ClassTag[Typed](classOf[Typed])
+ implicit val GenericApplyTag = ClassTag[GenericApply](classOf[GenericApply])
+ implicit val TypeApplyTag = ClassTag[TypeApply](classOf[TypeApply])
+ implicit val ApplyTag = ClassTag[Apply](classOf[Apply])
+ implicit val ApplyDynamicTag = ClassTag[ApplyDynamic](classOf[ApplyDynamic])
+ implicit val SuperTag = ClassTag[Super](classOf[Super])
+ implicit val ThisTag = ClassTag[This](classOf[This])
+ implicit val SelectTag = ClassTag[Select](classOf[Select])
+ implicit val IdentTag = ClassTag[Ident](classOf[Ident])
+ implicit val ReferenceToBoxedTag = ClassTag[ReferenceToBoxed](classOf[ReferenceToBoxed])
+ implicit val LiteralTag = ClassTag[Literal](classOf[Literal])
+ implicit val AnnotatedTag = ClassTag[Annotated](classOf[Annotated])
+ implicit val SingletonTypeTreeTag = ClassTag[SingletonTypeTree](classOf[SingletonTypeTree])
+ implicit val SelectFromTypeTreeTag = ClassTag[SelectFromTypeTree](classOf[SelectFromTypeTree])
+ implicit val CompoundTypeTreeTag = ClassTag[CompoundTypeTree](classOf[CompoundTypeTree])
+ implicit val AppliedTypeTreeTag = ClassTag[AppliedTypeTree](classOf[AppliedTypeTree])
+ implicit val TypeBoundsTreeTag = ClassTag[TypeBoundsTree](classOf[TypeBoundsTree])
+ implicit val ExistentialTypeTreeTag = ClassTag[ExistentialTypeTree](classOf[ExistentialTypeTree])
+ implicit val TypeTreeTag = ClassTag[TypeTree](classOf[TypeTree])
+}
diff --git a/src/reflect/scala/reflect/internal/TypeDebugging.scala b/src/reflect/scala/reflect/internal/TypeDebugging.scala
new file mode 100644
index 0000000000..33f6a645e8
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/TypeDebugging.scala
@@ -0,0 +1,71 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect
+package internal
+
+trait TypeDebugging {
+ self: SymbolTable =>
+
+ import definitions._
+
+ // @M toString that is safe during debugging (does not normalize, ...)
+ object typeDebug {
+ private def to_s(x: Any): String = x match {
+ // otherwise case classes are caught looking like products
+ case _: Tree | _: Type => "" + x
+ case x: TraversableOnce[_] => x mkString ", "
+ case x: Product => x.productIterator mkString ("(", ", ", ")")
+ case _ => "" + x
+ }
+ def ptIndent(x: Any) = ("" + x).replaceAll("\\n", " ")
+ def ptBlock(label: String, pairs: (String, Any)*): String = {
+ if (pairs.isEmpty) label + "{ }"
+ else {
+ val width = (pairs map (_._1.length)).max
+ val fmt = "%-" + (width + 1) + "s %s"
+ val strs = pairs map { case (k, v) => fmt.format(k, to_s(v)) }
+
+ strs.mkString(label + " {\n ", "\n ", "\n}")
+ }
+ }
+ def ptLine(label: String, pairs: (String, Any)*): String = {
+ val strs = pairs map { case (k, v) => k + "=" + to_s(v) }
+ strs.mkString(label + ": ", ", ", "")
+ }
+ def ptTree(t: Tree) = t match {
+ case PackageDef(pid, _) => "package " + pid
+ case ModuleDef(_, name, _) => "object " + name
+ case ClassDef(_, name, tparams, _) => "class " + name + str.brackets(tparams)
+ case _ => to_s(t)
+ }
+
+ object str {
+ def parentheses(xs: List[_]): String = xs.mkString("(", ", ", ")")
+ def brackets(xs: List[_]): String = if (xs.isEmpty) "" else xs.mkString("[", ", ", "]")
+ def tparams(tparams: List[Type]): String = brackets(tparams map debug)
+ def parents(ps: List[Type]): String = (ps map debug).mkString(" with ")
+ def refine(defs: Scope): String = defs.toList.mkString("{", " ;\n ", "}")
+ }
+
+ private def debug(tp: Type): String = tp match {
+ case TypeRef(pre, sym, args) => debug(pre) + "." + sym.nameString + str.tparams(args)
+ case ThisType(sym) => sym.nameString + ".this"
+ case SingleType(pre, sym) => debug(pre) +"."+ sym.nameString +".type"
+ case RefinedType(parents, defs) => str.parents(parents) + str.refine(defs)
+ case ClassInfoType(parents, defs, clazz) => "class "+ clazz.nameString + str.parents(parents) + str.refine(defs)
+ case PolyType(tparams, result) => str.brackets(tparams) + " " + debug(result)
+ case TypeBounds(lo, hi) => ">: "+ debug(lo) +" <: "+ debug(hi)
+ case tv @ TypeVar(_, _) => tv.toString
+ case ExistentialType(tparams, qtpe) => "forSome "+ str.brackets(tparams) + " " + debug(qtpe)
+ case _ => "?"+tp.getClass.getName+"?"//tp.toString might produce cyclic error...
+ }
+ def debugString(tp: Type) = debug(tp)
+ }
+ def paramString(tp: Type) = typeDebug.str parentheses (tp.params map (_.defString))
+ def typeParamsString(tp: Type) = typeDebug.str brackets (tp.typeParams map (_.defString))
+ def typeArgsString(tp: Type) = typeDebug.str brackets (tp.typeArgs map (_.safeToString))
+ def debugString(tp: Type) = typeDebug debugString tp
+}
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
new file mode 100644
index 0000000000..23921d73cc
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -0,0 +1,6820 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+
+import scala.collection.{ mutable, immutable, generic }
+import generic.Clearable
+import scala.ref.WeakReference
+import mutable.ListBuffer
+import Flags._
+import scala.util.control.ControlThrowable
+import scala.annotation.tailrec
+import util.Statistics._
+import language.postfixOps
+
+/* A standard type pattern match:
+ case ErrorType =>
+ // internal: error
+ case WildcardType =>
+ // internal: unknown
+ case NoType =>
+ case NoPrefix =>
+ case ThisType(sym) =>
+ // sym.this.type
+ case SuperType(thistpe, supertpe) =>
+ // super references
+ case SingleType(pre, sym) =>
+ // pre.sym.type
+ case ConstantType(value) =>
+ // Int(2)
+ case TypeRef(pre, sym, args) =>
+ // pre.sym[targs]
+ // Outer.this.C would be represented as TypeRef(ThisType(Outer), C, List())
+ case RefinedType(parents, defs) =>
+ // parent1 with ... with parentn { defs }
+ case ExistentialType(tparams, result) =>
+ // result forSome { tparams }
+ case AnnotatedType(annots, tp, selfsym) =>
+ // tp @annots
+
+ // the following are non-value types; you cannot write them down in Scala source.
+
+ case TypeBounds(lo, hi) =>
+ // >: lo <: hi
+ case ClassInfoType(parents, defs, clazz) =>
+ // same as RefinedType except as body of class
+ case MethodType(paramtypes, result) =>
+ // (paramtypes)result
+ // For instance def m(): T is represented as MethodType(List(), T)
+ case NullaryMethodType(result) => // eliminated by uncurry
+ // an eval-by-name type
+ // For instance def m: T is represented as NullaryMethodType(T)
+ case PolyType(tparams, result) =>
+ // [tparams]result where result is a (Nullary)MethodType or ClassInfoType
+
+ // The remaining types are not used after phase `typer`.
+ case OverloadedType(pre, tparams, alts) =>
+ // all alternatives of an overloaded ident
+ case AntiPolyType(pre, targs) =>
+ // rarely used, disappears when combined with a PolyType
+ case TypeVar(inst, constr) =>
+ // a type variable
+ // Replace occurrences of type parameters with type vars, where
+ // inst is the instantiation and constr is a list of bounds.
+ case DeBruijnIndex(level, index)
+ // for dependent method types: a type referring to a method parameter.
+ case ErasedValueType(tp)
+ // only used during erasure of derived value classes.
+*/
+
+trait Types extends api.Types { self: SymbolTable =>
+ import definitions._
+
+ //statistics
+ def uniqueTypeCount = if (uniques == null) 0 else uniques.size
+
+ private var explainSwitch = false
+ private final val emptySymbolSet = immutable.Set.empty[Symbol]
+
+ private final val LogPendingSubTypesThreshold = 50
+ private final val LogPendingBaseTypesThreshold = 50
+ private final val LogVolatileThreshold = 50
+
+ /** A don't care value for the depth parameter in lubs/glbs and related operations. */
+ private final val AnyDepth = -3
+
+ /** Decrement depth unless it is a don't care. */
+ private final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1
+
+ private final val printLubs = sys.props contains "scalac.debug.lub"
+ private final val traceTypeVars = sys.props contains "scalac.debug.tvar"
+ /** In case anyone wants to turn off lub verification without reverting anything. */
+ private final val verifyLubs = true
+ /** In case anyone wants to turn off type parameter bounds being used
+ * to seed type constraints.
+ */
+ private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints"
+
+ protected val enableTypeVarExperimentals = settings.Xexperimental.value
+
+ /** Empty immutable maps to avoid allocations. */
+ private val emptySymMap = immutable.Map[Symbol, Symbol]()
+ private val emptySymCount = immutable.Map[Symbol, Int]()
+
+ /** The current skolemization level, needed for the algorithms
+ * in isSameType, isSubType that do constraint solving under a prefix.
+ */
+ var skolemizationLevel = 0
+
+ /** 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
+
+ class UndoLog extends Clearable {
+ private type UndoPairs = List[(TypeVar, TypeConstraint)]
+ private var log: UndoPairs = List()
+
+ // register with the auto-clearing cache manager
+ perRunCaches.recordCache(this)
+
+ /** Undo all changes to constraints to type variables upto `limit`. */
+ private def undoTo(limit: UndoPairs) {
+ while ((log ne limit) && log.nonEmpty) {
+ val (tv, constr) = log.head
+ tv.constr = constr
+ log = log.tail
+ }
+ }
+
+ /** No sync necessary, because record should only
+ * be called from within a undo or undoUnless block,
+ * which is already synchronized.
+ */
+ private[reflect] def record(tv: TypeVar) = {
+ log ::= ((tv, tv.constr.cloneInternal))
+ }
+
+ def clear() {
+ if (settings.debug.value)
+ self.log("Clearing " + log.size + " entries from the undoLog.")
+
+ log = Nil
+ }
+ def size = log.size
+
+ // `block` should not affect constraints on typevars
+ def undo[T](block: => T): T = {
+ val before = log
+
+ try block
+ finally undoTo(before)
+ }
+
+ // if `block` evaluates to false, it should not affect constraints on typevars
+ def undoUnless(block: => Boolean): Boolean = {
+ val before = log
+ var result = false
+
+ try result = block
+ finally if (!result) undoTo(before)
+
+ result
+ }
+ }
+
+ /** 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]]()
+
+ /** A proxy for a type (identified by field `underlying`) that forwards most
+ * operations to it (for exceptions, see WrappingProxy, which forwards even more operations).
+ * every operation that is overridden for some kind of types should be forwarded.
+ */
+ trait SimpleTypeProxy extends Type {
+ def underlying: Type
+
+ // the following operations + those in RewrappingTypeProxy are all operations
+ // in class Type that are overridden in some subclass
+ // Important to keep this up-to-date when new operations are added!
+ override def isTrivial = underlying.isTrivial
+ override def isHigherKinded: Boolean = underlying.isHigherKinded
+ override def typeConstructor: Type = underlying.typeConstructor
+ override def isNotNull = underlying.isNotNull
+ override def isError = underlying.isError
+ override def isErroneous = underlying.isErroneous
+ override def isStable: Boolean = underlying.isStable
+ override def isVolatile = underlying.isVolatile
+ override def finalResultType = underlying.finalResultType
+ override def paramSectionCount = underlying.paramSectionCount
+ override def paramss = underlying.paramss
+ override def params = underlying.params
+ override def paramTypes = underlying.paramTypes
+ override def termSymbol = underlying.termSymbol
+ override def termSymbolDirect = underlying.termSymbolDirect
+ override def typeParams = underlying.typeParams
+ override def boundSyms = underlying.boundSyms
+ override def typeSymbol = underlying.typeSymbol
+ override def typeSymbolDirect = underlying.typeSymbolDirect
+ override def widen = underlying.widen
+ override def typeOfThis = underlying.typeOfThis
+ override def bounds = underlying.bounds
+ override def parents = underlying.parents
+ override def prefix = underlying.prefix
+ override def decls = underlying.decls
+ override def baseType(clazz: Symbol) = underlying.baseType(clazz)
+ override def baseTypeSeq = underlying.baseTypeSeq
+ override def baseTypeSeqDepth = underlying.baseTypeSeqDepth
+ override def baseClasses = underlying.baseClasses
+ }
+
+ /** A proxy for a type (identified by field `underlying`) that forwards most
+ * operations to it. Every operation that is overridden for some kind of types is
+ * forwarded here. Some operations are rewrapped again.
+ */
+ trait RewrappingTypeProxy extends SimpleTypeProxy {
+ protected def maybeRewrap(newtp: Type) = if (newtp eq underlying) this else rewrap(newtp)
+ protected def rewrap(newtp: Type): Type
+
+ // the following are all operations in class Type that are overridden in some subclass
+ // Important to keep this up-to-date when new operations are added!
+ override def widen = maybeRewrap(underlying.widen)
+ override def narrow = underlying.narrow
+ override def deconst = maybeRewrap(underlying.deconst)
+ override def resultType = maybeRewrap(underlying.resultType)
+ override def resultType(actuals: List[Type]) = maybeRewrap(underlying.resultType(actuals))
+ override def finalResultType = maybeRewrap(underlying.finalResultType)
+ override def paramSectionCount = 0
+ override def paramss: List[List[Symbol]] = List()
+ override def params: List[Symbol] = List()
+ override def paramTypes: List[Type] = List()
+ override def typeArgs = underlying.typeArgs
+ override def notNull = maybeRewrap(underlying.notNull)
+ override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = underlying.instantiateTypeParams(formals, actuals)
+ override def skolemizeExistential(owner: Symbol, origin: AnyRef) = underlying.skolemizeExistential(owner, origin)
+ override def normalize = maybeRewrap(underlying.normalize)
+ override def dealias = maybeRewrap(underlying.dealias)
+ override def cloneInfo(owner: Symbol) = maybeRewrap(underlying.cloneInfo(owner))
+ override def atOwner(owner: Symbol) = maybeRewrap(underlying.atOwner(owner))
+ override def prefixString = underlying.prefixString
+ override def isComplete = underlying.isComplete
+ override def complete(sym: Symbol) = underlying.complete(sym)
+ override def load(sym: Symbol) { underlying.load(sym) }
+ override def withAnnotations(annots: List[AnnotationInfo]) = maybeRewrap(underlying.withAnnotations(annots))
+ override def withoutAnnotations = maybeRewrap(underlying.withoutAnnotations)
+ }
+
+ case object UnmappableTree extends TermTree {
+ override def toString = "<unmappable>"
+ super.tpe_=(NoType)
+ override def tpe_=(t: Type) = if (t != NoType) {
+ throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>")
+ }
+ }
+
+ abstract class TypeApiImpl extends TypeApi { this: Type =>
+ def declaration(name: Name): Symbol = decl(name)
+ def nonPrivateDeclaration(name: Name): Symbol = nonPrivateDecl(name)
+ def declarations = decls
+ def typeArguments = typeArgs
+ def erasure = this match {
+ case ConstantType(value) => widen.erasure // [Eugene to Martin] constant types are unaffected by erasure. weird.
+ case _ =>
+ var result: Type = transformedType(this)
+ result = result.normalize match { // necessary to deal with erasures of HK types, typeConstructor won't work
+ case PolyType(undets, underlying) => existentialAbstraction(undets, underlying) // we don't want undets in the result
+ case _ => result
+ }
+ // [Eugene] erasure screws up all ThisTypes for modules into PackageTypeRefs
+ // we need to unscrew them, or certain typechecks will fail mysteriously
+ // http://groups.google.com/group/scala-internals/browse_thread/thread/6d3277ae21b6d581
+ result = result.map(tpe => tpe match {
+ case tpe: PackageTypeRef => ThisType(tpe.sym)
+ case _ => tpe
+ })
+ result
+ }
+ def substituteSymbols(from: List[Symbol], to: List[Symbol]): Type = substSym(from, to)
+ def substituteTypes(from: List[Symbol], to: List[Type]): Type = subst(from, to)
+
+ // [Eugene] to be discussed and refactored
+ def isConcrete = {
+ def notConcreteSym(sym: Symbol) =
+ sym.isAbstractType && !sym.isExistential
+
+ def notConcreteTpe(tpe: Type): Boolean = tpe match {
+ case ThisType(_) => false
+ case SuperType(_, _) => false
+ case SingleType(pre, sym) => notConcreteSym(sym)
+ case ConstantType(_) => false
+ case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists (arg => notConcreteTpe(arg)))
+ case RefinedType(_, _) => false
+ case ExistentialType(_, _) => false
+ case AnnotatedType(_, tp, _) => notConcreteTpe(tp)
+ case _ => true
+ }
+
+ !notConcreteTpe(this)
+ }
+
+ // [Eugene] is this comprehensive?
+ // the only thingies that we want to splice are: 1) type parameters, 2) type members
+ // the thingies that we don't want to splice are: 1) concrete types (obviously), 2) existential skolems
+ // this check seems to cover them all, right?
+ // todo. after we discuss this, move the check to subclasses
+ def isSpliceable = {
+ this.isInstanceOf[TypeRef] && typeSymbol.isAbstractType && !typeSymbol.isExistential
+ }
+ }
+
+ /** The base class for all types */
+ abstract class Type extends TypeApiImpl with Annotatable[Type] {
+ /** Types for which asSeenFrom always is the identity, no matter what
+ * prefix or owner.
+ */
+ def isTrivial: Boolean = false
+
+ /** Is this type higher-kinded, i.e., is it a type constructor @M */
+ def isHigherKinded: Boolean = false
+
+ /** Does this type denote a stable reference (i.e. singleton type)? */
+ def isStable: Boolean = false
+
+ /** Is this type dangerous (i.e. it might contain conflicting
+ * type information when empty, so that it can be constructed
+ * so that type unsoundness results.) A dangerous type has an underlying
+ * type of the form T_1 with T_n { decls }, where one of the
+ * T_i (i > 1) is an abstract type.
+ */
+ def isVolatile: Boolean = false
+
+ /** Is this type guaranteed not to have `null` as a value? */
+ def isNotNull: Boolean = false
+
+ /** Is this type a structural refinement type (it ''refines'' members that have not been inherited) */
+ def isStructuralRefinement: Boolean = false
+
+ /** Does this type depend immediately on an enclosing method parameter?
+ * I.e., is it a singleton type whose termSymbol refers to an argument of the symbol's owner (which is a method)?
+ */
+ def isImmediatelyDependent: Boolean = false
+
+ /** Does this depend on an enclosing method parameter? */
+ def isDependent: Boolean = IsDependentCollector.collect(this)
+
+ /** True for WildcardType or BoundedWildcardType. */
+ def isWildcard = false
+
+ /** Is this type produced as a repair for an error? */
+ def isError: Boolean = typeSymbol.isError || termSymbol.isError
+
+ /** Is this type produced as a repair for an error? */
+ def isErroneous: Boolean = ErroneousCollector.collect(this)
+
+ /** Does this type denote a reference type which can be null? */
+ // def isNullable: Boolean = false
+
+ /** Can this type only be subtyped by bottom types?
+ * This is assessed to be the case if the class is final,
+ * and all type parameters (if any) are invariant.
+ */
+ def isFinalType =
+ typeSymbol.isFinal && (typeSymbol.typeParams forall (_.variance == 0))
+
+ /** Is this type completed (i.e. not a lazy type)? */
+ def isComplete: Boolean = true
+
+ /** If this is a lazy type, assign a new type to `sym`. */
+ def complete(sym: Symbol) {}
+
+ /** The term symbol associated with the type
+ * Note that the symbol of the normalized type is returned (@see normalize)
+ */
+ def termSymbol: Symbol = NoSymbol
+
+ /** The type symbol associated with the type
+ * Note that the symbol of the normalized type is returned (@see normalize)
+ * A type's typeSymbol should if possible not be inspected directly, due to
+ * the likelihood that what is true for tp.typeSymbol is not true for
+ * tp.sym, due to normalization.
+ */
+ def typeSymbol: Symbol = NoSymbol
+
+ /** The term symbol ''directly'' associated with the type.
+ */
+ def termSymbolDirect: Symbol = termSymbol
+
+ /** The type symbol ''directly'' associated with the type.
+ * In other words, no normalization is performed: if this is an alias type,
+ * the symbol returned is that of the alias, not the underlying type.
+ */
+ def typeSymbolDirect: Symbol = typeSymbol
+
+ /** The base type underlying a type proxy, identity on all other types */
+ def underlying: Type = this
+
+ /** Widen from singleton type to its underlying non-singleton
+ * base type by applying one or more `underlying` dereferences,
+ * identity for all other types.
+ *
+ * class Outer { class C ; val x: C }
+ * val o: Outer
+ * <o.x.type>.widen = o.C
+ */
+ def widen: Type = this
+
+ /** Map a constant type or not-null-type to its underlying base type,
+ * identity for all other types.
+ */
+ def deconst: Type = this
+
+ /** The type of `this` of a class type or reference type. */
+ def typeOfThis: Type = typeSymbol.typeOfThis
+
+ /** Map to a singleton type which is a subtype of this type.
+ * The fallback implemented here gives
+ * T.narrow = T' forSome { type T' <: T with Singleton }
+ * Overridden where we know more about where types come from.
+ */
+ /*
+ Note: this implementation of narrow is theoretically superior to the one
+ in use below, but imposed a significant performance penalty. It was in trunk
+ from svn r24960 through r25080.
+ */
+ /*
+ def narrow: Type =
+ if (phase.erasedTypes) this
+ else commonOwner(this) freshExistential ".type" setInfo singletonBounds(this) tpe
+ */
+
+ /** Map to a singleton type which is a subtype of this type.
+ * The fallback implemented here gives:
+ * {{{
+ * T.narrow = (T {}).this.type
+ * }}}
+ * Overridden where we know more about where types come from.
+ */
+ def narrow: Type =
+ if (phase.erasedTypes) this
+ else {
+ val cowner = commonOwner(this)
+ refinedType(List(this), cowner, EmptyScope, cowner.pos).narrow
+ }
+
+ /** For a TypeBounds type, itself;
+ * for a reference denoting an abstract type, its bounds,
+ * for all other types, a TypeBounds type all of whose bounds are this type.
+ */
+ def bounds: TypeBounds = TypeBounds(this, this)
+
+ /** For a class or intersection type, its parents.
+ * For a TypeBounds type, the parents of its hi bound.
+ * inherited by typerefs, singleton types, and refinement types,
+ * The empty list for all other types */
+ def parents: List[Type] = List()
+
+ /** For a class with nonEmpty parents, the first parent.
+ * Otherwise some specific fixed top type.
+ */
+ def firstParent = if (parents.nonEmpty) parents.head else ObjectClass.tpe
+
+ /** For a typeref or single-type, the prefix of the normalized type (@see normalize).
+ * NoType for all other types. */
+ def prefix: Type = NoType
+
+ /** A chain of all typeref or singletype prefixes of this type, longest first.
+ * (Only used from safeToString.)
+ */
+ def prefixChain: List[Type] = this match {
+ case TypeRef(pre, _, _) => pre :: pre.prefixChain
+ case SingleType(pre, _) => pre :: pre.prefixChain
+ case _ => List()
+ }
+
+ /** This type, without its type arguments @M */
+ def typeConstructor: Type = this
+
+ /** For a typeref, its arguments. The empty list for all other types */
+ def typeArgs: List[Type] = List()
+
+ /** A list of placeholder types derived from the type parameters.
+ * Used by RefinedType and TypeRef.
+ */
+ protected def dummyArgs: List[Type] = typeParams map (_.typeConstructor)
+
+ /** For a (nullary) method or poly type, its direct result type,
+ * the type itself for all other types. */
+ def resultType: Type = this
+
+ def resultType(actuals: List[Type]) = this
+
+ /** Only used for dependent method types. */
+ def resultApprox: Type = ApproximateDependentMap(resultType)
+
+ /** If this is a TypeRef `clazz`[`T`], return the argument `T`
+ * otherwise return this type
+ */
+ def remove(clazz: Symbol): Type = this
+
+ /** For a curried/nullary method or poly type its non-method result type,
+ * the type itself for all other types */
+ def finalResultType: Type = this
+
+ /** For a method type, the number of its value parameter sections,
+ * 0 for all other types */
+ def paramSectionCount: Int = 0
+
+ /** For a method or poly type, a list of its value parameter sections,
+ * the empty list for all other types */
+ def paramss: List[List[Symbol]] = List()
+
+ /** For a method or poly type, its first value parameter section,
+ * the empty list for all other types */
+ def params: List[Symbol] = List()
+
+ /** For a method or poly type, the types of its first value parameter section,
+ * the empty list for all other types */
+ def paramTypes: List[Type] = List()
+
+ /** For a (potentially wrapped) poly type, its type parameters,
+ * the empty list for all other types */
+ def typeParams: List[Symbol] = List()
+
+ /** For a (potentially wrapped) poly or existential type, its bound symbols,
+ * the empty list for all other types */
+ def boundSyms: immutable.Set[Symbol] = emptySymbolSet
+
+ /** Mixin a NotNull trait unless type already has one
+ * ...if the option is given, since it is causing typing bugs.
+ */
+ def notNull: Type =
+ if (!settings.Ynotnull.value || isNotNull || phase.erasedTypes) this
+ else NotNullType(this)
+
+ /** Replace formal type parameter symbols with actual type arguments.
+ *
+ * Amounts to substitution except for higher-kinded types. (See overridden method in TypeRef) -- @M
+ */
+ def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
+ if (sameLength(formals, actuals)) this.subst(formals, actuals) else ErrorType
+
+ /** If this type is an existential, turn all existentially bound variables to type skolems.
+ * @param owner The owner of the created type skolems
+ * @param origin The tree whose type was an existential for which the skolem was created.
+ */
+ def skolemizeExistential(owner: Symbol, origin: AnyRef): Type = this
+
+ /** A simple version of skolemizeExistential for situations where
+ * owner or unpack location do not matter (typically used in subtype tests)
+ */
+ def skolemizeExistential: Type = skolemizeExistential(NoSymbol, null)
+
+ /** Reduce to beta eta-long normal form.
+ * Expands type aliases and converts higher-kinded TypeRefs to PolyTypes.
+ * Functions on types are also implemented as PolyTypes.
+ *
+ * Example: (in the below, <List> is the type constructor of List)
+ * TypeRef(pre, <List>, List()) is replaced by
+ * PolyType(X, TypeRef(pre, <List>, List(X)))
+ */
+ def normalize = this // @MAT
+
+ /** Expands type aliases. */
+ def dealias = this
+
+ /** For a classtype or refined type, its defined or declared members;
+ * inherited by subtypes and typerefs.
+ * The empty scope for all other types.
+ */
+ def decls: Scope = EmptyScope
+
+ /** The defined or declared members with name `name` in this type;
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ * Alternatives of overloaded symbol appear in the order they are declared.
+ */
+ def decl(name: Name): Symbol = findDecl(name, 0)
+
+ /** A list of all non-private members defined or declared in this type. */
+ def nonPrivateDecls: List[Symbol] = decls filter (x => !x.isPrivate) toList
+
+ /** The non-private defined or declared members with name `name` in this type;
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ * Alternatives of overloaded symbol appear in the order they are declared.
+ */
+ def nonPrivateDecl(name: Name): Symbol = findDecl(name, PRIVATE)
+
+ /** A list of all members of this type (defined or inherited)
+ * Members appear in linearization order of their owners.
+ * Members with the same owner appear in reverse order of their declarations.
+ */
+ def members: List[Symbol] = membersBasedOnFlags(0, 0)
+
+ /** A list of all non-private members of this type (defined or inherited) */
+ def nonPrivateMembers: List[Symbol] = membersBasedOnFlags(BridgeAndPrivateFlags, 0)
+
+ /** A list of all non-private members of this type (defined or inherited),
+ * admitting members with given flags `admit`
+ */
+ def nonPrivateMembersAdmitting(admit: Long): List[Symbol] = membersBasedOnFlags(BridgeAndPrivateFlags & ~admit, 0)
+
+ /** A list of all implicit symbols of this type (defined or inherited) */
+ def implicitMembers: List[Symbol] = membersBasedOnFlags(BridgeFlags, IMPLICIT)
+
+ /** A list of all deferred symbols of this type (defined or inherited) */
+ def deferredMembers: List[Symbol] = membersBasedOnFlags(BridgeFlags, DEFERRED)
+
+ /** The member with given name,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist */
+ def member(name: Name): Symbol =
+ memberBasedOnName(name, BridgeFlags)
+
+ /** The non-private member with given name,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist.
+ * Bridges are excluded from the result
+ */
+ def nonPrivateMember(name: Name): Symbol =
+ memberBasedOnName(name, BridgeAndPrivateFlags)
+
+ /** All members with the given flags, excluding bridges.
+ */
+ def membersWithFlags(requiredFlags: Long): List[Symbol] =
+ membersBasedOnFlags(BridgeFlags, requiredFlags)
+
+ /** All non-private members with the given flags, excluding bridges.
+ */
+ def nonPrivateMembersWithFlags(requiredFlags: Long): List[Symbol] =
+ membersBasedOnFlags(BridgeAndPrivateFlags, requiredFlags)
+
+ /** The non-private member with given name, admitting members with given flags `admit`.
+ * "Admitting" refers to the fact that members with a PRIVATE, BRIDGE, or VBRIDGE
+ * flag are usually excluded from findMember results, but supplying any of those flags
+ * to this method disables that exclusion.
+ *
+ * An OverloadedSymbol if several exist, NoSymbol if none exists.
+ */
+ def nonPrivateMemberAdmitting(name: Name, admit: Long): Symbol =
+ memberBasedOnName(name, BridgeAndPrivateFlags & ~admit)
+
+ /** The non-local member with given name,
+ * an OverloadedSymbol if several exist, NoSymbol if none exist */
+ def nonLocalMember(name: Name): Symbol =
+ memberBasedOnName(name, BridgeFlags | LOCAL)
+
+ /** Members excluding and requiring the given flags.
+ * Note: unfortunately it doesn't work to exclude DEFERRED this way.
+ */
+ def membersBasedOnFlags(excludedFlags: Long, requiredFlags: Long): List[Symbol] =
+ findMember(nme.ANYNAME, excludedFlags, requiredFlags, false).alternatives
+
+ def memberBasedOnName(name: Name, excludedFlags: Long): Symbol =
+ findMember(name, excludedFlags, 0, false)
+
+ /** The least type instance of given class which is a supertype
+ * of this type. Example:
+ * class D[T]
+ * class C extends p.D[Int]
+ * ThisType(C).baseType(D) = p.D[Int]
+ */
+ def baseType(clazz: Symbol): Type = NoType
+
+ /** This type as seen from prefix `pre` and class `clazz`. This means:
+ * Replace all thistypes of `clazz` or one of its subclasses
+ * by `pre` and instantiate all parameters by arguments of `pre`.
+ * Proceed analogously for thistypes referring to outer classes.
+ *
+ * Example:
+ * class D[T] { def m: T }
+ * class C extends p.D[Int]
+ * T.asSeenFrom(ThisType(C), D) (where D is owner of m)
+ * = Int
+ */
+ def asSeenFrom(pre: Type, clazz: Symbol): Type = {
+ if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this
+ else {
+// scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") {
+ incCounter(asSeenFromCount)
+ val start = startTimer(asSeenFromNanos)
+ val m = new AsSeenFromMap(pre.normalize, clazz)
+ val tp = m apply this
+ val tp1 = existentialAbstraction(m.capturedParams, tp)
+ val result: Type =
+ if (m.capturedSkolems.isEmpty) tp1
+ else deriveType(m.capturedSkolems, _.cloneSymbol setFlag CAPTURED)(tp1)
+
+ stopTimer(asSeenFromNanos, start)
+ result
+ }
+ }
+
+ /** The info of `sym`, seen as a member of this type.
+ *
+ * Example:
+ * {{{
+ * class D[T] { def m: T }
+ * class C extends p.D[Int]
+ * ThisType(C).memberType(m) = Int
+ * }}}
+ */
+ def memberInfo(sym: Symbol): Type = {
+ sym.info.asSeenFrom(this, sym.owner)
+ }
+
+ /** The type of `sym`, seen as a member of this type. */
+ def memberType(sym: Symbol): Type = sym match {
+ case meth: MethodSymbol =>
+ meth.typeAsMemberOf(this)
+ case _ =>
+ computeMemberType(sym)
+ }
+
+ def computeMemberType(sym: Symbol): Type = sym.tpeHK match { //@M don't prematurely instantiate higher-kinded types, they will be instantiated by transform, typedTypeApply, etc. when really necessary
+ case OverloadedType(_, alts) =>
+ OverloadedType(this, alts)
+ case tp =>
+ tp.asSeenFrom(this, sym.owner)
+ }
+
+ /** Substitute types `to` for occurrences of references to
+ * symbols `from` in this type.
+ */
+ def subst(from: List[Symbol], to: List[Type]): Type =
+ if (from.isEmpty) this
+ else new SubstTypeMap(from, to) apply this
+
+ /** Substitute symbols `to` for occurrences of symbols `from` in this type.
+ *
+ * !!! NOTE !!!: If you need to do a substThis and a substSym, the substThis has to come
+ * first, as otherwise symbols will immediately get rebound in typeRef to the old
+ * symbol.
+ */
+ def substSym(from: List[Symbol], to: List[Symbol]): Type =
+ if ((from eq to) || from.isEmpty) this
+ else new SubstSymMap(from, to) apply this
+
+ /** Substitute all occurrences of `ThisType(from)` in this type by `to`.
+ *
+ * !!! NOTE !!!: If you need to do a substThis and a substSym, the substThis has to come
+ * first, as otherwise symbols will immediately get rebound in typeRef to the old
+ * symbol.
+ */
+ def substThis(from: Symbol, to: Type): Type =
+ new SubstThisMap(from, to) apply this
+ def substThis(from: Symbol, to: Symbol): Type =
+ substThis(from, to.thisType)
+
+ /** Performs both substThis and substSym, in that order.
+ *
+ * [JZ] Reverted `SubstThisAndSymMap` from 334872, which was not the same as
+ * `substThis(from, to).substSym(symsFrom, symsTo)`.
+ *
+ * `SubstThisAndSymMap` performs a breadth-first map over this type, which meant that
+ * symbol substitution occured before `ThisType` substitution. Consequently, in substitution
+ * of a `SingleType(ThisType(`from`), sym), symbols were rebound to `from` rather than `to`.
+ */
+ def substThisAndSym(from: Symbol, to: Type, symsFrom: List[Symbol], symsTo: List[Symbol]): Type =
+ if (symsFrom eq symsTo) substThis(from, to)
+ else substThis(from, to).substSym(symsFrom, symsTo)
+
+ /** Returns all parts of this type which satisfy predicate `p` */
+ def filter(p: Type => Boolean): List[Type] = new FilterTypeCollector(p) collect this
+ def withFilter(p: Type => Boolean) = new FilterMapForeach(p)
+
+ class FilterMapForeach(p: Type => Boolean) extends FilterTypeCollector(p){
+ def foreach[U](f: Type => U): Unit = collect(Type.this) foreach f
+ def map[T](f: Type => T): List[T] = collect(Type.this) map f
+ }
+
+ /** Returns optionally first type (in a preorder traversal) which satisfies predicate `p`,
+ * or None if none exists.
+ */
+ def find(p: Type => Boolean): Option[Type] = new FindTypeCollector(p).collect(this)
+
+ /** Apply `f` to each part of this type */
+ def foreach(f: Type => Unit) { new ForEachTypeTraverser(f).traverse(this) }
+
+ /** Apply `pf' to each part of this type on which the function is defined */
+ def collect[T](pf: PartialFunction[Type, T]): List[T] = new CollectTypeCollector(pf).collect(this)
+
+ /** Apply `f` to each part of this type; children get mapped before their parents */
+ def map(f: Type => Type): Type = new TypeMap {
+ def apply(x: Type) = f(mapOver(x))
+ } apply this
+
+ /** Is there part of this type which satisfies predicate `p`? */
+ def exists(p: Type => Boolean): Boolean = !find(p).isEmpty
+
+ /** Does this type contain a reference to this symbol? */
+ def contains(sym: Symbol): Boolean = new ContainsCollector(sym).collect(this)
+
+ /** Does this type contain a reference to this type */
+ def containsTp(tp: Type): Boolean = new ContainsTypeCollector(tp).collect(this)
+
+ /** Is this type a subtype of that type? */
+ def <:<(that: Type): Boolean = {
+ if (util.Statistics.enabled) stat_<:<(that)
+ else {
+ (this eq that) ||
+ (if (explainSwitch) explain("<:", isSubType, this, that)
+ else isSubType(this, that, AnyDepth))
+ }
+ }
+
+ /** Is this type a subtype of that type in a pattern context?
+ * Any type arguments on the right hand side are replaced with
+ * fresh existentials, except for Arrays.
+ *
+ * See bug1434.scala for an example of code which would fail
+ * if only a <:< test were applied.
+ */
+ def matchesPattern(that: Type): Boolean = {
+ (this <:< that) || ((this, that) match {
+ case (TypeRef(_, ArrayClass, List(arg1)), TypeRef(_, ArrayClass, List(arg2))) if arg2.typeSymbol.typeParams.nonEmpty =>
+ arg1 matchesPattern arg2
+ case (_, TypeRef(_, _, args)) =>
+ val newtp = existentialAbstraction(args map (_.typeSymbol), that)
+ !(that =:= newtp) && (this <:< newtp)
+ case _ =>
+ false
+ })
+ }
+
+ def stat_<:<(that: Type): Boolean = {
+ incCounter(subtypeCount)
+ val start = startTimer(subtypeNanos)
+ val result =
+ (this eq that) ||
+ (if (explainSwitch) explain("<:", isSubType, this, that)
+ else isSubType(this, that, AnyDepth))
+ stopTimer(subtypeNanos, start)
+ result
+ }
+
+ /** Is this type a weak subtype of that type? True also for numeric types, i.e. Int weak_<:< Long.
+ */
+ def weak_<:<(that: Type): Boolean = {
+ incCounter(subtypeCount)
+ val start = startTimer(subtypeNanos)
+ val result =
+ ((this eq that) ||
+ (if (explainSwitch) explain("weak_<:", isWeakSubType, this, that)
+ else isWeakSubType(this, that)))
+ stopTimer(subtypeNanos, start)
+ result
+ }
+
+ /** Is this type equivalent to that type? */
+ def =:=(that: Type): Boolean = (
+ (this eq that) ||
+ (if (explainSwitch) explain("=", isSameType, this, that)
+ else isSameType(this, that))
+ );
+
+ /** Does this type implement symbol `sym` with same or stronger type? */
+ def specializes(sym: Symbol): Boolean =
+ if (explainSwitch) explain("specializes", specializesSym, this, sym)
+ else specializesSym(this, sym)
+
+ /** Is this type close enough to that type so that members
+ * with the two type would override each other?
+ * This means:
+ * - Either both types are polytypes with the same number of
+ * type parameters and their result types match after renaming
+ * corresponding type parameters
+ * - Or both types are (nullary) method types with equivalent type parameter types
+ * and matching result types
+ * - Or both types are equivalent
+ * - Or phase.erasedTypes is false and both types are neither method nor
+ * poly types.
+ */
+ def matches(that: Type): Boolean = matchesType(this, that, !phase.erasedTypes)
+
+ /** Same as matches, except that non-method types are always assumed to match. */
+ def looselyMatches(that: Type): Boolean = matchesType(this, that, true)
+
+ /** The shortest sorted upwards closed array of types that contains
+ * this type as first element.
+ *
+ * A list or array of types ts is upwards closed if
+ *
+ * for all t in ts:
+ * for all typerefs p.s[args] such that t <: p.s[args]
+ * there exists a typeref p'.s[args'] in ts such that
+ * t <: p'.s['args] <: p.s[args],
+ *
+ * and
+ *
+ * for all singleton types p.s such that t <: p.s
+ * there exists a singleton type p'.s in ts such that
+ * t <: p'.s <: p.s
+ *
+ * Sorting is with respect to Symbol.isLess() on type symbols.
+ */
+ def baseTypeSeq: BaseTypeSeq = baseTypeSingletonSeq(this)
+
+ /** The maximum depth (@see maxDepth)
+ * of each type in the BaseTypeSeq of this type.
+ */
+ def baseTypeSeqDepth: Int = 1
+
+ /** The list of all baseclasses of this type (including its own typeSymbol)
+ * in reverse linearization order, starting with the class itself and ending
+ * in class Any.
+ */
+ def baseClasses: List[Symbol] = List()
+
+ /**
+ * @param sym the class symbol
+ * @return the index of given class symbol in the BaseTypeSeq of this type,
+ * or -1 if no base type with given class symbol exists.
+ */
+ def baseTypeIndex(sym: Symbol): Int = {
+ val bts = baseTypeSeq
+ var lo = 0
+ var hi = bts.length - 1
+ while (lo <= hi) {
+ val mid = (lo + hi) / 2
+ val btssym = bts.typeSymbol(mid)
+ if (sym == btssym) return mid
+ else if (sym isLess btssym) hi = mid - 1
+ else if (btssym isLess sym) lo = mid + 1
+ else abort()
+ }
+ -1
+ }
+
+ /** If this is a poly- or methodtype, a copy with cloned type / value parameters
+ * owned by `owner`. Identity for all other types.
+ */
+ def cloneInfo(owner: Symbol) = this
+
+ /** Make sure this type is correct as the info of given owner; clone it if not. */
+ def atOwner(owner: Symbol) = this
+
+ protected def objectPrefix = "object "
+ protected def packagePrefix = "package "
+ def trimPrefix(str: String) = str stripPrefix objectPrefix stripPrefix packagePrefix
+
+ /** The string representation of this type used as a prefix */
+ def prefixString = trimPrefix(toString) + "#"
+
+ /** Convert toString avoiding infinite recursions by cutting off
+ * after `maxTostringRecursions` recursion levels. Uses `safeToString`
+ * to produce a string on each level.
+ */
+ override def toString: String = typeToString(this)
+
+ /** Method to be implemented in subclasses.
+ * Converts this type to a string in calling toString for its parts.
+ */
+ def safeToString: String = super.toString
+
+ /** The string representation of this type, with singletypes explained. */
+ def toLongString = {
+ val str = toString
+ if (str == "type") widen.toString
+ else if ((str endsWith ".type") && !typeSymbol.isModuleClass) str + " (with underlying type " + widen + ")"
+ else str
+ }
+
+ /** The string representation of this type when the direct object in a sentence.
+ * Normally this is no different from the regular representation, but modules
+ * read better as "object Foo" here and "Foo.type" the rest of the time.
+ */
+ def directObjectString = safeToString
+
+ /** A test whether a type contains any unification type variables.
+ * Overridden with custom logic except where trivially true.
+ */
+ def isGround: Boolean = this match {
+ case ThisType(_) | NoPrefix | WildcardType | NoType | ErrorType | ConstantType(_) =>
+ true
+ case _ =>
+ typeVarToOriginMap(this) eq this
+ }
+
+ /** If this is a symbol loader type, load and assign a new type to `sym`. */
+ def load(sym: Symbol) {}
+
+ private def findDecl(name: Name, excludedFlags: Int): Symbol = {
+ var alts: List[Symbol] = List()
+ var sym: Symbol = NoSymbol
+ var e: ScopeEntry = decls.lookupEntry(name)
+ while (e ne null) {
+ if (!e.sym.hasFlag(excludedFlags)) {
+ if (sym == NoSymbol) sym = e.sym
+ else {
+ if (alts.isEmpty) alts = List(sym)
+ alts = e.sym :: alts
+ }
+ }
+ e = decls.lookupNextEntry(e)
+ }
+ if (alts.isEmpty) sym
+ else (baseClasses.head.newOverloaded(this, alts))
+ }
+
+ /**
+ * Find member(s) in this type. If several members matching criteria are found, they are
+ * returned in an OverloadedSymbol
+ *
+ * @param name The member's name, where nme.ANYNAME means `unspecified`
+ * @param excludedFlags Returned members do not have these flags
+ * @param requiredFlags Returned members do have these flags
+ * @param stableOnly If set, return only members that are types or stable values
+ */
+ //TODO: use narrow only for modules? (correct? efficiency gain?)
+ def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = {
+ // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by
+ // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements
+ // without this, the matchesType call would lead to type variables on both sides
+ // of a subtyping/equality judgement, which can lead to recursive types being constructed.
+ // See (t0851) for a situation where this happens.
+ val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this)
+
+ incCounter(findMemberCount)
+ val start = startTimer(findMemberNanos)
+
+ //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
+ var members: Scope = null
+ var member: Symbol = NoSymbol
+ var excluded = excludedFlags | DEFERRED
+ var continue = true
+ var self: Type = null
+ var membertpe: Type = null
+ while (continue) {
+ continue = false
+ val bcs0 = baseClasses
+ var bcs = bcs0
+ while (!bcs.isEmpty) {
+ val decls = bcs.head.info.decls
+ var entry =
+ if (name == nme.ANYNAME) decls.elems else decls.lookupEntry(name)
+ while (entry ne null) {
+ val sym = entry.sym
+ if (sym hasAllFlags requiredFlags) {
+ val excl = sym.getFlag(excluded)
+ if (excl == 0L &&
+ (// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
+ (bcs eq bcs0) ||
+ !sym.isPrivateLocal ||
+ (bcs0.head.hasTransOwner(bcs.head)))) {
+ if (name.isTypeName || stableOnly && sym.isStable) {
+ stopTimer(findMemberNanos, start)
+ if (suspension ne null) suspension foreach (_.suspended = false)
+ return sym
+ } else if (member == NoSymbol) {
+ member = sym
+ } else if (members eq null) {
+ if (member.name != sym.name ||
+ !(member == sym ||
+ member.owner != sym.owner &&
+ !sym.isPrivate && {
+ if (self eq null) self = this.narrow
+ if (membertpe eq null) membertpe = self.memberType(member)
+ (membertpe matches self.memberType(sym))
+ })) {
+ members = newScope
+ members enter member
+ members enter sym
+ }
+ } else {
+ var prevEntry = members.lookupEntry(sym.name)
+ var symtpe: Type = null
+ while ((prevEntry ne null) &&
+ !(prevEntry.sym == sym ||
+ prevEntry.sym.owner != sym.owner &&
+ !sym.hasFlag(PRIVATE) && {
+ if (self eq null) self = this.narrow
+ if (symtpe eq null) symtpe = self.memberType(sym)
+ self.memberType(prevEntry.sym) matches symtpe
+ })) {
+ prevEntry = members lookupNextEntry prevEntry
+ }
+ if (prevEntry eq null) {
+ members enter sym
+ }
+ }
+ } else if (excl == DEFERRED.toLong) {
+ continue = true
+ }
+ }
+ entry = if (name == nme.ANYNAME) entry.next else decls lookupNextEntry entry
+ } // while (entry ne null)
+ // excluded = excluded | LOCAL
+ bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail
+ } // while (!bcs.isEmpty)
+ excluded = excludedFlags
+ } // while (continue)
+ stopTimer(findMemberNanos, start)
+ if (suspension ne null) suspension foreach (_.suspended = false)
+ if (members eq null) {
+ if (member == NoSymbol) incCounter(noMemberCount)
+ member
+ } else {
+ incCounter(multMemberCount)
+ baseClasses.head.newOverloaded(this, members.toList)
+ }
+ }
+ /** The (existential or otherwise) skolems and existentially quantified variables which are free in this type */
+ def skolemsExceptMethodTypeParams: List[Symbol] = {
+ var boundSyms: List[Symbol] = List()
+ var skolems: List[Symbol] = List()
+ for (t <- this) {
+ t match {
+ case ExistentialType(quantified, qtpe) =>
+ boundSyms = boundSyms ::: quantified
+ case TypeRef(_, sym, _) =>
+ if ((sym.isExistentialSkolem || sym.isGADTSkolem) && // treat GADT skolems like existential skolems
+ !((boundSyms contains sym) || (skolems contains sym)))
+ skolems = sym :: skolems
+ case _ =>
+ }
+ }
+ skolems
+ }
+
+ // Implementation of Annotatable for all types but AnnotatedType, which
+ // overrides these.
+ def annotations: List[AnnotationInfo] = Nil
+ def withoutAnnotations: Type = this
+ def filterAnnotations(p: AnnotationInfo => Boolean): Type = this
+ def setAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this)
+ def withAnnotations(annots: List[AnnotationInfo]): Type = annotatedType(annots, this)
+
+ /** Remove any annotations from this type and from any
+ * types embedded in this type. */
+ def stripAnnotations = StripAnnotationsMap(this)
+
+ /** Set the self symbol of an annotated type, or do nothing
+ * otherwise. */
+ def withSelfsym(sym: Symbol) = this
+
+ /** The selfsym of an annotated type, or NoSymbol of anything else */
+ def selfsym: Symbol = NoSymbol
+
+ /** The kind of this type; used for debugging */
+ def kind: String = "unknown type of class "+getClass()
+ }
+
+// Subclasses ------------------------------------------------------------
+
+ trait UniqueType extends Product {
+ final override val hashCode = scala.runtime.ScalaRunTime._hashCode(this)
+ }
+
+ /** A base class for types that defer some operations
+ * to their immediate supertype.
+ */
+ abstract class SubType extends Type {
+ def supertype: Type
+ override def parents: List[Type] = supertype.parents
+ override def decls: Scope = supertype.decls
+ override def baseType(clazz: Symbol): Type = supertype.baseType(clazz)
+ override def baseTypeSeq: BaseTypeSeq = supertype.baseTypeSeq
+ override def baseTypeSeqDepth: Int = supertype.baseTypeSeqDepth
+ override def baseClasses: List[Symbol] = supertype.baseClasses
+ override def isNotNull = supertype.isNotNull
+ }
+
+ case class NotNullType(override val underlying: Type) extends SubType with RewrappingTypeProxy {
+ def supertype = underlying
+ protected def rewrap(newtp: Type): Type = NotNullType(newtp)
+ override def isNotNull: Boolean = true
+ override def notNull = this
+ override def deconst: Type = underlying //todo: needed?
+ override def safeToString: String = underlying.toString + " with NotNull"
+ override def kind = "NotNullType"
+ }
+
+ /** A base class for types that represent a single value
+ * (single-types and this-types).
+ */
+ abstract class SingletonType extends SubType with SimpleTypeProxy {
+ def supertype = underlying
+ override def isTrivial = false
+ override def isStable = true
+ override def isVolatile = underlying.isVolatile
+ override def widen: Type = underlying.widen
+ override def baseTypeSeq: BaseTypeSeq = {
+ incCounter(singletonBaseTypeSeqCount)
+ underlying.baseTypeSeq prepend this
+ }
+ override def isHigherKinded = false // singleton type classifies objects, thus must be kind *
+ override def safeToString: String = {
+ // Avoiding printing Predef.type and scala.package.type as "type",
+ // since in all other cases we omit those prefixes.
+ val pre = underlying.typeSymbol.skipPackageObject
+ if (pre.isOmittablePrefix) pre.fullName + ".type"
+ else prefixString + "type"
+ }
+
+/*
+ override def typeOfThis: Type = typeSymbol.typeOfThis
+ override def bounds: TypeBounds = TypeBounds(this, this)
+ override def prefix: Type = NoType
+ override def typeArgs: List[Type] = List()
+ override def typeParams: List[Symbol] = List()
+*/
+ }
+
+ /** An object representing an erroneous type */
+ case object ErrorType extends Type {
+ // todo see whether we can do without
+ override def isError: Boolean = true
+ override def decls: Scope = new ErrorScope(NoSymbol)
+ override def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = {
+ var sym = decls lookup name
+ if (sym == NoSymbol) {
+ sym = NoSymbol.newErrorSymbol(name)
+ decls enter sym
+ }
+ sym
+ }
+ override def baseType(clazz: Symbol): Type = this
+ override def safeToString: String = "<error>"
+ override def narrow: Type = this
+ // override def isNullable: Boolean = true
+ override def kind = "ErrorType"
+ }
+
+ /** An object representing an unknown type, used during type inference.
+ * If you see WildcardType outside of inference it is almost certainly a bug.
+ */
+ case object WildcardType extends Type {
+ override def isWildcard = true
+ override def safeToString: String = "?"
+ // override def isNullable: Boolean = true
+ override def kind = "WildcardType"
+ }
+ /** BoundedWildcardTypes, used only during type inference, are created in
+ * two places that I can find:
+ *
+ * 1. If the expected type of an expression is an existential type,
+ * its hidden symbols are replaced with bounded wildcards.
+ * 2. When an implicit conversion is being sought based in part on
+ * the name of a method in the converted type, a HasMethodMatching
+ * type is created: a MethodType with parameters typed as
+ * BoundedWildcardTypes.
+ */
+ case class BoundedWildcardType(override val bounds: TypeBounds) extends Type with BoundedWildcardTypeApi {
+ override def isWildcard = true
+ override def safeToString: String = "?" + bounds
+ override def kind = "BoundedWildcardType"
+ }
+
+ object BoundedWildcardType extends BoundedWildcardTypeExtractor
+
+ /** An object representing a non-existing type */
+ case object NoType extends Type {
+ override def isTrivial: Boolean = true
+ override def safeToString: String = "<notype>"
+ // override def isNullable: Boolean = true
+ override def kind = "NoType"
+ }
+
+ /** An object representing a non-existing prefix */
+ case object NoPrefix extends Type {
+ override def isTrivial: Boolean = true
+ override def isStable: Boolean = true
+ override def prefixString = ""
+ override def safeToString: String = "<noprefix>"
+ // override def isNullable: Boolean = true
+ override def kind = "NoPrefixType"
+ }
+
+ /** A class for this-types of the form <sym>.this.type
+ */
+ abstract case class ThisType(sym: Symbol) extends SingletonType with ThisTypeApi {
+ assert(sym.isClass)
+ //assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym)
+ override def isTrivial: Boolean = sym.isPackageClass
+ override def isNotNull = true
+ override def typeSymbol = sym
+ override def underlying: Type = sym.typeOfThis
+ override def isVolatile = false
+ override def isHigherKinded = sym.isRefinementClass && underlying.isHigherKinded
+ override def prefixString =
+ if (settings.debug.value) sym.nameString + ".this."
+ else if (sym.isAnonOrRefinementClass) "this."
+ else if (sym.isOmittablePrefix) ""
+ else if (sym.isModuleClass) sym.fullNameString + "."
+ else sym.nameString + ".this."
+ override def safeToString: String =
+ if (sym.isEffectiveRoot) "" + sym.name
+ else super.safeToString
+ override def narrow: Type = this
+ override def kind = "ThisType"
+ }
+
+ final class UniqueThisType(sym: Symbol) extends ThisType(sym) with UniqueType { }
+
+ object ThisType extends ThisTypeExtractor {
+ def apply(sym: Symbol): Type = {
+ if (!phase.erasedTypes) unique(new UniqueThisType(sym))
+ else if (sym.isImplClass) sym.typeOfThis
+ else sym.tpe
+ }
+ }
+
+ /** A class for singleton types of the form `<prefix>.<sym.name>.type`.
+ * Cannot be created directly; one should always use `singleType` for creation.
+ */
+ abstract case class SingleType(pre: Type, sym: Symbol) extends SingletonType with SingleTypeApi {
+ override val isTrivial: Boolean = pre.isTrivial
+ override def isGround = sym.isPackageClass || pre.isGround
+
+ // override def isNullable = underlying.isNullable
+ override def isNotNull = underlying.isNotNull
+ private[reflect] var underlyingCache: Type = NoType
+ private[reflect] var underlyingPeriod = NoPeriod
+ override def underlying: Type = {
+ val cache = underlyingCache
+ if (underlyingPeriod == currentPeriod && cache != null) cache
+ else {
+ defineUnderlyingOfSingleType(this)
+ underlyingCache
+ }
+ }
+
+ // more precise conceptually, but causes cyclic errors: (paramss exists (_ contains sym))
+ override def isImmediatelyDependent = (sym ne NoSymbol) && (sym.owner.isMethod && sym.isValueParameter)
+
+ override def isVolatile : Boolean = underlying.isVolatile && !sym.isStable
+/*
+ override def narrow: Type = {
+ if (phase.erasedTypes) this
+ else {
+ val thissym = refinedType(List(this), sym.owner, EmptyScope).typeSymbol
+ if (sym.owner != NoSymbol) {
+ //Console.println("narrowing module " + sym + thissym.owner);
+ thissym.typeOfThis = this
+ }
+ thissym.thisType
+ }
+ }
+*/
+ override def narrow: Type = this
+
+ override def termSymbol = sym
+ override def prefix: Type = pre
+ override def prefixString = (
+ if (sym.skipPackageObject.isOmittablePrefix) ""
+ else if (sym.isPackageObjectOrClass) pre.prefixString
+ else pre.prefixString + sym.nameString + "."
+ )
+ override def kind = "SingleType"
+ }
+
+ final class UniqueSingleType(pre: Type, sym: Symbol) extends SingleType(pre, sym) with UniqueType { }
+
+ object SingleType extends SingleTypeExtractor {
+ def apply(pre: Type, sym: Symbol): Type = {
+ unique(new UniqueSingleType(pre, sym))
+ }
+ }
+
+ protected def defineUnderlyingOfSingleType(tpe: SingleType) = {
+ val period = tpe.underlyingPeriod
+ if (period != currentPeriod) {
+ tpe.underlyingPeriod = currentPeriod
+ if (!isValid(period)) {
+ // [Eugene to Paul] needs review
+ tpe.underlyingCache = if (tpe.sym == NoSymbol) ThisType(rootMirror.RootClass) else tpe.pre.memberType(tpe.sym).resultType;
+ assert(tpe.underlyingCache ne tpe, tpe)
+ }
+ }
+ }
+
+ abstract case class SuperType(thistpe: Type, supertpe: Type) extends SingletonType with SuperTypeApi {
+ override val isTrivial: Boolean = thistpe.isTrivial && supertpe.isTrivial
+ override def isNotNull = true;
+ override def typeSymbol = thistpe.typeSymbol
+ override def underlying = supertpe
+ override def prefix: Type = supertpe.prefix
+ override def prefixString = thistpe.prefixString.replaceAll("""\bthis\.$""", "super.")
+ override def narrow: Type = thistpe.narrow
+ override def kind = "SuperType"
+ }
+
+ final class UniqueSuperType(thistp: Type, supertp: Type) extends SuperType(thistp, supertp) with UniqueType { }
+
+ object SuperType extends SuperTypeExtractor {
+ def apply(thistp: Type, supertp: Type): Type = {
+ if (phase.erasedTypes) supertp
+ else unique(new UniqueSuperType(thistp, supertp))
+ }
+ }
+
+ /** A class for the bounds of abstract types and type parameters
+ */
+ abstract case class TypeBounds(lo: Type, hi: Type) extends SubType with TypeBoundsApi {
+ def supertype = hi
+ override val isTrivial: Boolean = lo.isTrivial && hi.isTrivial
+ override def bounds: TypeBounds = this
+ def containsType(that: Type) = that match {
+ case TypeBounds(_, _) => that <:< this
+ case _ => lo <:< that && that <:< hi
+ }
+ private def lowerString = if (emptyLowerBound) "" else " >: " + lo
+ private def upperString = if (emptyUpperBound) "" else " <: " + hi
+ private def emptyLowerBound = lo.typeSymbolDirect eq NothingClass
+ private def emptyUpperBound = hi.typeSymbolDirect eq AnyClass
+ def isEmptyBounds = emptyLowerBound && emptyUpperBound
+
+ // override def isNullable: Boolean = NullClass.tpe <:< lo;
+ override def safeToString = lowerString + upperString
+ override def kind = "TypeBoundsType"
+ }
+
+ final class UniqueTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) with UniqueType { }
+
+ object TypeBounds extends TypeBoundsExtractor {
+ def empty: TypeBounds = apply(NothingClass.tpe, AnyClass.tpe)
+ def upper(hi: Type): TypeBounds = apply(NothingClass.tpe, hi)
+ def lower(lo: Type): TypeBounds = apply(lo, AnyClass.tpe)
+ def apply(lo: Type, hi: Type): TypeBounds = {
+ unique(new UniqueTypeBounds(lo, hi)).asInstanceOf[TypeBounds]
+ }
+ }
+
+ /** A common base class for intersection types and class types
+ */
+ abstract class CompoundType extends Type {
+
+ private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
+ private[reflect] var baseTypeSeqPeriod = NoPeriod
+ private[reflect] var baseClassesCache: List[Symbol] = _
+ private[reflect] var baseClassesPeriod = NoPeriod
+
+ override def baseTypeSeq: BaseTypeSeq = {
+ val cached = baseTypeSeqCache
+ if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq)
+ cached
+ else {
+ defineBaseTypeSeqOfCompoundType(this)
+ if (baseTypeSeqCache eq undetBaseTypeSeq)
+ throw new RecoverableCyclicReference(typeSymbol)
+
+ baseTypeSeqCache
+ }
+ }
+
+ override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth
+
+ override def baseClasses: List[Symbol] = {
+ val cached = baseClassesCache
+ if (baseClassesPeriod == currentPeriod && cached != null) cached
+ else {
+ defineBaseClassesOfCompoundType(this)
+ if (baseClassesCache eq null)
+ throw new RecoverableCyclicReference(typeSymbol)
+
+ baseClassesCache
+ }
+ }
+
+ /** The slightly less idiomatic use of Options is due to
+ * performance considerations. A version using for comprehensions
+ * might be too slow (this is deemed a hotspot of the type checker).
+ *
+ * See with Martin before changing this method.
+ */
+ def memo[A](op1: => A)(op2: Type => A): A = {
+ def updateCache(): A = {
+ intersectionWitness(parents) = new WeakReference(this)
+ op1
+ }
+
+ intersectionWitness get parents match {
+ case Some(ref) =>
+ ref.get match {
+ case Some(w) => if (w eq this) op1 else op2(w)
+ case None => updateCache()
+ }
+ case None => updateCache()
+ }
+ }
+
+ override def baseType(sym: Symbol): Type = {
+ val index = baseTypeIndex(sym)
+ if (index >= 0) baseTypeSeq(index) else NoType
+ }
+
+ override def narrow: Type = typeSymbol.thisType
+ override def isNotNull: Boolean = parents exists (_.isNotNull)
+
+ override def isStructuralRefinement: Boolean =
+ typeSymbol.isAnonOrRefinementClass && decls.exists(_.isPossibleInRefinement)
+
+ // override def isNullable: Boolean =
+ // parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
+
+ override def safeToString: String = parentsString(parents) + (
+ (if (settings.debug.value || parents.isEmpty || (decls.elems ne null))
+ decls.mkString("{", "; ", "}") else "")
+ )
+ }
+
+ protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = {
+ val period = tpe.baseTypeSeqPeriod
+ if (period != currentPeriod) {
+ tpe.baseTypeSeqPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ if (tpe.parents.exists(_.exists(_.isInstanceOf[TypeVar]))) {
+ // rename type vars to fresh type params, take base type sequence of
+ // resulting type, and rename back all the entries in that sequence
+ var tvs = Set[TypeVar]()
+ for (p <- tpe.parents)
+ for (t <- p) t match {
+ case tv: TypeVar => tvs += tv
+ case _ =>
+ }
+ val varToParamMap: Map[Type, Symbol] =
+ mapFrom[TypeVar, Type, Symbol](tvs.toList)(_.origin.typeSymbol.cloneSymbol)
+ val paramToVarMap = varToParamMap map (_.swap)
+ val varToParam = new TypeMap {
+ def apply(tp: Type) = varToParamMap get tp match {
+ case Some(sym) => sym.tpe
+ case _ => mapOver(tp)
+ }
+ }
+ val paramToVar = new TypeMap {
+ def apply(tp: Type) = tp match {
+ case TypeRef(_, tsym, _) if paramToVarMap.isDefinedAt(tsym) => paramToVarMap(tsym)
+ case _ => mapOver(tp)
+ }
+ }
+ val bts = copyRefinedType(tpe.asInstanceOf[RefinedType], tpe.parents map varToParam, varToParam mapOver tpe.decls).baseTypeSeq
+ tpe.baseTypeSeqCache = bts lateMap paramToVar
+ } else {
+ incCounter(compoundBaseTypeSeqCount)
+ tpe.baseTypeSeqCache = undetBaseTypeSeq
+ tpe.baseTypeSeqCache = if (tpe.typeSymbol.isRefinementClass)
+ tpe.memo(compoundBaseTypeSeq(tpe))(_.baseTypeSeq updateHead tpe.typeSymbol.tpe)
+ else
+ compoundBaseTypeSeq(tpe)
+ // [Martin] suppressing memo-ization solves the problem with "same type after erasure" errors
+ // when compiling with
+ // scalac scala.collection.IterableViewLike.scala scala.collection.IterableLike.scala
+ // I have not yet figured out precisely why this is the case.
+ // My current assumption is that taking memos forces baseTypeSeqs to be computed
+ // at stale types (i.e. the underlying typeSymbol has already another type).
+ // I do not yet see precisely why this would cause a problem, but it looks
+ // fishy in any case.
+ }
+ }
+ }
+ //Console.println("baseTypeSeq(" + typeSymbol + ") = " + baseTypeSeqCache.toList);//DEBUG
+ if (tpe.baseTypeSeqCache eq undetBaseTypeSeq)
+ throw new TypeError("illegal cyclic inheritance involving " + tpe.typeSymbol)
+ }
+
+ protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = {
+ def computeBaseClasses: List[Symbol] =
+ if (tpe.parents.isEmpty) List(tpe.typeSymbol)
+ else {
+ //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG
+ // optimized, since this seems to be performance critical
+ val superclazz = tpe.firstParent
+ var mixins = tpe.parents.tail
+ val sbcs = superclazz.baseClasses
+ var bcs = sbcs
+ def isNew(clazz: Symbol): Boolean =
+ superclazz.baseTypeIndex(clazz) < 0 &&
+ { var p = bcs;
+ while ((p ne sbcs) && (p.head != clazz)) p = p.tail;
+ p eq sbcs
+ }
+ while (!mixins.isEmpty) {
+ def addMixinBaseClasses(mbcs: List[Symbol]): List[Symbol] =
+ if (mbcs.isEmpty) bcs
+ else if (isNew(mbcs.head)) mbcs.head :: addMixinBaseClasses(mbcs.tail)
+ else addMixinBaseClasses(mbcs.tail)
+ bcs = addMixinBaseClasses(mixins.head.baseClasses)
+ mixins = mixins.tail
+ }
+ tpe.typeSymbol :: bcs
+ }
+ val period = tpe.baseClassesPeriod
+ if (period != currentPeriod) {
+ tpe.baseClassesPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ tpe.baseClassesCache = null
+ tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail)
+ }
+ }
+ if (tpe.baseClassesCache eq null)
+ throw new TypeError("illegal cyclic reference involving " + tpe.typeSymbol)
+ }
+
+ /** A class representing intersection types with refinements of the form
+ * `<parents_0> with ... with <parents_n> { decls }`
+ * Cannot be created directly;
+ * one should always use `refinedType` for creation.
+ */
+ case class RefinedType(override val parents: List[Type],
+ override val decls: Scope) extends CompoundType with RefinedTypeApi {
+
+ override def isHigherKinded = (
+ parents.nonEmpty &&
+ (parents forall (_.isHigherKinded)) &&
+ !phase.erasedTypes
+ )
+
+ override def typeParams =
+ if (isHigherKinded) firstParent.typeParams
+ else super.typeParams
+
+ //@M may result in an invalid type (references to higher-order args become dangling )
+ override def typeConstructor =
+ copyRefinedType(this, parents map (_.typeConstructor), decls)
+
+ final override def normalize: Type =
+ if (phase.erasedTypes) normalizeImpl
+ else {
+ if (normalized eq null) normalized = normalizeImpl
+ normalized
+ }
+
+ private var normalized: Type = _
+ private def normalizeImpl = {
+ // TODO see comments around def intersectionType and def merge
+ def flatten(tps: List[Type]): List[Type] = tps flatMap { case RefinedType(parents, ds) if ds.isEmpty => flatten(parents) case tp => List(tp) }
+ val flattened = flatten(parents).distinct
+ if (decls.isEmpty && flattened.tail.isEmpty) {
+ flattened.head
+ } else if (flattened != parents) {
+ refinedType(flattened, if (typeSymbol eq NoSymbol) NoSymbol else typeSymbol.owner, decls, NoPosition)
+ } else if (isHigherKinded) {
+ // MO to AM: This is probably not correct
+ // If they are several higher-kinded parents with different bounds we need
+ // to take the intersection of their bounds
+ typeFun(
+ typeParams,
+ RefinedType(
+ parents map {
+ case TypeRef(pre, sym, List()) => TypeRef(pre, sym, dummyArgs)
+ case p => p
+ },
+ decls,
+ typeSymbol))
+ } else super.normalize
+ }
+
+ /** A refined type P1 with ... with Pn { decls } is volatile if
+ * one of the parent types Pi is an abstract type, and
+ * either i > 1, or decls or a following parent Pj, j > 1, contributes
+ * an abstract member.
+ * A type contributes an abstract member if it has an abstract member which
+ * is also a member of the whole refined type. A scope `decls` contributes
+ * an abstract member if it has an abstract definition which is also
+ * a member of the whole type.
+ */
+ override def isVolatile = {
+ def isVisible(m: Symbol) =
+ this.nonPrivateMember(m.name).alternatives contains m
+ def contributesAbstractMembers(p: Type) =
+ p.deferredMembers exists isVisible
+
+ ((parents exists (_.isVolatile))
+ ||
+ (parents dropWhile (! _.typeSymbol.isAbstractType) match {
+ case ps @ (_ :: ps1) =>
+ (ps ne parents) ||
+ (ps1 exists contributesAbstractMembers) ||
+ (decls.iterator exists (m => m.isDeferred && isVisible(m)))
+ case _ =>
+ false
+ }))
+ }
+
+ override def kind = "RefinedType"
+ }
+
+ final class RefinedType0(parents: List[Type], decls: Scope, clazz: Symbol) extends RefinedType(parents, decls) {
+ override def typeSymbol = clazz
+ }
+
+ object RefinedType extends RefinedTypeExtractor {
+ def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType =
+ new RefinedType0(parents, decls, clazz)
+ }
+
+ /** Overridden in reflection compiler */
+ def validateClassInfo(tp: ClassInfoType) {}
+
+ /** A class representing a class info
+ */
+ case class ClassInfoType(
+ override val parents: List[Type],
+ override val decls: Scope,
+ override val typeSymbol: Symbol) extends CompoundType with ClassInfoTypeApi
+ {
+ validateClassInfo(this)
+
+ /** refs indices */
+ private final val NonExpansive = 0
+ private final val Expansive = 1
+
+ /** initialization states */
+ private final val UnInitialized = 0
+ private final val Initializing = 1
+ private final val Initialized = 2
+
+ private type RefMap = Map[Symbol, immutable.Set[Symbol]]
+
+ /** All type parameters reachable from given type parameter
+ * by a path which contains at least one expansive reference.
+ * @See Kennedy, Pierce: On Decidability of Nominal Subtyping with Variance
+ */
+ private[scala] def expansiveRefs(tparam: Symbol) = {
+ if (state == UnInitialized) {
+ computeRefs()
+ while (state != Initialized) propagate()
+ }
+ getRefs(Expansive, tparam)
+ }
+
+ /* The rest of this class is auxiliary code for `expansiveRefs`
+ */
+
+ /** The type parameters which are referenced type parameters of this class.
+ * Two entries: refs(0): Non-expansive references
+ * refs(1): Expansive references
+ * Syncnote: This var need not be protected with synchronized, because
+ * it is accessed only from expansiveRefs, which is called only from
+ * Typer.
+ */
+ private var refs: Array[RefMap] = _
+
+ /** The initialization state of the class: UnInialized --> Initializing --> Initialized
+ * Syncnote: This var need not be protected with synchronized, because
+ * it is accessed only from expansiveRefs, which is called only from
+ * Typer.
+ */
+ private var state = UnInitialized
+
+ /** Get references for given type parameter
+ * @param which in {NonExpansive, Expansive}
+ * @param from The type parameter from which references originate.
+ */
+ private def getRefs(which: Int, from: Symbol): Set[Symbol] = refs(which) get from match {
+ case Some(set) => set
+ case none => Set()
+ }
+
+ /** Augment existing refs map with reference <pre>from -> to</pre>
+ * @param which <- {NonExpansive, Expansive}
+ */
+ private def addRef(which: Int, from: Symbol, to: Symbol) {
+ refs(which) = refs(which) + (from -> (getRefs(which, from) + to))
+ }
+
+ /** Augment existing refs map with references <pre>from -> sym</pre>, for
+ * all elements <pre>sym</pre> of set `to`.
+ * @param which <- {NonExpansive, Expansive}
+ */
+ private def addRefs(which: Int, from: Symbol, to: Set[Symbol]) {
+ refs(which) = refs(which) + (from -> (getRefs(which, from) ++ to))
+ }
+
+ /** The ClassInfoType which belongs to the class containing given type parameter
+ */
+ private def classInfo(tparam: Symbol): ClassInfoType =
+ tparam.owner.info.resultType match {
+ case ci: ClassInfoType => ci
+ case _ => classInfo(ObjectClass) // something's wrong; fall back to safe value
+ // (this can happen only for erroneous programs).
+ }
+
+ private object enterRefs extends TypeMap {
+ private var tparam: Symbol = _
+
+ def apply(tp: Type): Type = {
+ tp match {
+ case tr @ TypeRef(_, sym, args) if args.nonEmpty =>
+ val tparams = tr.initializedTypeParams
+ if (settings.debug.value && !sameLength(tparams, args))
+ debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args)
+
+ foreach2(tparams, args) { (tparam1, arg) =>
+ if (arg contains tparam) {
+ addRef(NonExpansive, tparam, tparam1)
+ if (arg.typeSymbol != tparam)
+ addRef(Expansive, tparam, tparam1)
+ }
+ }
+ case _ =>
+ }
+ mapOver(tp)
+ }
+ def enter(tparam0: Symbol, parent: Type) {
+ this.tparam = tparam0
+ this(parent)
+ }
+ }
+
+ /** Compute initial (one-step) references and set state to `Initializing`.
+ */
+ private def computeRefs() {
+ refs = Array(Map(), Map())
+ typeSymbol.typeParams foreach { tparam =>
+ parents foreach { p =>
+ enterRefs.enter(tparam, p)
+ }
+ }
+ state = Initializing
+ }
+
+ /** Propagate to form transitive closure.
+ * Set state to Initialized if no change resulted from propagation.
+ * @return true iff there as a change in last iteration
+ */
+ private def propagate(): Boolean = {
+ if (state == UnInitialized) computeRefs()
+ //Console.println("Propagate "+symbol+", initial expansive = "+refs(Expansive)+", nonexpansive = "+refs(NonExpansive))//DEBUG
+ val lastRefs = Array(refs(0), refs(1))
+ state = Initialized
+ var change = false
+ for ((from, targets) <- refs(NonExpansive).iterator)
+ for (target <- targets) {
+ var thatInfo = classInfo(target)
+ if (thatInfo.state != Initialized)
+ change = change | thatInfo.propagate()
+ addRefs(NonExpansive, from, thatInfo.getRefs(NonExpansive, target))
+ addRefs(Expansive, from, thatInfo.getRefs(Expansive, target))
+ }
+ for ((from, targets) <- refs(Expansive).iterator)
+ for (target <- targets) {
+ var thatInfo = classInfo(target)
+ if (thatInfo.state != Initialized)
+ change = change | thatInfo.propagate()
+ addRefs(Expansive, from, thatInfo.getRefs(NonExpansive, target))
+ }
+ change = change || refs(0) != lastRefs(0) || refs(1) != lastRefs(1)
+ if (change) state = Initializing
+ //else Console.println("Propagate "+symbol+", final expansive = "+refs(Expansive)+", nonexpansive = "+refs(NonExpansive))//DEBUG
+ change
+ }
+
+ // override def isNullable: Boolean =
+ // symbol == AnyClass ||
+ // symbol != NothingClass && (symbol isSubClass ObjectClass) && !(symbol isSubClass NonNullClass);
+
+ // override def isNonNull: Boolean = symbol == NonNullClass || super.isNonNull;
+ override def kind = "ClassInfoType"
+
+ override def safeToString =
+ if (settings.debug.value || decls.size > 1)
+ formattedToString
+ else
+ super.safeToString
+
+ /** A nicely formatted string with newlines and such.
+ */
+ def formattedToString: String =
+ parents.mkString("\n with ") +
+ (if (settings.debug.value || parents.isEmpty || (decls.elems ne null))
+ decls.mkString(" {\n ", "\n ", "\n}") else "")
+ }
+
+ object ClassInfoType extends ClassInfoTypeExtractor
+
+ class PackageClassInfoType(decls: Scope, clazz: Symbol)
+ extends ClassInfoType(List(), decls, clazz)
+
+ /** A class representing a constant type.
+ *
+ * @param value ...
+ */
+ abstract case class ConstantType(value: Constant) extends SingletonType with ConstantTypeApi {
+ override def underlying: Type = value.tpe
+ assert(underlying.typeSymbol != UnitClass)
+ override def isTrivial: Boolean = true
+ override def isNotNull = value.value != null
+ override def deconst: Type = underlying
+ override def safeToString: String =
+ underlying.toString + "(" + value.escapedStringValue + ")"
+ // override def isNullable: Boolean = value.value eq null
+ // override def isNonNull: Boolean = value.value ne null
+ override def kind = "ConstantType"
+ }
+
+ final class UniqueConstantType(value: Constant) extends ConstantType(value) with UniqueType {
+ /** Save the type of `value`. For Java enums, it depends on finding the linked class,
+ * which might not be found after `flatten`. */
+ private lazy val _tpe: Type = value.tpe
+ override def underlying: Type = _tpe
+ }
+
+ object ConstantType extends ConstantTypeExtractor {
+ def apply(value: Constant): ConstantType = {
+ val tpe = new UniqueConstantType(value)
+ if (value.tag == ClazzTag) {
+ // if we carry a classOf, we might be in trouble
+ // http://groups.google.com/group/scala-internals/browse_thread/thread/45185b341aeb6a30
+ // I don't have time for a thorough fix, so I put a hacky workaround here
+ val alreadyThere = uniques findEntry tpe
+ if ((alreadyThere ne null) && (alreadyThere ne tpe) && (alreadyThere.toString != tpe.toString)) {
+ // we need to remove a stale type that has the same hashcode as we do
+ // HashSet doesn't support removal, and this makes our task non-trivial
+ // also we cannot simply recreate it, because that'd skew hashcodes (that change over time, omg!)
+ // the only solution I can see is getting into the underlying array and sneakily manipulating it
+ val ftable = uniques.getClass.getDeclaredFields().find(f => f.getName endsWith "table").get
+ ftable.setAccessible(true)
+ val table = ftable.get(uniques).asInstanceOf[Array[AnyRef]]
+ def overwrite(hc: Int, x: Type) {
+ def index(x: Int): Int = math.abs(x % table.length)
+ var h = index(hc)
+ var entry = table(h)
+ while (entry ne null) {
+ if (x == entry)
+ table(h) = x
+ h = index(h + 1)
+ entry = table(h)
+ }
+ }
+ overwrite(tpe.##, tpe)
+ }
+ }
+ unique(tpe).asInstanceOf[ConstantType]
+ }
+ }
+
+ /* 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]
+
+ class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType {
+ require(args0.nonEmpty, this)
+
+ /** No unapplied type params size it has (should have) equally as many args. */
+ override def isHigherKinded = false
+ override def typeParams = Nil
+
+ override def transform(tp: Type): Type = {
+ // This situation arises when a typevar is encountered for which
+ // too little information is known to determine its kind, and
+ // it later turns out not to have kind *. See SI-4070. Only
+ // logging it for now.
+ if (sym.typeParams.size != args.size)
+ log("!!! %s.transform(%s), but tparams.isEmpty and args=".format(this, tp, args))
+
+ asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args)
+ }
+
+ // note: does not go through typeRef. There's no need to because
+ // neither `pre` nor `sym` changes. And there's a performance
+ // advantage to call TypeRef directly.
+ override def typeConstructor = TypeRef(pre, sym, Nil)
+ }
+
+ class ModuleTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef {
+ require(sym.isModuleClass, sym)
+ private[this] var narrowedCache: Type = _
+ override def isStable = true
+ override def narrow = {
+ if (narrowedCache eq null)
+ narrowedCache = singleType(pre, sym.sourceModule)
+
+ narrowedCache
+ }
+ final override def isNotNull = true
+ override protected def finishPrefix(rest: String) = objectPrefix + rest
+ override def directObjectString = super.safeToString
+ override def toLongString = toString
+ override def safeToString = narrow.toString
+ }
+ class PackageTypeRef(pre0: Type, sym0: Symbol) extends ModuleTypeRef(pre0, sym0) {
+ require(sym.isPackageClass, sym)
+ override protected def finishPrefix(rest: String) = packagePrefix + rest
+ }
+ class RefinementTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef {
+ require(sym.isRefinementClass, sym)
+
+ // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers
+ override protected def normalizeImpl: Type = sym.info.normalize
+ override protected def finishPrefix(rest: String) = "" + thisInfo
+ }
+
+ class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType {
+ // A reference (in a Scala program) to a type that has type parameters, but where the reference
+ // does not include type arguments. Note that it doesn't matter whether the symbol refers
+ // to a java or scala symbol, but it does matter whether it occurs in java or scala code.
+ // TypeRefs w/o type params that occur in java signatures/code are considered raw types, and are
+ // represented as existential types.
+ override def isHigherKinded = typeParams.nonEmpty
+ override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams
+ private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym)
+
+ override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
+ if (isHigherKinded) {
+ if (sameLength(formals intersect typeParams, typeParams))
+ copyTypeRef(this, pre, sym, actuals)
+ // partial application (needed in infer when bunching type arguments from classes and methods together)
+ else
+ copyTypeRef(this, pre, sym, dummyArgs).instantiateTypeParams(formals, actuals)
+ }
+ else
+ super.instantiateTypeParams(formals, actuals)
+
+ override def transform(tp: Type): Type = {
+ val res = asSeenFromOwner(tp)
+ if (isHigherKinded && !isRaw)
+ res.instantiateTypeParams(typeParams, dummyArgs)
+ else
+ res
+ }
+
+ override def transformInfo(tp: Type): Type =
+ appliedType(asSeenFromOwner(tp), dummyArgs)
+
+ override def narrow =
+ if (sym.isModuleClass) singleType(pre, sym.sourceModule)
+ else super.narrow
+
+ override def typeConstructor = this
+ // eta-expand, subtyping relies on eta-expansion of higher-kinded types
+
+ override protected def normalizeImpl: Type =
+ if (isHigherKinded) etaExpand else super.normalizeImpl
+ }
+
+ trait ClassTypeRef extends TypeRef {
+ // !!! There are scaladoc-created symbols arriving which violate this require.
+ // require(sym.isClass, sym)
+
+ override def baseType(clazz: Symbol): Type =
+ if (sym == clazz) this
+ else transform(sym.info.baseType(clazz))
+ }
+
+ trait NonClassTypeRef extends TypeRef {
+ require(sym.isNonClassType, sym)
+
+ /* Syncnote: These are pure caches for performance; no problem to evaluate these
+ * several times. Hence, no need to protected with synchronzied in a mutli-threaded
+ * usage scenario.
+ */
+ private var relativeInfoCache: Type = _
+ private var memberInfoCache: Type = _
+
+ private[Types] def relativeInfo = {
+ val memberInfo = pre.memberInfo(sym)
+ if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) {
+ memberInfoCache = memberInfo
+ relativeInfoCache = transformInfo(memberInfo)
+ }
+ relativeInfoCache
+ }
+
+ override def baseType(clazz: Symbol): Type =
+ if (sym == clazz) this else baseTypeOfNonClassTypeRef(this, clazz)
+ }
+
+ protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = try {
+ basetypeRecursions += 1
+ if (basetypeRecursions < LogPendingBaseTypesThreshold)
+ tpe.relativeInfo.baseType(clazz)
+ else if (pendingBaseTypes contains tpe)
+ if (clazz == AnyClass) clazz.tpe else NoType
+ else
+ try {
+ pendingBaseTypes += tpe
+ tpe.relativeInfo.baseType(clazz)
+ } finally {
+ pendingBaseTypes -= tpe
+ }
+ } finally {
+ basetypeRecursions -= 1
+ }
+
+ trait AliasTypeRef extends NonClassTypeRef {
+ require(sym.isAliasType, sym)
+
+ override def dealias = if (typeParamsMatchArgs) betaReduce.dealias else super.dealias
+ override def isStable = normalize.isStable
+ override def isVolatile = normalize.isVolatile
+ override def narrow = normalize.narrow
+ override def thisInfo = normalize
+ override def prefix = if (this ne normalize) normalize.prefix else pre
+ override def termSymbol = if (this ne normalize) normalize.termSymbol else super.termSymbol
+ override def typeSymbol = if (this ne normalize) normalize.typeSymbol else sym
+
+ // beta-reduce, but don't do partial application -- cycles have been checked in typeRef
+ override protected def normalizeImpl =
+ if (typeParamsMatchArgs) betaReduce.normalize
+ else if (isHigherKinded) super.normalizeImpl
+ else ErrorType
+
+ // isHKSubType0 introduces synthetic type params so that
+ // betaReduce can first apply sym.info to typeArgs before calling
+ // asSeenFrom. asSeenFrom then skips synthetic type params, which
+ // are used to reduce HO subtyping to first-order subtyping, but
+ // which can't be instantiated from the given prefix and class.
+ //
+ // this crashes pos/depmet_implicit_tpbetareduce.scala
+ // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner)
+ def betaReduce = transform(sym.info.resultType)
+
+ // #3731: return sym1 for which holds: pre bound sym.name to sym and
+ // pre1 now binds sym.name to sym1, conceptually exactly the same
+ // symbol as sym. The selection of sym on pre must be updated to the
+ // selection of sym1 on pre1, since sym's info was probably updated
+ // by the TypeMap to yield a new symbol, sym1 with transformed info.
+ // @returns sym1
+ override def coevolveSym(pre1: Type): Symbol =
+ if (pre eq pre1) sym else (pre, pre1) match {
+ // don't look at parents -- it would be an error to override alias types anyway
+ case (RefinedType(_, _), RefinedType(_, decls1)) => decls1 lookup sym.name
+ // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre?
+ case _ => sym
+ }
+ override def kind = "AliasTypeRef"
+ }
+
+ trait AbstractTypeRef extends NonClassTypeRef {
+ require(sym.isAbstractType, sym)
+
+ /** Syncnote: Pure performance caches; no need to synchronize in multi-threaded environment
+ */
+ private var symInfoCache: Type = _
+ private var thisInfoCache: Type = _
+
+ override def isVolatile = {
+ // need to be careful not to fall into an infinite recursion here
+ // because volatile checking is done before all cycles are detected.
+ // the case to avoid is an abstract type directly or
+ // indirectly upper-bounded by itself. See #2918
+ try {
+ volatileRecursions += 1
+ if (volatileRecursions < LogVolatileThreshold)
+ bounds.hi.isVolatile
+ else if (pendingVolatiles(sym))
+ true // we can return true here, because a cycle will be detected
+ // here afterwards and an error will result anyway.
+ else
+ try {
+ pendingVolatiles += sym
+ bounds.hi.isVolatile
+ } finally {
+ pendingVolatiles -= sym
+ }
+ } finally {
+ volatileRecursions -= 1
+ }
+ }
+
+ override def thisInfo = {
+ val symInfo = sym.info
+ if (thisInfoCache == null || (symInfo ne symInfoCache)) {
+ symInfoCache = symInfo
+ thisInfoCache = transformInfo(symInfo) match {
+ // If a subtyping cycle is not detected here, we'll likely enter an infinite
+ // loop before a sensible error can be issued. SI-5093 is one example.
+ case x: SubType if x.supertype eq this =>
+ throw new RecoverableCyclicReference(sym)
+ case tp => tp
+ }
+ }
+ thisInfoCache
+ }
+ override def isStable = bounds.hi.typeSymbol isSubClass SingletonClass
+ override def bounds = thisInfo.bounds
+ // def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies)
+ override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this
+ override def kind = "AbstractTypeRef"
+ }
+
+ /** A class for named types of the form
+ * `<prefix>.<sym.name>[args]`
+ * Cannot be created directly; one should always use `typeRef`
+ * for creation. (@M: Otherwise hashing breaks)
+ *
+ * @M: a higher-kinded type is represented as a TypeRef with sym.typeParams.nonEmpty, but args.isEmpty
+ */
+ abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type with TypeRefApi {
+ private[reflect] var parentsCache: List[Type] = _
+ private[reflect] var parentsPeriod = NoPeriod
+ private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
+ private[reflect] var baseTypeSeqPeriod = NoPeriod
+ private var normalized: Type = _
+
+ // @M: propagate actual type params (args) to `tp`, by replacing
+ // formal type parameters with actual ones. If tp is higher kinded,
+ // the "actual" type arguments are types that simply reference the
+ // corresponding type parameters (unbound type variables)
+ def transform(tp: Type): Type
+
+ // eta-expand, subtyping relies on eta-expansion of higher-kinded types
+ protected def normalizeImpl: Type = if (isHigherKinded) etaExpand else super.normalize
+
+ // TODO: test case that is compiled in a specific order and in different runs
+ final override def normalize: Type = {
+ // arises when argument-dependent types are approximated (see def depoly in implicits)
+ if (pre eq WildcardType) WildcardType
+ else if (phase.erasedTypes) normalizeImpl
+ else {
+ if (normalized eq null)
+ normalized = normalizeImpl
+ normalized
+ }
+ }
+
+ override def isGround = (
+ sym.isPackageClass
+ || pre.isGround && args.forall(_.isGround)
+ )
+
+ def etaExpand: Type = {
+ // must initialise symbol, see test/files/pos/ticket0137.scala
+ val tpars = initializedTypeParams
+ if (tpars.isEmpty) this
+ else typeFunAnon(tpars, copyTypeRef(this, pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce?
+ }
+
+ // only need to rebind type aliases, as typeRef already handles abstract types
+ // (they are allowed to be rebound more liberally)
+ def coevolveSym(pre1: Type): Symbol = sym
+
+ //@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs)
+ def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), args)
+
+ def thisInfo = sym.info
+ def initializedTypeParams = sym.info.typeParams
+ def typeParamsMatchArgs = sameLength(initializedTypeParams, args)
+ def asSeenFromOwner(tp: Type) = tp.asSeenFrom(pre, sym.owner)
+
+ override def baseClasses = thisInfo.baseClasses
+ override def baseTypeSeqDepth = baseTypeSeq.maxDepth
+ override def isStable = (sym eq NothingClass) || (sym eq SingletonClass)
+ override def prefix = pre
+ override def termSymbol = super.termSymbol
+ override def termSymbolDirect = super.termSymbol
+ override def typeArgs = args
+ override def typeOfThis = transform(sym.typeOfThis)
+ override def typeSymbol = sym
+ override def typeSymbolDirect = sym
+
+ override lazy val isTrivial: Boolean =
+ !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial)
+
+ override def isNotNull =
+ sym.isModuleClass || sym == NothingClass || (sym isNonBottomSubClass NotNullClass) || super.isNotNull
+
+ override def parents: List[Type] = {
+ val cache = parentsCache
+ if (parentsPeriod == currentPeriod && cache != null) cache
+ else {
+ defineParentsOfTypeRef(this)
+ parentsCache
+ }
+ }
+
+ override def decls: Scope = {
+ sym.info match {
+ case TypeRef(_, sym1, _) =>
+ assert(sym1 != sym, this) // @MAT was != typeSymbol
+ case _ =>
+ }
+ thisInfo.decls
+ }
+
+ protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform
+
+ override def baseTypeSeq: BaseTypeSeq = {
+ val cache = baseTypeSeqCache
+ if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq)
+ cache
+ else {
+ defineBaseTypeSeqOfTypeRef(this)
+ if (baseTypeSeqCache == undetBaseTypeSeq)
+ throw new RecoverableCyclicReference(sym)
+
+ baseTypeSeqCache
+ }
+ }
+
+ // ensure that symbol is not a local copy with a name coincidence
+ private def needsPreString = (
+ settings.debug.value
+ || !shorthands(sym.fullName)
+ || sym.ownerChain.exists(s => !s.isClass)
+ )
+ private def preString = if (needsPreString) pre.prefixString else ""
+ private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]")
+
+ def refinementString = (
+ if (sym.isStructuralRefinement) (
+ decls filter (sym => sym.isPossibleInRefinement && sym.isPublic)
+ map (_.defString)
+ mkString("{", "; ", "}")
+ )
+ else ""
+ )
+
+ protected def finishPrefix(rest: String) = (
+ if (sym.isInitialized && sym.isAnonymousClass && !phase.erasedTypes)
+ parentsString(thisInfo.parents) + refinementString
+ else rest
+ )
+ private def customToString = sym match {
+ case RepeatedParamClass => args.head + "*"
+ case ByNameParamClass => "=> " + args.head
+ case _ =>
+ def targs = normalize.typeArgs
+
+ if (isFunctionType(this)) {
+ // Aesthetics: printing Function1 as T => R rather than (T) => R
+ // ...but only if it's not a tuple, so ((T1, T2)) => R is distinguishable
+ // from (T1, T2) => R.
+ targs match {
+ case in :: out :: Nil if !isTupleType(in) =>
+ // A => B => C should be (A => B) => C or A => (B => C)
+ val in_s = if (isFunctionType(in)) "(" + in + ")" else "" + in
+ val out_s = if (isFunctionType(out)) "(" + out + ")" else "" + out
+ in_s + " => " + out_s
+ case xs =>
+ xs.init.mkString("(", ", ", ")") + " => " + xs.last
+ }
+ }
+ else if (isTupleType(this))
+ targs.mkString("(", ", ", if (hasLength(targs, 1)) ",)" else ")")
+ else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (this ne this.normalize))
+ "" + normalize
+ else
+ ""
+ }
+ override def safeToString = {
+ val custom = if (settings.debug.value) "" else customToString
+ if (custom != "") custom
+ else finishPrefix(preString + sym.nameString + argsString)
+ }
+ override def prefixString = "" + (
+ if (settings.debug.value)
+ super.prefixString
+ else if (sym.isOmittablePrefix)
+ ""
+ else if (sym.isPackageClass || sym.isPackageObjectOrClass)
+ sym.skipPackageObject.fullName + "."
+ else if (isStable && nme.isSingletonName(sym.name))
+ tpnme.dropSingletonName(sym.name) + "."
+ else
+ super.prefixString
+ )
+ override def kind = "TypeRef"
+ }
+
+ object TypeRef extends TypeRefExtractor {
+ def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({
+ if (args.nonEmpty) {
+ if (sym.isAliasType) new ArgsTypeRef(pre, sym, args) with AliasTypeRef
+ else if (sym.isAbstractType) new ArgsTypeRef(pre, sym, args) with AbstractTypeRef
+ else new ArgsTypeRef(pre, sym, args) with ClassTypeRef
+ }
+ else {
+ if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef
+ else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef
+ else if (sym.isRefinementClass) new RefinementTypeRef(pre, sym)
+ else if (sym.isPackageClass) new PackageTypeRef(pre, sym)
+ else if (sym.isModuleClass) new ModuleTypeRef(pre, sym)
+ else new NoArgsTypeRef(pre, sym) with ClassTypeRef
+ }
+ })
+ }
+
+ protected def defineParentsOfTypeRef(tpe: TypeRef) = {
+ val period = tpe.parentsPeriod
+ if (period != currentPeriod) {
+ tpe.parentsPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ tpe.parentsCache = tpe.thisInfo.parents map tpe.transform
+ } else if (tpe.parentsCache == null) { // seems this can happen if things are corrupted enough, see #2641
+ tpe.parentsCache = List(AnyClass.tpe)
+ }
+ }
+ }
+
+ protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = {
+ val period = tpe.baseTypeSeqPeriod
+ if (period != currentPeriod) {
+ tpe.baseTypeSeqPeriod = currentPeriod
+ if (!isValidForBaseClasses(period)) {
+ incCounter(typerefBaseTypeSeqCount)
+ tpe.baseTypeSeqCache = undetBaseTypeSeq
+ tpe.baseTypeSeqCache = tpe.baseTypeSeqImpl
+ }
+ }
+ if (tpe.baseTypeSeqCache == undetBaseTypeSeq)
+ throw new TypeError("illegal cyclic inheritance involving " + tpe.sym)
+ }
+
+ /** A class representing a method type with parameters.
+ * Note that a parameterless method is represented by a NullaryMethodType:
+ *
+ * def m(): Int MethodType(Nil, Int)
+ * def m: Int NullaryMethodType(Int)
+ */
+ case class MethodType(override val params: List[Symbol],
+ override val resultType: Type) extends Type with MethodTypeApi {
+ override def isTrivial: Boolean = isTrivial0 && (resultType eq resultType.withoutAnnotations)
+ private lazy val isTrivial0 =
+ resultType.isTrivial && params.forall{p => p.tpe.isTrivial && (
+ !(params.exists(_.tpe.contains(p)) || resultType.contains(p)))
+ }
+
+ def isImplicit = params.nonEmpty && params.head.isImplicit
+ def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized?
+
+ //assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG
+ override def paramSectionCount: Int = resultType.paramSectionCount + 1
+
+ override def paramss: List[List[Symbol]] = params :: resultType.paramss
+
+ override def paramTypes = params map (_.tpe)
+
+ override def boundSyms = resultType.boundSyms ++ params
+
+ override def resultType(actuals: List[Type]) =
+ if (isTrivial || phase.erasedTypes) resultType
+ else if (sameLength(actuals, params)) {
+ val idm = new InstantiateDependentMap(params, actuals)
+ val res = idm(resultType)
+ existentialAbstraction(idm.existentialsNeeded, res)
+ }
+ else existentialAbstraction(params, resultType)
+
+ // implicit args can only be depended on in result type:
+ //TODO this may be generalised so that the only constraint is dependencies are acyclic
+ def approximate: MethodType = MethodType(params, resultApprox)
+
+ override def finalResultType: Type = resultType.finalResultType
+
+ override def safeToString = paramString(this) + resultType
+
+ override def cloneInfo(owner: Symbol) = {
+ val vparams = cloneSymbolsAtOwner(params, owner)
+ copyMethodType(this, vparams, resultType.substSym(params, vparams).cloneInfo(owner))
+ }
+
+ override def atOwner(owner: Symbol) =
+ if ((params exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
+ cloneInfo(owner)
+ else
+ this
+
+ override def kind = "MethodType"
+ }
+
+ object MethodType extends MethodTypeExtractor
+
+ class JavaMethodType(ps: List[Symbol], rt: Type) extends MethodType(ps, rt) {
+ override def isJava = true
+ }
+
+ case class NullaryMethodType(override val resultType: Type) extends Type with NullaryMethodTypeApi {
+ override def isTrivial = resultType.isTrivial && (resultType eq resultType.withoutAnnotations)
+ override def prefix: Type = resultType.prefix
+ override def narrow: Type = resultType.narrow
+ override def finalResultType: Type = resultType.finalResultType
+ override def termSymbol: Symbol = resultType.termSymbol
+ override def typeSymbol: Symbol = resultType.typeSymbol
+ override def parents: List[Type] = resultType.parents
+ override def decls: Scope = resultType.decls
+ override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq
+ override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth
+ override def baseClasses: List[Symbol] = resultType.baseClasses
+ override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
+ override def boundSyms = resultType.boundSyms
+ override def isVolatile = resultType.isVolatile
+ override def safeToString: String = "=> "+ resultType
+ override def kind = "NullaryMethodType"
+ }
+
+ object NullaryMethodType extends NullaryMethodTypeExtractor
+
+ /** A type function or the type of a polymorphic value (and thus of kind *).
+ *
+ * Before the introduction of NullaryMethodType, a polymorphic nullary method (e.g, def isInstanceOf[T]: Boolean)
+ * used to be typed as PolyType(tps, restpe), and a monomorphic one as PolyType(Nil, restpe)
+ * This is now: PolyType(tps, NullaryMethodType(restpe)) and NullaryMethodType(restpe)
+ * by symmetry to MethodTypes: PolyType(tps, MethodType(params, restpe)) and MethodType(params, restpe)
+ *
+ * Thus, a PolyType(tps, TypeRef(...)) unambiguously indicates a type function (which results from eta-expanding a type constructor alias).
+ * Similarly, PolyType(tps, ClassInfoType(...)) is a type constructor.
+ *
+ * A polytype is of kind * iff its resultType is a (nullary) method type.
+ */
+ case class PolyType(override val typeParams: List[Symbol], override val resultType: Type)
+ extends Type with PolyTypeApi {
+ //assert(!(typeParams contains NoSymbol), this)
+ assert(typeParams nonEmpty, this) // used to be a marker for nullary method type, illegal now (see @NullaryMethodType)
+
+ override def paramSectionCount: Int = resultType.paramSectionCount
+ override def paramss: List[List[Symbol]] = resultType.paramss
+ override def params: List[Symbol] = resultType.params
+ override def paramTypes: List[Type] = resultType.paramTypes
+ override def parents: List[Type] = resultType.parents
+ override def decls: Scope = resultType.decls
+ override def termSymbol: Symbol = resultType.termSymbol
+ override def typeSymbol: Symbol = resultType.typeSymbol
+ override def boundSyms = immutable.Set[Symbol](typeParams ++ resultType.boundSyms: _*)
+ override def prefix: Type = resultType.prefix
+ override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq
+ override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth
+ override def baseClasses: List[Symbol] = resultType.baseClasses
+ override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
+ override def narrow: Type = resultType.narrow
+ override def isVolatile = resultType.isVolatile
+ override def finalResultType: Type = resultType.finalResultType
+
+ /** @M: typeDefSig wraps a TypeBounds in a PolyType
+ * to represent a higher-kinded type parameter
+ * wrap lo&hi in polytypes to bind variables
+ */
+ override def bounds: TypeBounds =
+ TypeBounds(typeFun(typeParams, resultType.bounds.lo),
+ typeFun(typeParams, resultType.bounds.hi))
+
+ override def isHigherKinded = !typeParams.isEmpty
+
+ override def safeToString = typeParamsString(this) + resultType
+
+ override def cloneInfo(owner: Symbol) = {
+ val tparams = cloneSymbolsAtOwner(typeParams, owner)
+ PolyType(tparams, resultType.substSym(typeParams, tparams).cloneInfo(owner))
+ }
+
+ override def atOwner(owner: Symbol) =
+ if ((typeParams exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
+ cloneInfo(owner)
+ else
+ this
+
+ override def kind = "PolyType"
+ }
+
+ object PolyType extends PolyTypeExtractor
+
+ /** A creator for existential types which flattens nested existentials.
+ */
+ def newExistentialType(quantified: List[Symbol], underlying: Type): Type =
+ if (quantified.isEmpty) underlying
+ else underlying match {
+ case ExistentialType(qs, restpe) => newExistentialType(quantified ::: qs, restpe)
+ case _ => ExistentialType(quantified, underlying)
+ }
+
+ case class ExistentialType(quantified: List[Symbol],
+ override val underlying: Type) extends RewrappingTypeProxy with ExistentialTypeApi
+ {
+ override protected def rewrap(newtp: Type) = existentialAbstraction(quantified, newtp)
+
+ override def isTrivial = false
+ override def isStable: Boolean = false
+ override def bounds = TypeBounds(maybeRewrap(underlying.bounds.lo), maybeRewrap(underlying.bounds.hi))
+ override def parents = underlying.parents map maybeRewrap
+ override def boundSyms = quantified.toSet
+ override def prefix = maybeRewrap(underlying.prefix)
+ override def typeArgs = underlying.typeArgs map maybeRewrap
+ override def params = underlying.params mapConserve { param =>
+ val tpe1 = rewrap(param.tpeHK)
+ if (tpe1 eq param.tpeHK) param else param.cloneSymbol.setInfo(tpe1)
+ }
+ override def paramTypes = underlying.paramTypes map maybeRewrap
+ override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = {
+// maybeRewrap(underlying.instantiateTypeParams(formals, actuals))
+
+ val quantified1 = new SubstTypeMap(formals, actuals) mapOver quantified
+ val underlying1 = underlying.instantiateTypeParams(formals, actuals)
+ if ((quantified1 eq quantified) && (underlying1 eq underlying)) this
+ else existentialAbstraction(quantified1, underlying1.substSym(quantified, quantified1))
+
+ }
+ override def baseType(clazz: Symbol) = maybeRewrap(underlying.baseType(clazz))
+ override def baseTypeSeq = underlying.baseTypeSeq map maybeRewrap
+ override def isHigherKinded = false
+
+ override def skolemizeExistential(owner: Symbol, origin: AnyRef) =
+ deriveType(quantified, tparam => (owner orElse tparam.owner).newExistentialSkolem(tparam, origin))(underlying)
+
+ private def wildcardArgsString(qset: Set[Symbol], args: List[Type]): List[String] = args map {
+ case TypeRef(_, sym, _) if (qset contains sym) =>
+ "_"+sym.infoString(sym.info)
+ case arg =>
+ arg.toString
+ }
+
+ /** An existential can only be printed with wildcards if:
+ * - the underlying type is a typeref
+ * - every quantified variable appears at most once as a type argument and
+ * nowhere inside a type argument
+ * - no quantified type argument contains a quantified variable in its bound
+ * - the typeref's symbol is not itself quantified
+ * - the prefix is not quanitified
+ */
+ def isRepresentableWithWildcards = {
+ val qset = quantified.toSet
+ underlying match {
+ case TypeRef(pre, sym, args) =>
+ def isQuantified(tpe: Type): Boolean = {
+ (tpe exists (t => qset contains t.typeSymbol)) ||
+ tpe.typeSymbol.isRefinementClass && (tpe.parents exists isQuantified)
+ }
+ val (wildcardArgs, otherArgs) = args partition (arg => qset contains arg.typeSymbol)
+ wildcardArgs.distinct == wildcardArgs &&
+ !(otherArgs exists (arg => isQuantified(arg))) &&
+ !(wildcardArgs exists (arg => isQuantified(arg.typeSymbol.info.bounds))) &&
+ !(qset contains sym) &&
+ !isQuantified(pre)
+ case _ => false
+ }
+ }
+
+ override def safeToString: String = {
+ def clauses = {
+ val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }")
+ if (settings.explaintypes.value) "(" + str + ")" else str
+ }
+ underlying match {
+ case TypeRef(pre, sym, args) if !settings.debug.value && isRepresentableWithWildcards =>
+ "" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]")
+ case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) =>
+ "(" + underlying + ")" + clauses
+ case _ =>
+ "" + underlying + clauses
+ }
+ }
+
+ override def cloneInfo(owner: Symbol) =
+ createFromClonedSymbolsAtOwner(quantified, owner, underlying)(newExistentialType)
+
+ override def atOwner(owner: Symbol) =
+ if (quantified exists (_.owner != owner)) cloneInfo(owner) else this
+
+ override def kind = "ExistentialType"
+
+ def withTypeVars(op: Type => Boolean): Boolean = withTypeVars(op, AnyDepth)
+
+ def withTypeVars(op: Type => Boolean, depth: Int): Boolean = {
+ val quantifiedFresh = cloneSymbols(quantified)
+ val tvars = quantifiedFresh map (tparam => TypeVar(tparam))
+ val underlying1 = underlying.instantiateTypeParams(quantified, tvars) // fuse subst quantified -> quantifiedFresh -> tvars
+ op(underlying1) && {
+ solve(tvars, quantifiedFresh, quantifiedFresh map (x => 0), false, depth) &&
+ isWithinBounds(NoPrefix, NoSymbol, quantifiedFresh, tvars map (_.constr.inst))
+ }
+ }
+ }
+
+ object ExistentialType extends ExistentialTypeExtractor
+
+ /** A class containing the alternatives and type prefix of an overloaded symbol.
+ * Not used after phase `typer`.
+ */
+ case class OverloadedType(pre: Type, alternatives: List[Symbol]) extends Type {
+ override def prefix: Type = pre
+ override def safeToString =
+ (alternatives map pre.memberType).mkString("", " <and> ", "")
+ override def kind = "OverloadedType"
+ }
+
+ def overloadedType(pre: Type, alternatives: List[Symbol]): Type =
+ if (alternatives.tail.isEmpty) pre memberType alternatives.head
+ else OverloadedType(pre, alternatives)
+
+ /** A class remembering a type instantiation for some a set of overloaded
+ * polymorphic symbols.
+ * Not used after phase `typer`.
+ */
+ case class AntiPolyType(pre: Type, targs: List[Type]) extends Type {
+ override def safeToString =
+ pre.toString + targs.mkString("(with type arguments ", ", ", ")");
+ override def memberType(sym: Symbol) = appliedType(pre.memberType(sym), targs)
+// override def memberType(sym: Symbol) = pre.memberType(sym) match {
+// case PolyType(tparams, restp) =>
+// restp.subst(tparams, targs)
+// /* I don't think this is needed, as existential types close only over value types
+// case ExistentialType(tparams, qtpe) =>
+// existentialAbstraction(tparams, qtpe.memberType(sym))
+// */
+// case ErrorType =>
+// ErrorType
+// }
+ override def kind = "AntiPolyType"
+ }
+
+ //private var tidCount = 0 //DEBUG
+
+ object HasTypeMember {
+ def apply(name: TypeName, tp: Type): Type = {
+ val bound = refinedType(List(WildcardType), NoSymbol)
+ val bsym = bound.typeSymbol.newAliasType(name)
+ bsym setInfo tp
+ bound.decls enter bsym
+ bound
+ }
+ def unapply(tp: Type): Option[(TypeName, Type)] = tp match {
+ case RefinedType(List(WildcardType), Scope(sym)) => Some((sym.name.toTypeName, sym.info))
+ case _ => None
+ }
+ }
+
+ // Not used yet.
+ object HasTypeParams {
+ def unapply(tp: Type): Option[(List[Symbol], Type)] = tp match {
+ case AnnotatedType(_, tp, _) => unapply(tp)
+ case ExistentialType(tparams, qtpe) => Some((tparams, qtpe))
+ case PolyType(tparams, restpe) => Some((tparams, restpe))
+ case _ => None
+ }
+ }
+
+ //@M
+ // a TypeVar used to be a case class with only an origin and a constr
+ // then, constr became mutable (to support UndoLog, I guess),
+ // but pattern-matching returned the original constr0 (a bug)
+ // now, pattern-matching returns the most recent constr
+ object TypeVar {
+ @inline final def trace[T](action: String, msg: => String)(value: T): T = {
+ if (traceTypeVars) {
+ val s = msg match {
+ case "" => ""
+ case str => "( " + str + " )"
+ }
+ Console.err.println("[%10s] %-25s%s".format(action, value, s))
+ }
+ value
+ }
+
+ /** Create a new TypeConstraint based on the given symbol.
+ */
+ private def deriveConstraint(tparam: Symbol): TypeConstraint = {
+ /** Must force the type parameter's info at this point
+ * or things don't end well for higher-order type params.
+ * See SI-5359.
+ */
+ val bounds = tparam.info.bounds
+ /** We can seed the type constraint with the type parameter
+ * bounds as long as the types are concrete. This should lower
+ * the complexity of the search even if it doesn't improve
+ * any results.
+ */
+ if (propagateParameterBoundsToTypeVars) {
+ val exclude = bounds.isEmptyBounds || bounds.exists(_.typeSymbolDirect.isNonClassType)
+
+ if (exclude) new TypeConstraint
+ else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(new TypeConstraint(bounds))
+ }
+ else new TypeConstraint
+ }
+ def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr))
+ def untouchable(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = true)
+ def apply(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = false)
+ def apply(origin: Type, constr: TypeConstraint): TypeVar = apply(origin, constr, Nil, Nil)
+ def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]): TypeVar =
+ createTypeVar(origin, constr, args, params, untouchable = false)
+
+ /** This is the only place TypeVars should be instantiated.
+ */
+ private def createTypeVar(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol], untouchable: Boolean): TypeVar = {
+ val tv = (
+ if (args.isEmpty && params.isEmpty) {
+ if (untouchable) new TypeVar(origin, constr) with UntouchableTypeVar
+ else new TypeVar(origin, constr)
+ }
+ else if (args.size == params.size) {
+ if (untouchable) new AppliedTypeVar(origin, constr, params zip args) with UntouchableTypeVar
+ else new AppliedTypeVar(origin, constr, params zip args)
+ }
+ else if (args.isEmpty) {
+ if (untouchable) new HKTypeVar(origin, constr, params) with UntouchableTypeVar
+ else new HKTypeVar(origin, constr, params)
+ }
+ else throw new Error("Invalid TypeVar construction: " + ((origin, constr, args, params)))
+ )
+
+ trace("create", "In " + tv.originLocation)(tv)
+ }
+ private def createTypeVar(tparam: Symbol, untouchable: Boolean): TypeVar =
+ createTypeVar(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams, untouchable)
+ }
+
+ /** Repack existential types, otherwise they sometimes get unpacked in the
+ * wrong location (type inference comes up with an unexpected skolem)
+ */
+ def repackExistential(tp: Type): Type = (
+ if (tp == NoType) tp
+ else existentialAbstraction(existentialsInType(tp), tp)
+ )
+ def containsExistential(tpe: Type) =
+ tpe exists (_.typeSymbol.isExistentiallyBound)
+
+ def existentialsInType(tpe: Type) = (
+ for (tp <- tpe ; if tp.typeSymbol.isExistentiallyBound) yield
+ tp.typeSymbol
+ )
+
+ /** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.)
+ */
+ class HKTypeVar(
+ _origin: Type,
+ _constr: TypeConstraint,
+ override val params: List[Symbol]
+ ) extends TypeVar(_origin, _constr) {
+
+ require(params.nonEmpty, this)
+ override def isHigherKinded = true
+ override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName)
+ }
+
+ /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.)
+ */
+ class AppliedTypeVar(
+ _origin: Type,
+ _constr: TypeConstraint,
+ zippedArgs: List[(Symbol, Type)]
+ ) extends TypeVar(_origin, _constr) {
+
+ require(zippedArgs.nonEmpty, this)
+
+ override def params: List[Symbol] = zippedArgs map (_._1)
+ override def typeArgs: List[Type] = zippedArgs map (_._2)
+
+ override protected def typeVarString = (
+ zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]")
+ )
+ }
+
+ trait UntouchableTypeVar extends TypeVar {
+ override def untouchable = true
+ override def isGround = true
+ override def registerTypeEquality(tp: Type, typeVarLHS: Boolean) = tp match {
+ case t: TypeVar if !t.untouchable =>
+ t.registerTypeEquality(this, !typeVarLHS)
+ case _ =>
+ super.registerTypeEquality(tp, typeVarLHS)
+ }
+ override def registerBound(tp: Type, isLowerBound: Boolean, isNumericBound: Boolean = false): Boolean = tp match {
+ case t: TypeVar if !t.untouchable =>
+ t.registerBound(this, !isLowerBound, isNumericBound)
+ case _ =>
+ super.registerBound(tp, isLowerBound, isNumericBound)
+ }
+ }
+
+ /** A class representing a type variable: not used after phase `typer`.
+ *
+ * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types).
+ * A TypeVar with nonEmpty typeArgs can only be instantiated by a higher-kinded
+ * type that can be applied to those args. A TypeVar is much like a TypeRef,
+ * except it has special logic for equality and subtyping.
+ *
+ * Precondition for this class, enforced structurally: args.isEmpty && params.isEmpty.
+ */
+ class TypeVar(
+ val origin: Type,
+ val constr0: TypeConstraint
+ ) extends Type {
+ def untouchable = false // by other typevars
+ override def params: List[Symbol] = Nil
+ override def typeArgs: List[Type] = Nil
+ override def isHigherKinded = false
+
+ /** The constraint associated with the variable
+ * Syncnote: Type variables are assumed to be used from only one
+ * thread. They are not exposed in api.Types and are used only locally
+ * in operations that are exposed from types. Hence, no syncing of `constr`
+ * or `encounteredHigherLevel` or `suspended` accesses should be necessary.
+ */
+ var constr = constr0
+ def instValid = constr.instValid
+ override def isGround = instValid && constr.inst.isGround
+
+ /** The variable's skolemization level */
+ val level = skolemizationLevel
+
+ /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to
+ * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`.
+ *
+ * `constr` for `?CC` only tracks type constructors anyway,
+ * so when `?CC[Int] <:< List[Int]` and `?CC[String] <:< Iterable[String]`
+ * `?CC's` hibounds contains List and Iterable.
+ */
+ def applyArgs(newArgs: List[Type]): TypeVar = (
+ if (newArgs.isEmpty && typeArgs.isEmpty)
+ this
+ else if (newArgs.size == params.size) {
+ val tv = TypeVar(origin, constr, newArgs, params)
+ TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv)
+ }
+ else
+ throw new Error("Invalid type application in TypeVar: " + params + ", " + newArgs)
+ )
+ // newArgs.length may differ from args.length (could've been empty before)
+ //
+ // !!! @PP - I need an example of this, since this exception never triggers
+ // even though I am requiring the size match.
+ //
+ // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A]
+ // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver)
+ // TypeVars get applied to different arguments over time (in asSeenFrom)
+ // -- see pos/tcpoly_infer_implicit_tuplewrapper.scala
+ // thus: make new TypeVar's for every application of a TV to args,
+ // inference may generate several TypeVar's for a single type parameter that must be inferred,
+ // only one of them is in the set of tvars that need to be solved, but
+ // they share the same TypeConstraint instance
+
+ // When comparing to types containing skolems, remember the highest level
+ // of skolemization. If that highest level is higher than our initial
+ // skolemizationLevel, we can't re-use those skolems as the solution of this
+ // typevar, which means we'll need to repack our constr.inst into a fresh
+ // existential.
+ // were we compared to skolems at a higher skolemizationLevel?
+ // EXPERIMENTAL: value will not be considered unless enableTypeVarExperimentals is true
+ // see SI-5729 for why this is still experimental
+ private var encounteredHigherLevel = false
+ private def shouldRepackType = enableTypeVarExperimentals && encounteredHigherLevel
+
+ // <region name="constraint mutators + undoLog">
+ // invariant: before mutating constr, save old state in undoLog
+ // (undoLog is used to reset constraints to avoid piling up unrelated ones)
+ def setInst(tp: Type) {
+// assert(!(tp containsTp this), this)
+ undoLog record this
+ // if we were compared against later typeskolems, repack the existential,
+ // because skolems are only compatible if they were created at the same level
+ val res = if (shouldRepackType) repackExistential(tp) else tp
+ constr.inst = TypeVar.trace("setInst", "In " + originLocation + ", " + originName + "=" + res)(res)
+ }
+
+ def addLoBound(tp: Type, isNumericBound: Boolean = false) {
+ assert(tp != this, tp) // implies there is a cycle somewhere (?)
+ //println("addLoBound: "+(safeToString, debugString(tp))) //DEBUG
+ undoLog record this
+ constr.addLoBound(tp, isNumericBound)
+ }
+
+ def addHiBound(tp: Type, isNumericBound: Boolean = false) {
+ // assert(tp != this)
+ //println("addHiBound: "+(safeToString, debugString(tp))) //DEBUG
+ undoLog record this
+ constr.addHiBound(tp, isNumericBound)
+ }
+ // </region>
+
+ // ignore subtyping&equality checks while true -- see findMember
+ private[Types] var suspended = false
+
+ /** Called when a TypeVar is involved in a subtyping check. Result is whether
+ * this TypeVar could plausibly be a [super/sub]type of argument `tp` and if so,
+ * tracks tp as a [lower/upper] bound of this TypeVar.
+ *
+ * if (isLowerBound) this typevar could be a subtype, track tp as a lower bound
+ * if (!isLowerBound) this typevar could be a supertype, track tp as an upper bound
+ *
+ * If isNumericBound is true, the subtype check is performed with weak_<:< instead of <:<.
+ */
+ def registerBound(tp: Type, isLowerBound: Boolean, isNumericBound: Boolean = false): Boolean = {
+ // println("regBound: "+(safeToString, debugString(tp), isLowerBound)) //@MDEBUG
+ if (isLowerBound)
+ assert(tp != this)
+
+ // side effect: adds the type to upper or lower bounds
+ def addBound(tp: Type) {
+ if (isLowerBound) addLoBound(tp, isNumericBound)
+ else addHiBound(tp, isNumericBound)
+ }
+ // swaps the arguments if it's an upper bound
+ def checkSubtype(tp1: Type, tp2: Type) = {
+ val lhs = if (isLowerBound) tp1 else tp2
+ val rhs = if (isLowerBound) tp2 else tp1
+
+ if (isNumericBound) lhs weak_<:< rhs
+ else lhs <:< rhs
+ }
+
+ /** Simple case: type arguments can be ignored, because either this typevar has
+ * no type parameters, or we are comparing to Any/Nothing.
+ *
+ * The latter condition is needed because HK unification is limited to constraints of the shape
+ * {{{
+ * TC1[T1,..., TN] <: TC2[T'1,...,T'N]
+ * }}}
+ * which would preclude the following important constraints:
+ * {{{
+ * Nothing <: ?TC[?T]
+ * ?TC[?T] <: Any
+ * }}}
+ */
+ def unifySimple = (
+ (params.isEmpty || tp.typeSymbol == NothingClass || tp.typeSymbol == AnyClass) && {
+ addBound(tp)
+ true
+ }
+ )
+
+ /** Full case: involving a check of the form
+ * {{{
+ * TC1[T1,..., TN] <: TC2[T'1,...,T'N]
+ * }}}
+ * Checks subtyping of higher-order type vars, and uses variances as defined in the
+ * type parameter we're trying to infer (the result will be sanity-checked later).
+ */
+ def unifyFull(tpe: Type) = {
+ // The alias/widen variations are often no-ops.
+ val tpes = (
+ if (isLowerBound) List(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias).distinct
+ else List(tpe)
+ )
+ tpes exists { tp =>
+ val lhs = if (isLowerBound) tp.typeArgs else typeArgs
+ val rhs = if (isLowerBound) typeArgs else tp.typeArgs
+
+ sameLength(lhs, rhs) && {
+ // this is a higher-kinded type var with same arity as tp.
+ // side effect: adds the type constructor itself as a bound
+ addBound(tp.typeConstructor)
+ isSubArgs(lhs, rhs, params)
+ }
+ }
+ }
+
+ // There's a <: test taking place right now, where tp is a concrete type and this is a typevar
+ // attempting to satisfy that test. Either the test will be unsatisfiable, in which case
+ // registerBound will return false; or the upper or lower bounds of this type var will be
+ // supplemented with the type being tested against.
+ //
+ // Eventually the types which have accumulated in the upper and lower bounds will be lubbed
+ // (resp. glbbed) to instantiate the typevar.
+ //
+ // The only types which are eligible for unification are those with the same number of
+ // typeArgs as this typevar, or Any/Nothing, which are kind-polymorphic. For the upper bound,
+ // any parent or base type of `tp` may be tested here (leading to a corresponding relaxation
+ // in the upper bound.) The universe of possible glbs, being somewhat more infinite, is not
+ // addressed here: all lower bounds are retained and their intersection calculated when the
+ // bounds are solved.
+ //
+ // In a side-effect free universe, checking tp and tp.parents beofre checking tp.baseTypeSeq
+ // would be pointless. In this case, each check we perform causes us to lose specificity: in
+ // the end the best we'll do is the least specific type we tested against, since the typevar
+ // does not see these checks as "probes" but as requirements to fulfill.
+ // TODO: can the `suspended` flag be used to poke around without leaving a trace?
+ //
+ // So the strategy used here is to test first the type, then the direct parents, and finally
+ // to fall back on the individual base types. This warrants eventual re-examination.
+
+ // AM: I think we could use the `suspended` flag to avoid side-effecting during unification
+ if (suspended) // constraint accumulation is disabled
+ checkSubtype(tp, origin)
+ else if (constr.instValid) // type var is already set
+ checkSubtype(tp, constr.inst)
+ else isRelatable(tp) && {
+ unifySimple || unifyFull(tp) || (
+ // only look harder if our gaze is oriented toward Any
+ isLowerBound && (
+ (tp.parents exists unifyFull) || (
+ // @PP: Is it going to be faster to filter out the parents we just checked?
+ // That's what's done here but I'm not sure it matters.
+ tp.baseTypeSeq.toList.tail filterNot (tp.parents contains _) exists unifyFull
+ )
+ )
+ )
+ }
+ }
+
+ def registerTypeEquality(tp: Type, typeVarLHS: Boolean): Boolean = {
+// println("regTypeEq: "+(safeToString, debugString(tp), tp.getClass, if (typeVarLHS) "in LHS" else "in RHS", if (suspended) "ZZ" else if (constr.instValid) "IV" else "")) //@MDEBUG
+// println("constr: "+ constr)
+ def checkIsSameType(tp: Type) =
+ if(typeVarLHS) constr.inst =:= tp
+ else tp =:= constr.inst
+
+ if (suspended) tp =:= origin
+ else if (constr.instValid) checkIsSameType(tp)
+ else isRelatable(tp) && {
+ val newInst = wildcardToTypeVarMap(tp)
+ (constr isWithinBounds newInst) && { setInst(tp); true }
+ }
+ }
+
+ /**
+ * `?A.T =:= tp` is rewritten as the constraint `?A <: {type T = tp}`
+ *
+ * TODO: make these constraints count (incorporate them into implicit search in `applyImplicitArgs`)
+ * (`T` corresponds to @param sym)
+ */
+ def registerTypeSelection(sym: Symbol, tp: Type): Boolean = {
+ registerBound(HasTypeMember(sym.name.toTypeName, tp), false)
+ }
+
+ private def isSkolemAboveLevel(tp: Type) = tp.typeSymbol match {
+ case ts: TypeSkolem => ts.level > level
+ case _ => false
+ }
+ // side-effects encounteredHigherLevel
+ private def containsSkolemAboveLevel(tp: Type) =
+ (tp exists isSkolemAboveLevel) && { encounteredHigherLevel = true ; true }
+
+ /** Can this variable be related in a constraint to type `tp`?
+ * This is not the case if `tp` contains type skolems whose
+ * skolemization level is higher than the level of this variable.
+ */
+ def isRelatable(tp: Type) = (
+ shouldRepackType // short circuit if we already know we've seen higher levels
+ || !containsSkolemAboveLevel(tp) // side-effects tracking boolean
+ || enableTypeVarExperimentals // -Xexperimental: always say we're relatable, track consequences
+ )
+
+ override def normalize: Type = (
+ if (constr.instValid) constr.inst
+ // get here when checking higher-order subtyping of the typevar by itself
+ // TODO: check whether this ever happens?
+ else if (isHigherKinded) typeFun(params, applyArgs(params map (_.typeConstructor)))
+ else super.normalize
+ )
+ override def typeSymbol = origin.typeSymbol
+ override def isStable = origin.isStable
+ override def isVolatile = origin.isVolatile
+
+ private def tparamsOfSym(sym: Symbol) = sym.info match {
+ case PolyType(tparams, _) if tparams.nonEmpty =>
+ tparams map (_.defString) mkString("[", ",", "]")
+ case _ => ""
+ }
+ def originName = origin.typeSymbolDirect.decodedName
+ def originLocation = {
+ val sym = origin.typeSymbolDirect
+ val encl = sym.owner.logicallyEnclosingMember
+
+ // This should display somewhere between one and three
+ // things which enclose the origin: at most, a class, a
+ // a method, and a term. At least, a class.
+ List(
+ Some(encl.enclClass),
+ if (encl.isMethod) Some(encl) else None,
+ if (sym.owner.isTerm && (sym.owner != encl)) Some(sym.owner) else None
+ ).flatten map (s => s.decodedName + tparamsOfSym(s)) mkString "#"
+ }
+ private def levelString = if (settings.explaintypes.value) level else ""
+ protected def typeVarString = originName
+ override def safeToString = (
+ if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>"
+ else if (constr.inst ne NoType) "=?" + constr.inst
+ else (if(untouchable) "!?" else "?") + levelString + originName
+ )
+ override def kind = "TypeVar"
+
+ def cloneInternal = {
+ // cloning a suspended type variable when it's suspended will cause the clone
+ // to never be resumed with the current implementation
+ assert(!suspended, this)
+ TypeVar.trace("clone", originLocation)(
+ TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params?
+ )
+ }
+ }
+
+ /** A type carrying some annotations. Created by the typechecker
+ * when eliminating ''Annotated'' trees (see typedAnnotated).
+ *
+ * @param annotations the list of annotations on the type
+ * @param underlying the type without the annotation
+ * @param selfsym a "self" symbol with type `underlying`;
+ * only available if -Yself-in-annots is turned on. Can be `NoSymbol`
+ * if it is not used.
+ */
+ case class AnnotatedType(override val annotations: List[AnnotationInfo],
+ override val underlying: Type,
+ override val selfsym: Symbol)
+ extends RewrappingTypeProxy with AnnotatedTypeApi {
+
+ assert(!annotations.isEmpty, "" + underlying)
+
+ override protected def rewrap(tp: Type) = copy(underlying = tp)
+
+ override def isTrivial: Boolean = isTrivial0
+ private lazy val isTrivial0 = underlying.isTrivial && annotations.forall(_.isTrivial)
+
+ override def safeToString = annotations.mkString(underlying + " @", " @", "")
+
+ override def filterAnnotations(p: AnnotationInfo => Boolean): Type = {
+ val (yes, no) = annotations partition p
+ if (yes.isEmpty) underlying
+ else if (no.isEmpty) this
+ else copy(annotations = yes)
+ }
+ override def setAnnotations(annots: List[AnnotationInfo]): Type =
+ if (annots.isEmpty) underlying
+ else copy(annotations = annots)
+
+ /** Add a number of annotations to this type */
+ override def withAnnotations(annots: List[AnnotationInfo]): Type =
+ if (annots.isEmpty) this
+ else copy(annots ::: this.annotations)
+
+ /** Remove any annotations from this type.
+ * TODO - is it allowed to nest AnnotatedTypes? If not then let's enforce
+ * that at creation. At the moment if they do ever turn up nested this
+ * recursively calls withoutAnnotations.
+ */
+ override def withoutAnnotations = underlying.withoutAnnotations
+
+ /** Set the self symbol */
+ override def withSelfsym(sym: Symbol) = copy(selfsym = sym)
+
+ /** Drop the annotations on the bounds, unless the low and high
+ * bounds are exactly tp.
+ */
+ override def bounds: TypeBounds = underlying.bounds match {
+ case TypeBounds(_: this.type, _: this.type) => TypeBounds(this, this)
+ case oftp => oftp
+ }
+
+ // ** Replace formal type parameter symbols with actual type arguments. * /
+ override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = {
+ val annotations1 = annotations.map(info => AnnotationInfo(info.atp.instantiateTypeParams(
+ formals, actuals), info.args, info.assocs).setPos(info.pos))
+ val underlying1 = underlying.instantiateTypeParams(formals, actuals)
+ if ((annotations1 eq annotations) && (underlying1 eq underlying)) this
+ else AnnotatedType(annotations1, underlying1, selfsym)
+ }
+
+ /** Return the base type sequence of tp, dropping the annotations, unless the base type sequence of tp
+ * is precisely tp itself. */
+ override def baseTypeSeq: BaseTypeSeq = {
+ val oftp = underlying.baseTypeSeq
+ if ((oftp.length == 1) && (oftp(0) eq underlying))
+ baseTypeSingletonSeq(this)
+ else
+ oftp
+ }
+
+ override def kind = "AnnotatedType"
+ }
+
+ /** Creator for AnnotatedTypes. It returns the underlying type if annotations.isEmpty
+ * rather than walking into the assertion.
+ */
+ def annotatedType(annots: List[AnnotationInfo], underlying: Type, selfsym: Symbol = NoSymbol): Type =
+ if (annots.isEmpty) underlying
+ else AnnotatedType(annots, underlying, selfsym)
+
+ object AnnotatedType extends AnnotatedTypeExtractor
+
+ /** A class representing types with a name. When an application uses
+ * named arguments, the named argument types for calling isApplicable
+ * are represented as NamedType.
+ */
+ case class NamedType(name: Name, tp: Type) extends Type {
+ override def safeToString: String = name.toString +": "+ tp
+ }
+
+ /** A De Bruijn index referring to a previous type argument. Only used
+ * as a serialization format.
+ */
+ case class DeBruijnIndex(level: Int, idx: Int, args: List[Type]) extends Type {
+ override def safeToString: String = "De Bruijn index("+level+","+idx+")"
+ }
+
+ /** A binder defining data associated with De Bruijn indices. Only used
+ * as a serialization format.
+ */
+ case class DeBruijnBinder(pnames: List[Name], ptypes: List[Type], restpe: Type) extends Type {
+ override def safeToString = {
+ val kind = if (pnames.head.isTypeName) "poly" else "method"
+ "De Bruijn "+kind+"("+(pnames mkString ",")+";"+(ptypes mkString ",")+";"+restpe+")"
+ }
+ }
+
+ abstract case class ErasedValueType(sym: Symbol) extends Type {
+ override def safeToString = sym.name+"$unboxed"
+ }
+
+ final class UniqueErasedValueType(sym: Symbol) extends ErasedValueType(sym) with UniqueType
+
+ object ErasedValueType {
+ def apply(sym: Symbol): Type = {
+ assert(sym ne NoSymbol, "ErasedValueType cannot be NoSymbol")
+ unique(new UniqueErasedValueType(sym))
+ }
+ }
+
+ /** A class representing an as-yet unevaluated type.
+ */
+ abstract class LazyType extends Type {
+ override def isComplete: Boolean = false
+ override def complete(sym: Symbol)
+ override def safeToString = "<?>"
+ override def kind = "LazyType"
+ }
+
+ abstract class LazyPolyType(override val typeParams: List[Symbol]) extends LazyType {
+ override def safeToString =
+ (if (typeParams.isEmpty) "" else typeParamsString(this)) + super.safeToString
+ }
+
+ // def mkLazyType(tparams: Symbol*)(f: Symbol => Unit): LazyType = (
+ // if (tparams.isEmpty) new LazyType { override def complete(sym: Symbol) = f(sym) }
+ // else new LazyPolyType(tparams.toList) { override def complete(sym: Symbol) = f(sym) }
+ // )
+
+// Creators ---------------------------------------------------------------
+
+ /** Rebind symbol `sym` to an overriding member in type `pre`. */
+ private def rebind(pre: Type, sym: Symbol): Symbol = {
+ if (!sym.isOverridableMember || sym.owner == pre.typeSymbol) sym
+ else pre.nonPrivateMember(sym.name).suchThat(sym => sym.isType || sym.isStable) orElse sym
+ }
+
+ /** Convert a `super` prefix to a this-type if `sym` is abstract or final. */
+ private def removeSuper(tp: Type, sym: Symbol): Type = tp match {
+ case SuperType(thistp, _) =>
+ if (sym.isEffectivelyFinal || sym.isDeferred) thistp
+ else tp
+ case _ =>
+ tp
+ }
+
+ /** The canonical creator for single-types */
+ def singleType(pre: Type, sym: Symbol): Type = {
+ if (phase.erasedTypes)
+ sym.tpe.resultType
+ else if (sym.isRootPackage)
+ ThisType(sym.moduleClass)
+ else {
+ var sym1 = rebind(pre, sym)
+ val pre1 = removeSuper(pre, sym1)
+ if (pre1 ne pre) sym1 = rebind(pre1, sym1)
+ SingleType(pre1, sym1)
+ }
+ }
+
+ /** the canonical creator for a refined type with a given scope */
+ def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): Type = {
+ if (phase.erasedTypes)
+ if (parents.isEmpty) ObjectClass.tpe else parents.head
+ else {
+ val clazz = owner.newRefinementClass(pos) // TODO: why were we passing in NoPosition instead of pos?
+ val result = RefinedType(parents, decls, clazz)
+ clazz.setInfo(result)
+ result
+ }
+ }
+
+ /** The canonical creator for a refined type with an initially empty scope.
+ *
+ * @param parents ...
+ * @param owner ...
+ * @return ...
+ */
+ def refinedType(parents: List[Type], owner: Symbol): Type =
+ refinedType(parents, owner, newScope, owner.pos)
+
+ def copyRefinedType(original: RefinedType, parents: List[Type], decls: Scope) =
+ if ((parents eq original.parents) && (decls eq original.decls)) original
+ else {
+ val owner = if (original.typeSymbol == NoSymbol) NoSymbol else original.typeSymbol.owner
+ val result = refinedType(parents, owner)
+ val syms1 = decls.toList
+ for (sym <- syms1)
+ result.decls.enter(sym.cloneSymbol(result.typeSymbol))
+ val syms2 = result.decls.toList
+ val resultThis = result.typeSymbol.thisType
+ for (sym <- syms2)
+ sym modifyInfo (_ substThisAndSym(original.typeSymbol, resultThis, syms1, syms2))
+
+ result
+ }
+
+ /** The canonical creator for typerefs
+ * todo: see how we can clean this up a bit
+ */
+ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = {
+ // type alias selections are rebound in TypeMap ("coevolved",
+ // actually -- see #3731) e.g., when type parameters that are
+ // referenced by the alias are instantiated in the prefix. See
+ // pos/depmet_rebind_typealias.
+
+ val sym1 = if (sym.isAbstractType) rebind(pre, sym) else sym
+ // don't expand cyclical type alias
+ // we require that object is initialized, thus info.typeParams instead of typeParams.
+ if (sym1.isAliasType && sameLength(sym1.info.typeParams, args) && !sym1.lockOK)
+ throw new RecoverableCyclicReference(sym1)
+
+ val pre1 = pre match {
+ case x: SuperType if sym1.isEffectivelyFinal || sym1.isDeferred =>
+ x.thistpe
+ case _: CompoundType if sym1.isClass =>
+ // sharpen prefix so that it is maximal and still contains the class.
+ pre.parents.reverse dropWhile (_.member(sym1.name) != sym1) match {
+ case Nil => pre
+ case parent :: _ => parent
+ }
+ case _ => pre
+ }
+ if (pre eq pre1) TypeRef(pre, sym1, args)
+ else if (sym1.isAbstractType && !sym1.isClass) typeRef(pre1, rebind(pre1, sym1), args)
+ else typeRef(pre1, sym1, args)
+ }
+
+ // Optimization to avoid creating unnecessary new typerefs.
+ def copyTypeRef(tp: Type, pre: Type, sym: Symbol, args: List[Type]): Type = tp match {
+ case TypeRef(pre0, sym0, _) if pre == pre0 && sym0.name == sym.name =>
+ if (sym.isAliasType && sameLength(sym.info.typeParams, args) && !sym.lockOK)
+ throw new RecoverableCyclicReference(sym)
+
+ TypeRef(pre, sym, args)
+ case _ =>
+ typeRef(pre, sym, args)
+ }
+
+ /** The canonical creator for implicit method types */
+ def JavaMethodType(params: List[Symbol], resultType: Type): JavaMethodType =
+ new JavaMethodType(params, resultType) // don't unique this!
+
+ /** Create a new MethodType of the same class as tp, i.e. keep JavaMethodType */
+ def copyMethodType(tp: Type, params: List[Symbol], restpe: Type): Type = tp match {
+ case _: JavaMethodType => JavaMethodType(params, restpe)
+ case _ => MethodType(params, restpe)
+ }
+
+ /** A creator for intersection type where intersections of a single type are
+ * replaced by the type itself, and repeated parent classes are merged.
+ *
+ * !!! Repeated parent classes are not merged - is this a bug in the
+ * comment or in the code?
+ */
+ def intersectionType(tps: List[Type], owner: Symbol): Type = tps match {
+ case tp :: Nil => tp
+ case _ => refinedType(tps, owner)
+ }
+ /** A creator for intersection type where intersections of a single type are
+ * replaced by the type itself.
+ */
+ def intersectionType(tps: List[Type]): Type = tps match {
+ case tp :: Nil => tp
+ case _ => refinedType(tps, commonOwner(tps))
+ }
+
+/**** This implementation to merge parents was checked in in commented-out
+ form and has languished unaltered for five years. I think we should
+ use it or lose it.
+
+ def merge(tps: List[Type]): List[Type] = tps match {
+ case tp :: tps1 =>
+ val tps1a = tps1 filter (_.typeSymbol.==(tp.typeSymbol))
+ val tps1b = tps1 filter (_.typeSymbol.!=(tp.typeSymbol))
+ mergePrefixAndArgs(tps1a, -1) match {
+ case Some(tp1) => tp1 :: merge(tps1b)
+ case None => throw new MalformedType(
+ "malformed type: "+refinedType(tps, owner)+" has repeated parent class "+
+ tp.typeSymbol+" with incompatible prefixes or type arguments")
+ }
+ case _ => tps
+ }
+ refinedType(merge(tps), owner)
+*/
+
+ /** A creator for type applications */
+ def appliedType(tycon: Type, args: List[Type]): Type =
+ if (args.isEmpty) tycon //@M! `if (args.isEmpty) tycon' is crucial (otherwise we create new types in phases after typer and then they don't get adapted (??))
+ else tycon match {
+ case TypeRef(pre, sym @ (NothingClass|AnyClass), _) => copyTypeRef(tycon, pre, sym, Nil) //@M drop type args to Any/Nothing
+ case TypeRef(pre, sym, _) => copyTypeRef(tycon, pre, sym, args)
+ case PolyType(tparams, restpe) => restpe.instantiateTypeParams(tparams, args)
+ case ExistentialType(tparams, restpe) => newExistentialType(tparams, appliedType(restpe, args))
+ case st: SingletonType => appliedType(st.widen, args) // @M TODO: what to do? see bug1
+ case RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // MO to AM: please check
+ case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args))
+ case tv@TypeVar(_, _) => tv.applyArgs(args)
+ case AnnotatedType(annots, underlying, self) => AnnotatedType(annots, appliedType(underlying, args), self)
+ case ErrorType => tycon
+ case WildcardType => tycon // needed for neg/t0226
+ case _ => abort(debugString(tycon))
+ }
+
+ /** Very convenient. */
+ def appliedType(tyconSym: Symbol, args: Type*): Type =
+ appliedType(tyconSym.typeConstructor, args.toList)
+
+ /** A creator for existential types where the type arguments,
+ * rather than being applied directly, are interpreted as the
+ * upper bounds of unknown types. For instance if the type argument
+ * list given is List(AnyRefClass), the resulting type would be
+ * e.g. Set[_ <: AnyRef] rather than Set[AnyRef] .
+ */
+ def appliedTypeAsUpperBounds(tycon: Type, args: List[Type]): Type = {
+ tycon match {
+ case TypeRef(pre, sym, _) if sameLength(sym.typeParams, args) =>
+ val eparams = typeParamsToExistentials(sym)
+ val bounds = args map (TypeBounds upper _)
+ foreach2(eparams, bounds)(_ setInfo _)
+
+ newExistentialType(eparams, typeRef(pre, sym, eparams map (_.tpe)))
+ case _ =>
+ appliedType(tycon, args)
+ }
+ }
+
+ /** A creator and extractor for type parameterizations that strips empty type parameter lists.
+ * Use this factory method to indicate the type has kind * (it's a polymorphic value)
+ * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty).
+ *
+ * PP to AM: I've co-opted this for where I know tparams may well be empty, and
+ * expecting to get back `tpe` in such cases. Re being "forgiving" below,
+ * can we instead say this is the canonical creator for polyTypes which
+ * may or may not be poly? (It filched the standard "canonical creator" name.)
+ */
+ object GenPolyType {
+ def apply(tparams: List[Symbol], tpe: Type): Type = (
+ if (tparams nonEmpty) typeFun(tparams, tpe)
+ else tpe // it's okay to be forgiving here
+ )
+ def unapply(tpe: Type): Option[(List[Symbol], Type)] = tpe match {
+ case PolyType(tparams, restpe) => Some((tparams, restpe))
+ case _ => Some((Nil, tpe))
+ }
+ }
+ def genPolyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe)
+
+ @deprecated("use genPolyType(...) instead", "2.10.0")
+ def polyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe)
+
+ /** A creator for anonymous type functions, where the symbol for the type function still needs to be created.
+ *
+ * TODO:
+ * type params of anonymous type functions, which currently can only arise from normalising type aliases, are owned by the type alias of which they are the eta-expansion
+ * higher-order subtyping expects eta-expansion of type constructors that arise from a class; here, the type params are owned by that class, but is that the right thing to do?
+ */
+ def typeFunAnon(tps: List[Symbol], body: Type): Type = typeFun(tps, body)
+
+ /** A creator for a type functions, assuming the type parameters tps already have the right owner. */
+ def typeFun(tps: List[Symbol], body: Type): Type = PolyType(tps, body)
+
+ /** A creator for existential types. This generates:
+ *
+ * tpe1 where { tparams }
+ *
+ * where `tpe1` is the result of extrapolating `tpe` wrt to `tparams`.
+ * Extrapolating means that type variables in `tparams` occurring
+ * in covariant positions are replaced by upper bounds, (minus any
+ * SingletonClass markers), type variables in `tparams` occurring in
+ * contravariant positions are replaced by upper bounds, provided the
+ * resulting type is legal wrt to stability, and does not contain any type
+ * variable in `tparams`.
+ *
+ * The abstraction drops all type parameters that are not directly or
+ * indirectly referenced by type `tpe1`. If there are no remaining type
+ * parameters, simply returns result type `tpe`.
+ */
+ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type =
+ if (tparams.isEmpty) tpe0
+ else {
+ val tpe = deAlias(tpe0)
+ val tpe1 = new ExistentialExtrapolation(tparams) extrapolate tpe
+ var tparams0 = tparams
+ var tparams1 = tparams0 filter tpe1.contains
+
+ while (tparams1 != tparams0) {
+ tparams0 = tparams1
+ tparams1 = tparams filter { p =>
+ tparams1 exists { p1 => p1 == p || (p1.info contains p) }
+ }
+ }
+ newExistentialType(tparams1, tpe1)
+ }
+
+ /** Remove any occurrences of type aliases from this type */
+ object deAlias extends TypeMap {
+ def apply(tp: Type): Type = mapOver {
+ tp match {
+ case TypeRef(pre, sym, args) if sym.isAliasType => tp.normalize
+ case _ => tp
+ }
+ }
+ }
+
+ /** Remove any occurrence of type <singleton> from this type and its parents */
+ object dropSingletonType extends TypeMap {
+ def apply(tp: Type): Type = {
+ tp match {
+ case TypeRef(_, SingletonClass, _) =>
+ AnyClass.tpe
+ case tp1 @ RefinedType(parents, decls) =>
+ var parents1 = parents filter (_.typeSymbol != SingletonClass)
+ if (parents1.isEmpty) parents1 = List(AnyClass.tpe)
+ if (parents1.tail.isEmpty && decls.isEmpty) mapOver(parents1.head)
+ else mapOver(copyRefinedType(tp1, parents1, decls))
+ case tp1 =>
+ mapOver(tp1)
+ }
+ }
+ }
+
+ /** Substitutes the empty scope for any non-empty decls in the type. */
+ object dropAllRefinements extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case rt @ RefinedType(parents, decls) if !decls.isEmpty =>
+ mapOver(copyRefinedType(rt, parents, EmptyScope))
+ case ClassInfoType(parents, decls, clazz) if !decls.isEmpty =>
+ mapOver(ClassInfoType(parents, EmptyScope, clazz))
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ /** Type with all top-level occurrences of abstract types replaced by their bounds */
+ def abstractTypesToBounds(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala )
+ case TypeRef(_, sym, _) if sym.isAbstractType =>
+ abstractTypesToBounds(tp.bounds.hi)
+ case TypeRef(_, sym, _) if sym.isAliasType =>
+ abstractTypesToBounds(tp.normalize)
+ case rtp @ RefinedType(parents, decls) =>
+ copyRefinedType(rtp, parents mapConserve abstractTypesToBounds, decls)
+ case AnnotatedType(_, underlying, _) =>
+ abstractTypesToBounds(underlying)
+ case _ =>
+ tp
+ }
+
+ // Set to true for A* => Seq[A]
+ // (And it will only rewrite A* in method result types.)
+ // This is the pre-existing behavior.
+ // Or false for Seq[A] => Seq[A]
+ // (It will rewrite A* everywhere but method parameters.)
+ // This is the specified behavior.
+ protected def etaExpandKeepsStar = false
+
+ object dropRepeatedParamType extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case MethodType(params, restpe) =>
+ MethodType(params, apply(restpe))
+ case PolyType(tparams, restpe) =>
+ PolyType(tparams, apply(restpe))
+ case TypeRef(_, RepeatedParamClass, arg :: Nil) =>
+ seqType(arg)
+ case _ =>
+ if (etaExpandKeepsStar) tp else mapOver(tp)
+ }
+ }
+
+ object toDeBruijn extends TypeMap {
+ private var paramStack: List[List[Symbol]] = Nil
+ def mkDebruijnBinder(params: List[Symbol], restpe: Type) = {
+ paramStack = params :: paramStack
+ try {
+ DeBruijnBinder(params map (_.name), params map (p => this(p.info)), this(restpe))
+ } finally paramStack = paramStack.tail
+ }
+ def apply(tp: Type): Type = tp match {
+ case PolyType(tparams, restpe) =>
+ mkDebruijnBinder(tparams, restpe)
+ case MethodType(params, restpe) =>
+ mkDebruijnBinder(params, restpe)
+ case TypeRef(NoPrefix, sym, args) =>
+ val level = paramStack indexWhere (_ contains sym)
+ if (level < 0) mapOver(tp)
+ else DeBruijnIndex(level, paramStack(level) indexOf sym, args mapConserve this)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ def fromDeBruijn(owner: Symbol) = new TypeMap {
+ private var paramStack: List[List[Symbol]] = Nil
+ def apply(tp: Type): Type = tp match {
+ case DeBruijnBinder(pnames, ptypes, restpe) =>
+ val isType = pnames.head.isTypeName
+ val newParams = for (name <- pnames) yield
+ if (isType) owner.newTypeParameter(name.toTypeName)
+ else owner.newValueParameter(name.toTermName)
+ paramStack = newParams :: paramStack
+ try {
+ foreach2(newParams, ptypes)((p, t) => p setInfo this(t))
+ val restpe1 = this(restpe)
+ if (isType) PolyType(newParams, restpe1)
+ else MethodType(newParams, restpe1)
+ } finally paramStack = paramStack.tail
+ case DeBruijnIndex(level, idx, args) =>
+ TypeRef(NoPrefix, paramStack(level)(idx), args map this)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+// Hash consing --------------------------------------------------------------
+
+ private val initialUniquesCapacity = 4096
+ private var uniques: util.HashSet[Type] = _
+ private var uniqueRunId = NoRunId
+
+ protected def unique[T <: Type](tp: T): T = {
+ incCounter(rawTypeCount)
+ if (uniqueRunId != currentRunId) {
+ uniques = util.HashSet[Type]("uniques", initialUniquesCapacity)
+ uniqueRunId = currentRunId
+ }
+ (uniques findEntryOrUpdate tp).asInstanceOf[T]
+ }
+
+// Helper Classes ---------------------------------------------------------
+
+ /** @PP: Unable to see why these apparently constant types should need vals
+ * in every TypeConstraint, I lifted them out.
+ */
+ private lazy val numericLoBound = IntClass.tpe
+ private lazy val numericHiBound = intersectionType(List(ByteClass.tpe, CharClass.tpe), ScalaPackageClass)
+
+ /** A class expressing upper and lower bounds constraints of type variables,
+ * as well as their instantiations.
+ */
+ class TypeConstraint(lo0: List[Type], hi0: List[Type], numlo0: Type, numhi0: Type, avoidWidening0: Boolean = false) {
+ def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType)
+ def this(bounds: TypeBounds) = this(List(bounds.lo), List(bounds.hi))
+ def this() = this(List(), List())
+
+ /* Syncnote: Type constraints are assumed to be used from only one
+ * thread. They are not exposed in api.Types and are used only locally
+ * in operations that are exposed from types. Hence, no syncing of any
+ * variables should be ncessesary.
+ */
+
+ /** Guard these lists against AnyClass and NothingClass appearing,
+ * else loBounds.isEmpty will have different results for an empty
+ * constraint and one with Nothing as a lower bound. [Actually
+ * guarding addLoBound/addHiBound somehow broke raw types so it
+ * only guards against being created with them.]
+ */
+ private var lobounds = lo0 filterNot (_.typeSymbolDirect eq NothingClass)
+ private var hibounds = hi0 filterNot (_.typeSymbolDirect eq AnyClass)
+ private var numlo = numlo0
+ private var numhi = numhi0
+ private var avoidWidening = avoidWidening0
+
+ def loBounds: List[Type] = if (numlo == NoType) lobounds else numlo :: lobounds
+ def hiBounds: List[Type] = if (numhi == NoType) hibounds else numhi :: hibounds
+ def avoidWiden: Boolean = avoidWidening
+
+ def addLoBound(tp: Type, isNumericBound: Boolean = false) {
+ if (isNumericBound && isNumericValueType(tp)) {
+ if (numlo == NoType || isNumericSubType(numlo, tp))
+ numlo = tp
+ else if (!isNumericSubType(tp, numlo))
+ numlo = numericLoBound
+ }
+ else lobounds ::= tp
+ }
+
+ def checkWidening(tp: Type) {
+ if(tp.isStable) avoidWidening = true
+ else tp match {
+ case HasTypeMember(_, _) => avoidWidening = true
+ case _ =>
+ }
+ }
+
+ def addHiBound(tp: Type, isNumericBound: Boolean = false) {
+ checkWidening(tp)
+ if (isNumericBound && isNumericValueType(tp)) {
+ if (numhi == NoType || isNumericSubType(tp, numhi))
+ numhi = tp
+ else if (!isNumericSubType(numhi, tp))
+ numhi = numericHiBound
+ }
+ else hibounds ::= tp
+ }
+
+ def isWithinBounds(tp: Type): Boolean =
+ lobounds.forall(_ <:< tp) &&
+ hibounds.forall(tp <:< _) &&
+ (numlo == NoType || (numlo weak_<:< tp)) &&
+ (numhi == NoType || (tp weak_<:< numhi))
+
+ var inst: Type = NoType // @M reduce visibility?
+
+ def instValid = (inst ne null) && (inst ne NoType)
+
+ def cloneInternal = {
+ val tc = new TypeConstraint(lobounds, hibounds, numlo, numhi, avoidWidening)
+ tc.inst = inst
+ tc
+ }
+
+ override def toString = {
+ val boundsStr = {
+ val lo = loBounds filterNot (_.typeSymbolDirect eq NothingClass)
+ val hi = hiBounds filterNot (_.typeSymbolDirect eq AnyClass)
+ val lostr = if (lo.isEmpty) Nil else List(lo.mkString(" >: (", ", ", ")"))
+ val histr = if (hi.isEmpty) Nil else List(hi.mkString(" <: (", ", ", ")"))
+
+ lostr ++ histr mkString ("[", " | ", "]")
+ }
+ if (inst eq NoType) boundsStr
+ else boundsStr + " _= " + inst.safeToString
+ }
+ }
+
+ class TypeUnwrapper(poly: Boolean, existential: Boolean, annotated: Boolean, nullary: Boolean) extends (Type => Type) {
+ def apply(tp: Type): Type = tp match {
+ case AnnotatedType(_, underlying, _) if annotated => apply(underlying)
+ case ExistentialType(_, underlying) if existential => apply(underlying)
+ case PolyType(_, underlying) if poly => apply(underlying)
+ case NullaryMethodType(underlying) if nullary => apply(underlying)
+ case tp => tp
+ }
+ }
+ class ClassUnwrapper(existential: Boolean) extends TypeUnwrapper(poly = true, existential, annotated = true, nullary = false) {
+ override def apply(tp: Type) = super.apply(tp.normalize)
+ }
+
+ object unwrapToClass extends ClassUnwrapper(existential = true) { }
+ object unwrapToStableClass extends ClassUnwrapper(existential = false) { }
+ object unwrapWrapperTypes extends TypeUnwrapper(true, true, true, true) { }
+
+ trait AnnotationFilter extends TypeMap {
+ def keepAnnotation(annot: AnnotationInfo): Boolean
+
+ override def mapOver(annot: AnnotationInfo) =
+ if (keepAnnotation(annot)) super.mapOver(annot)
+ else UnmappableAnnotation
+ }
+
+ trait KeepOnlyTypeConstraints extends AnnotationFilter {
+ // filter keeps only type constraint annotations
+ def keepAnnotation(annot: AnnotationInfo) = annot matches TypeConstraintClass
+ }
+
+ trait VariantTypeMap extends TypeMap {
+ private[this] var _variance = 1
+
+ override def variance = _variance
+ def variance_=(x: Int) = _variance = x
+
+ override protected def noChangeToSymbols(origSyms: List[Symbol]) = {
+ origSyms forall { sym =>
+ val v = variance
+ if (sym.isAliasType) variance = 0
+ val result = this(sym.info)
+ variance = v
+ result eq sym.info
+ }
+ }
+
+ override protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
+ map2Conserve(args, tparams) { (arg, tparam) =>
+ val v = variance
+ if (tparam.isContravariant) variance = -variance
+ else if (!tparam.isCovariant) variance = 0
+ val arg1 = this(arg)
+ variance = v
+ arg1
+ }
+
+ /** Map this function over given type */
+ override def mapOver(tp: Type): Type = tp match {
+ case MethodType(params, result) =>
+ variance = -variance
+ val params1 = mapOver(params)
+ variance = -variance
+ val result1 = this(result)
+ if ((params1 eq params) && (result1 eq result)) tp
+ else copyMethodType(tp, params1, result1.substSym(params, params1))
+ case PolyType(tparams, result) =>
+ variance = -variance
+ val tparams1 = mapOver(tparams)
+ variance = -variance
+ var result1 = this(result)
+ if ((tparams1 eq tparams) && (result1 eq result)) tp
+ else PolyType(tparams1, result1.substSym(tparams, tparams1))
+ case TypeBounds(lo, hi) =>
+ variance = -variance
+ val lo1 = this(lo)
+ variance = -variance
+ val hi1 = this(hi)
+ if ((lo1 eq lo) && (hi1 eq hi)) tp
+ else TypeBounds(lo1, hi1)
+ case tr @ TypeRef(pre, sym, args) =>
+ val pre1 = this(pre)
+ val args1 =
+ if (args.isEmpty)
+ args
+ else if (variance == 0) // fast & safe path: don't need to look at typeparams
+ args mapConserve this
+ else {
+ val tparams = sym.typeParams
+ if (tparams.isEmpty) args
+ else mapOverArgs(args, tparams)
+ }
+ if ((pre1 eq pre) && (args1 eq args)) tp
+ else copyTypeRef(tp, pre1, tr.coevolveSym(pre1), args1)
+ case _ =>
+ super.mapOver(tp)
+ }
+ }
+
+ // todo. move these into scala.reflect.api
+
+ /** A prototype for mapping a function over all possible types
+ */
+ abstract class TypeMap extends (Type => Type) {
+ def apply(tp: Type): Type
+
+ /** Mix in VariantTypeMap if you want variances to be significant.
+ */
+ def variance = 0
+
+ /** Map this function over given type */
+ def mapOver(tp: Type): Type = tp match {
+ case tr @ TypeRef(pre, sym, args) =>
+ val pre1 = this(pre)
+ val args1 = args mapConserve this
+ if ((pre1 eq pre) && (args1 eq args)) tp
+ else copyTypeRef(tp, pre1, tr.coevolveSym(pre1), args1)
+ case ThisType(_) => tp
+ case SingleType(pre, sym) =>
+ if (sym.isPackageClass) tp // short path
+ else {
+ val pre1 = this(pre)
+ if (pre1 eq pre) tp
+ else singleType(pre1, sym)
+ }
+ case MethodType(params, result) =>
+ val params1 = mapOver(params)
+ val result1 = this(result)
+ if ((params1 eq params) && (result1 eq result)) tp
+ else copyMethodType(tp, params1, result1.substSym(params, params1))
+ case PolyType(tparams, result) =>
+ val tparams1 = mapOver(tparams)
+ var result1 = this(result)
+ if ((tparams1 eq tparams) && (result1 eq result)) tp
+ else PolyType(tparams1, result1.substSym(tparams, tparams1))
+ case NullaryMethodType(result) =>
+ val result1 = this(result)
+ if (result1 eq result) tp
+ else NullaryMethodType(result1)
+ case ConstantType(_) => tp
+ case SuperType(thistp, supertp) =>
+ val thistp1 = this(thistp)
+ val supertp1 = this(supertp)
+ if ((thistp1 eq thistp) && (supertp1 eq supertp)) tp
+ else SuperType(thistp1, supertp1)
+ case TypeBounds(lo, hi) =>
+ val lo1 = this(lo)
+ val hi1 = this(hi)
+ if ((lo1 eq lo) && (hi1 eq hi)) tp
+ else TypeBounds(lo1, hi1)
+ case BoundedWildcardType(bounds) =>
+ val bounds1 = this(bounds)
+ if (bounds1 eq bounds) tp
+ else BoundedWildcardType(bounds1.asInstanceOf[TypeBounds])
+ case rtp @ RefinedType(parents, decls) =>
+ val parents1 = parents mapConserve this
+ val decls1 = mapOver(decls)
+ //if ((parents1 eq parents) && (decls1 eq decls)) tp
+ //else refinementOfClass(tp.typeSymbol, parents1, decls1)
+ copyRefinedType(rtp, parents1, decls1)
+ case ExistentialType(tparams, result) =>
+ val tparams1 = mapOver(tparams)
+ var result1 = this(result)
+ if ((tparams1 eq tparams) && (result1 eq result)) tp
+ else newExistentialType(tparams1, result1.substSym(tparams, tparams1))
+ case OverloadedType(pre, alts) =>
+ val pre1 = if (pre.isInstanceOf[ClassInfoType]) pre else this(pre)
+ if (pre1 eq pre) tp
+ else OverloadedType(pre1, alts)
+ case AntiPolyType(pre, args) =>
+ val pre1 = this(pre)
+ val args1 = args mapConserve (this)
+ if ((pre1 eq pre) && (args1 eq args)) tp
+ else AntiPolyType(pre1, args1)
+ case tv@TypeVar(_, constr) =>
+ if (constr.instValid) this(constr.inst)
+ else tv.applyArgs(mapOverArgs(tv.typeArgs, tv.params)) //@M !args.isEmpty implies !typeParams.isEmpty
+ case NotNullType(tp) =>
+ val tp1 = this(tp)
+ if (tp1 eq tp) tp
+ else NotNullType(tp1)
+ case AnnotatedType(annots, atp, selfsym) =>
+ val annots1 = mapOverAnnotations(annots)
+ val atp1 = this(atp)
+ if ((annots1 eq annots) && (atp1 eq atp)) tp
+ else if (annots1.isEmpty) atp1
+ else AnnotatedType(annots1, atp1, selfsym)
+ case DeBruijnIndex(shift, idx, args) =>
+ val args1 = args mapConserve this
+ if (args1 eq args) tp
+ else DeBruijnIndex(shift, idx, args1)
+/*
+ case ErrorType => tp
+ case WildcardType => tp
+ case NoType => tp
+ case NoPrefix => tp
+ case ErasedSingleType(sym) => tp
+*/
+ case _ =>
+ tp
+ // throw new Error("mapOver inapplicable for " + tp);
+ }
+
+ protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
+ args mapConserve this
+
+ /** Called by mapOver to determine whether the original symbols can
+ * be returned, or whether they must be cloned. Overridden in VariantTypeMap.
+ */
+ protected def noChangeToSymbols(origSyms: List[Symbol]) =
+ origSyms forall (sym => sym.info eq this(sym.info))
+
+ /** Map this function over given scope */
+ def mapOver(scope: Scope): Scope = {
+ val elems = scope.toList
+ val elems1 = mapOver(elems)
+ if (elems1 eq elems) scope
+ else newScopeWith(elems1: _*)
+ }
+
+ /** Map this function over given list of symbols */
+ def mapOver(origSyms: List[Symbol]): List[Symbol] = {
+ // fast path in case nothing changes due to map
+ if (noChangeToSymbols(origSyms)) origSyms
+ // map is not the identity --> do cloning properly
+ else cloneSymbolsAndModify(origSyms, TypeMap.this)
+ }
+
+ def mapOver(annot: AnnotationInfo): AnnotationInfo = {
+ val AnnotationInfo(atp, args, assocs) = annot
+ val atp1 = mapOver(atp)
+ val args1 = mapOverAnnotArgs(args)
+ // there is no need to rewrite assocs, as they are constants
+
+ if ((args eq args1) && (atp eq atp1)) annot
+ else if (args1.isEmpty && args.nonEmpty) UnmappableAnnotation // some annotation arg was unmappable
+ else AnnotationInfo(atp1, args1, assocs) setPos annot.pos
+ }
+
+ def mapOverAnnotations(annots: List[AnnotationInfo]): List[AnnotationInfo] = {
+ val annots1 = annots mapConserve mapOver
+ if (annots1 eq annots) annots
+ else annots1 filterNot (_ eq UnmappableAnnotation)
+ }
+
+ /** Map over a set of annotation arguments. If any
+ * of the arguments cannot be mapped, then return Nil. */
+ def mapOverAnnotArgs(args: List[Tree]): List[Tree] = {
+ val args1 = args mapConserve mapOver
+ if (args1 contains UnmappableTree) Nil
+ else args1
+ }
+
+ def mapOver(tree: Tree): Tree =
+ mapOver(tree, () => return UnmappableTree)
+
+ /** Map a tree that is part of an annotation argument.
+ * If the tree cannot be mapped, then invoke giveup().
+ * The default is to transform the tree with
+ * TypeMapTransformer.
+ */
+ def mapOver(tree: Tree, giveup: ()=>Nothing): Tree =
+ (new TypeMapTransformer).transform(tree)
+
+ /** This transformer leaves the tree alone except to remap
+ * its types. */
+ class TypeMapTransformer extends Transformer {
+ override def transform(tree: Tree) = {
+ val tree1 = super.transform(tree)
+ val tpe1 = TypeMap.this(tree1.tpe)
+ if ((tree eq tree1) && (tree.tpe eq tpe1))
+ tree
+ else
+ tree1.shallowDuplicate.setType(tpe1)
+ }
+ }
+ }
+
+ abstract class TypeTraverser extends TypeMap {
+ def traverse(tp: Type): Unit
+ def apply(tp: Type): Type = { traverse(tp); tp }
+ }
+
+ abstract class TypeTraverserWithResult[T] extends TypeTraverser {
+ def result: T
+ def clear(): Unit
+ }
+
+ abstract class TypeCollector[T](initial: T) extends TypeTraverser {
+ var result: T = _
+ def collect(tp: Type) = {
+ result = initial
+ traverse(tp)
+ result
+ }
+ }
+
+ /** A collector that tests for existential types appearing at given variance in a type
+ * @PP: Commenting out due to not being used anywhere.
+ */
+ // class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) with VariantTypeMap {
+ // variance = v
+ //
+ // def traverse(tp: Type) = tp match {
+ // case ExistentialType(_, _) if (variance == v) => result = true
+ // case _ => mapOver(tp)
+ // }
+ // }
+ //
+ // val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1)
+ // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1)
+
+ def typeParamsToExistentials(clazz: Symbol, tparams: List[Symbol]): List[Symbol] = {
+ val eparams = mapWithIndex(tparams)((tparam, i) =>
+ clazz.newExistential(newTypeName("?"+i), clazz.pos) setInfo tparam.info.bounds)
+
+ eparams map (_ substInfo (tparams, eparams))
+ }
+ def typeParamsToExistentials(clazz: Symbol): List[Symbol] =
+ typeParamsToExistentials(clazz, clazz.typeParams)
+
+ // note: it's important to write the two tests in this order,
+ // as only typeParams forces the classfile to be read. See #400
+ private def isRawIfWithoutArgs(sym: Symbol) =
+ sym.isClass && sym.typeParams.nonEmpty && sym.isJavaDefined
+
+ def isRaw(sym: Symbol, args: List[Type]) =
+ !phase.erasedTypes && isRawIfWithoutArgs(sym) && args.isEmpty
+
+ /** Is type tp a ''raw type''? */
+ def isRawType(tp: Type) = tp match {
+ case TypeRef(_, sym, args) => isRaw(sym, args)
+ case _ => false
+ }
+
+ /** The raw to existential map converts a ''raw type'' to an existential type.
+ * It is necessary because we might have read a raw type of a
+ * parameterized Java class from a class file. At the time we read the type
+ * the corresponding class file might still not be read, so we do not
+ * know what the type parameters of the type are. Therefore
+ * the conversion of raw types to existential types might not have taken place
+ * in ClassFileparser.sigToType (where it is usually done).
+ */
+ def rawToExistential = new TypeMap {
+ private var expanded = immutable.Set[Symbol]()
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, List()) if isRawIfWithoutArgs(sym) =>
+ if (expanded contains sym) AnyRefClass.tpe
+ else try {
+ expanded += sym
+ val eparams = mapOver(typeParamsToExistentials(sym))
+ existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))
+ } finally {
+ expanded -= sym
+ }
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ /** Used by existentialAbstraction.
+ */
+ class ExistentialExtrapolation(tparams: List[Symbol]) extends VariantTypeMap {
+ private val occurCount = mutable.HashMap[Symbol, Int]()
+ private def countOccs(tp: Type) = {
+ tp foreach {
+ case TypeRef(_, sym, _) =>
+ if (tparams contains sym)
+ occurCount(sym) += 1
+ case _ => ()
+ }
+ }
+ def extrapolate(tpe: Type): Type = {
+ tparams foreach (t => occurCount(t) = 0)
+ countOccs(tpe)
+ for (tparam <- tparams)
+ countOccs(tparam.info)
+
+ apply(tpe)
+ }
+
+ def apply(tp: Type): Type = {
+ val tp1 = mapOver(tp)
+ if (variance == 0) tp1
+ else tp1 match {
+ case TypeRef(pre, sym, args) if tparams contains sym =>
+ val repl = if (variance == 1) dropSingletonType(tp1.bounds.hi) else tp1.bounds.lo
+ //println("eliminate "+sym+"/"+repl+"/"+occurCount(sym)+"/"+(tparams exists (repl.contains)))//DEBUG
+ if (!repl.typeSymbol.isBottomClass && occurCount(sym) == 1 && !(tparams exists (repl.contains)))
+ repl
+ else tp1
+ case _ =>
+ tp1
+ }
+ }
+ override def mapOver(tp: Type): Type = tp match {
+ case SingleType(pre, sym) =>
+ if (sym.isPackageClass) tp // short path
+ else {
+ val pre1 = this(pre)
+ if ((pre1 eq pre) || !pre1.isStable) tp
+ else singleType(pre1, sym)
+ }
+ case _ => super.mapOver(tp)
+ }
+
+ // Do not discard the types of existential ident's. The
+ // symbol of the Ident itself cannot be listed in the
+ // existential's parameters, so the resulting existential
+ // type would be ill-formed.
+ override def mapOver(tree: Tree) = tree match {
+ case Ident(_) if tree.tpe.isStable => tree
+ case _ => super.mapOver(tree)
+ }
+ }
+
+ def singletonBounds(hi: Type) = TypeBounds.upper(intersectionType(List(hi, SingletonClass.tpe)))
+
+ /** A map to compute the asSeenFrom method */
+ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap with KeepOnlyTypeConstraints {
+ var capturedSkolems: List[Symbol] = List()
+ var capturedParams: List[Symbol] = List()
+ var capturedPre = emptySymMap
+
+ override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
+ object annotationArgRewriter extends TypeMapTransformer {
+ /** Rewrite `This` trees in annotation argument trees */
+ def rewriteThis(tree: Tree): Tree =
+ tree match {
+ case This(_)
+ if (tree.symbol isNonBottomSubClass clazz) &&
+ (pre.widen.typeSymbol isNonBottomSubClass tree.symbol) =>
+ if (pre.isStable) { // XXX why is this in this method? pull it out and guard the call `annotationArgRewriter.transform(tree)`?
+ val termSym = (
+ pre.typeSymbol.owner.newValue(pre.typeSymbol.name.toTermName, pre.typeSymbol.pos) // what symbol should really be used?
+ setInfo pre
+ )
+ gen.mkAttributedQualifier(pre, termSym)
+ } else
+ giveup()
+
+ case tree => tree
+ }
+
+ override def transform(tree: Tree): Tree = {
+ val tree1 = rewriteThis(super.transform(tree))
+ tree1
+ }
+ }
+
+ annotationArgRewriter.transform(tree)
+ }
+
+ def stabilize(pre: Type, clazz: Symbol): Type =
+ capturedPre.getOrElse(clazz, {
+ val qvar = clazz freshExistential ".type" setInfo singletonBounds(pre)
+ capturedPre += (clazz -> qvar)
+ capturedParams = qvar :: capturedParams
+ qvar
+ }).tpe
+
+ /** Return `pre.baseType(clazz)`, or if that's `NoType` and `clazz` is a refinement, `pre` itself.
+ * See bug397.scala for an example where the second alternative is needed.
+ * The problem is that when forming the base type sequence of an abstract type,
+ * any refinements in the base type list might be regenerated, and thus acquire
+ * new class symbols. However, since refinements always have non-interesting prefixes
+ * it looks OK to me to just take the prefix directly. */
+ def base(pre: Type, clazz: Symbol) = {
+ val b = pre.baseType(clazz)
+ if (b == NoType && clazz.isRefinementClass) pre
+ else b
+ }
+
+ def apply(tp: Type): Type =
+ if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
+ else tp match {
+ case ThisType(sym) =>
+ def toPrefix(pre: Type, clazz: Symbol): Type =
+ if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp
+ else if ((sym isNonBottomSubClass clazz) &&
+ (pre.widen.typeSymbol isNonBottomSubClass sym)) {
+ val pre1 = pre match {
+ case SuperType(thistp, _) => thistp
+ case _ => pre
+ }
+ if (!(pre1.isStable ||
+ pre1.typeSymbol.isPackageClass ||
+ pre1.typeSymbol.isModuleClass && pre1.typeSymbol.isStatic)) {
+ stabilize(pre1, sym)
+ } else {
+ pre1
+ }
+ } else {
+ toPrefix(base(pre, clazz).prefix, clazz.owner)
+ }
+ toPrefix(pre, clazz)
+ case SingleType(pre, sym) =>
+ if (sym.isPackageClass) tp // short path
+ else {
+ val pre1 = this(pre)
+ if (pre1 eq pre) tp
+ else if (pre1.isStable) singleType(pre1, sym)
+ else pre1.memberType(sym).resultType //todo: this should be rolled into existential abstraction
+ }
+ // AM: Martin, is this description accurate?
+ // walk the owner chain of `clazz` (the original argument to asSeenFrom) until we find the type param's owner (while rewriting pre as we crawl up the owner chain)
+ // once we're at the owner, extract the information that pre encodes about the type param,
+ // by minimally subsuming pre to the type instance of the class that owns the type param,
+ // the type we're looking for is the type instance's type argument at the position corresponding to the type parameter
+ // optimisation: skip this type parameter if it's not owned by a class, as those params are not influenced by the prefix through which they are seen
+ // (concretely: type params of anonymous type functions, which currently can only arise from normalising type aliases, are owned by the type alias of which they are the eta-expansion)
+ // (skolems also aren't affected: they are ruled out by the isTypeParameter check)
+ case TypeRef(prefix, sym, args) if (sym.isTypeParameter && sym.owner.isClass) =>
+ def toInstance(pre: Type, clazz: Symbol): Type =
+ if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) mapOver(tp)
+ //@M! see test pos/tcpoly_return_overriding.scala why mapOver is necessary
+ else {
+ def throwError = abort("" + tp + sym.locationString + " cannot be instantiated from " + pre.widen)
+
+ val symclazz = sym.owner
+ if (symclazz == clazz && !pre.widen.isInstanceOf[TypeVar] && (pre.widen.typeSymbol isNonBottomSubClass symclazz)) {
+ // have to deconst because it may be a Class[T].
+ pre.baseType(symclazz).deconst match {
+ case TypeRef(_, basesym, baseargs) =>
+
+ def instParam(ps: List[Symbol], as: List[Type]): Type =
+ if (ps.isEmpty) {
+ if (forInteractive) {
+ val saved = settings.uniqid.value
+ try {
+ settings.uniqid.value = true
+ println("*** stale type parameter: " + tp + sym.locationString + " cannot be instantiated from " + pre.widen)
+ println("*** confused with params: " + sym + " in " + sym.owner + " not in " + ps + " of " + basesym)
+ println("*** stacktrace = ")
+ new Error().printStackTrace()
+ } finally settings.uniqid.value = saved
+ instParamRelaxed(basesym.typeParams, baseargs)
+ } else throwError
+ } else if (sym eq ps.head)
+ // @M! don't just replace the whole thing, might be followed by type application
+ appliedType(as.head, args mapConserve (this)) // @M: was as.head
+ else instParam(ps.tail, as.tail)
+
+ /** Relaxed version of instParams which matches on names not symbols.
+ * This is a last fallback in interactive mode because races in calls
+ * from the IDE to the compiler may in rare cases lead to symbols referring
+ * to type parameters that are no longer current.
+ */
+ def instParamRelaxed(ps: List[Symbol], as: List[Type]): Type =
+ if (ps.isEmpty) throwError
+ else if (sym.name == ps.head.name)
+ // @M! don't just replace the whole thing, might be followed by type application
+ appliedType(as.head, args mapConserve (this)) // @M: was as.head
+ else instParamRelaxed(ps.tail, as.tail)
+
+ //Console.println("instantiating " + sym + " from " + basesym + " with " + basesym.typeParams + " and " + baseargs+", pre = "+pre+", symclazz = "+symclazz);//DEBUG
+ if (sameLength(basesym.typeParams, baseargs))
+ instParam(basesym.typeParams, baseargs)
+ else
+ if (symclazz.tpe.parents.exists(_.isErroneous))
+ ErrorType // don't be to overzealous with throwing exceptions, see #2641
+ else
+ throw new Error(
+ "something is wrong (wrong class file?): "+basesym+
+ " with type parameters "+
+ basesym.typeParams.map(_.name).mkString("[",",","]")+
+ " gets applied to arguments "+baseargs.mkString("[",",","]")+", phase = "+phase)
+ case ExistentialType(tparams, qtpe) =>
+ capturedSkolems = capturedSkolems union tparams
+ toInstance(qtpe, clazz)
+ case t =>
+ throwError
+ }
+ } else toInstance(base(pre, clazz).prefix, clazz.owner)
+ }
+ toInstance(pre, clazz)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ /** A base class to compute all substitutions */
+ abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap {
+ assert(sameLength(from, to), "Unsound substitution from "+ from +" to "+ to)
+
+ /** Are `sym` and `sym1` the same? Can be tuned by subclasses. */
+ protected def matches(sym: Symbol, sym1: Symbol): Boolean = sym eq sym1
+
+ /** Map target to type, can be tuned by subclasses */
+ protected def toType(fromtp: Type, tp: T): Type
+
+ protected def renameBoundSyms(tp: Type): Type = tp match {
+ case MethodType(ps, restp) =>
+ createFromClonedSymbols(ps, restp)((ps1, tp1) => copyMethodType(tp, ps1, renameBoundSyms(tp1)))
+ case PolyType(bs, restp) =>
+ createFromClonedSymbols(bs, restp)((ps1, tp1) => PolyType(ps1, renameBoundSyms(tp1)))
+ case ExistentialType(bs, restp) =>
+ createFromClonedSymbols(bs, restp)(newExistentialType)
+ case _ =>
+ tp
+ }
+
+ def apply(tp0: Type): Type = if (from.isEmpty) tp0 else {
+ @tailrec def subst(tp: Type, sym: Symbol, from: List[Symbol], to: List[T]): Type =
+ if (from.isEmpty) tp
+ // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(tp, from))
+ else if (matches(from.head, sym)) toType(tp, to.head)
+ else subst(tp, sym, from.tail, to.tail)
+
+ val boundSyms = tp0.boundSyms
+ val tp1 = if (boundSyms exists from.contains) renameBoundSyms(tp0) else tp0
+ val tp = mapOver(tp1)
+
+ tp match {
+ // @M
+ // 1) arguments must also be substituted (even when the "head" of the
+ // applied type has already been substituted)
+ // example: (subst RBound[RT] from [type RT,type RBound] to
+ // [type RT&,type RBound&]) = RBound&[RT&]
+ // 2) avoid loops (which occur because alpha-conversion is
+ // not performed properly imo)
+ // e.g. if in class Iterable[a] there is a new Iterable[(a,b)],
+ // we must replace the a in Iterable[a] by (a,b)
+ // (must not recurse --> loops)
+ // 3) replacing m by List in m[Int] should yield List[Int], not just List
+ case TypeRef(NoPrefix, sym, args) =>
+ appliedType(subst(tp, sym, from, to), args) // if args.isEmpty, appliedType is the identity
+ case SingleType(NoPrefix, sym) =>
+ subst(tp, sym, from, to)
+ case _ =>
+ tp
+ }
+ }
+ }
+
+ /** A map to implement the `substSym` method. */
+ class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends SubstMap(from, to) {
+ protected def toType(fromtp: Type, sym: Symbol) = fromtp match {
+ case TypeRef(pre, _, args) => copyTypeRef(fromtp, pre, sym, args)
+ case SingleType(pre, _) => singleType(pre, sym)
+ }
+ override def apply(tp: Type): Type = if (from.isEmpty) tp else {
+ @tailrec def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol =
+ if (from.isEmpty) sym
+ // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(sym, from))
+ else if (matches(from.head, sym)) to.head
+ else subst(sym, from.tail, to.tail)
+ tp match {
+ case TypeRef(pre, sym, args) if pre ne NoPrefix =>
+ val newSym = subst(sym, from, to)
+ // assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams))
+ mapOver(copyTypeRef(tp, pre, newSym, args)) // mapOver takes care of subst'ing in args
+ case SingleType(pre, sym) if pre ne NoPrefix =>
+ mapOver(singleType(pre, subst(sym, from, to)))
+ case _ =>
+ super.apply(tp)
+ }
+ }
+
+ override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
+ object trans extends TypeMapTransformer {
+
+ def termMapsTo(sym: Symbol) = from indexOf sym match {
+ case -1 => None
+ case idx => Some(to(idx))
+ }
+
+ override def transform(tree: Tree) =
+ tree match {
+ case tree@Ident(_) =>
+ termMapsTo(tree.symbol) match {
+ case Some(tosym) =>
+ if (tosym.info.bounds.hi.typeSymbol isSubClass SingletonClass) {
+ Ident(tosym.existentialToString)
+ .setSymbol(tosym)
+ .setPos(tosym.pos)
+ .setType(dropSingletonType(tosym.info.bounds.hi))
+ } else {
+ giveup()
+ }
+ case none => super.transform(tree)
+ }
+ case tree => super.transform(tree)
+ }
+ }
+ trans.transform(tree)
+ }
+ }
+
+ /** A map to implement the `subst` method. */
+ class SubstTypeMap(from: List[Symbol], to: List[Type])
+ extends SubstMap(from, to) {
+ protected def toType(fromtp: Type, tp: Type) = tp
+
+ override def mapOver(tree: Tree, giveup: () => Nothing): Tree = {
+ object trans extends TypeMapTransformer {
+ override def transform(tree: Tree) = tree match {
+ case Ident(name) =>
+ from indexOf tree.symbol match {
+ case -1 => super.transform(tree)
+ case idx =>
+ val totpe = to(idx)
+ if (totpe.isStable) tree.duplicate setType totpe
+ else giveup()
+ }
+ case _ =>
+ super.transform(tree)
+ }
+ }
+ trans.transform(tree)
+ }
+ }
+
+ /** A map to implement the `substThis` method. */
+ class SubstThisMap(from: Symbol, to: Type) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case ThisType(sym) if (sym == from) => to
+ case _ => mapOver(tp)
+ }
+ }
+
+ class SubstWildcardMap(from: List[Symbol]) extends TypeMap {
+ def apply(tp: Type): Type = try {
+ tp match {
+ case TypeRef(_, sym, _) if from contains sym =>
+ BoundedWildcardType(sym.info.bounds)
+ case _ =>
+ mapOver(tp)
+ }
+ } catch {
+ case ex: MalformedType =>
+ WildcardType
+ }
+ }
+
+// dependent method types
+ object IsDependentCollector extends TypeCollector(false) {
+ def traverse(tp: Type) {
+ if(tp isImmediatelyDependent) result = true
+ else if (!result) mapOver(tp)
+ }
+ }
+
+ object ApproximateDependentMap extends TypeMap {
+ def apply(tp: Type): Type =
+ if(tp isImmediatelyDependent) WildcardType
+ else mapOver(tp)
+ }
+
+ class InstantiateDependentMap(params: List[Symbol], actuals0: List[Type]) extends TypeMap with KeepOnlyTypeConstraints {
+ private val actuals = actuals0.toIndexedSeq
+ private val existentials = new Array[Symbol](actuals.size)
+ def existentialsNeeded: List[Symbol] = existentials.filter(_ ne null).toList
+
+ private object StableArg {
+ def unapply(param: Symbol) = Arg unapply param map actuals filter (tp =>
+ tp.isStable && (tp.typeSymbol != NothingClass)
+ )
+ }
+ private object Arg {
+ def unapply(param: Symbol) = Some(params indexOf param) filter (_ >= 0)
+ }
+
+ def apply(tp: Type): Type = mapOver(tp) match {
+ // unsound to replace args by unstable actual #3873
+ case SingleType(NoPrefix, StableArg(arg)) => arg
+ // (soundly) expand type alias selections on implicit arguments,
+ // see depmet_implicit_oopsla* test cases -- typically, `param.isImplicit`
+ case tp1 @ TypeRef(SingleType(NoPrefix, Arg(pid)), sym, targs) =>
+ val arg = actuals(pid)
+ val res = typeRef(arg, sym, targs)
+ if (res.typeSymbolDirect.isAliasType) res.dealias else tp1
+ // don't return the original `tp`, which may be different from `tp1`,
+ // due to dropping annotations
+ case tp1 => tp1
+ }
+
+ /* Return the type symbol for referencing a parameter inside the existential quantifier.
+ * (Only needed if the actual is unstable.)
+ */
+ private def existentialFor(pid: Int) = {
+ if (existentials(pid) eq null) {
+ val param = params(pid)
+ existentials(pid) = (
+ param.owner.newExistential(newTypeName(param.name + ".type"), param.pos, param.flags)
+ setInfo singletonBounds(actuals(pid))
+ )
+ }
+ existentials(pid)
+ }
+
+ //AM propagate more info to annotations -- this seems a bit ad-hoc... (based on code by spoon)
+ override def mapOver(arg: Tree, giveup: ()=>Nothing): Tree = {
+ // TODO: this should be simplified; in the stable case, one can
+ // probably just use an Ident to the tree.symbol.
+ //
+ // @PP: That leads to failure here, where stuff no longer has type
+ // 'String @Annot("stuff")' but 'String @Annot(x)'.
+ //
+ // def m(x: String): String @Annot(x) = x
+ // val stuff = m("stuff")
+ //
+ // (TODO cont.) Why an existential in the non-stable case?
+ //
+ // @PP: In the following:
+ //
+ // def m = { val x = "three" ; val y: String @Annot(x) = x; y }
+ //
+ // m is typed as 'String @Annot(x) forSome { val x: String }'.
+ //
+ // Both examples are from run/constrained-types.scala.
+ object treeTrans extends Transformer {
+ override def transform(tree: Tree): Tree = tree.symbol match {
+ case StableArg(actual) =>
+ gen.mkAttributedQualifier(actual, tree.symbol)
+ case Arg(pid) =>
+ val sym = existentialFor(pid)
+ Ident(sym) copyAttrs tree setType typeRef(NoPrefix, sym, Nil)
+ case _ =>
+ super.transform(tree)
+ }
+ }
+ treeTrans transform arg
+ }
+ }
+
+ object StripAnnotationsMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case AnnotatedType(_, atp, _) =>
+ mapOver(atp)
+ case tp =>
+ mapOver(tp)
+ }
+ }
+
+ /** A map to convert every occurrence of a wildcard type to a fresh
+ * type variable */
+ object wildcardToTypeVarMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case WildcardType =>
+ TypeVar(tp, new TypeConstraint)
+ case BoundedWildcardType(bounds) =>
+ TypeVar(tp, new TypeConstraint(bounds))
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ /** A map to convert every occurrence of a type variable to a wildcard type. */
+ object typeVarToOriginMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeVar(origin, _) => origin
+ case _ => mapOver(tp)
+ }
+ }
+
+ /** A map to implement the `contains` method. */
+ class ContainsCollector(sym: Symbol) extends TypeCollector(false) {
+ def traverse(tp: Type) {
+ if (!result) {
+ tp.normalize match {
+ case TypeRef(_, sym1, _) if (sym == sym1) => result = true
+ case SingleType(_, sym1) if (sym == sym1) => result = true
+ case _ => mapOver(tp)
+ }
+ }
+ }
+
+ override def mapOver(arg: Tree) = {
+ for (t <- arg) {
+ traverse(t.tpe)
+ if (t.symbol == sym)
+ result = true
+ }
+ arg
+ }
+ }
+
+ /** A map to implement the `contains` method. */
+ class ContainsTypeCollector(t: Type) extends TypeCollector(false) {
+ def traverse(tp: Type) {
+ if (!result) {
+ if (tp eq t) result = true
+ else mapOver(tp)
+ }
+ }
+ override def mapOver(arg: Tree) = {
+ for (t <- arg)
+ traverse(t.tpe)
+
+ arg
+ }
+ }
+
+ /** A map to implement the `filter` method. */
+ class FilterTypeCollector(p: Type => Boolean) extends TypeCollector[List[Type]](Nil) {
+ def withFilter(q: Type => Boolean) = new FilterTypeCollector(tp => p(tp) && q(tp))
+
+ override def collect(tp: Type) = super.collect(tp).reverse
+
+ def traverse(tp: Type) {
+ if (p(tp)) result ::= tp
+ mapOver(tp)
+ }
+ }
+
+ /** A map to implement the `collect` method. */
+ class CollectTypeCollector[T](pf: PartialFunction[Type, T]) extends TypeCollector[List[T]](Nil) {
+ override def collect(tp: Type) = super.collect(tp).reverse
+
+ def traverse(tp: Type) {
+ if (pf.isDefinedAt(tp)) result ::= pf(tp)
+ mapOver(tp)
+ }
+ }
+
+ class ForEachTypeTraverser(f: Type => Unit) extends TypeTraverser {
+ def traverse(tp: Type) {
+ f(tp)
+ mapOver(tp)
+ }
+ }
+
+ /** A map to implement the `filter` method. */
+ class FindTypeCollector(p: Type => Boolean) extends TypeCollector[Option[Type]](None) {
+ def traverse(tp: Type) {
+ if (result.isEmpty) {
+ if (p(tp)) result = Some(tp)
+ mapOver(tp)
+ }
+ }
+ }
+
+ /** A map to implement the `contains` method. */
+ object ErroneousCollector extends TypeCollector(false) {
+ def traverse(tp: Type) {
+ if (!result) {
+ result = tp.isError
+ mapOver(tp)
+ }
+ }
+ }
+
+ /** The most deeply nested owner that contains all the symbols
+ * of thistype or prefixless typerefs/singletype occurrences in given type.
+ */
+ private def commonOwner(t: Type): Symbol = commonOwner(t :: Nil)
+
+ /** The most deeply nested owner that contains all the symbols
+ * of thistype or prefixless typerefs/singletype occurrences in given list
+ * of types.
+ */
+ private def commonOwner(tps: List[Type]): Symbol = {
+ if (tps.isEmpty) NoSymbol
+ else {
+ commonOwnerMap.clear()
+ tps foreach (commonOwnerMap traverse _)
+ if (commonOwnerMap.result ne null) commonOwnerMap.result else NoSymbol
+ }
+ }
+
+ protected def commonOwnerMap: CommonOwnerMap = commonOwnerMapObj
+
+ protected class CommonOwnerMap extends TypeTraverserWithResult[Symbol] {
+ var result: Symbol = _
+
+ def clear() { result = null }
+
+ private def register(sym: Symbol) {
+ // First considered type is the trivial result.
+ if ((result eq null) || (sym eq NoSymbol))
+ result = sym
+ else
+ while ((result ne NoSymbol) && (result ne sym) && !(sym isNestedIn result))
+ result = result.owner
+ }
+ def traverse(tp: Type) = tp.normalize match {
+ case ThisType(sym) => register(sym)
+ case TypeRef(NoPrefix, sym, args) => register(sym.owner) ; args foreach traverse
+ case SingleType(NoPrefix, sym) => register(sym.owner)
+ case _ => mapOver(tp)
+ }
+ }
+
+ private lazy val commonOwnerMapObj = new CommonOwnerMap
+
+ class MissingAliasControl extends ControlThrowable
+ val missingAliasException = new MissingAliasControl
+ class MissingTypeControl extends ControlThrowable
+
+ object adaptToNewRunMap extends TypeMap {
+
+ private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = {
+ if (phase.flatClasses || sym.isRootSymbol || (pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass)
+ sym
+ else if (sym.isModuleClass) {
+ val sourceModule1 = adaptToNewRun(pre, sym.sourceModule)
+
+ sourceModule1.moduleClass orElse sourceModule1.initialize.moduleClass orElse {
+ val msg = "Cannot adapt module class; sym = %s, sourceModule = %s, sourceModule.moduleClass = %s => sourceModule1 = %s, sourceModule1.moduleClass = %s"
+ debuglog(msg.format(sym, sym.sourceModule, sym.sourceModule.moduleClass, sourceModule1, sourceModule1.moduleClass))
+ sym
+ }
+ }
+ else {
+ var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) orElse {
+ if (sym.isAliasType) throw missingAliasException
+ debugwarn(pre+"."+sym+" does no longer exist, phase = "+phase)
+ throw new MissingTypeControl // For build manager and presentation compiler purposes
+ }
+ /** The two symbols have the same fully qualified name */
+ def corresponds(sym1: Symbol, sym2: Symbol): Boolean =
+ sym1.name == sym2.name && (sym1.isPackageClass || corresponds(sym1.owner, sym2.owner))
+ if (!corresponds(sym.owner, rebind0.owner)) {
+ debuglog("ADAPT1 pre = "+pre+", sym = "+sym.fullLocationString+", rebind = "+rebind0.fullLocationString)
+ val bcs = pre.baseClasses.dropWhile(bc => !corresponds(bc, sym.owner));
+ if (bcs.isEmpty)
+ assert(pre.typeSymbol.isRefinementClass, pre) // if pre is a refinementclass it might be a structural type => OK to leave it in.
+ else
+ rebind0 = pre.baseType(bcs.head).member(sym.name)
+ debuglog(
+ "ADAPT2 pre = " + pre +
+ ", bcs.head = " + bcs.head +
+ ", sym = " + sym.fullLocationString +
+ ", rebind = " + rebind0.fullLocationString
+ )
+ }
+ rebind0.suchThat(sym => sym.isType || sym.isStable) orElse {
+ debuglog("" + phase + " " +phase.flatClasses+sym.owner+sym.name+" "+sym.isType)
+ throw new MalformedType(pre, sym.nameString)
+ }
+ }
+ }
+ def apply(tp: Type): Type = tp match {
+ case ThisType(sym) =>
+ try {
+ val sym1 = adaptToNewRun(sym.owner.thisType, sym)
+ if (sym1 == sym) tp else ThisType(sym1)
+ } catch {
+ case ex: MissingTypeControl =>
+ tp
+ }
+ case SingleType(pre, sym) =>
+ if (sym.isPackage) tp
+ else {
+ val pre1 = this(pre)
+ try {
+ val sym1 = adaptToNewRun(pre1, sym)
+ if ((pre1 eq pre) && (sym1 eq sym)) tp
+ else singleType(pre1, sym1)
+ } catch {
+ case _: MissingTypeControl =>
+ tp
+ }
+ }
+ case TypeRef(pre, sym, args) =>
+ if (sym.isPackageClass) tp
+ else {
+ val pre1 = this(pre)
+ val args1 = args mapConserve (this)
+ try {
+ val sym1 = adaptToNewRun(pre1, sym)
+ if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) {
+ tp
+ } else if (sym1 == NoSymbol) {
+ debugwarn("adapt fail: "+pre+" "+pre1+" "+sym)
+ tp
+ } else {
+ copyTypeRef(tp, pre1, sym1, args1)
+ }
+ } catch {
+ case ex: MissingAliasControl =>
+ apply(tp.dealias)
+ case _: MissingTypeControl =>
+ tp
+ }
+ }
+ case MethodType(params, restp) =>
+ val restp1 = this(restp)
+ if (restp1 eq restp) tp
+ else copyMethodType(tp, params, restp1)
+ case NullaryMethodType(restp) =>
+ val restp1 = this(restp)
+ if (restp1 eq restp) tp
+ else NullaryMethodType(restp1)
+ case PolyType(tparams, restp) =>
+ val restp1 = this(restp)
+ if (restp1 eq restp) tp
+ else PolyType(tparams, restp1)
+
+ // Lukas: we need to check (together) whether we should also include parameter types
+ // of PolyType and MethodType in adaptToNewRun
+
+ case ClassInfoType(parents, decls, clazz) =>
+ if (clazz.isPackageClass) tp
+ else {
+ val parents1 = parents mapConserve (this)
+ if (parents1 eq parents) tp
+ else ClassInfoType(parents1, decls, clazz)
+ }
+ case RefinedType(parents, decls) =>
+ val parents1 = parents mapConserve (this)
+ if (parents1 eq parents) tp
+ else refinedType(parents1, tp.typeSymbol.owner, decls, tp.typeSymbol.owner.pos)
+ case SuperType(_, _) => mapOver(tp)
+ case TypeBounds(_, _) => mapOver(tp)
+ case TypeVar(_, _) => mapOver(tp)
+ case AnnotatedType(_,_,_) => mapOver(tp)
+ case NotNullType(_) => mapOver(tp)
+ case ExistentialType(_, _) => mapOver(tp)
+ case _ => tp
+ }
+ }
+
+ class SubTypePair(val tp1: Type, val tp2: Type) {
+ override def hashCode = tp1.hashCode * 41 + tp2.hashCode
+ override def equals(other: Any) = other match {
+ case stp: SubTypePair =>
+ // suspend TypeVars in types compared by =:=,
+ // since we don't want to mutate them simply to check whether a subtype test is pending
+ // in addition to making subtyping "more correct" for type vars,
+ // it should avoid the stackoverflow that's been plaguing us (https://groups.google.com/d/topic/scala-internals/2gHzNjtB4xA/discussion)
+ // this method is only called when subtyping hits a recursion threshold (subsametypeRecursions >= LogPendingSubTypesThreshold)
+ @inline def suspend(tp: Type) =
+ if (tp.isGround) null else suspendTypeVarsInType(tp)
+ @inline def revive(suspension: List[TypeVar]) =
+ if (suspension ne null) suspension foreach (_.suspended = false)
+
+ val suspensions = Array(tp1, stp.tp1, tp2, stp.tp2) map suspend
+
+ val sameTypes = (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2)
+
+ suspensions foreach revive
+
+ sameTypes
+ case _ =>
+ false
+ }
+ override def toString = tp1+" <:<? "+tp2
+ }
+
+// Helper Methods -------------------------------------------------------------
+
+ final val LubGlbMargin = 0
+
+ /** The maximum allowable depth of lubs or glbs over types `ts`.
+ * This is the maximum depth of all types in the base type sequences
+ * of each of the types `ts`, plus LubGlbMargin.
+ */
+ def lubDepth(ts: List[Type]) = {
+ var d = 0
+ for (tp <- ts) d = math.max(d, tp.baseTypeSeqDepth)
+ d + LubGlbMargin
+ }
+
+ /** Is intersection of given types populated? That is,
+ * for all types tp1, tp2 in intersection
+ * for all common base classes bc of tp1 and tp2
+ * let bt1, bt2 be the base types of tp1, tp2 relative to class bc
+ * Then:
+ * bt1 and bt2 have the same prefix, and
+ * any corresponding non-variant type arguments of bt1 and bt2 are the same
+ */
+ def isPopulated(tp1: Type, tp2: Type): Boolean = {
+ def isConsistent(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {
+ case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
+ assert(sym1 == sym2)
+ pre1 =:= pre2 &&
+ forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) =>
+ //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG
+ if (tparam.variance == 0) arg1 =:= arg2
+ else if (arg1.isInstanceOf[TypeVar])
+ // if left-hand argument is a typevar, make it compatible with variance
+ // this is for more precise pattern matching
+ // todo: work this in the spec of this method
+ // also: think what happens if there are embedded typevars?
+ if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1
+ else true
+ }
+ case (et: ExistentialType, _) =>
+ et.withTypeVars(isConsistent(_, tp2))
+ case (_, et: ExistentialType) =>
+ et.withTypeVars(isConsistent(tp1, _))
+ }
+
+ def check(tp1: Type, tp2: Type) =
+ if (tp1.typeSymbol.isClass && tp1.typeSymbol.hasFlag(FINAL))
+ tp1 <:< tp2 || isNumericValueClass(tp1.typeSymbol) && isNumericValueClass(tp2.typeSymbol)
+ else tp1.baseClasses forall (bc =>
+ tp2.baseTypeIndex(bc) < 0 || isConsistent(tp1.baseType(bc), tp2.baseType(bc)))
+
+ check(tp1, tp2)/* && check(tp2, tp1)*/ // need to investgate why this can't be made symmetric -- neg/gadts1 fails, and run/existials also.
+ }
+
+ /** Does a pattern of type `patType` need an outer test when executed against
+ * selector type `selType` in context defined by `currentOwner`?
+ */
+ def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = {
+ def createDummyClone(pre: Type): Type = {
+ val dummy = currentOwner.enclClass.newValue(nme.ANYNAME).setInfo(pre.widen)
+ singleType(ThisType(currentOwner.enclClass), dummy)
+ }
+ def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match {
+ case SingleType(pre1, sym1) =>
+ if (sym1.isModule && sym1.isStatic) {
+ NoType
+ } else if (sym1.isModule && sym.owner == sym1.moduleClass) {
+ val pre2 = maybeCreateDummyClone(pre1, sym1)
+ if (pre2 eq NoType) pre2
+ else singleType(pre2, sym1)
+ } else {
+ createDummyClone(pre)
+ }
+ case ThisType(clazz) =>
+ if (clazz.isModuleClass)
+ maybeCreateDummyClone(clazz.typeOfThis, sym)
+ else if (sym.owner == clazz && (sym.hasFlag(PRIVATE) || sym.privateWithin == clazz))
+ NoType
+ else
+ createDummyClone(pre)
+ case _ =>
+ NoType
+ }
+ patType match {
+ case TypeRef(pre, sym, args) =>
+ val pre1 = maybeCreateDummyClone(pre, sym)
+ (pre1 ne NoType) && isPopulated(copyTypeRef(patType, pre1, sym, args), selType)
+ case _ =>
+ false
+ }
+ }
+
+ private var subsametypeRecursions: Int = 0
+
+ private def isUnifiable(pre1: Type, pre2: Type) =
+ (beginsWithTypeVarOrIsRefined(pre1) || beginsWithTypeVarOrIsRefined(pre2)) && (pre1 =:= pre2)
+
+ /** Returns true iff we are past phase specialize,
+ * sym1 and sym2 are two existential skolems with equal names and bounds,
+ * and pre1 and pre2 are equal prefixes
+ */
+ private def isSameSpecializedSkolem(sym1: Symbol, sym2: Symbol, pre1: Type, pre2: Type) = {
+ sym1.isExistentialSkolem && sym2.isExistentialSkolem &&
+ sym1.name == sym2.name &&
+ phase.specialized &&
+ sym1.info =:= sym2.info &&
+ pre1 =:= pre2
+ }
+
+ private def isSubPre(pre1: Type, pre2: Type, sym: Symbol) =
+ if ((pre1 ne pre2) && (pre1 ne NoPrefix) && (pre2 ne NoPrefix) && pre1 <:< pre2) {
+ if (settings.debug.value) println(s"new isSubPre $sym: $pre1 <:< $pre2")
+ true
+ } else
+ false
+
+ private def equalSymsAndPrefixes(sym1: Symbol, pre1: Type, sym2: Symbol, pre2: Type): Boolean =
+ if (sym1 == sym2) sym1.hasPackageFlag || phase.erasedTypes || pre1 =:= pre2
+ else (sym1.name == sym2.name) && isUnifiable(pre1, pre2)
+
+ /** Do `tp1` and `tp2` denote equivalent types? */
+ def isSameType(tp1: Type, tp2: Type): Boolean = try {
+ incCounter(sametypeCount)
+ subsametypeRecursions += 1
+ undoLog undoUnless {
+ isSameType1(tp1, tp2)
+ }
+ } 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)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
+ }
+
+ def isDifferentType(tp1: Type, tp2: Type): Boolean = try {
+ subsametypeRecursions += 1
+ undoLog undo { // undo type constraints that arise from operations in this block
+ !isSameType1(tp1, tp2)
+ }
+ } 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)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
+ }
+
+ def isDifferentTypeConstructor(tp1: Type, tp2: Type): Boolean = tp1 match {
+ case TypeRef(pre1, sym1, _) =>
+ tp2 match {
+ case TypeRef(pre2, sym2, _) => sym1 != sym2 || isDifferentType(pre1, pre2)
+ case _ => true
+ }
+ case _ => true
+ }
+
+ def normalizePlus(tp: Type) =
+ if (isRawType(tp)) rawToExistential(tp)
+ else tp.normalize
+
+ /*
+ todo: change to:
+ def normalizePlus(tp: Type) = tp match {
+ case TypeRef(pre, sym, List()) =>
+ if (!sym.isInitialized) sym.rawInfo.load(sym)
+ if (sym.isJavaDefined && !sym.typeParams.isEmpty) rawToExistential(tp)
+ else tp.normalize
+ case _ => tp.normalize
+ }
+ */
+/*
+ private def isSameType0(tp1: Type, tp2: Type): Boolean = {
+ if (tp1 eq tp2) return true
+ ((tp1, tp2) match {
+ case (ErrorType, _) => true
+ case (WildcardType, _) => true
+ case (_, ErrorType) => true
+ case (_, WildcardType) => true
+
+ case (NoType, _) => false
+ case (NoPrefix, _) => tp2.typeSymbol.isPackageClass
+ case (_, NoType) => false
+ case (_, NoPrefix) => tp1.typeSymbol.isPackageClass
+
+ case (ThisType(sym1), ThisType(sym2))
+ if (sym1 == sym2) =>
+ true
+ case (SingleType(pre1, sym1), SingleType(pre2, sym2))
+ if (equalSymsAndPrefixes(sym1, pre1, sym2, pre2)) =>
+ true
+/*
+ case (SingleType(pre1, sym1), ThisType(sym2))
+ if (sym1.isModule &&
+ sym1.moduleClass == sym2 &&
+ pre1 =:= sym2.owner.thisType) =>
+ true
+ case (ThisType(sym1), SingleType(pre2, sym2))
+ if (sym2.isModule &&
+ sym2.moduleClass == sym1 &&
+ pre2 =:= sym1.owner.thisType) =>
+ true
+*/
+ case (ConstantType(value1), ConstantType(value2)) =>
+ value1 == value2
+ case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) =>
+ equalSymsAndPrefixes(sym1, pre1, sym2, pre2) &&
+ ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) ||
+ isSameTypes(args1, args2))
+ // @M! normalize reduces higher-kinded case to PolyType's
+ case (RefinedType(parents1, ref1), RefinedType(parents2, ref2)) =>
+ def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall {
+ sym2 =>
+ var e1 = s1.lookupEntry(sym2.name)
+ (e1 ne null) && {
+ val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner.thisType)
+ var isEqual = false
+ while (!isEqual && (e1 ne null)) {
+ isEqual = e1.sym.info =:= substSym
+ e1 = s1.lookupNextEntry(e1)
+ }
+ isEqual
+ }
+ }
+ //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG
+ isSameTypes(parents1, parents2) && isSubScope(ref1, ref2) && isSubScope(ref2, ref1)
+ case (MethodType(params1, res1), MethodType(params2, res2)) =>
+ // new dependent types: probably fix this, use substSym as done for PolyType
+ (isSameTypes(tp1.paramTypes, tp2.paramTypes) &&
+ res1 =:= res2 &&
+ tp1.isImplicit == tp2.isImplicit)
+ case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
+ // assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length)))
+ (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210
+ res1 =:= res2.substSym(tparams2, tparams1)
+ case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
+ (tparams1.length == tparams2.length) && (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) && // @M looks like it might suffer from same problem as #2210
+ res1 =:= res2.substSym(tparams2, tparams1)
+ case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
+ lo1 =:= lo2 && hi1 =:= hi2
+ case (BoundedWildcardType(bounds), _) =>
+ bounds containsType tp2
+ case (_, BoundedWildcardType(bounds)) =>
+ bounds containsType tp1
+ case (tv @ TypeVar(_,_), tp) =>
+ tv.registerTypeEquality(tp, true)
+ case (tp, tv @ TypeVar(_,_)) =>
+ tv.registerTypeEquality(tp, false)
+ case (AnnotatedType(_,_,_), _) =>
+ annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations
+ case (_, AnnotatedType(_,_,_)) =>
+ annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations
+ case (_: SingletonType, _: SingletonType) =>
+ var origin1 = tp1
+ while (origin1.underlying.isInstanceOf[SingletonType]) {
+ assert(origin1 ne origin1.underlying, origin1)
+ origin1 = origin1.underlying
+ }
+ var origin2 = tp2
+ while (origin2.underlying.isInstanceOf[SingletonType]) {
+ assert(origin2 ne origin2.underlying, origin2)
+ origin2 = origin2.underlying
+ }
+ ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2)
+ case _ =>
+ false
+ }) || {
+ val tp1n = normalizePlus(tp1)
+ val tp2n = normalizePlus(tp2)
+ ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n)
+ }
+ }
+*/
+ private def isSameType1(tp1: Type, tp2: Type): Boolean = {
+ if ((tp1 eq tp2) ||
+ (tp1 eq ErrorType) || (tp1 eq WildcardType) ||
+ (tp2 eq ErrorType) || (tp2 eq WildcardType))
+ true
+ else if ((tp1 eq NoType) || (tp2 eq NoType))
+ false
+ else if (tp1 eq NoPrefix) // !! I do not see how this would be warranted by the spec
+ tp2.typeSymbol.isPackageClass
+ else if (tp2 eq NoPrefix) // !! I do not see how this would be warranted by the spec
+ tp1.typeSymbol.isPackageClass
+ else {
+ isSameType2(tp1, tp2) || {
+ val tp1n = normalizePlus(tp1)
+ val tp2n = normalizePlus(tp2)
+ ((tp1n ne tp1) || (tp2n ne tp2)) && isSameType(tp1n, tp2n)
+ }
+ }
+ }
+
+ def isSameType2(tp1: Type, tp2: Type): Boolean = {
+ tp1 match {
+ case tr1: TypeRef =>
+ tp2 match {
+ case tr2: TypeRef =>
+ return (equalSymsAndPrefixes(tr1.sym, tr1.pre, tr2.sym, tr2.pre) &&
+ ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) ||
+ isSameTypes(tr1.args, tr2.args))) ||
+ ((tr1.pre, tr2.pre) match {
+ case (tv @ TypeVar(_,_), _) => tv.registerTypeSelection(tr1.sym, tr2)
+ case (_, tv @ TypeVar(_,_)) => tv.registerTypeSelection(tr2.sym, tr1)
+ case _ => false
+ })
+ case _: SingleType =>
+ return isSameType2(tp2, tp1) // put singleton type on the left, caught below
+ case _ =>
+ }
+ case tt1: ThisType =>
+ tp2 match {
+ case tt2: ThisType =>
+ if (tt1.sym == tt2.sym) return true
+ case _ =>
+ }
+ case st1: SingleType =>
+ tp2 match {
+ case st2: SingleType =>
+ if (equalSymsAndPrefixes(st1.sym, st1.pre, st2.sym, st2.pre)) return true
+ case TypeRef(pre2, sym2, Nil) =>
+ if (sym2.isModuleClass && equalSymsAndPrefixes(st1.sym, st1.pre, sym2.sourceModule, pre2)) return true
+ case _ =>
+ }
+ case ct1: ConstantType =>
+ tp2 match {
+ case ct2: ConstantType =>
+ return (ct1.value == ct2.value)
+ case _ =>
+ }
+ case rt1: RefinedType =>
+ tp2 match {
+ case rt2: RefinedType => //
+ def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall {
+ sym2 =>
+ var e1 = s1.lookupEntry(sym2.name)
+ (e1 ne null) && {
+ val substSym = sym2.info.substThis(sym2.owner, e1.sym.owner)
+ var isEqual = false
+ while (!isEqual && (e1 ne null)) {
+ isEqual = e1.sym.info =:= substSym
+ e1 = s1.lookupNextEntry(e1)
+ }
+ isEqual
+ }
+ }
+ //Console.println("is same? " + tp1 + " " + tp2 + " " + tp1.typeSymbol.owner + " " + tp2.typeSymbol.owner)//DEBUG
+ return isSameTypes(rt1.parents, rt2.parents) && {
+ val decls1 = rt1.decls
+ val decls2 = rt2.decls
+ isSubScope(decls1, decls2) && isSubScope(decls2, decls1)
+ }
+ case _ =>
+ }
+ case mt1: MethodType =>
+ tp2 match {
+ case mt2: MethodType =>
+ return isSameTypes(mt1.paramTypes, mt2.paramTypes) &&
+ mt1.resultType =:= mt2.resultType.substSym(mt2.params, mt1.params) &&
+ mt1.isImplicit == mt2.isImplicit
+ // note: no case NullaryMethodType(restpe) => return mt1.params.isEmpty && mt1.resultType =:= restpe
+ case _ =>
+ }
+ case NullaryMethodType(restpe1) =>
+ tp2 match {
+ // note: no case mt2: MethodType => return mt2.params.isEmpty && restpe =:= mt2.resultType
+ case NullaryMethodType(restpe2) =>
+ return restpe1 =:= restpe2
+ case _ =>
+ }
+ case PolyType(tparams1, res1) =>
+ tp2 match {
+ case PolyType(tparams2, res2) =>
+// assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length)))
+ // @M looks like it might suffer from same problem as #2210
+ return (
+ (sameLength(tparams1, tparams2)) && // corresponds does not check length of two sequences before checking the predicate
+ (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) &&
+ res1 =:= res2.substSym(tparams2, tparams1)
+ )
+ case _ =>
+ }
+ case ExistentialType(tparams1, res1) =>
+ tp2 match {
+ case ExistentialType(tparams2, res2) =>
+ // @M looks like it might suffer from same problem as #2210
+ return (
+ // corresponds does not check length of two sequences before checking the predicate -- faster & needed to avoid crasher in #2956
+ sameLength(tparams1, tparams2) &&
+ (tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) &&
+ res1 =:= res2.substSym(tparams2, tparams1)
+ )
+ case _ =>
+ }
+ case TypeBounds(lo1, hi1) =>
+ tp2 match {
+ case TypeBounds(lo2, hi2) =>
+ return lo1 =:= lo2 && hi1 =:= hi2
+ case _ =>
+ }
+ case BoundedWildcardType(bounds) =>
+ return bounds containsType tp2
+ case _ =>
+ }
+ tp2 match {
+ case BoundedWildcardType(bounds) =>
+ return bounds containsType tp1
+ case _ =>
+ }
+ tp1 match {
+ case tv @ TypeVar(_,_) =>
+ return tv.registerTypeEquality(tp2, true)
+ case _ =>
+ }
+ tp2 match {
+ case tv @ TypeVar(_,_) =>
+ return tv.registerTypeEquality(tp1, false)
+ case _ =>
+ }
+ tp1 match {
+ case _: AnnotatedType =>
+ return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations
+ case _ =>
+ }
+ tp2 match {
+ case _: AnnotatedType =>
+ return annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations
+ case _ =>
+ }
+ tp1 match {
+ case _: SingletonType =>
+ tp2 match {
+ case _: SingletonType =>
+ @inline def chaseDealiasedUnderlying(tp: Type): Type = {
+ var origin = tp
+ var next = origin.underlying.dealias
+ while (next.isInstanceOf[SingletonType]) {
+ assert(origin ne next, origin)
+ origin = next
+ next = origin.underlying.dealias
+ }
+ origin
+ }
+ val origin1 = chaseDealiasedUnderlying(tp1)
+ val origin2 = chaseDealiasedUnderlying(tp2)
+ ((origin1 ne tp1) || (origin2 ne tp2)) && (origin1 =:= origin2)
+ case _ =>
+ false
+ }
+ case _ =>
+ false
+ }
+ }
+
+ /** Are `tps1` and `tps2` lists of pairwise equivalent types? */
+ def isSameTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ =:= _)
+
+ /** True if two lists have the same length. Since calling length on linear sequences
+ * is O(n), it is an inadvisable way to test length equality.
+ */
+ final def sameLength(xs1: List[_], xs2: List[_]) = compareLengths(xs1, xs2) == 0
+ @tailrec final def compareLengths(xs1: List[_], xs2: List[_]): Int =
+ if (xs1.isEmpty) { if (xs2.isEmpty) 0 else -1 }
+ else if (xs2.isEmpty) 1
+ else compareLengths(xs1.tail, xs2.tail)
+
+ /** Again avoiding calling length, but the lengthCompare interface is clunky.
+ */
+ final def hasLength(xs: List[_], len: Int) = xs.lengthCompare(len) == 0
+
+ private val pendingSubTypes = new mutable.HashSet[SubTypePair]
+ private var basetypeRecursions: Int = 0
+ private val pendingBaseTypes = new mutable.HashSet[Type]
+
+ def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, AnyDepth)
+
+ def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = try {
+ subsametypeRecursions += 1
+
+ undoLog undoUnless { // 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
+ isSubType2(tp1, tp2, depth)
+ } finally {
+ pendingSubTypes -= p
+ }
+ } else {
+ isSubType2(tp1, tp2, depth)
+ }
+ }
+ } 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)
+ // it doesn't help to keep separate recursion counts for the three methods that now share it
+ // if (subsametypeRecursions == 0) undoLog.clear()
+ }
+
+ /** 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,
+ * type selections with the same name of equal (wrt) =:= prefixes are
+ * considered equal wrt =:=
+ */
+ def beginsWithTypeVarOrIsRefined(tp: Type): Boolean = tp match {
+ case SingleType(pre, sym) =>
+ !(sym hasFlag PACKAGE) && beginsWithTypeVarOrIsRefined(pre)
+ case tv@TypeVar(_, constr) =>
+ !tv.instValid || beginsWithTypeVarOrIsRefined(constr.inst)
+ case RefinedType(_, _) =>
+ true
+ case _ =>
+ false
+ }
+
+ def instTypeVar(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) =>
+ copyTypeRef(tp, instTypeVar(pre), sym, args)
+ case SingleType(pre, sym) =>
+ singleType(instTypeVar(pre), sym)
+ case TypeVar(_, constr) =>
+ instTypeVar(constr.inst)
+ case _ =>
+ tp
+ }
+
+ def isErrorOrWildcard(tp: Type) = (tp eq ErrorType) || (tp eq WildcardType)
+
+ def isSingleType(tp: Type) = tp match {
+ case ThisType(_) | SuperType(_, _) | SingleType(_, _) => true
+ case _ => false
+ }
+
+ def isConstantType(tp: Type) = tp match {
+ case ConstantType(_) => true
+ case _ => false
+ }
+
+ // @assume tp1.isHigherKinded || tp2.isHigherKinded
+ def isHKSubType0(tp1: Type, tp2: Type, depth: Int): Boolean = (
+ tp1.typeSymbol == NothingClass
+ ||
+ tp2.typeSymbol == AnyClass // @M Any and Nothing are super-type resp. subtype of every well-kinded type
+ || // @M! normalize reduces higher-kinded case to PolyType's
+ ((tp1.normalize.withoutAnnotations , tp2.normalize.withoutAnnotations) match {
+ case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => // @assume tp1.isHigherKinded && tp2.isHigherKinded (as they were both normalized to PolyType)
+ sameLength(tparams1, tparams2) && {
+ if (tparams1.head.owner.isMethod) { // fast-path: polymorphic method type -- type params cannot be captured
+ (tparams1 corresponds tparams2)((p1, p2) => p2.info.substSym(tparams2, tparams1) <:< p1.info) &&
+ res1 <:< res2.substSym(tparams2, tparams1)
+ } else { // normalized higher-kinded type
+ //@M for an example of why we need to generate fresh symbols, see neg/tcpoly_ticket2101.scala
+ val tpsFresh = cloneSymbols(tparams1)
+
+ (tparams1 corresponds tparams2)((p1, p2) =>
+ p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh)) &&
+ res1.substSym(tparams1, tpsFresh) <:< res2.substSym(tparams2, tpsFresh)
+
+ //@M the forall in the previous test could be optimised to the following,
+ // but not worth the extra complexity since it only shaves 1s from quick.comp
+ // (List.forall2(tpsFresh/*optimisation*/, tparams2)((p1, p2) =>
+ // p2.info.substSym(tparams2, tpsFresh) <:< p1.info /*optimisation, == (p1 from tparams1).info.substSym(tparams1, tpsFresh)*/) &&
+ // this optimisation holds because inlining cloneSymbols in `val tpsFresh = cloneSymbols(tparams1)` gives:
+ // val tpsFresh = tparams1 map (_.cloneSymbol)
+ // for (tpFresh <- tpsFresh) tpFresh.setInfo(tpFresh.info.substSym(tparams1, tpsFresh))
+ }
+ } && annotationsConform(tp1.normalize, tp2.normalize)
+ case (_, _) => false // @assume !tp1.isHigherKinded || !tp2.isHigherKinded
+ // --> thus, cannot be subtypes (Any/Nothing has already been checked)
+ }))
+
+ def isSubArg(t1: Type, t2: Type, variance: Int) =
+ (variance > 0 || t2 <:< t1) && (variance < 0 || t1 <:< t2)
+
+ def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean =
+ corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg)
+
+ def differentOrNone(tp1: Type, tp2: Type) = if (tp1 eq tp2) NoType else tp1
+
+ /** Does type `tp1` conform to `tp2`? */
+ private def isSubType2(tp1: Type, tp2: Type, depth: Int): Boolean = {
+ if ((tp1 eq tp2) || isErrorOrWildcard(tp1) || isErrorOrWildcard(tp2)) return true
+ if ((tp1 eq NoType) || (tp2 eq NoType)) return false
+ if (tp1 eq NoPrefix) return (tp2 eq NoPrefix) || tp2.typeSymbol.isPackageClass // !! I do not see how the "isPackageClass" would be warranted by the spec
+ if (tp2 eq NoPrefix) return tp1.typeSymbol.isPackageClass
+ if (isSingleType(tp1) && isSingleType(tp2) || isConstantType(tp1) && isConstantType(tp2)) return tp1 =:= tp2
+ if (tp1.isHigherKinded || tp2.isHigherKinded) return isHKSubType0(tp1, tp2, depth)
+
+ /** First try, on the right:
+ * - unwrap Annotated types, BoundedWildcardTypes,
+ * - bind TypeVars on the right, if lhs is not Annotated nor BoundedWildcard
+ * - handle common cases for first-kind TypeRefs on both sides as a fast path.
+ */
+ def firstTry = tp2 match {
+ // fast path: two typerefs, none of them HK
+ case tr2: TypeRef =>
+ tp1 match {
+ case tr1: TypeRef =>
+ val sym1 = tr1.sym
+ val sym2 = tr2.sym
+ val pre1 = tr1.pre
+ val pre2 = tr2.pre
+ (((if (sym1 == sym2) phase.erasedTypes || pre1 <:< pre2
+ else (sym1.name == sym2.name && !sym1.isModuleClass && !sym2.isModuleClass &&
+ (isUnifiable(pre1, pre2) ||
+ isSameSpecializedSkolem(sym1, sym2, pre1, pre2) ||
+ sym2.isAbstractType && isSubPre(pre1, pre2, sym2)))) &&
+ isSubArgs(tr1.args, tr2.args, sym1.typeParams))
+ ||
+ sym2.isClass && {
+ val base = tr1 baseType sym2
+ (base ne tr1) && base <:< tr2
+ }
+ ||
+ thirdTryRef(tr1, tr2))
+ case _ =>
+ secondTry
+ }
+ case AnnotatedType(_, _, _) =>
+ tp1.withoutAnnotations <:< tp2.withoutAnnotations && annotationsConform(tp1, tp2)
+ case BoundedWildcardType(bounds) =>
+ tp1 <:< bounds.hi
+ case tv2 @ TypeVar(_, constr2) =>
+ tp1 match {
+ case AnnotatedType(_, _, _) | BoundedWildcardType(_) =>
+ secondTry
+ case _ =>
+ tv2.registerBound(tp1, true)
+ }
+ case _ =>
+ secondTry
+ }
+
+ /** Second try, on the left:
+ * - unwrap AnnotatedTypes, BoundedWildcardTypes,
+ * - bind typevars,
+ * - handle existential types by skolemization.
+ */
+ def secondTry = tp1 match {
+ case AnnotatedType(_, _, _) =>
+ tp1.withoutAnnotations <:< tp2.withoutAnnotations && annotationsConform(tp1, tp2)
+ case BoundedWildcardType(bounds) =>
+ tp1.bounds.lo <:< tp2
+ case tv @ TypeVar(_,_) =>
+ tv.registerBound(tp2, false)
+ case ExistentialType(_, _) =>
+ try {
+ skolemizationLevel += 1
+ tp1.skolemizeExistential <:< tp2
+ } finally {
+ skolemizationLevel -= 1
+ }
+ case _ =>
+ thirdTry
+ }
+
+ def thirdTryRef(tp1: Type, tp2: TypeRef): Boolean = {
+ val sym2 = tp2.sym
+ sym2 match {
+ case NotNullClass => tp1.isNotNull
+ case SingletonClass => tp1.isStable || fourthTry
+ case _: ClassSymbol =>
+ if (isRaw(sym2, tp2.args))
+ isSubType(tp1, rawToExistential(tp2), depth)
+ else if (sym2.name == tpnme.REFINE_CLASS_NAME)
+ isSubType(tp1, sym2.info, depth)
+ else
+ fourthTry
+ case _: TypeSymbol =>
+ if (sym2 hasFlag DEFERRED) {
+ val tp2a = tp2.bounds.lo
+ isDifferentTypeConstructor(tp2, tp2a) && tp1 <:< tp2a || fourthTry
+ } else {
+ isSubType(tp1.normalize, tp2.normalize, depth)
+ }
+ case _ =>
+ fourthTry
+ }
+ }
+
+ /** Third try, on the right:
+ * - decompose refined types.
+ * - handle typerefs, existentials, and notnull types.
+ * - handle left+right method types, polytypes, typebounds
+ */
+ def thirdTry = tp2 match {
+ case tr2: TypeRef =>
+ thirdTryRef(tp1, tr2)
+ case rt2: RefinedType =>
+ (rt2.parents forall (tp1 <:< _)) &&
+ (rt2.decls forall tp1.specializes)
+ case et2: ExistentialType =>
+ et2.withTypeVars(tp1 <:< _, depth) || fourthTry
+ case nn2: NotNullType =>
+ tp1.isNotNull && tp1 <:< nn2.underlying
+ case mt2: MethodType =>
+ tp1 match {
+ case mt1 @ MethodType(params1, res1) =>
+ val params2 = mt2.params
+ val res2 = mt2.resultType
+ (sameLength(params1, params2) &&
+ mt1.isImplicit == mt2.isImplicit &&
+ matchingParams(params1, params2, mt1.isJava, mt2.isJava) &&
+ (res1 <:< res2.substSym(params2, params1)))
+ // TODO: if mt1.params.isEmpty, consider NullaryMethodType?
+ case _ =>
+ false
+ }
+ case pt2 @ NullaryMethodType(_) =>
+ tp1 match {
+ // TODO: consider MethodType mt for which mt.params.isEmpty??
+ case pt1 @ NullaryMethodType(_) =>
+ pt1.resultType <:< pt2.resultType
+ case _ =>
+ false
+ }
+ case TypeBounds(lo2, hi2) =>
+ tp1 match {
+ case TypeBounds(lo1, hi1) =>
+ lo2 <:< lo1 && hi1 <:< hi2
+ case _ =>
+ false
+ }
+ case _ =>
+ fourthTry
+ }
+
+ /** Fourth try, on the left:
+ * - handle typerefs, refined types, notnull and singleton types.
+ */
+ def fourthTry = tp1 match {
+ case tr1 @ TypeRef(pre1, sym1, _) =>
+ sym1 match {
+ case NothingClass => true
+ case NullClass =>
+ tp2 match {
+ case TypeRef(_, sym2, _) =>
+ containsNull(sym2)
+ case _ =>
+ isSingleType(tp2) && tp1 <:< tp2.widen
+ }
+ case _: ClassSymbol =>
+ if (isRaw(sym1, tr1.args))
+ isSubType(rawToExistential(tp1), tp2, depth)
+ else if (sym1.isModuleClass) tp2 match {
+ case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2)
+ case _ => false
+ }
+ else if (sym1.isRefinementClass)
+ isSubType(sym1.info, tp2, depth)
+ else false
+
+ case _: TypeSymbol =>
+ if (sym1 hasFlag DEFERRED) {
+ val tp1a = tp1.bounds.hi
+ isDifferentTypeConstructor(tp1, tp1a) && tp1a <:< tp2
+ } else {
+ isSubType(tp1.normalize, tp2.normalize, depth)
+ }
+ case _ =>
+ false
+ }
+ case RefinedType(parents1, _) =>
+ parents1 exists (_ <:< tp2)
+ case _: SingletonType | _: NotNullType =>
+ tp1.underlying <:< tp2
+ case _ =>
+ false
+ }
+
+ firstTry
+ }
+
+ private def containsNull(sym: Symbol): Boolean =
+ sym.isClass && sym != NothingClass &&
+ !(sym isNonBottomSubClass AnyValClass) &&
+ !(sym isNonBottomSubClass NotNullClass)
+
+ /** Are `tps1` and `tps2` lists of equal length such that all elements
+ * of `tps1` conform to corresponding elements of `tps2`?
+ */
+ def isSubTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ <:< _)
+
+ /** Does type `tp` implement symbol `sym` with same or
+ * stronger type? Exact only if `sym` is a member of some
+ * refinement type, otherwise we might return false negatives.
+ */
+ def specializesSym(tp: Type, sym: Symbol): Boolean =
+ tp.typeSymbol == NothingClass ||
+ tp.typeSymbol == NullClass && containsNull(sym.owner) ||
+ (tp.nonPrivateMember(sym.name).alternatives exists
+ (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym)))
+
+ /** Does member `sym1` of `tp1` have a stronger type
+ * than member `sym2` of `tp2`?
+ */
+ private def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol): Boolean = {
+ val info1 = tp1.memberInfo(sym1)
+ val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1)
+ //System.out.println("specializes "+tp1+"."+sym1+":"+info1+sym1.locationString+" AND "+tp2+"."+sym2+":"+info2)//DEBUG
+ ( sym2.isTerm && (info1 <:< info2) && (!sym2.isStable || sym1.isStable)
+ || sym2.isAbstractType && {
+ val memberTp1 = tp1.memberType(sym1)
+ // println("kinds conform? "+(memberTp1, tp1, sym2, kindsConform(List(sym2), List(memberTp1), tp2, sym2.owner)))
+ info2.bounds.containsType(memberTp1) &&
+ kindsConform(List(sym2), List(memberTp1), tp1, sym1.owner)
+ }
+ || sym2.isAliasType && tp2.memberType(sym2).substThis(tp2.typeSymbol, tp1) =:= tp1.memberType(sym1) //@MAT ok
+ )
+ }
+
+ /** A function implementing `tp1` matches `tp2`. */
+ final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = {
+ def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = (
+ sameLength(tparams1, tparams2) &&
+ matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple)
+ )
+ def lastTry =
+ tp2 match {
+ case ExistentialType(_, res2) if alwaysMatchSimple =>
+ matchesType(tp1, res2, true)
+ case MethodType(_, _) =>
+ false
+ case PolyType(_, _) =>
+ false
+ case _ =>
+ alwaysMatchSimple || tp1 =:= tp2
+ }
+ tp1 match {
+ case mt1 @ MethodType(params1, res1) =>
+ tp2 match {
+ case mt2 @ MethodType(params2, res2) =>
+ // sameLength(params1, params2) was used directly as pre-screening optimization (now done by matchesQuantified -- is that ok, performancewise?)
+ mt1.isImplicit == mt2.isImplicit &&
+ matchingParams(params1, params2, mt1.isJava, mt2.isJava) &&
+ matchesQuantified(params1, params2, res1, res2)
+ case NullaryMethodType(res2) =>
+ if (params1.isEmpty) matchesType(res1, res2, alwaysMatchSimple)
+ else matchesType(tp1, res2, alwaysMatchSimple)
+ case ExistentialType(_, res2) =>
+ alwaysMatchSimple && matchesType(tp1, res2, true)
+ case TypeRef(_, sym, Nil) =>
+ params1.isEmpty && sym.isModuleClass && matchesType(res1, tp2, alwaysMatchSimple)
+ case _ =>
+ false
+ }
+ case mt1 @ NullaryMethodType(res1) =>
+ tp2 match {
+ case mt2 @ MethodType(Nil, res2) => // could never match if params nonEmpty, and !mt2.isImplicit is implied by empty param list
+ matchesType(res1, res2, alwaysMatchSimple)
+ case NullaryMethodType(res2) =>
+ matchesType(res1, res2, alwaysMatchSimple)
+ case ExistentialType(_, res2) =>
+ alwaysMatchSimple && matchesType(tp1, res2, true)
+ case TypeRef(_, sym, Nil) if sym.isModuleClass =>
+ matchesType(res1, tp2, alwaysMatchSimple)
+ case _ =>
+ matchesType(res1, tp2, alwaysMatchSimple)
+ }
+ case PolyType(tparams1, res1) =>
+ tp2 match {
+ case PolyType(tparams2, res2) =>
+ if ((tparams1 corresponds tparams2)(_ eq _))
+ matchesType(res1, res2, alwaysMatchSimple)
+ else
+ matchesQuantified(tparams1, tparams2, res1, res2)
+ case ExistentialType(_, res2) =>
+ alwaysMatchSimple && matchesType(tp1, res2, true)
+ case _ =>
+ false // remember that tparams1.nonEmpty is now an invariant of PolyType
+ }
+ case ExistentialType(tparams1, res1) =>
+ tp2 match {
+ case ExistentialType(tparams2, res2) =>
+ matchesQuantified(tparams1, tparams2, res1, res2)
+ case _ =>
+ if (alwaysMatchSimple) matchesType(res1, tp2, true)
+ else lastTry
+ }
+ case TypeRef(_, sym, Nil) if sym.isModuleClass =>
+ tp2 match {
+ case MethodType(Nil, res2) => matchesType(tp1, res2, alwaysMatchSimple)
+ case NullaryMethodType(res2) => matchesType(tp1, res2, alwaysMatchSimple)
+ case _ => lastTry
+ }
+ case _ =>
+ lastTry
+ }
+ }
+
+/** matchesType above is an optimized version of the following implementation:
+
+ def matchesType2(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = {
+ def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean =
+ tparams1.length == tparams2.length &&
+ matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple)
+ (tp1, tp2) match {
+ case (MethodType(params1, res1), MethodType(params2, res2)) =>
+ params1.length == params2.length && // useful pre-secreening optimization
+ matchingParams(params1, params2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) &&
+ matchesType(res1, res2, alwaysMatchSimple) &&
+ tp1.isImplicit == tp2.isImplicit
+ case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
+ matchesQuantified(tparams1, tparams2, res1, res2)
+ case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) =>
+ matchesType(rtp1, rtp2, alwaysMatchSimple)
+ case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) =>
+ matchesType(rtp1, rtp2, alwaysMatchSimple)
+ case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
+ matchesQuantified(tparams1, tparams2, res1, res2)
+ case (ExistentialType(_, res1), _) if alwaysMatchSimple =>
+ matchesType(res1, tp2, alwaysMatchSimple)
+ case (_, ExistentialType(_, res2)) if alwaysMatchSimple =>
+ matchesType(tp1, res2, alwaysMatchSimple)
+ case (NullaryMethodType(rtp1), _) =>
+ matchesType(rtp1, tp2, alwaysMatchSimple)
+ case (_, NullaryMethodType(rtp2)) =>
+ matchesType(tp1, rtp2, alwaysMatchSimple)
+ case (MethodType(_, _), _) => false
+ case (PolyType(_, _), _) => false
+ case (_, MethodType(_, _)) => false
+ case (_, PolyType(_, _)) => false
+ case _ =>
+ alwaysMatchSimple || tp1 =:= tp2
+ }
+ }
+*/
+
+ /** Are `syms1` and `syms2` parameter lists with pairwise equivalent types? */
+ private def matchingParams(syms1: List[Symbol], syms2: List[Symbol], syms1isJava: Boolean, syms2isJava: Boolean): Boolean = syms1 match {
+ case Nil =>
+ syms2.isEmpty
+ case sym1 :: rest1 =>
+ syms2 match {
+ case Nil =>
+ false
+ case sym2 :: rest2 =>
+ val tp1 = sym1.tpe
+ val tp2 = sym2.tpe
+ (tp1 =:= tp2 ||
+ syms1isJava && tp2.typeSymbol == ObjectClass && tp1.typeSymbol == AnyClass ||
+ syms2isJava && tp1.typeSymbol == ObjectClass && tp2.typeSymbol == AnyClass) &&
+ matchingParams(rest1, rest2, syms1isJava, syms2isJava)
+ }
+ }
+
+ /** like map2, but returns list `xs` itself - instead of a copy - if function
+ * `f` maps all elements to themselves.
+ */
+ def map2Conserve[A <: AnyRef, B](xs: List[A], ys: List[B])(f: (A, B) => A): List[A] =
+ if (xs.isEmpty) xs
+ else {
+ val x1 = f(xs.head, ys.head)
+ val xs1 = map2Conserve(xs.tail, ys.tail)(f)
+ if ((x1 eq xs.head) && (xs1 eq xs.tail)) xs
+ else x1 :: xs1
+ }
+
+ /** Solve constraint collected in types `tvars`.
+ *
+ * @param tvars All type variables to be instantiated.
+ * @param tparams The type parameters corresponding to `tvars`
+ * @param variances The variances of type parameters; need to reverse
+ * solution direction for all contravariant variables.
+ * @param upper When `true` search for max solution else min.
+ */
+ def solve(tvars: List[TypeVar], tparams: List[Symbol],
+ variances: List[Int], upper: Boolean): Boolean =
+ solve(tvars, tparams, variances, upper, AnyDepth)
+
+ def solve(tvars: List[TypeVar], tparams: List[Symbol],
+ variances: List[Int], upper: Boolean, depth: Int): Boolean = {
+
+ def solveOne(tvar: TypeVar, tparam: Symbol, variance: Int) {
+ if (tvar.constr.inst == NoType) {
+ val up = if (variance != CONTRAVARIANT) upper else !upper
+ tvar.constr.inst = null
+ val bound: Type = if (up) tparam.info.bounds.hi else tparam.info.bounds.lo
+ //Console.println("solveOne0(tv, tp, v, b)="+(tvar, tparam, variance, bound))
+ var cyclic = bound contains tparam
+ foreach3(tvars, tparams, variances)((tvar2, tparam2, variance2) => {
+ val ok = (tparam2 != tparam) && (
+ (bound contains tparam2)
+ || up && (tparam2.info.bounds.lo =:= tparam.tpeHK)
+ || !up && (tparam2.info.bounds.hi =:= tparam.tpeHK)
+ )
+ if (ok) {
+ if (tvar2.constr.inst eq null) cyclic = true
+ solveOne(tvar2, tparam2, variance2)
+ }
+ })
+ if (!cyclic) {
+ if (up) {
+ if (bound.typeSymbol != AnyClass)
+ tvar addHiBound bound.instantiateTypeParams(tparams, tvars)
+ for (tparam2 <- tparams)
+ tparam2.info.bounds.lo.dealias match {
+ case TypeRef(_, `tparam`, _) =>
+ tvar addHiBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars)
+ case _ =>
+ }
+ } else {
+ if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) {
+ tvar addLoBound bound.instantiateTypeParams(tparams, tvars)
+ }
+ for (tparam2 <- tparams)
+ tparam2.info.bounds.hi.dealias match {
+ case TypeRef(_, `tparam`, _) =>
+ tvar addLoBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars)
+ case _ =>
+ }
+ }
+ }
+ tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar
+
+ //println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen)))
+
+ tvar setInst (
+ if (up) {
+ if (depth != AnyDepth) glb(tvar.constr.hiBounds, depth) else glb(tvar.constr.hiBounds)
+ } else {
+ if (depth != AnyDepth) lub(tvar.constr.loBounds, depth) else lub(tvar.constr.loBounds)
+ })
+
+ //Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))+" = "+tvar.constr.inst)//@MDEBUG
+ }
+ }
+
+ // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info)))
+ foreach3(tvars, tparams, variances)(solveOne)
+ tvars forall (tvar => tvar.constr.isWithinBounds(tvar.constr.inst))
+ }
+
+ /** Do type arguments `targs` conform to formal parameters `tparams`?
+ */
+ def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = {
+ var bounds = instantiatedBounds(pre, owner, tparams, targs)
+ if (targs.exists(_.annotations.nonEmpty))
+ bounds = adaptBoundsToAnnotations(bounds, tparams, targs)
+ (bounds corresponds targs)(_ containsType _)
+ }
+
+ def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] =
+ tparams map (_.info.asSeenFrom(pre, owner).instantiateTypeParams(tparams, targs).bounds)
+
+// Lubs and Glbs ---------------------------------------------------------
+
+ private def printLubMatrix(btsMap: Map[Type, List[Type]], depth: Int) {
+ import util.TableDef
+ import TableDef.Column
+ def str(tp: Type) = {
+ if (tp == NoType) ""
+ else {
+ val s = ("" + tp).replaceAll("""[\w.]+\.(\w+)""", "$1")
+ if (s.length < 60) s
+ else (s take 57) + "..."
+ }
+ }
+
+ val sorted = btsMap.toList.sortWith((x, y) => x._1.typeSymbol isLess y._1.typeSymbol)
+ val maxSeqLength = sorted map (_._2.size) max
+ val padded = sorted map (_._2.padTo(maxSeqLength, NoType))
+ val transposed = padded.transpose
+
+ val columns: List[Column[List[Type]]] = mapWithIndex(sorted) {
+ case ((k, v), idx) =>
+ Column(str(k), (xs: List[Type]) => str(xs(idx)), true)
+ }
+
+ val tableDef = TableDef(columns: _*)
+ val formatted = tableDef.table(transposed)
+ println("** Depth is " + depth + "\n" + formatted)
+ }
+
+ /** From a list of types, find any which take type parameters
+ * where the type parameter bounds contain references to other
+ * any types in the list (including itself.)
+ *
+ * @return List of symbol pairs holding the recursive type
+ * parameter and the parameter which references it.
+ */
+ def findRecursiveBounds(ts: List[Type]): List[(Symbol, Symbol)] = {
+ if (ts.isEmpty) Nil
+ else {
+ val sym = ts.head.typeSymbol
+ require(ts.tail forall (_.typeSymbol == sym), ts)
+ for (p <- sym.typeParams ; in <- sym.typeParams ; if in.info.bounds contains p) yield
+ p -> in
+ }
+ }
+
+ /** Given a matrix `tsBts` whose columns are basetype sequences (and the symbols `tsParams` that should be interpreted as type parameters in this matrix),
+ * compute its least sorted upwards closed upper bound relative to the following ordering <= between lists of types:
+ *
+ * xs <= ys iff forall y in ys exists x in xs such that x <: y
+ *
+ * @arg tsParams for each type in the original list of types `ts0`, its list of type parameters (if that type is a type constructor)
+ * (these type parameters may be referred to by type arguments in the BTS column of those types,
+ * and must be interpreted as bound variables; i.e., under a type lambda that wraps the types that refer to these type params)
+ * @arg tsBts a matrix whose columns are basetype sequences
+ * the first row is the original list of types for which we're computing the lub
+ * (except that type constructors have been applied to their dummyArgs)
+ * @See baseTypeSeq for a definition of sorted and upwards closed.
+ */
+ private def lubList(ts: List[Type], depth: Int): List[Type] = {
+ // Matching the type params of one of the initial types means dummies.
+ val initialTypeParams = ts map (_.typeParams)
+ def isHotForTs(xs: List[Type]) = initialTypeParams contains xs.map(_.typeSymbol)
+
+ def elimHigherOrderTypeParam(tp: Type) = tp match {
+ case TypeRef(pre, sym, args) if args.nonEmpty && isHotForTs(args) => tp.typeConstructor
+ case _ => tp
+ }
+ var lubListDepth = 0
+ def loop(tsBts: List[List[Type]]): List[Type] = {
+ lubListDepth += 1
+
+ if (tsBts.isEmpty || tsBts.exists(_.isEmpty)) Nil
+ else if (tsBts.tail.isEmpty) tsBts.head
+ else {
+ // ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts.
+ // Invariant: all symbols "under" (closer to the first row) the frontier
+ // are smaller (according to _.isLess) than the ones "on and beyond" the frontier
+ val ts0 = tsBts map (_.head)
+
+ // Is the frontier made up of types with the same symbol?
+ val isUniformFrontier = (ts0: @unchecked) match {
+ case t :: ts => ts forall (_.typeSymbol == t.typeSymbol)
+ }
+
+ // Produce a single type for this frontier by merging the prefixes and arguments of those
+ // typerefs that share the same symbol: that symbol is the current maximal symbol for which
+ // the invariant holds, i.e., the one that conveys most information wrt subtyping. Before
+ // merging, strip targs that refer to bound tparams (when we're computing the lub of type
+ // constructors.) Also filter out all types that are a subtype of some other type.
+ if (isUniformFrontier) {
+ if (settings.debug.value || printLubs) {
+ val fbounds = findRecursiveBounds(ts0)
+ if (fbounds.nonEmpty) {
+ println("Encountered " + fbounds.size + " recursive bounds while lubbing " + ts0.size + " types.")
+ for ((p0, p1) <- fbounds) {
+ val desc = if (p0 == p1) "its own bounds" else "the bounds of " + p1
+
+ println(" " + p0.fullLocationString + " appears in " + desc)
+ println(" " + p1 + " " + p1.info.bounds)
+ }
+ println("")
+ }
+ }
+ val tails = tsBts map (_.tail)
+ mergePrefixAndArgs(elimSub(ts0 map elimHigherOrderTypeParam, depth), 1, depth) match {
+ case Some(tp) => tp :: loop(tails)
+ case _ => loop(tails)
+ }
+ }
+ else {
+ // frontier is not uniform yet, move it beyond the current minimal symbol;
+ // lather, rinSe, repeat
+ val sym = minSym(ts0)
+ val newtps = tsBts map (ts => if (ts.head.typeSymbol == sym) ts.tail else ts)
+ if (printLubs) {
+ val str = (newtps.zipWithIndex map { case (tps, idx) =>
+ tps.map(" " + _ + "\n").mkString(" (" + idx + ")\n", "", "\n")
+ }).mkString("")
+
+ println("Frontier(\n" + str + ")")
+ printLubMatrix(ts zip tsBts toMap, lubListDepth)
+ }
+
+ loop(newtps)
+ }
+ }
+ }
+
+ val initialBTSes = ts map (_.baseTypeSeq.toList)
+ if (printLubs)
+ printLubMatrix(ts zip initialBTSes toMap, depth)
+
+ loop(initialBTSes)
+ }
+
+ /** The minimal symbol (wrt Symbol.isLess) of a list of types */
+ private def minSym(tps: List[Type]): Symbol =
+ (tps.head.typeSymbol /: tps.tail) {
+ (sym1, tp2) => if (tp2.typeSymbol isLess sym1) tp2.typeSymbol else sym1
+ }
+
+ /** A minimal type list which has a given list of types as its base type sequence */
+ def spanningTypes(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case first :: rest =>
+ first :: spanningTypes(
+ rest filter (t => !first.typeSymbol.isSubClass(t.typeSymbol)))
+ }
+
+ /** Eliminate from list of types all elements which are a supertype
+ * of some other element of the list. */
+ private def elimSuper(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case t :: ts1 =>
+ val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
+ if (rest exists (t1 => t1 <:< t)) rest else t :: rest
+ }
+ def elimAnonymousClass(t: Type) = t match {
+ case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass =>
+ clazz.classBound.asSeenFrom(pre, clazz.owner)
+ case _ =>
+ t
+ }
+ def elimRefinement(t: Type) = t match {
+ case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents)
+ case _ => t
+ }
+
+ /** Eliminate from list of types all elements which are a subtype
+ * of some other element of the list. */
+ private def elimSub(ts: List[Type], depth: Int): List[Type] = {
+ def elimSub0(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case t :: ts1 =>
+ val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, decr(depth))))
+ if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest
+ }
+ val ts0 = elimSub0(ts)
+ if (ts0.isEmpty || ts0.tail.isEmpty) ts0
+ else {
+ val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.underlying))
+ if (ts1 eq ts0) ts0
+ else elimSub(ts1, depth)
+ }
+ }
+
+ private def stripExistentialsAndTypeVars(ts: List[Type]): (List[Type], List[Symbol]) = {
+ val quantified = ts flatMap {
+ case ExistentialType(qs, _) => qs
+ case t => List()
+ }
+ def stripType(tp: Type) = tp match {
+ case ExistentialType(_, res) =>
+ res
+ case tv@TypeVar(_, constr) =>
+ if (tv.instValid) constr.inst
+ else if (tv.untouchable) tv
+ else abort("trying to do lub/glb of typevar "+tp)
+ case t => t
+ }
+ val strippedTypes = ts mapConserve stripType
+ (strippedTypes, quantified)
+ }
+
+ def weakLub(ts: List[Type]) =
+ if (ts.nonEmpty && (ts forall isNumericValueType)) (numericLub(ts), true)
+ else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty)))
+ (annotationsLub(lub(ts map (_.withoutAnnotations)), ts), true)
+ else (lub(ts), false)
+
+ def weakGlb(ts: List[Type]) = {
+ if (ts.nonEmpty && (ts forall isNumericValueType)) {
+ val nglb = numericGlb(ts)
+ if (nglb != NoType) (nglb, true)
+ else (glb(ts), false)
+ } else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) {
+ (annotationsGlb(glb(ts map (_.withoutAnnotations)), ts), true)
+ } else (glb(ts), false)
+ }
+
+ def numericLub(ts: List[Type]) =
+ ts reduceLeft ((t1, t2) =>
+ if (isNumericSubType(t1, t2)) t2
+ else if (isNumericSubType(t2, t1)) t1
+ else IntClass.tpe)
+
+ def numericGlb(ts: List[Type]) =
+ ts reduceLeft ((t1, t2) =>
+ if (isNumericSubType(t1, t2)) t1
+ else if (isNumericSubType(t2, t1)) t2
+ else NoType)
+
+ def isWeakSubType(tp1: Type, tp2: Type) =
+ tp1.deconst.normalize match {
+ case TypeRef(_, sym1, _) if isNumericValueClass(sym1) =>
+ tp2.deconst.normalize match {
+ case TypeRef(_, sym2, _) if isNumericValueClass(sym2) =>
+ isNumericSubClass(sym1, sym2)
+ case tv2 @ TypeVar(_, _) =>
+ tv2.registerBound(tp1, isLowerBound = true, isNumericBound = true)
+ case _ =>
+ isSubType(tp1, tp2)
+ }
+ case tv1 @ TypeVar(_, _) =>
+ tp2.deconst.normalize match {
+ case TypeRef(_, sym2, _) if isNumericValueClass(sym2) =>
+ tv1.registerBound(tp2, isLowerBound = false, isNumericBound = true)
+ case _ =>
+ isSubType(tp1, tp2)
+ }
+ case _ =>
+ isSubType(tp1, tp2)
+ }
+
+ /** The isNumericValueType tests appear redundant, but without them
+ * test/continuations-neg/function3.scala goes into an infinite loop.
+ * (Even if the calls are to typeSymbolDirect.)
+ */
+ def isNumericSubType(tp1: Type, tp2: Type) = (
+ isNumericValueType(tp1)
+ && isNumericValueType(tp2)
+ && isNumericSubClass(tp1.typeSymbol, tp2.typeSymbol)
+ )
+
+ private val lubResults = new mutable.HashMap[(Int, List[Type]), Type]
+ private val glbResults = new mutable.HashMap[(Int, List[Type]), Type]
+
+ def lub(ts: List[Type]): Type = ts match {
+ case List() => NothingClass.tpe
+ case List(t) => t
+ case _ =>
+ try {
+ lub(ts, lubDepth(ts))
+ } finally {
+ lubResults.clear()
+ glbResults.clear()
+ }
+ }
+
+ /** The least upper bound wrt <:< of a list of types */
+ private def lub(ts: List[Type], depth: Int): Type = {
+ def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match {
+ case List() => NothingClass.tpe
+ case List(t) => t
+ case ts @ PolyType(tparams, _) :: _ =>
+ val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
+ tparam.cloneSymbol.setInfo(glb(bounds, depth)))
+ PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1)))
+ case ts @ MethodType(params, _) :: rest =>
+ MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe))))
+ case ts @ NullaryMethodType(_) :: rest =>
+ NullaryMethodType(lub0(matchingRestypes(ts, Nil)))
+ case ts @ TypeBounds(_, _) :: rest =>
+ TypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth))
+ case ts =>
+ lubResults get (depth, ts) match {
+ case Some(lubType) =>
+ lubType
+ case None =>
+ lubResults((depth, ts)) = AnyClass.tpe
+ val res = if (depth < 0) AnyClass.tpe else lub1(ts)
+ lubResults((depth, ts)) = res
+ res
+ }
+ }
+ def lub1(ts0: List[Type]): Type = {
+ val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
+ val lubBaseTypes: List[Type] = lubList(ts, depth)
+ val lubParents = spanningTypes(lubBaseTypes)
+ val lubOwner = commonOwner(ts)
+ val lubBase = intersectionType(lubParents, lubOwner)
+ val lubType =
+ if (phase.erasedTypes || depth == 0) lubBase
+ else {
+ val lubRefined = refinedType(lubParents, lubOwner)
+ val lubThisType = lubRefined.typeSymbol.thisType
+ val narrowts = ts map (_.narrow)
+ def excludeFromLub(sym: Symbol) = (
+ sym.isClass
+ || sym.isConstructor
+ || !sym.isPublic
+ || isGetClass(sym)
+ || narrowts.exists(t => !refines(t, sym))
+ )
+ def lubsym(proto: Symbol): Symbol = {
+ val prototp = lubThisType.memberInfo(proto)
+ val syms = narrowts map (t =>
+ t.nonPrivateMember(proto.name).suchThat(sym =>
+ sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t)))
+ if (syms contains NoSymbol) NoSymbol
+ else {
+ val symtypes =
+ map2(narrowts, syms)((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType))
+ if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class
+ proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth)))
+ else if (symtypes.tail forall (symtypes.head =:=))
+ proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(symtypes.head)
+ else {
+ def lubBounds(bnds: List[TypeBounds]): TypeBounds =
+ TypeBounds(glb(bnds map (_.lo), decr(depth)), lub(bnds map (_.hi), decr(depth)))
+ lubRefined.typeSymbol.newAbstractType(proto.name.toTypeName, proto.pos)
+ .setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds)))
+ }
+ }
+ }
+ def refines(tp: Type, sym: Symbol): Boolean = {
+ val syms = tp.nonPrivateMember(sym.name).alternatives;
+ !syms.isEmpty && (syms forall (alt =>
+ // todo alt != sym is strictly speaking not correct, but without it we lose
+ // efficiency.
+ alt != sym && !specializesSym(lubThisType, sym, tp, alt)))
+ }
+ // add a refinement symbol for all non-class members of lubBase
+ // which are refined by every type in ts.
+ for (sym <- lubBase.nonPrivateMembers ; if !excludeFromLub(sym)) {
+ try {
+ val lsym = lubsym(sym)
+ if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lsym)
+ } catch {
+ case ex: NoCommonType =>
+ }
+ }
+ if (lubRefined.decls.isEmpty) lubBase
+ else if (!verifyLubs) lubRefined
+ else {
+ // Verify that every given type conforms to the calculated lub.
+ // In theory this should not be necessary, but higher-order type
+ // parameters are not handled correctly.
+ val ok = ts forall { t =>
+ (t <:< lubRefined) || {
+ if (settings.debug.value || printLubs) {
+ Console.println(
+ "Malformed lub: " + lubRefined + "\n" +
+ "Argument " + t + " does not conform. Falling back to " + lubBase
+ )
+ }
+ false
+ }
+ }
+ // If not, fall back on the more conservative calculation.
+ if (ok) lubRefined
+ else lubBase
+ }
+ }
+ existentialAbstraction(tparams, lubType)
+ }
+ if (printLubs) {
+ println(indent + "lub of " + ts + " at depth "+depth)//debug
+ indent = indent + " "
+ assert(indent.length <= 100)
+ }
+ val res = lub0(ts)
+ if (printLubs) {
+ indent = indent stripSuffix " "
+ println(indent + "lub of " + ts + " is " + res)//debug
+ }
+ if (ts forall (_.isNotNull)) res.notNull else res
+ }
+
+ val GlbFailure = new Throwable
+
+ /** A global counter for glb calls in the `specializes` query connected to the `addMembers`
+ * call in `glb`. There's a possible infinite recursion when `specializes` calls
+ * memberType, which calls baseTypeSeq, which calls mergePrefixAndArgs, which calls glb.
+ * The counter breaks this recursion after two calls.
+ * If the recursion is broken, no member is added to the glb.
+ */
+ private var globalGlbDepth = 0
+ private final val globalGlbLimit = 2
+
+ /** The greatest lower bound wrt <:< of a list of types */
+ def glb(ts: List[Type]): Type = elimSuper(ts) match {
+ case List() => AnyClass.tpe
+ case List(t) => t
+ case ts0 =>
+ try {
+ glbNorm(ts0, lubDepth(ts0))
+ } finally {
+ lubResults.clear()
+ glbResults.clear()
+ }
+ }
+
+ private def glb(ts: List[Type], depth: Int): Type = elimSuper(ts) match {
+ case List() => AnyClass.tpe
+ case List(t) => t
+ case ts0 => glbNorm(ts0, depth)
+ }
+
+ /** The greatest lower bound wrt <:< of a list of types, which have been normalized
+ * wrt elimSuper */
+ protected def glbNorm(ts: List[Type], depth: Int): Type = {
+ def glb0(ts0: List[Type]): Type = ts0 match {
+ case List() => AnyClass.tpe
+ case List(t) => t
+ case ts @ PolyType(tparams, _) :: _ =>
+ val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
+ tparam.cloneSymbol.setInfo(lub(bounds, depth)))
+ PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth))
+ case ts @ MethodType(params, _) :: rest =>
+ MethodType(params, glbNorm(matchingRestypes(ts, params map (_.tpe)), depth))
+ case ts @ NullaryMethodType(_) :: rest =>
+ NullaryMethodType(glbNorm(matchingRestypes(ts, Nil), depth))
+ case ts @ TypeBounds(_, _) :: rest =>
+ TypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth))
+ case ts =>
+ glbResults get (depth, ts) match {
+ case Some(glbType) =>
+ glbType
+ case _ =>
+ glbResults((depth, ts)) = NothingClass.tpe
+ val res = if (depth < 0) NothingClass.tpe else glb1(ts)
+ glbResults((depth, ts)) = res
+ res
+ }
+ }
+ def glb1(ts0: List[Type]): Type = {
+ try {
+ val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
+ val glbOwner = commonOwner(ts)
+ def refinedToParents(t: Type): List[Type] = t match {
+ case RefinedType(ps, _) => ps flatMap refinedToParents
+ case _ => List(t)
+ }
+ def refinedToDecls(t: Type): List[Scope] = t match {
+ case RefinedType(ps, decls) =>
+ val dss = ps flatMap refinedToDecls
+ if (decls.isEmpty) dss else decls :: dss
+ case _ => List()
+ }
+ val ts1 = ts flatMap refinedToParents
+ val glbBase = intersectionType(ts1, glbOwner)
+ val glbType =
+ if (phase.erasedTypes || depth == 0) glbBase
+ else {
+ val glbRefined = refinedType(ts1, glbOwner)
+ val glbThisType = glbRefined.typeSymbol.thisType
+ def glbsym(proto: Symbol): Symbol = {
+ val prototp = glbThisType.memberInfo(proto)
+ val syms = for (t <- ts;
+ alt <- (t.nonPrivateMember(proto.name).alternatives);
+ if glbThisType.memberInfo(alt) matches prototp
+ ) yield alt
+ val symtypes = syms map glbThisType.memberInfo
+ assert(!symtypes.isEmpty)
+ proto.cloneSymbol(glbRefined.typeSymbol).setInfoOwnerAdjusted(
+ if (proto.isTerm) glb(symtypes, decr(depth))
+ else {
+ def isTypeBound(tp: Type) = tp match {
+ case TypeBounds(_, _) => true
+ case _ => false
+ }
+ def glbBounds(bnds: List[Type]): TypeBounds = {
+ val lo = lub(bnds map (_.bounds.lo), decr(depth))
+ val hi = glb(bnds map (_.bounds.hi), decr(depth))
+ if (lo <:< hi) TypeBounds(lo, hi)
+ else throw GlbFailure
+ }
+ val symbounds = symtypes filter isTypeBound
+ var result: Type =
+ if (symbounds.isEmpty)
+ TypeBounds.empty
+ else glbBounds(symbounds)
+ for (t <- symtypes if !isTypeBound(t))
+ if (result.bounds containsType t) result = t
+ else throw GlbFailure
+ result
+ })
+ }
+ if (globalGlbDepth < globalGlbLimit)
+ try {
+ globalGlbDepth += 1
+ val dss = ts flatMap refinedToDecls
+ for (ds <- dss; sym <- ds.iterator)
+ if (globalGlbDepth < globalGlbLimit && !(glbThisType specializes sym))
+ try {
+ addMember(glbThisType, glbRefined, glbsym(sym))
+ } catch {
+ case ex: NoCommonType =>
+ }
+ } finally {
+ globalGlbDepth -= 1
+ }
+ if (glbRefined.decls.isEmpty) glbBase else glbRefined
+ }
+ existentialAbstraction(tparams, glbType)
+ } catch {
+ case GlbFailure =>
+ if (ts forall (t => NullClass.tpe <:< t)) NullClass.tpe
+ else NothingClass.tpe
+ }
+ }
+ // if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG
+
+ val res = glb0(ts)
+
+ // if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
+
+ if (ts exists (_.isNotNull)) res.notNull else res
+ }
+
+ /** A list of the typevars in a type. */
+ def typeVarsInType(tp: Type): List[TypeVar] = {
+ var tvs: List[TypeVar] = Nil
+ tp foreach {
+ case t: TypeVar => tvs ::= t
+ case _ =>
+ }
+ tvs.reverse
+ }
+ /** Make each type var in this type use its original type for comparisons instead
+ * of collecting constraints.
+ */
+ def suspendTypeVarsInType(tp: Type): List[TypeVar] = {
+ val tvs = typeVarsInType(tp)
+ // !!! Is it somehow guaranteed that this will not break under nesting?
+ // In general one has to save and restore the contents of the field...
+ tvs foreach (_.suspended = true)
+ tvs
+ }
+
+ /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list
+ * of types `tps`. All types in `tps` are typerefs or singletypes
+ * with the same symbol.
+ * Return `Some(x)` if the computation succeeds with result `x`.
+ * Return `None` if the computation fails.
+ */
+ def mergePrefixAndArgs(tps: List[Type], variance: Int, depth: Int): Option[Type] = tps match {
+ case List(tp) =>
+ Some(tp)
+ case TypeRef(_, sym, _) :: rest =>
+ val pres = tps map (_.prefix) // prefix normalizes automatically
+ val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth)
+ val argss = tps map (_.normalize.typeArgs) // symbol equality (of the tp in tps) was checked using typeSymbol, which normalizes, so should normalize before retrieving arguments
+ val capturedParams = new ListBuffer[Symbol]
+ try {
+ if (sym == ArrayClass && phase.erasedTypes) {
+ // special treatment for lubs of array types after erasure:
+ // if argss contain one value type and some other type, the lub is Object
+ // if argss contain several reference types, the lub is an array over lub of argtypes
+ if (argss exists (_.isEmpty)) {
+ None // something is wrong: an array without a type arg.
+ } else {
+ val args = argss map (_.head)
+ if (args.tail forall (_ =:= args.head)) Some(typeRef(pre, sym, List(args.head)))
+ else if (args exists (arg => isPrimitiveValueClass(arg.typeSymbol))) Some(ObjectClass.tpe)
+ else Some(typeRef(pre, sym, List(lub(args))))
+ }
+ }
+ else transposeSafe(argss) match {
+ case None =>
+ // transpose freaked out because of irregular argss
+ // catching just in case (shouldn't happen, but also doesn't cost us)
+ // [JZ] It happens: see SI-5683.
+ debuglog("transposed irregular matrix!?" +(tps, argss))
+ None
+ case Some(argsst) =>
+ val args = map2(sym.typeParams, argsst) { (tparam, as) =>
+ if (depth == 0) {
+ if (tparam.variance == variance) {
+ // Take the intersection of the upper bounds of the type parameters
+ // rather than falling all the way back to "Any", otherwise we end up not
+ // conforming to bounds.
+ val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass)
+ if (bounds0.isEmpty) AnyClass.tpe
+ else intersectionType(bounds0 map (b => b.asSeenFrom(tps.head, sym)))
+ }
+ else if (tparam.variance == -variance) NothingClass.tpe
+ else NoType
+ }
+ else {
+ if (tparam.variance == variance) lub(as, decr(depth))
+ else if (tparam.variance == -variance) glb(as, decr(depth))
+ else {
+ val l = lub(as, decr(depth))
+ val g = glb(as, decr(depth))
+ if (l <:< g) l
+ else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we
+ // just err on the conservative side, i.e. with a bound that is too high.
+ // if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251
+
+ val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
+ capturedParams += qvar
+ qvar.tpe
+ }
+ }
+ }
+ }
+ if (args contains NoType) None
+ else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)))
+ }
+ } catch {
+ case ex: MalformedType => None
+ }
+ case SingleType(_, sym) :: rest =>
+ val pres = tps map (_.prefix)
+ val pre = if (variance == 1) lub(pres, depth) else glb(pres, depth)
+ try {
+ Some(singleType(pre, sym))
+ } catch {
+ case ex: MalformedType => None
+ }
+ case ExistentialType(tparams, quantified) :: rest =>
+ mergePrefixAndArgs(quantified :: rest, variance, depth) map (existentialAbstraction(tparams, _))
+ case _ =>
+ assert(false, tps); None
+ }
+
+ /** Make symbol `sym` a member of scope `tp.decls`
+ * where `thistp` is the narrowed owner type of the scope.
+ */
+ def addMember(thistp: Type, tp: Type, sym: Symbol) {
+ assert(sym != NoSymbol)
+ // debuglog("add member " + sym+":"+sym.info+" to "+thistp) //DEBUG
+ if (!(thistp specializes sym)) {
+ if (sym.isTerm)
+ for (alt <- tp.nonPrivateDecl(sym.name).alternatives)
+ if (specializesSym(thistp, sym, thistp, alt))
+ tp.decls unlink alt;
+ tp.decls enter sym
+ }
+ }
+
+ /** All types in list must be polytypes with type parameter lists of
+ * same length as tparams.
+ * Returns list of list of bounds infos, where corresponding type
+ * parameters are renamed to tparams.
+ */
+ private def matchingBounds(tps: List[Type], tparams: List[Symbol]): List[List[Type]] = {
+ def getBounds(tp: Type): List[Type] = tp match {
+ case PolyType(tparams1, _) if sameLength(tparams1, tparams) =>
+ tparams1 map (tparam => tparam.info.substSym(tparams1, tparams))
+ case tp =>
+ if (tp ne tp.normalize) getBounds(tp.normalize)
+ else throw new NoCommonType(tps)
+ }
+ tps map getBounds
+ }
+
+ /** All types in list must be polytypes with type parameter lists of
+ * same length as tparams.
+ * Returns list of instance types, where corresponding type
+ * parameters are renamed to tparams.
+ */
+ private def matchingInstTypes(tps: List[Type], tparams: List[Symbol]): List[Type] = {
+ def transformResultType(tp: Type): Type = tp match {
+ case PolyType(tparams1, restpe) if sameLength(tparams1, tparams) =>
+ restpe.substSym(tparams1, tparams)
+ case tp =>
+ if (tp ne tp.normalize) transformResultType(tp.normalize)
+ else throw new NoCommonType(tps)
+ }
+ tps map transformResultType
+ }
+
+ /** All types in list must be method types with equal parameter types.
+ * Returns list of their result types.
+ */
+ private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] =
+ tps map {
+ case MethodType(params1, res) if (isSameTypes(params1 map (_.tpe), pts)) =>
+ res
+ case NullaryMethodType(res) if pts isEmpty =>
+ res
+ case _ =>
+ throw new NoCommonType(tps)
+ }
+
+// Errors and Diagnostics -----------------------------------------------------
+
+ /** A throwable signalling a type error */
+ class TypeError(var pos: Position, val msg: String) extends Throwable(msg) {
+ def this(msg: String) = this(NoPosition, msg)
+ }
+
+ // TODO: RecoverableCyclicReference should be separated from TypeError,
+ // but that would be a big change. Left for further refactoring.
+ /** An exception for cyclic references from which we can recover */
+ case class RecoverableCyclicReference(sym: Symbol)
+ extends TypeError("illegal cyclic reference involving " + sym) {
+ if (settings.debug.value) printStackTrace()
+ }
+
+ class NoCommonType(tps: List[Type]) extends Throwable(
+ "lub/glb of incompatible types: " + tps.mkString("", " and ", "")) with ControlThrowable
+
+ /** A throwable signalling a malformed type */
+ class MalformedType(msg: String) extends TypeError(msg) {
+ def this(pre: Type, tp: String) = this("malformed type: " + pre + "#" + tp)
+ }
+
+ /** The current indentation string for traces */
+ private var indent: String = ""
+
+ /** 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 = {
+ Console.println(indent + tp1 + " " + op + " " + arg2 + "?" /* + "("+tp1.getClass+","+arg2.getClass+")"*/)
+ indent = indent + " "
+ val result = p(tp1, arg2)
+ indent = indent stripSuffix " "
+ Console.println(indent + result)
+ result
+ }
+
+ /** If option `explaintypes` is set, print a subtype trace for `found <:< required`. */
+ def explainTypes(found: Type, required: Type) {
+ if (settings.explaintypes.value) withTypesExplained(found <:< required)
+ }
+
+ /** If option `explaintypes` is set, print a subtype trace for `op(found, required)`. */
+ def explainTypes(op: (Type, Type) => Any, found: Type, required: Type) {
+ if (settings.explaintypes.value) withTypesExplained(op(found, required))
+ }
+
+ /** Execute `op` while printing a trace of the operations on types executed. */
+ def withTypesExplained[A](op: => A): A = {
+ val s = explainSwitch
+ try { explainSwitch = true; op } finally { explainSwitch = s }
+ }
+
+ def isUnboundedGeneric(tp: Type) = tp match {
+ case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefClass.tpe)
+ case _ => false
+ }
+ def isBoundedGeneric(tp: Type) = tp match {
+ case TypeRef(_, sym, _) if sym.isAbstractType => (tp <:< AnyRefClass.tpe)
+ case TypeRef(_, sym, _) => !isPrimitiveValueClass(sym)
+ case _ => false
+ }
+ // Add serializable to a list of parents, unless one of them already is
+ def addSerializable(ps: Type*): List[Type] = (
+ if (ps exists (_ <:< SerializableClass.tpe)) ps.toList
+ else (ps :+ SerializableClass.tpe).toList
+ )
+
+ def objToAny(tp: Type): Type =
+ if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe
+ else tp
+
+ val shorthands = Set(
+ "scala.collection.immutable.List",
+ "scala.collection.immutable.Nil",
+ "scala.collection.Seq",
+ "scala.collection.Traversable",
+ "scala.collection.Iterable",
+ "scala.collection.mutable.StringBuilder",
+ "scala.collection.IndexedSeq",
+ "scala.collection.Iterator")
+
+
+ /** The maximum number of recursions allowed in toString
+ */
+ final val maxTostringRecursions = 50
+
+ private var tostringRecursions = 0
+
+ protected def typeToString(tpe: Type): String =
+ if (tostringRecursions >= maxTostringRecursions)
+ "..."
+ else
+ try {
+ tostringRecursions += 1
+ tpe.safeToString
+ } finally {
+ tostringRecursions -= 1
+ }
+
+ implicit val AnnotatedTypeTag = ClassTag[AnnotatedType](classOf[AnnotatedType])
+ implicit val BoundedWildcardTypeTag = ClassTag[BoundedWildcardType](classOf[BoundedWildcardType])
+ implicit val ClassInfoTypeTag = ClassTag[ClassInfoType](classOf[ClassInfoType])
+ implicit val CompoundTypeTag = ClassTag[CompoundType](classOf[CompoundType])
+ implicit val ConstantTypeTag = ClassTag[ConstantType](classOf[ConstantType])
+ implicit val ExistentialTypeTag = ClassTag[ExistentialType](classOf[ExistentialType])
+ implicit val MethodTypeTag = ClassTag[MethodType](classOf[MethodType])
+ implicit val NullaryMethodTypeTag = ClassTag[NullaryMethodType](classOf[NullaryMethodType])
+ implicit val PolyTypeTag = ClassTag[PolyType](classOf[PolyType])
+ implicit val RefinedTypeTag = ClassTag[RefinedType](classOf[RefinedType])
+ implicit val SingletonTypeTag = ClassTag[SingletonType](classOf[SingletonType])
+ implicit val SingleTypeTag = ClassTag[SingleType](classOf[SingleType])
+ implicit val SuperTypeTag = ClassTag[SuperType](classOf[SuperType])
+ implicit val ThisTypeTag = ClassTag[ThisType](classOf[ThisType])
+ implicit val TypeBoundsTag = ClassTag[TypeBounds](classOf[TypeBounds])
+ implicit val TypeRefTag = ClassTag[TypeRef](classOf[TypeRef])
+ implicit val TypeTagg = ClassTag[Type](classOf[Type])
+}
diff --git a/src/reflect/scala/reflect/internal/package.scala b/src/reflect/scala/reflect/internal/package.scala
new file mode 100644
index 0000000000..99b837152d
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/package.scala
@@ -0,0 +1,6 @@
+package scala.reflect
+
+package object internal {
+
+ type MirrorOf[U <: base.Universe with Singleton] = base.MirrorOf[U]
+}
diff --git a/src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala b/src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala
new file mode 100644
index 0000000000..4670bd4eef
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/pickling/ByteCodecs.scala
@@ -0,0 +1,221 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+package scala.reflect.internal.pickling
+
+object ByteCodecs {
+
+ def avoidZero(src: Array[Byte]): Array[Byte] = {
+ var i = 0
+ val srclen = src.length
+ var count = 0
+ while (i < srclen) {
+ if (src(i) == 0x7f) count += 1
+ i += 1
+ }
+ val dst = new Array[Byte](srclen + count)
+ i = 0
+ var j = 0
+ while (i < srclen) {
+ val in = src(i)
+ if (in == 0x7f) {
+ dst(j) = (0xc0).toByte
+ dst(j + 1) = (0x80).toByte
+ j += 2
+ } else {
+ dst(j) = (in + 1).toByte
+ j += 1
+ }
+ i += 1
+ }
+ dst
+ }
+
+ def regenerateZero(src: Array[Byte]): Int = {
+ var i = 0
+ val srclen = src.length
+ var j = 0
+ while (i < srclen) {
+ val in: Int = src(i) & 0xff
+ if (in == 0xc0 && (src(i + 1) & 0xff) == 0x80) {
+ src(j) = 0x7f
+ i += 2
+ } else if (in == 0) {
+ src(j) = 0x7f
+ i += 1
+ } else {
+ src(j) = (in - 1).toByte
+ i += 1
+ }
+ j += 1
+ }
+ j
+ }
+
+ def encode8to7(src: Array[Byte]): Array[Byte] = {
+ val srclen = src.length
+ val dstlen = (srclen * 8 + 6) / 7
+ val dst = new Array[Byte](dstlen)
+ var i = 0
+ var j = 0
+ while (i + 6 < srclen) {
+ var in: Int = src(i) & 0xff
+ dst(j) = (in & 0x7f).toByte
+ var out: Int = in >>> 7
+ in = src(i + 1) & 0xff
+ dst(j + 1) = (out | (in << 1) & 0x7f).toByte
+ out = in >>> 6
+ in = src(i + 2) & 0xff
+ dst(j + 2) = (out | (in << 2) & 0x7f).toByte
+ out = in >>> 5
+ in = src(i + 3) & 0xff
+ dst(j + 3) = (out | (in << 3) & 0x7f).toByte
+ out = in >>> 4
+ in = src(i + 4) & 0xff
+ dst(j + 4) = (out | (in << 4) & 0x7f).toByte
+ out = in >>> 3
+ in = src(i + 5) & 0xff
+ dst(j + 5) = (out | (in << 5) & 0x7f).toByte
+ out = in >>> 2
+ in = src(i + 6) & 0xff
+ dst(j + 6) = (out | (in << 6) & 0x7f).toByte
+ out = in >>> 1
+ dst(j + 7) = out.toByte
+ i += 7
+ j += 8
+ }
+ if (i < srclen) {
+ var in: Int = src(i) & 0xff
+ dst(j) = (in & 0x7f).toByte; j += 1
+ var out: Int = in >>> 7
+ if (i + 1 < srclen) {
+ in = src(i + 1) & 0xff
+ dst(j) = (out | (in << 1) & 0x7f).toByte; j += 1
+ out = in >>> 6
+ if (i + 2 < srclen) {
+ in = src(i + 2) & 0xff
+ dst(j) = (out | (in << 2) & 0x7f).toByte; j += 1
+ out = in >>> 5
+ if (i + 3 < srclen) {
+ in = src(i + 3) & 0xff
+ dst(j) = (out | (in << 3) & 0x7f).toByte; j += 1
+ out = in >>> 4
+ if (i + 4 < srclen) {
+ in = src(i + 4) & 0xff
+ dst(j) = (out | (in << 4) & 0x7f).toByte; j += 1
+ out = in >>> 3
+ if (i + 5 < srclen) {
+ in = src(i + 5) & 0xff
+ dst(j) = (out | (in << 5) & 0x7f).toByte; j += 1
+ out = in >>> 2
+ }
+ }
+ }
+ }
+ }
+ if (j < dstlen) dst(j) = out.toByte
+ }
+ dst
+ }
+
+ def decode7to8(src: Array[Byte], srclen: Int): Int = {
+ var i = 0
+ var j = 0
+ val dstlen = (srclen * 7 + 7) / 8
+ while (i + 7 < srclen) {
+ var out: Int = src(i)
+ var in: Byte = src(i + 1)
+ src(j) = (out | (in & 0x01) << 7).toByte
+ out = in >>> 1
+ in = src(i + 2)
+ src(j + 1) = (out | (in & 0x03) << 6).toByte
+ out = in >>> 2
+ in = src(i + 3)
+ src(j + 2) = (out | (in & 0x07) << 5).toByte
+ out = in >>> 3
+ in = src(i + 4)
+ src(j + 3) = (out | (in & 0x0f) << 4).toByte
+ out = in >>> 4
+ in = src(i + 5)
+ src(j + 4) = (out | (in & 0x1f) << 3).toByte
+ out = in >>> 5
+ in = src(i + 6)
+ src(j + 5) = (out | (in & 0x3f) << 2).toByte
+ out = in >>> 6
+ in = src(i + 7)
+ src(j + 6) = (out | in << 1).toByte
+ i += 8
+ j += 7
+ }
+ if (i < srclen) {
+ var out: Int = src(i)
+ if (i + 1 < srclen) {
+ var in: Byte = src(i + 1)
+ src(j) = (out | (in & 0x01) << 7).toByte; j += 1
+ out = in >>> 1
+ if (i + 2 < srclen) {
+ in = src(i + 2)
+ src(j) = (out | (in & 0x03) << 6).toByte; j += 1
+ out = in >>> 2
+ if (i + 3 < srclen) {
+ in = src(i + 3)
+ src(j) = (out | (in & 0x07) << 5).toByte; j += 1
+ out = in >>> 3
+ if (i + 4 < srclen) {
+ in = src(i + 4)
+ src(j) = (out | (in & 0x0f) << 4).toByte; j += 1
+ out = in >>> 4
+ if (i + 5 < srclen) {
+ in = src(i + 5)
+ src(j) = (out | (in & 0x1f) << 3).toByte; j += 1
+ out = in >>> 5
+ if (i + 6 < srclen) {
+ in = src(i + 6)
+ src(j) = (out | (in & 0x3f) << 2).toByte; j += 1
+ out = in >>> 6
+ }
+ }
+ }
+ }
+ }
+ }
+ if (j < dstlen) src(j) = out.toByte
+ }
+ dstlen
+ }
+
+ def encode(xs: Array[Byte]): Array[Byte] = avoidZero(encode8to7(xs))
+
+ /**
+ * Destructively decodes array xs and returns the length of the decoded array.
+ *
+ * Sometimes returns (length+1) of the decoded array. Example:
+ *
+ * scala> val enc = reflect.generic.ByteCodecs.encode(Array(1,2,3))
+ * enc: Array[Byte] = Array(2, 5, 13, 1)
+ *
+ * scala> reflect.generic.ByteCodecs.decode(enc)
+ * res43: Int = 4
+ *
+ * scala> enc
+ * res44: Array[Byte] = Array(1, 2, 3, 0)
+ *
+ * However, this does not always happen.
+ */
+ def decode(xs: Array[Byte]): Int = {
+ val len = regenerateZero(xs)
+ decode7to8(xs, len)
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala b/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala
new file mode 100644
index 0000000000..7f0895ce64
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/pickling/PickleBuffer.scala
@@ -0,0 +1,188 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+package pickling
+
+/** Variable length byte arrays, with methods for basic pickling and unpickling.
+ *
+ * @param data The initial buffer
+ * @param from The first index where defined data are found
+ * @param to The first index where new data can be written
+ */
+class PickleBuffer(data: Array[Byte], from: Int, to: Int) {
+
+ var bytes = data
+ var readIndex = from
+ var writeIndex = to
+
+ /** Double bytes array */
+ private def dble() {
+ val bytes1 = new Array[Byte](bytes.length * 2)
+ Array.copy(bytes, 0, bytes1, 0, writeIndex)
+ bytes = bytes1
+ }
+
+ def ensureCapacity(capacity: Int) =
+ while (bytes.length < writeIndex + capacity) dble()
+
+ // -- Basic output routines --------------------------------------------
+
+ /** Write a byte of data */
+ def writeByte(b: Int) {
+ if (writeIndex == bytes.length) dble()
+ bytes(writeIndex) = b.toByte
+ writeIndex += 1
+ }
+
+ /** Write a natural number in big endian format, base 128.
+ * All but the last digits have bit 0x80 set.
+ */
+ def writeNat(x: Int) =
+ writeLongNat(x.toLong & 0x00000000FFFFFFFFL)
+
+ /**
+ * Like writeNat, but for longs. This is not the same as
+ * writeLong, which writes in base 256. Note that the
+ * binary representation of LongNat is identical to Nat
+ * if the long value is in the range Int.MIN_VALUE to
+ * Int.MAX_VALUE.
+ */
+ def writeLongNat(x: Long) {
+ def writeNatPrefix(x: Long) {
+ val y = x >>> 7
+ if (y != 0L) writeNatPrefix(y)
+ writeByte(((x & 0x7f) | 0x80).toInt)
+ }
+ val y = x >>> 7
+ if (y != 0L) writeNatPrefix(y)
+ writeByte((x & 0x7f).toInt)
+ }
+
+ /** Write a natural number <code>x</code> at position <code>pos</code>.
+ * If number is more than one byte, shift rest of array to make space.
+ *
+ * @param pos ...
+ * @param x ...
+ */
+ def patchNat(pos: Int, x: Int) {
+ def patchNatPrefix(x: Int) {
+ writeByte(0)
+ Array.copy(bytes, pos, bytes, pos+1, writeIndex - (pos+1))
+ bytes(pos) = ((x & 0x7f) | 0x80).toByte
+ val y = x >>> 7
+ if (y != 0) patchNatPrefix(y)
+ }
+ bytes(pos) = (x & 0x7f).toByte
+ val y = x >>> 7
+ if (y != 0) patchNatPrefix(y)
+ }
+
+ /** Write a long number <code>x</code> in signed big endian format, base 256.
+ *
+ * @param x The long number to be written.
+ */
+ def writeLong(x: Long) {
+ val y = x >> 8
+ val z = x & 0xff
+ if (-y != (z >> 7)) writeLong(y)
+ writeByte(z.toInt)
+ }
+
+ // -- Basic input routines --------------------------------------------
+
+ /** Peek at the current byte without moving the read index */
+ def peekByte(): Int = bytes(readIndex)
+
+ /** Read a byte */
+ def readByte(): Int = {
+ val x = bytes(readIndex); readIndex += 1; x
+ }
+
+ /** Read a natural number in big endian format, base 128.
+ * All but the last digits have bit 0x80 set.*/
+ def readNat(): Int = readLongNat().toInt
+
+ def readLongNat(): Long = {
+ var b = 0L
+ var x = 0L
+ do {
+ b = readByte()
+ x = (x << 7) + (b & 0x7f)
+ } while ((b & 0x80) != 0L);
+ x
+ }
+
+ /** Read a long number in signed big endian format, base 256. */
+ def readLong(len: Int): Long = {
+ var x = 0L
+ var i = 0
+ while (i < len) {
+ x = (x << 8) + (readByte() & 0xff)
+ i += 1
+ }
+ val leading = 64 - (len << 3)
+ x << leading >> leading
+ }
+
+ /** Returns the buffer as a sequence of (Int, Array[Byte]) representing
+ * (tag, data) of the individual entries. Saves and restores buffer state.
+ */
+
+ def toIndexedSeq: IndexedSeq[(Int, Array[Byte])] = {
+ val saved = readIndex
+ readIndex = 0
+ readNat() ; readNat() // discarding version
+ val result = new Array[(Int, Array[Byte])](readNat())
+
+ result.indices foreach { index =>
+ val tag = readNat()
+ val len = readNat()
+ val bytes = data.slice(readIndex, len + readIndex)
+ readIndex += len
+
+ result(index) = tag -> bytes
+ }
+
+ readIndex = saved
+ result.toIndexedSeq
+ }
+
+ /** Perform operation <code>op</code> until the condition
+ * <code>readIndex == end</code> is satisfied.
+ * Concatenate results into a list.
+ *
+ * @param end ...
+ * @param op ...
+ * @return ...
+ */
+ def until[T](end: Int, op: () => T): List[T] =
+ if (readIndex == end) List() else op() :: until(end, op);
+
+ /** Perform operation <code>op</code> the number of
+ * times specified. Concatenate the results into a list.
+ */
+ def times[T](n: Int, op: ()=>T): List[T] =
+ if (n == 0) List() else op() :: times(n-1, op)
+
+ /** Pickle = majorVersion_Nat minorVersion_Nat nbEntries_Nat {Entry}
+ * Entry = type_Nat length_Nat [actual entries]
+ *
+ * Assumes that the ..Version_Nat are already consumed.
+ *
+ * @return an array mapping entry numbers to locations in
+ * the byte array where the entries start.
+ */
+ def createIndex: Array[Int] = {
+ val index = new Array[Int](readNat()) // nbEntries_Nat
+ for (i <- 0 until index.length) {
+ index(i) = readIndex
+ readByte() // skip type_Nat
+ readIndex = readNat() + readIndex // read length_Nat, jump to next entry
+ }
+ index
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala b/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala
new file mode 100644
index 0000000000..16747af08a
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/pickling/PickleFormat.scala
@@ -0,0 +1,225 @@
+package scala.reflect
+package internal
+package pickling
+
+/** This object provides constants for pickling attributes.
+ *
+ * If you extend the format, be sure to increase the
+ * version minor number.
+ *
+ * @author Martin Odersky
+ * @version 1.0
+ */
+object PickleFormat {
+
+/***************************************************
+ * Symbol table attribute format:
+ * Symtab = nentries_Nat {Entry}
+ * Entry = 1 TERMNAME len_Nat NameInfo
+ * | 2 TYPENAME len_Nat NameInfo
+ * | 3 NONEsym len_Nat
+ * | 4 TYPEsym len_Nat SymbolInfo
+ * | 5 ALIASsym len_Nat SymbolInfo
+ * | 6 CLASSsym len_Nat SymbolInfo [thistype_Ref]
+ * | 7 MODULEsym len_Nat SymbolInfo
+ * | 8 VALsym len_Nat [defaultGetter_Ref /* no longer needed*/] SymbolInfo [alias_Ref]
+ * | 9 EXTref len_Nat name_Ref [owner_Ref]
+ * | 10 EXTMODCLASSref len_Nat name_Ref [owner_Ref]
+ * | 11 NOtpe len_Nat
+ * | 12 NOPREFIXtpe len_Nat
+ * | 13 THIStpe len_Nat sym_Ref
+ * | 14 SINGLEtpe len_Nat type_Ref sym_Ref
+ * | 15 CONSTANTtpe len_Nat constant_Ref
+ * | 16 TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref}
+ * | 17 TYPEBOUNDStpe len_Nat tpe_Ref tpe_Ref
+ * | 18 REFINEDtpe len_Nat classsym_Ref {tpe_Ref}
+ * | 19 CLASSINFOtpe len_Nat classsym_Ref {tpe_Ref}
+ * | 20 METHODtpe len_Nat tpe_Ref {sym_Ref}
+ * | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref}
+ * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {sym_Ref} /* no longer needed */
+ * | 52 SUPERtpe len_Nat tpe_Ref tpe_Ref
+ * | 24 LITERALunit len_Nat
+ * | 25 LITERALboolean len_Nat value_Long
+ * | 26 LITERALbyte len_Nat value_Long
+ * | 27 LITERALshort len_Nat value_Long
+ * | 28 LITERALchar len_Nat value_Long
+ * | 29 LITERALint len_Nat value_Long
+ * | 30 LITERALlong len_Nat value_Long
+ * | 31 LITERALfloat len_Nat value_Long
+ * | 32 LITERALdouble len_Nat value_Long
+ * | 33 LITERALstring len_Nat name_Ref
+ * | 34 LITERALnull len_Nat
+ * | 35 LITERALclass len_Nat tpe_Ref
+ * | 36 LITERALenum len_Nat sym_Ref
+ * | 40 SYMANNOT len_Nat sym_Ref AnnotInfoBody
+ * | 41 CHILDREN len_Nat sym_Ref {sym_Ref}
+ * | 42 ANNOTATEDtpe len_Nat [sym_Ref /* no longer needed */] tpe_Ref {annotinfo_Ref}
+ * | 43 ANNOTINFO len_Nat AnnotInfoBody
+ * | 44 ANNOTARGARRAY len_Nat {constAnnotArg_Ref}
+ * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat
+ * | 48 EXISTENTIALtpe len_Nat type_Ref {symbol_Ref}
+ * | 49 TREE len_Nat 1 EMPTYtree
+ * | 49 TREE len_Nat 2 PACKAGEtree type_Ref sym_Ref mods_Ref name_Ref {tree_Ref}
+ * | 49 TREE len_Nat 3 CLASStree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 4 MODULEtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref
+ * | 49 TREE len_Nat 5 VALDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 6 DEFDEFtree type_Ref sym_Ref mods_Ref name_Ref numtparams_Nat {tree_Ref} numparamss_Nat {numparams_Nat {tree_Ref}} tree_Ref tree_Ref
+ * | 49 TREE len_Nat 7 TYPEDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 8 LABELtree type_Ref sym_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 9 IMPORTtree type_Ref sym_Ref tree_Ref {name_Ref name_Ref}
+ * | 49 TREE len_Nat 11 DOCDEFtree type_Ref sym_Ref string_Ref tree_Ref
+ * | 49 TREE len_Nat 12 TEMPLATEtree type_Ref sym_Ref numparents_Nat {tree_Ref} tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 13 BLOCKtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 14 CASEtree type_Ref tree_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 15 SEQUENCEtree type_Ref {tree_Ref}
+ * | 49 TREE len_Nat 16 ALTERNATIVEtree type_Ref {tree_Ref}
+ * | 49 TREE len_Nat 17 STARtree type_Ref {tree_Ref}
+ * | 49 TREE len_Nat 18 BINDtree type_Ref sym_Ref name_Ref tree_Ref
+ * | 49 TREE len_Nat 19 UNAPPLYtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 20 ARRAYVALUEtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 21 FUNCTIONtree type_Ref sym_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 22 ASSIGNtree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 23 IFtree type_Ref tree_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 24 MATCHtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 25 RETURNtree type_Ref sym_Ref tree_Ref
+ * | 49 TREE len_Nat 26 TREtree type_Ref tree_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 27 THROWtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 28 NEWtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 29 TYPEDtree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 30 TYPEAPPLYtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 31 APPLYtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 32 APPLYDYNAMICtree type_Ref sym_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 33 SUPERtree type_Ref sym_Ref tree_Ref name_Ref
+ * | 49 TREE len_Nat 34 THIStree type_Ref sym_Ref name_Ref
+ * | 49 TREE len_Nat 35 SELECTtree type_Ref sym_Ref tree_Ref name_Ref
+ * | 49 TREE len_Nat 36 IDENTtree type_Ref sym_Ref name_Ref
+ * | 49 TREE len_Nat 37 LITERALtree type_Ref constant_Ref
+ * | 49 TREE len_Nat 38 TYPEtree type_Ref
+ * | 49 TREE len_Nat 39 ANNOTATEDtree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 40 SINGLETONTYPEtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 41 SELECTFROMTYPEtree type_Ref tree_Ref name_Ref
+ * | 49 TREE len_Nat 42 COMPOUNDTYPEtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 43 APPLIEDTYPEtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 44 TYPEBOUNDStree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 45 EXISTENTIALTYPEtree type_Ref tree_Ref {tree_Ref}
+ * | 50 MODIFIERS len_Nat flags_Long privateWithin_Ref
+ * SymbolInfo = name_Ref owner_Ref flags_LongNat [privateWithin_Ref] info_Ref
+ * NameInfo = <character sequence of length len_Nat in Utf8 format>
+ * NumInfo = <len_Nat-byte signed number in big endian format>
+ * Ref = Nat
+ * AnnotInfoBody = info_Ref {annotArg_Ref} {name_Ref constAnnotArg_Ref}
+ * AnnotArg = Tree | Constant
+ * ConstAnnotArg = Constant | AnnotInfo | AnnotArgArray
+ *
+ * len is remaining length after `len`.
+ */
+ val MajorVersion = 5
+ val MinorVersion = 0
+ def VersionString = "V" + MajorVersion + "." + MinorVersion
+
+ final val TERMname = 1
+ final val TYPEname = 2
+ final val NONEsym = 3
+ final val TYPEsym = 4
+ final val ALIASsym = 5
+ final val CLASSsym = 6
+ final val MODULEsym = 7
+ final val VALsym = 8
+ final val EXTref = 9
+ final val EXTMODCLASSref = 10
+ final val NOtpe = 11
+ final val NOPREFIXtpe = 12
+ final val THIStpe = 13
+ final val SINGLEtpe = 14
+ final val CONSTANTtpe = 15
+ final val TYPEREFtpe = 16
+ final val TYPEBOUNDStpe = 17
+ final val REFINEDtpe = 18
+ final val CLASSINFOtpe = 19
+ final val METHODtpe = 20
+ final val POLYtpe = 21
+ final val IMPLICITMETHODtpe = 22 // no longer generated
+
+ final val LITERAL = 23 // base line for literals
+ final val LITERALunit = 24
+ final val LITERALboolean = 25
+ final val LITERALbyte = 26
+ final val LITERALshort = 27
+ final val LITERALchar = 28
+ final val LITERALint = 29
+ final val LITERALlong = 30
+ final val LITERALfloat = 31
+ final val LITERALdouble = 32
+ final val LITERALstring = 33
+ final val LITERALnull = 34
+ final val LITERALclass = 35
+ final val LITERALenum = 36
+ final val SYMANNOT = 40
+ final val CHILDREN = 41
+ final val ANNOTATEDtpe = 42
+ final val ANNOTINFO = 43
+ final val ANNOTARGARRAY = 44
+
+ final val SUPERtpe = 46
+ final val DEBRUIJNINDEXtpe = 47
+ final val EXISTENTIALtpe = 48
+
+ final val TREE = 49 // prefix code that means a tree is coming
+ final val EMPTYtree = 1
+ final val PACKAGEtree = 2
+ final val CLASStree = 3
+ final val MODULEtree = 4
+ final val VALDEFtree = 5
+ final val DEFDEFtree = 6
+ final val TYPEDEFtree = 7
+ final val LABELtree = 8
+ final val IMPORTtree = 9
+ final val DOCDEFtree = 11
+ final val TEMPLATEtree = 12
+ final val BLOCKtree = 13
+ final val CASEtree = 14
+ // This node type has been removed.
+ // final val SEQUENCEtree = 15
+ final val ALTERNATIVEtree = 16
+ final val STARtree = 17
+ final val BINDtree = 18
+ final val UNAPPLYtree = 19
+ final val ARRAYVALUEtree = 20
+ final val FUNCTIONtree = 21
+ final val ASSIGNtree = 22
+ final val IFtree = 23
+ final val MATCHtree = 24
+ final val RETURNtree = 25
+ final val TREtree = 26
+ final val THROWtree = 27
+ final val NEWtree = 28
+ final val TYPEDtree = 29
+ final val TYPEAPPLYtree = 30
+ final val APPLYtree = 31
+ final val APPLYDYNAMICtree = 32
+ final val SUPERtree = 33
+ final val THIStree = 34
+ final val SELECTtree = 35
+ final val IDENTtree = 36
+ final val LITERALtree = 37
+ final val TYPEtree = 38
+ final val ANNOTATEDtree = 39
+ final val SINGLETONTYPEtree = 40
+ final val SELECTFROMTYPEtree = 41
+ final val COMPOUNDTYPEtree = 42
+ final val APPLIEDTYPEtree = 43
+ final val TYPEBOUNDStree = 44
+ final val EXISTENTIALTYPEtree = 45
+
+ final val MODIFIERS = 50
+
+ final val firstSymTag = NONEsym
+ final val lastSymTag = VALsym
+ final val lastExtSymTag = EXTMODCLASSref
+
+
+ //The following two are no longer accurate, because ANNOTATEDtpe,
+ //SUPERtpe, ... are not in the same range as the other types
+ //final val firstTypeTag = NOtpe
+ //final val lastTypeTag = POLYtpe
+}
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
new file mode 100644
index 0000000000..757163a074
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -0,0 +1,871 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect
+package internal
+package pickling
+
+import java.io.IOException
+import java.lang.Float.intBitsToFloat
+import java.lang.Double.longBitsToDouble
+
+import Flags._
+import PickleFormat._
+import scala.collection.{ mutable, immutable }
+import collection.mutable.ListBuffer
+import annotation.switch
+
+/** @author Martin Odersky
+ * @version 1.0
+ */
+abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
+ val global: SymbolTable
+ import global._
+
+ /** Unpickle symbol table information descending from a class and/or module root
+ * from an array of bytes.
+ * @param bytes bytearray from which we unpickle
+ * @param offset offset from which unpickling starts
+ * @param classroot the top-level class which is unpickled, or NoSymbol if inapplicable
+ * @param moduleroot the top-level module which is unpickled, or NoSymbol if inapplicable
+ * @param filename filename associated with bytearray, only used for error messages
+ */
+ def unpickle(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) {
+ try {
+ new Scan(bytes, offset, classRoot, moduleRoot, filename).run()
+ } catch {
+ case ex: IOException =>
+ throw ex
+ case ex: MissingRequirementError =>
+ throw ex
+ case ex: Throwable =>
+ /*if (settings.debug.value)*/ ex.printStackTrace()
+ throw new RuntimeException("error reading Scala signature of "+filename+": "+ex.getMessage())
+ }
+ }
+
+ class Scan(_bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) extends PickleBuffer(_bytes, offset, -1) {
+ //println("unpickle " + classRoot + " and " + moduleRoot)//debug
+
+ protected def debug = settings.debug.value
+
+ checkVersion()
+
+ private val loadingMirror = mirrorThatLoaded(classRoot)
+
+ /** A map from entry numbers to array offsets */
+ private val index = createIndex
+
+ /** A map from entry numbers to symbols, types, or annotations */
+ private val entries = new Array[AnyRef](index.length)
+
+ /** A map from symbols to their associated `decls` scopes */
+ private val symScopes = mutable.HashMap[Symbol, Scope]()
+
+ //println("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug
+
+ // 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
+ }
+ 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
+ }
+ }
+ i += 1
+ }
+ }
+
+ private def checkVersion() {
+ val major = readNat()
+ val minor = readNat()
+ if (major != MajorVersion || minor > MinorVersion)
+ throw new IOException("Scala signature " + classRoot.decodedName +
+ " has wrong version\n expected: " +
+ MajorVersion + "." + MinorVersion +
+ "\n found: " + major + "." + minor +
+ " in "+filename)
+ }
+
+ /** The `decls` scope associated with given symbol */
+ protected def symScope(sym: Symbol) = symScopes.getOrElseUpdate(sym, newScope)
+
+ /** Does entry represent an (internal) symbol */
+ protected def isSymbolEntry(i: Int): Boolean = {
+ val tag = bytes(index(i)).toInt
+ (firstSymTag <= tag && tag <= lastSymTag &&
+ (tag != CLASSsym || !isRefinementSymbolEntry(i)))
+ }
+
+ /** Does entry represent an (internal or external) symbol */
+ protected def isSymbolRef(i: Int): Boolean = {
+ val tag = bytes(index(i))
+ (firstSymTag <= tag && tag <= lastExtSymTag)
+ }
+
+ /** Does entry represent a name? */
+ protected def isNameEntry(i: Int): Boolean = {
+ val tag = bytes(index(i)).toInt
+ tag == TERMname || tag == TYPEname
+ }
+
+ /** Does entry represent a symbol annotation? */
+ protected def isSymbolAnnotationEntry(i: Int): Boolean = {
+ val tag = bytes(index(i)).toInt
+ tag == SYMANNOT
+ }
+
+ /** Does the entry represent children of a symbol? */
+ protected def isChildrenEntry(i: Int): Boolean = {
+ val tag = bytes(index(i)).toInt
+ tag == CHILDREN
+ }
+
+ /** Does entry represent a refinement symbol?
+ * pre: Entry is a class symbol
+ */
+ protected def isRefinementSymbolEntry(i: Int): Boolean = {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ val tag = readByte().toInt
+ assert(tag == CLASSsym)
+
+ readNat(); // read length
+ val result = readNameRef() == tpnme.REFINE_CLASS_NAME
+ readIndex = savedIndex
+ result
+ }
+
+ /** If entry at <code>i</code> is undefined, define it by performing
+ * operation <code>op</code> with <code>readIndex at start of i'th
+ * entry. Restore <code>readIndex</code> afterwards.
+ */
+ protected def at[T <: AnyRef](i: Int, op: () => T): T = {
+ var r = entries(i)
+ if (r eq null) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ r = op()
+ assert(entries(i) eq null, entries(i))
+ entries(i) = r
+ readIndex = savedIndex
+ }
+ r.asInstanceOf[T]
+ }
+
+ /** Read a name */
+ protected def readName(): Name = {
+ val tag = readByte()
+ val len = readNat()
+ tag match {
+ case TERMname => newTermName(bytes, readIndex, len)
+ case TYPEname => newTypeName(bytes, readIndex, len)
+ case _ => errorBadSignature("bad name tag: " + tag)
+ }
+ }
+ protected def readTermName(): TermName = readName().toTermName
+ protected def readTypeName(): TypeName = readName().toTypeName
+
+ /** Read a symbol */
+ protected def readSymbol(): Symbol = {
+ val tag = readByte()
+ val end = readNat() + readIndex
+ def atEnd = readIndex == end
+
+ def readExtSymbol(): Symbol = {
+ val name = readNameRef()
+ val owner = if (atEnd) loadingMirror.RootClass else readSymbolRef()
+
+ def adjust(sym: Symbol) = if (tag == EXTref) sym else sym.moduleClass
+
+ def fromName(name: Name) = name.toTermName match {
+ case nme.ROOT => loadingMirror.RootClass
+ case nme.ROOTPKG => loadingMirror.RootPackage
+ case _ => adjust(owner.info.decl(name))
+ }
+ def nestedObjectSymbol: Symbol = {
+ // If the owner is overloaded (i.e. a method), it's not possible to select the
+ // right member, so return NoSymbol. This can only happen when unpickling a tree.
+ // the "case Apply" in readTree() takes care of selecting the correct alternative
+ // after parsing the arguments.
+ if (owner.isOverloaded)
+ return NoSymbol
+
+ if (tag == EXTMODCLASSref) {
+ val moduleVar = owner.info.decl(nme.moduleVarName(name.toTermName))
+ if (moduleVar.isLazyAccessor)
+ return moduleVar.lazyAccessor.lazyAccessor
+ }
+ NoSymbol
+ }
+
+ // (1) Try name.
+ fromName(name) orElse {
+ // (2) Try with expanded name. Can happen if references to private
+ // symbols are read from outside: for instance when checking the children
+ // of a class. See #1722.
+ fromName(nme.expandedName(name.toTermName, owner)) orElse {
+ // (3) Try as a nested object symbol.
+ nestedObjectSymbol orElse {
+ // (4) Otherwise, fail.
+ //System.err.println("missing "+name+" in "+owner+"/"+owner.id+" "+owner.info.decls)
+ adjust(errorMissingRequirement(name, owner))
+ }
+ }
+ }
+ }
+
+ tag match {
+ case NONEsym => return NoSymbol
+ case EXTref | EXTMODCLASSref => return readExtSymbol()
+ case _ => ()
+ }
+
+ // symbols that were pickled with Pickler.writeSymInfo
+ val nameref = readNat()
+ 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
+ }
+
+ def isModuleFlag = (flags & MODULE) != 0L
+ def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner)
+ def isModuleRoot = (name == moduleRoot.name) && (owner == moduleRoot.owner)
+ def pflags = flags & PickledFlags
+
+ def finishSym(sym: Symbol): Symbol = {
+ sym.privateWithin = privateWithin
+ sym.info = (
+ if (atEnd) {
+ assert(!sym.isSuperAccessor, sym)
+ newLazyTypeRef(inforef)
+ }
+ else {
+ assert(sym.isSuperAccessor || sym.isParamAccessor, sym)
+ newLazyTypeRefAndAlias(inforef, readNat())
+ }
+ )
+ if (sym.owner.isClass && sym != classRoot && sym != moduleRoot &&
+ !sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter && !sym.isExistentiallyBound)
+ symScope(sym.owner) enter sym
+
+ sym
+ }
+
+ finishSym(tag match {
+ case TYPEsym | ALIASsym =>
+ owner.newNonClassSymbol(name.toTypeName, NoPosition, pflags)
+ case CLASSsym =>
+ val sym = (
+ if (isClassRoot) {
+ if (isModuleFlag) moduleRoot.moduleClass setFlag pflags
+ else classRoot setFlag pflags
+ }
+ else owner.newClassSymbol(name.toTypeName, NoPosition, pflags)
+ )
+ if (!atEnd)
+ sym.typeOfThis = newLazyTypeRef(readNat())
+
+ sym
+ case MODULEsym =>
+ val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... ()
+ if (isModuleRoot) moduleRoot setFlag pflags
+ else owner.newLinkedModule(clazz, pflags)
+ case VALsym =>
+ if (isModuleRoot) { assert(false); NoSymbol }
+ else owner.newTermSymbol(name.toTermName, NoPosition, pflags)
+
+ case _ =>
+ errorBadSignature("bad symbol tag: " + tag)
+ })
+ }
+
+ /** 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 = readNat() + readIndex
+ (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()
+ var 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()
+ // @PP: Where is the flag setting supposed to happen? I infer
+ // from the lack of flag setting in the rest of the unpickler
+ // that it isn't right here. See #4757 for the immediate
+ // motivation to fix it.
+ val tparams = until(end, readSymbolRef) map (_ setFlag EXISTENTIAL)
+ newExistentialType(tparams, 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)
+ }
+ }
+
+ def noSuchTypeTag(tag: Int, end: Int): Type =
+ errorBadSignature("bad type tag: " + tag)
+
+ /** Read a constant */
+ protected def readConstant(): Constant = {
+ val tag = readByte().toInt
+ val len = readNat()
+ (tag: @switch) match {
+ case LITERALunit => Constant(())
+ case LITERALboolean => Constant(readLong(len) != 0L)
+ case LITERALbyte => Constant(readLong(len).toByte)
+ case LITERALshort => Constant(readLong(len).toShort)
+ case LITERALchar => Constant(readLong(len).toChar)
+ case LITERALint => Constant(readLong(len).toInt)
+ case LITERALlong => Constant(readLong(len))
+ case LITERALfloat => Constant(intBitsToFloat(readLong(len).toInt))
+ case LITERALdouble => Constant(longBitsToDouble(readLong(len)))
+ case LITERALstring => Constant(readNameRef().toString)
+ case LITERALnull => Constant(null)
+ case LITERALclass => Constant(readTypeRef())
+ case LITERALenum => Constant(readSymbolRef())
+ case _ => noSuchConstantTag(tag, len)
+ }
+ }
+
+ def noSuchConstantTag(tag: Int, len: Int): Constant =
+ errorBadSignature("bad constant tag: " + tag)
+
+ /** Read children and store them into the corresponding symbol.
+ */
+ protected def readChildren() {
+ val tag = readByte()
+ assert(tag == CHILDREN)
+ val end = readNat() + readIndex
+ val target = readSymbolRef()
+ while (readIndex != end) target addChild readSymbolRef()
+ }
+
+ /** Read an annotation argument, which is pickled either
+ * as a Constant or a Tree.
+ */
+ protected def readAnnotArg(i: Int): Tree = bytes(index(i)) match {
+ case TREE => at(i, readTree)
+ case _ =>
+ val const = at(i, readConstant)
+ Literal(const) setType const.tpe
+ }
+
+ /** Read a ClassfileAnnotArg (argument to a classfile annotation)
+ */
+ private def readArrayAnnot() = {
+ readByte() // skip the `annotargarray` tag
+ val end = readNat() + readIndex
+ until(end, () => readClassfileAnnotArg(readNat())).toArray(ClassfileAnnotArgTag)
+ }
+ protected def readClassfileAnnotArg(i: Int): ClassfileAnnotArg = bytes(index(i)) match {
+ case ANNOTINFO => NestedAnnotArg(at(i, readAnnotation))
+ case ANNOTARGARRAY => at(i, () => ArrayAnnotArg(readArrayAnnot()))
+ case _ => LiteralAnnotArg(at(i, readConstant))
+ }
+
+ /** Read an AnnotationInfo. Not to be called directly, use
+ * readAnnotation or readSymbolAnnotation
+ */
+ protected def readAnnotationInfo(end: Int): AnnotationInfo = {
+ val atp = readTypeRef()
+ val args = new ListBuffer[Tree]
+ val assocs = new ListBuffer[(Name, ClassfileAnnotArg)]
+ while (readIndex != end) {
+ val argref = readNat()
+ if (isNameEntry(argref)) {
+ val name = at(argref, readName)
+ val arg = readClassfileAnnotArg(readNat())
+ assocs += ((name, arg))
+ }
+ else
+ args += readAnnotArg(argref)
+ }
+ AnnotationInfo(atp, args.toList, assocs.toList)
+ }
+
+ /** Read an annotation and as a side effect store it into
+ * 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 +")")
+ val end = readNat() + readIndex
+ val target = readSymbolRef()
+ target.addAnnotation(readAnnotationInfo(end))
+ }
+
+ /** Read an annotation and return it. Used when unpickling
+ * an ANNOTATED(WSELF)tpe or a NestedAnnotArg */
+ protected def readAnnotation(): AnnotationInfo = {
+ val tag = readByte()
+ if (tag != ANNOTINFO)
+ errorBadSignature("annotation expected (" + tag + ")")
+ val end = readNat() + readIndex
+ readAnnotationInfo(end)
+ }
+
+ /* Read an abstract syntax tree */
+ protected def readTree(): Tree = {
+ val outerTag = readByte()
+ if (outerTag != TREE)
+ errorBadSignature("tree expected (" + outerTag + ")")
+ val end = readNat() + readIndex
+ 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()
+ }
+ /** Read a Symbol and a Name */
+ def setSymName() {
+ symbol = readSymbolRef()
+ name = readNameRef()
+ }
+ /** Read a Symbol */
+ def setSym() {
+ symbol = readSymbolRef()
+ }
+
+ 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)
+
+ case _ =>
+ noSuchTreeTag(tag, end)
+ }
+
+ if (symbol == null) t setType tpe
+ else t setSymbol symbol setType tpe
+ }
+
+ def noSuchTreeTag(tag: Int, end: Int) =
+ errorBadSignature("unknown tree type (" + tag + ")")
+
+ def readModifiers(): Modifiers = {
+ val tag = readNat()
+ if (tag != MODIFIERS)
+ errorBadSignature("expected a modifiers tag (" + tag + ")")
+ val end = readNat() + readIndex
+ val pflagsHi = readNat()
+ val pflagsLo = readNat()
+ val pflags = (pflagsHi.toLong << 32) + pflagsLo
+ val flags = pickledToRawFlags(pflags)
+ val privateWithin = readNameRef()
+ Modifiers(flags, privateWithin, Nil)
+ }
+
+ /* Read a reference to a pickled item */
+ protected def readNameRef(): Name = at(readNat(), readName)
+ protected def readSymbolRef(): Symbol = at(readNat(), readSymbol)
+ protected def readTypeRef(): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... ()
+ protected def readConstantRef(): Constant = at(readNat(), readConstant)
+ protected def readAnnotationRef(): AnnotationInfo = at(readNat(), readAnnotation)
+ protected def readModifiersRef(): Modifiers = at(readNat(), readModifiers)
+ protected def readTreeRef(): Tree = at(readNat(), readTree)
+
+ protected def readTypeNameRef(): TypeName = readNameRef().toTypeName
+ protected def readTermNameRef(): TermName = readNameRef().toTermName
+
+ protected def readTemplateRef(): Template =
+ readTreeRef() match {
+ case templ:Template => templ
+ case other =>
+ errorBadSignature("expected a template (" + other + ")")
+ }
+ protected def readCaseDefRef(): CaseDef =
+ readTreeRef() match {
+ case tree:CaseDef => tree
+ case other =>
+ errorBadSignature("expected a case def (" + other + ")")
+ }
+ protected def readValDefRef(): ValDef =
+ readTreeRef() match {
+ case tree:ValDef => tree
+ case other =>
+ errorBadSignature("expected a ValDef (" + other + ")")
+ }
+ protected def readIdentRef(): Ident =
+ readTreeRef() match {
+ case tree:Ident => tree
+ case other =>
+ errorBadSignature("expected an Ident (" + other + ")")
+ }
+ protected def readTypeDefRef(): TypeDef =
+ readTreeRef() match {
+ case tree:TypeDef => tree
+ case other =>
+ errorBadSignature("expected an TypeDef (" + other + ")")
+ }
+
+ protected def errorBadSignature(msg: String) =
+ throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg)
+
+ protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol =
+ missingHook(owner, name) orElse MissingRequirementError.signal(
+ s"bad reference while unpickling $filename: ${name.longString} not found in ${owner.tpe.widen}"
+ )
+
+ def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) {} // can't do it; need a compiler for that.
+
+ def newLazyTypeRef(i: Int): LazyType = new LazyTypeRef(i)
+ def newLazyTypeRefAndAlias(i: Int, j: Int): LazyType = new LazyTypeRefAndAlias(i, j)
+
+ /** Convert to a type error, that is printed gracefully instead of crashing.
+ *
+ * Similar in intent to what SymbolLoader does (but here we don't have access to
+ * error reporting, so we rely on the typechecker to report the error).
+ */
+ def toTypeError(e: MissingRequirementError) =
+ new TypeError(e.msg)
+
+ /** A lazy type which when completed returns type at index `i`. */
+ private class LazyTypeRef(i: Int) extends LazyType {
+ private val definedAtRunId = currentRunId
+ private val p = phase
+ override def complete(sym: Symbol) : Unit = try {
+ val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType`
+ atPhase(p) (sym setInfo tp)
+ if (currentRunId != definedAtRunId)
+ sym.setInfo(adaptToNewRunMap(tp))
+ }
+ catch {
+ case e: MissingRequirementError => throw toTypeError(e)
+ }
+ override def load(sym: Symbol) { complete(sym) }
+ }
+
+ /** A lazy type which when completed returns type at index `i` and sets alias
+ * of completed symbol to symbol at index `j`.
+ */
+ private class LazyTypeRefAndAlias(i: Int, j: Int) extends LazyTypeRef(i) {
+ override def complete(sym: Symbol) = try {
+ super.complete(sym)
+ var alias = at(j, readSymbol)
+ if (alias.isOverloaded)
+ alias = atPhase(picklerPhase)((alias suchThat (alt => sym.tpe =:= sym.owner.thisType.memberType(alt))))
+
+ sym.asInstanceOf[TermSymbol].setAlias(alias)
+ }
+ catch {
+ case e: MissingRequirementError => throw toTypeError(e)
+ }
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/settings/AbsSettings.scala b/src/reflect/scala/reflect/internal/settings/AbsSettings.scala
new file mode 100644
index 0000000000..9bbba3f079
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/settings/AbsSettings.scala
@@ -0,0 +1,23 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect.internal
+package settings
+
+/** A Settings abstraction boiled out of the original highly mutable Settings
+ * class with the intention of creating an ImmutableSettings which can be used
+ * interchangeably. Except of course without the mutants.
+ */
+
+trait AbsSettings {
+ type Setting <: AbsSettingValue // Fix to the concrete Setting type
+
+ trait AbsSettingValue {
+ type T <: Any
+ def value: T
+ def isDefault: Boolean
+ }
+}
+
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
new file mode 100644
index 0000000000..8640a23aa7
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -0,0 +1,48 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+
+package scala.reflect.internal
+package settings
+
+/** A mutable Settings object.
+ */
+abstract class MutableSettings extends AbsSettings {
+
+ type Setting <: SettingValue
+ type BooleanSetting <: Setting { type T = Boolean }
+ type IntSetting <: Setting { type T = Int }
+
+ // basically this is a value which remembers if it's been modified
+ trait SettingValue extends AbsSettingValue {
+ protected var v: T
+ protected var setByUser: Boolean = false
+
+ def postSetHook(): Unit = ()
+ def isDefault = !setByUser
+ def isSetByUser = setByUser
+ def value: T = v
+ def value_=(arg: T) = {
+ setByUser = true
+ v = arg
+ postSetHook()
+ }
+ }
+
+ def overrideObjects: BooleanSetting
+ def printtypes: BooleanSetting
+ def debug: BooleanSetting
+ def Ynotnull: BooleanSetting
+ def explaintypes: BooleanSetting
+ def verbose: BooleanSetting
+ def uniqid: BooleanSetting
+ def Yshowsymkinds: BooleanSetting
+ def Xprintpos: BooleanSetting
+ def Yrecursion: IntSetting
+ def maxClassfileName: IntSetting
+ def Xexperimental: BooleanSetting
+ def XoldPatmat: BooleanSetting
+ def XnoPatmatAnalysis: BooleanSetting
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
new file mode 100644
index 0000000000..5beec70d62
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -0,0 +1,336 @@
+package scala.reflect
+package internal
+package transform
+
+import Flags.PARAMACCESSOR
+
+trait Erasure {
+
+ val global: SymbolTable
+ import global._
+ import definitions._
+
+ /** An extractor object for generic arrays */
+ object GenericArray {
+
+ /** Is `tp` an unbounded generic type (i.e. which could be instantiated
+ * with primitive as well as class types)?.
+ */
+ private def genericCore(tp: Type): Type = tp.normalize match {
+ /* A Java Array<T> is erased to Array[Object] (T can only be a reference type), where as a Scala Array[T] is
+ * erased to Object. However, there is only symbol for the Array class. So to make the distinction between
+ * a Java and a Scala array, we check if the owner of T comes from a Java class.
+ * This however caused issue SI-5654. The additional test for EXSITENTIAL fixes it, see the ticket comments.
+ * In short, members of an existential type (e.g. `T` in `forSome { type T }`) can have pretty arbitrary
+ * owners (e.g. when computing lubs, <root> is used). All packageClass symbols have `isJavaDefined == true`.
+ */
+ case TypeRef(_, sym, _) if sym.isAbstractType && (!sym.owner.isJavaDefined || sym.hasFlag(Flags.EXISTENTIAL)) =>
+ tp
+ case ExistentialType(tparams, restp) =>
+ genericCore(restp)
+ case _ =>
+ NoType
+ }
+
+ /** If `tp` is of the form Array[...Array[T]...] where `T` is an abstract type
+ * then Some((N, T)) where N is the number of Array constructors enclosing `T`,
+ * otherwise None. Existentials on any level are ignored.
+ */
+ def unapply(tp: Type): Option[(Int, Type)] = tp.normalize match {
+ case TypeRef(_, ArrayClass, List(arg)) =>
+ genericCore(arg) match {
+ case NoType =>
+ unapply(arg) match {
+ case Some((level, core)) => Some((level + 1, core))
+ case None => None
+ }
+ case core =>
+ Some((1, core))
+ }
+ case ExistentialType(tparams, restp) =>
+ unapply(restp)
+ case _ =>
+ None
+ }
+ }
+
+ protected def unboundedGenericArrayLevel(tp: Type): Int = tp match {
+ case GenericArray(level, core) if !(core <:< AnyRefClass.tpe) => level
+ case _ => 0
+ }
+
+ // @M #2585 when generating a java generic signature that includes
+ // a selection of an inner class p.I, (p = `pre`, I = `cls`) must
+ // rewrite to p'.I, where p' refers to the class that directly defines
+ // the nested class I.
+ //
+ // See also #2585 marker in javaSig: there, type arguments must be
+ // included (use pre.baseType(cls.owner)).
+ //
+ // This requires that cls.isClass.
+ protected def rebindInnerClass(pre: Type, cls: Symbol): Type = {
+ if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass?
+ }
+
+ def underlyingOfValueClass(clazz: Symbol): Type =
+ clazz.firstParamAccessor.tpe.resultType
+
+ abstract class ErasureMap extends TypeMap {
+ private lazy val ObjectArray = arrayType(ObjectClass.tpe)
+ private lazy val ErasedObject = erasedTypeRef(ObjectClass)
+
+ def mergeParents(parents: List[Type]): Type
+
+ def eraseNormalClassRef(pre: Type, clazz: Symbol): Type =
+ typeRef(apply(rebindInnerClass(pre, clazz)), clazz, List()) // #2585
+
+ protected def eraseDerivedValueClassRef(clazz: Symbol): Type =
+ scalaErasure(underlyingOfValueClass(clazz))
+
+ def apply(tp: Type): Type = tp match {
+ case ConstantType(_) =>
+ tp
+ case st: SubType =>
+ apply(st.supertype)
+ case TypeRef(pre, sym, args) =>
+ if (sym == ArrayClass)
+ if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe
+ else if (args.head.typeSymbol.isBottomClass) ObjectArray
+ else typeRef(apply(pre), sym, args map applyInArray)
+ else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) ErasedObject
+ else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
+ else if (sym.isRefinementClass) apply(mergeParents(tp.parents))
+ else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(sym)
+ else if (sym.isClass) eraseNormalClassRef(pre, sym)
+ else apply(sym.info) // alias type or abstract type
+ case PolyType(tparams, restpe) =>
+ apply(restpe)
+ case ExistentialType(tparams, restpe) =>
+ apply(restpe)
+ case mt @ MethodType(params, restpe) =>
+ MethodType(
+ cloneSymbolsAndModify(params, ErasureMap.this),
+ if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
+ // this replaces each typeref that refers to an argument
+ // by the type `p.tpe` of the actual argument p (p in params)
+ else apply(mt.resultType(params map (_.tpe))))
+ case RefinedType(parents, decls) =>
+ apply(mergeParents(parents))
+ case AnnotatedType(_, atp, _) =>
+ apply(atp)
+ case ClassInfoType(parents, decls, clazz) =>
+ ClassInfoType(
+ if (clazz == ObjectClass || isPrimitiveValueClass(clazz)) Nil
+ else if (clazz == ArrayClass) List(ErasedObject)
+ else removeLaterObjects(parents map this),
+ decls, clazz)
+ case _ =>
+ mapOver(tp)
+ }
+
+ def applyInArray(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) if (sym.isDerivedValueClass) => eraseNormalClassRef(pre, sym)
+ case _ => apply(tp)
+ }
+ }
+
+ protected def verifyJavaErasure = false
+
+ /** The erasure |T| of a type T. This is:
+ *
+ * - For a constant type, itself.
+ * - For a type-bounds structure, the erasure of its upper bound.
+ * - For every other singleton type, the erasure of its supertype.
+ * - For a typeref scala.Array+[T] where T is an abstract type, AnyRef.
+ * - For a typeref scala.Array+[T] where T is not an abstract type, scala.Array+[|T|].
+ * - For a typeref scala.Any or scala.AnyVal, java.lang.Object.
+ * - For a typeref scala.Unit, scala.runtime.BoxedUnit.
+ * - For a typeref P.C[Ts] where C refers to a class, |P|.C.
+ * (Where P is first rebound to the class that directly defines C.)
+ * - For a typeref P.C[Ts] where C refers to an alias type, the erasure of C's alias.
+ * - For a typeref P.C[Ts] where C refers to an abstract type, the
+ * erasure of C's upper bound.
+ * - For a non-empty type intersection (possibly with refinement)
+ * - in scala, the erasure of the intersection dominator
+ * - in java, the erasure of its first parent <--- @PP: not yet in spec.
+ * - For an empty type intersection, java.lang.Object.
+ * - For a method type (Fs)scala.Unit, (|Fs|)scala#Unit.
+ * - For any other method type (Fs)Y, (|Fs|)|T|.
+ * - For a polymorphic type, the erasure of its result type.
+ * - For the class info type of java.lang.Object, the same type without any parents.
+ * - For a class info type of a value class, the same type without any parents.
+ * - For any other class info type with parents Ps, the same type with
+ * parents |Ps|, but with duplicate references of Object removed.
+ * - for all other types, the type itself (with any sub-components erased)
+ */
+ def erasure(sym: Symbol): ErasureMap =
+ if (sym == NoSymbol || !sym.enclClass.isJavaDefined) scalaErasure
+ else if (verifyJavaErasure && sym.isMethod) verifiedJavaErasure
+ else javaErasure
+
+ /** This is used as the Scala erasure during the erasure phase itself
+ * It differs from normal erasure in that value classes are erased to ErasedValueTypes which
+ * are then later converted to the underlying parameter type in phase posterasure.
+ */
+ def specialErasure(sym: Symbol)(tp: Type): Type =
+ if (sym != NoSymbol && sym.enclClass.isJavaDefined)
+ erasure(sym)(tp)
+ else if (sym.isTerm && sym.owner.isDerivedValueClass)
+ specialErasureAvoiding(sym.owner, tp)
+ else if (sym.isValue && sym.owner.isMethodWithExtension)
+ specialErasureAvoiding(sym.owner.owner, tp)
+ else
+ specialScalaErasure(tp)
+
+ def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = {
+ tpe match {
+ case PolyType(tparams, restpe) =>
+ specialErasureAvoiding(clazz, restpe)
+ case ExistentialType(tparams, restpe) =>
+ specialErasureAvoiding(clazz, restpe)
+ case mt @ MethodType(params, restpe) =>
+ MethodType(
+ cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)),
+ if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
+ else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
+ case TypeRef(pre, `clazz`, args) =>
+ typeRef(pre, clazz, List())
+ case _ =>
+ specialScalaErasure(tpe)
+ }
+ }
+
+ /** Scala's more precise erasure than java's is problematic as follows:
+ *
+ * - Symbols are read from classfiles and populated with types
+ * - The textual signature read from the bytecode is forgotten
+ * - Bytecode generation must know the precise signature of a method
+ * - the signature is derived from the erasure of the method type
+ * - If that derivation does not adhere to the rules by which the original
+ * signature was created, a NoSuchMethod error will result.
+ *
+ * For this reason and others (such as distinguishing constructors from other methods)
+ * erasure is now (Symbol, Type) => Type rather than Type => Type.
+ */
+ class ScalaErasureMap extends ErasureMap {
+ /** In scala, calculate a useful parent.
+ * An intersection such as `Object with Trait` erases to Trait.
+ */
+ def mergeParents(parents: List[Type]): Type =
+ intersectionDominator(parents)
+ }
+
+ class JavaErasureMap extends ErasureMap {
+ /** In java, always take the first parent.
+ * An intersection such as `Object with Trait` erases to Object.
+ */
+ def mergeParents(parents: List[Type]): Type =
+ if (parents.isEmpty) ObjectClass.tpe
+ else parents.head
+ }
+
+ object scalaErasure extends ScalaErasureMap
+
+ /** This is used as the Scala erasure during the erasure phase itself
+ * It differs from normal erasure in that value classes are erased to ErasedValueTypes which
+ * are then later converted to the underlying parameter type in phase posterasure.
+ */
+ object specialScalaErasure extends ScalaErasureMap {
+ override def eraseDerivedValueClassRef(clazz: Symbol): Type = ErasedValueType(clazz)
+ }
+
+ object javaErasure extends JavaErasureMap
+
+ object verifiedJavaErasure extends JavaErasureMap {
+ override def apply(tp: Type): Type = {
+ val res = javaErasure(tp)
+ val old = scalaErasure(tp)
+ if (!(res =:= old))
+ log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res)
+ res
+ }
+ }
+
+ /** The intersection dominator (SLS 3.7) of a list of types is computed as follows.
+ *
+ * - If the list contains one or more occurrences of scala.Array with
+ * type parameters El1, El2, ... then the dominator is scala.Array with
+ * type parameter of intersectionDominator(List(El1, El2, ...)). <--- @PP: not yet in spec.
+ * - Otherwise, the list is reduced to a subsequence containing only types
+ * which are not subtypes of other listed types (the span.)
+ * - If the span is empty, the dominator is Object.
+ * - If the span contains a class Tc which is not a trait and which is
+ * not Object, the dominator is Tc. <--- @PP: "which is not Object" not in spec.
+ * - Otherwise, the dominator is the first element of the span.
+ */
+ def intersectionDominator(parents: List[Type]): Type = {
+ if (parents.isEmpty) ObjectClass.tpe
+ else {
+ val psyms = parents map (_.typeSymbol)
+ if (psyms contains ArrayClass) {
+ // treat arrays specially
+ arrayType(
+ intersectionDominator(
+ parents filter (_.typeSymbol == ArrayClass) map (_.typeArgs.head)))
+ } else {
+ // implement new spec for erasure of refined types.
+ def isUnshadowed(psym: Symbol) =
+ !(psyms exists (qsym => (psym ne qsym) && (qsym isNonBottomSubClass psym)))
+ val cs = parents.iterator.filter { p => // isUnshadowed is a bit expensive, so try classes first
+ val psym = p.typeSymbol
+ psym.initialize
+ psym.isClass && !psym.isTrait && isUnshadowed(psym)
+ }
+ (if (cs.hasNext) cs else parents.iterator.filter(p => isUnshadowed(p.typeSymbol))).next()
+ }
+ }
+ }
+
+ /** Type reference after erasure */
+ def erasedTypeRef(sym: Symbol): Type =
+ typeRef(erasure(sym)(sym.owner.tpe), sym, Nil)
+
+ /** The symbol's erased info. This is the type's erasure, except for the following symbols:
+ *
+ * - For $asInstanceOf : [T]T
+ * - For $isInstanceOf : [T]scala#Boolean
+ * - For class Array : [T]C where C is the erased classinfo of the Array class.
+ * - For Array[T].<init> : {scala#Int)Array[T]
+ * - For a type parameter : A type bounds type consisting of the erasures of its bounds.
+ */
+ def transformInfo(sym: Symbol, tp: Type): Type = {
+ if (sym == Object_asInstanceOf)
+ sym.info
+ else if (sym == Object_isInstanceOf || sym == ArrayClass)
+ PolyType(sym.info.typeParams, specialErasure(sym)(sym.info.resultType))
+ else if (sym.isAbstractType)
+ TypeBounds(WildcardType, WildcardType)
+ else if (sym.isTerm && sym.owner == ArrayClass) {
+ if (sym.isClassConstructor)
+ tp match {
+ case MethodType(params, TypeRef(pre, sym1, args)) =>
+ MethodType(cloneSymbolsAndModify(params, specialErasure(sym)),
+ typeRef(specialErasure(sym)(pre), sym1, args))
+ }
+ else if (sym.name == nme.apply)
+ tp
+ else if (sym.name == nme.update)
+ (tp: @unchecked) match {
+ case MethodType(List(index, tvar), restpe) =>
+ MethodType(List(index.cloneSymbol.setInfo(specialErasure(sym)(index.tpe)), tvar),
+ erasedTypeRef(UnitClass))
+ }
+ else specialErasure(sym)(tp)
+ } else if (
+ sym.owner != NoSymbol &&
+ sym.owner.owner == ArrayClass &&
+ sym == Array_update.paramss.head(1)) {
+ // special case for Array.update: the non-erased type remains, i.e. (Int,A)Unit
+ // since the erasure type map gets applied to every symbol, we have to catch the
+ // symbol here
+ tp
+ } else {
+ specialErasure(sym)(tp)
+ }
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/transform/RefChecks.scala b/src/reflect/scala/reflect/internal/transform/RefChecks.scala
new file mode 100644
index 0000000000..d6108ab665
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/transform/RefChecks.scala
@@ -0,0 +1,13 @@
+package scala.reflect
+package internal
+package transform
+
+trait RefChecks {
+
+ val global: SymbolTable
+ import global._
+
+ def transformInfo(sym: Symbol, tp: Type): Type =
+ if (sym.isModule && !sym.isStatic) NullaryMethodType(tp)
+ else tp
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/transform/Transforms.scala b/src/reflect/scala/reflect/internal/transform/Transforms.scala
new file mode 100644
index 0000000000..c4c5dc3a1c
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/transform/Transforms.scala
@@ -0,0 +1,41 @@
+package scala.reflect
+package internal
+package transform
+
+import language.existentials
+
+trait Transforms { self: SymbolTable =>
+
+ /** We need to encode laziness by hand here because the three components refChecks, uncurry and erasure
+ * are overwritten by objects in Global.
+ * It would be best of objects could override lazy values. See SI-5187.
+ * In the absence of this, the Lazy functionality should probably be somewhere
+ * in the standard library. Or is it already?
+ */
+ private class Lazy[T](op: => T) {
+ private var value: T = _
+ private var _isDefined = false
+ def isDefined = _isDefined
+ def force: T = {
+ if (!isDefined) { value = op; _isDefined = true }
+ value
+ }
+ }
+
+ private val refChecksLazy = new Lazy(new { val global: Transforms.this.type = self } with RefChecks)
+ private val uncurryLazy = new Lazy(new { val global: Transforms.this.type = self } with UnCurry)
+ private val erasureLazy = new Lazy(new { val global: Transforms.this.type = self } with Erasure)
+
+ def refChecks = refChecksLazy.force
+ def uncurry = uncurryLazy.force
+ def erasure = erasureLazy.force
+
+ def transformedType(sym: Symbol) =
+ erasure.transformInfo(sym,
+ uncurry.transformInfo(sym,
+ refChecks.transformInfo(sym, sym.info)))
+
+ def transformedType(tpe: Type) =
+ erasure.scalaErasure(uncurry.uncurry(tpe))
+
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala
new file mode 100644
index 0000000000..0c1640ceb9
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala
@@ -0,0 +1,64 @@
+package scala.reflect
+package internal
+package transform
+
+import Flags._
+
+trait UnCurry {
+
+ val global: SymbolTable
+ import global._
+ import definitions._
+
+ private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp
+
+ val uncurry: TypeMap = new TypeMap {
+ def apply(tp0: Type): Type = {
+ val tp = expandAlias(tp0)
+ tp match {
+ case MethodType(params, MethodType(params1, restpe)) =>
+ apply(MethodType(params ::: params1, restpe))
+ case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) =>
+ assert(false, "unexpected curried method types with intervening existential")
+ tp0
+ case MethodType(h :: t, restpe) if h.isImplicit =>
+ apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
+ case NullaryMethodType(restpe) =>
+ apply(MethodType(List(), restpe))
+ case TypeRef(pre, ByNameParamClass, arg :: Nil) =>
+ apply(functionType(List(), arg))
+ case TypeRef(pre, RepeatedParamClass, arg :: Nil) =>
+ apply(seqType(arg))
+ case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) =>
+ apply(arrayType(
+ if (isUnboundedGeneric(arg)) ObjectClass.tpe else arg))
+ case _ =>
+ expandAlias(mapOver(tp))
+ }
+ }
+ }
+
+ private val uncurryType = new TypeMap {
+ def apply(tp0: Type): Type = {
+ val tp = expandAlias(tp0)
+ tp match {
+ case ClassInfoType(parents, decls, clazz) =>
+ val parents1 = parents mapConserve uncurry
+ if (parents1 eq parents) tp
+ else ClassInfoType(parents1, decls, clazz) // @MAT normalize in decls??
+ case PolyType(_, _) =>
+ mapOver(tp)
+ case _ =>
+ tp
+ }
+ }
+ }
+
+ /** - return symbol's transformed type,
+ * - if symbol is a def parameter with transformed type T, return () => T
+ *
+ * @MAT: starting with this phase, the info of every symbol will be normalized
+ */
+ def transformInfo(sym: Symbol, tp: Type): Type =
+ if (sym.isType) uncurryType(tp) else uncurry(tp)
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala
new file mode 100644
index 0000000000..1f8eb15c90
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/Collections.scala
@@ -0,0 +1,213 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect.internal.util
+
+import scala.collection.{ mutable, immutable }
+import scala.annotation.tailrec
+import mutable.ListBuffer
+
+/** Profiler driven changes.
+ * TODO - inlining doesn't work from here because of the bug that
+ * methods in traits aren't inlined.
+ */
+trait Collections {
+ /** True if all three arguments have the same number of elements and
+ * the function is true for all the triples.
+ */
+ @tailrec final def corresponds3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])
+ (f: (A, B, C) => Boolean): Boolean = (
+ if (xs1.isEmpty) xs2.isEmpty && xs3.isEmpty
+ else !xs2.isEmpty && !xs3.isEmpty && f(xs1.head, xs2.head, xs3.head) && corresponds3(xs1.tail, xs2.tail, xs3.tail)(f)
+ )
+
+ /** All these mm methods are "deep map" style methods for
+ * mapping etc. on a list of lists while avoiding unnecessary
+ * intermediate structures like those created via flatten.
+ */
+ final def mexists[A](xss: List[List[A]])(p: A => Boolean) =
+ xss exists (_ exists p)
+ final def mforall[A](xss: List[List[A]])(p: A => Boolean) =
+ xss forall (_ forall p)
+ final def mmap[A, B](xss: List[List[A]])(f: A => B) =
+ xss map (_ map f)
+ final def mforeach[A](xss: List[List[A]])(f: A => Unit) =
+ xss foreach (_ foreach f)
+ final def mfind[A](xss: List[List[A]])(p: A => Boolean): Option[A] = {
+ var res: Option[A] = null
+ mforeach(xss)(x => if ((res eq null) && p(x)) res = Some(x))
+ if (res eq null) None else res
+ }
+ final def mfilter[A](xss: List[List[A]])(p: A => Boolean) =
+ for (xs <- xss; x <- xs; if p(x)) yield x
+
+ final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = {
+ val lb = new ListBuffer[C]
+ var ys1 = xs1
+ var ys2 = xs2
+ while (!ys1.isEmpty && !ys2.isEmpty) {
+ lb += f(ys1.head, ys2.head)
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ }
+ lb.toList
+ }
+ final def map3[A, B, C, D](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => D): List[D] = {
+ if (xs1.isEmpty || xs2.isEmpty || xs3.isEmpty) Nil
+ else f(xs1.head, xs2.head, xs3.head) :: map3(xs1.tail, xs2.tail, xs3.tail)(f)
+ }
+ final def flatMap2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => List[C]): List[C] = {
+ val lb = new ListBuffer[C]
+ var ys1 = xs1
+ var ys2 = xs2
+ while (!ys1.isEmpty && !ys2.isEmpty) {
+ lb ++= f(ys1.head, ys2.head)
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ }
+ lb.toList
+ }
+
+ final def flatCollect[A, B](elems: List[A])(pf: PartialFunction[A, Traversable[B]]): List[B] = {
+ val lb = new ListBuffer[B]
+ for (x <- elems ; if pf isDefinedAt x)
+ lb ++= pf(x)
+
+ lb.toList
+ }
+
+ final def distinctBy[A, B](xs: List[A])(f: A => B): List[A] = {
+ val buf = new ListBuffer[A]
+ val seen = mutable.Set[B]()
+ xs foreach { x =>
+ val y = f(x)
+ if (!seen(y)) {
+ buf += x
+ seen += y
+ }
+ }
+ buf.toList
+ }
+
+ @tailrec final def flattensToEmpty(xss: Seq[Seq[_]]): Boolean = {
+ xss.isEmpty || xss.head.isEmpty && flattensToEmpty(xss.tail)
+ }
+
+ final def foreachWithIndex[A, B](xs: List[A])(f: (A, Int) => Unit) {
+ var index = 0
+ var ys = xs
+ while (!ys.isEmpty) {
+ f(ys.head, index)
+ ys = ys.tail
+ index += 1
+ }
+ }
+
+ // @inline
+ final def findOrElse[A](xs: TraversableOnce[A])(p: A => Boolean)(orElse: => A): A = {
+ xs find p getOrElse orElse
+ }
+
+ final def mapFrom[A, A1 >: A, B](xs: List[A])(f: A => B): Map[A1, B] = {
+ Map[A1, B](xs map (x => (x, f(x))): _*)
+ }
+
+ final def mapWithIndex[A, B](xs: List[A])(f: (A, Int) => B): List[B] = {
+ val lb = new ListBuffer[B]
+ var index = 0
+ var ys = xs
+ while (!ys.isEmpty) {
+ lb += f(ys.head, index)
+ ys = ys.tail
+ index += 1
+ }
+ lb.toList
+ }
+ final def collectMap2[A, B, C](xs1: List[A], xs2: List[B])(p: (A, B) => Boolean): Map[A, B] = {
+ if (xs1.isEmpty || xs2.isEmpty)
+ return Map()
+
+ val buf = immutable.Map.newBuilder[A, B]
+ var ys1 = xs1
+ var ys2 = xs2
+ while (!ys1.isEmpty && !ys2.isEmpty) {
+ val x1 = ys1.head
+ val x2 = ys2.head
+ if (p(x1, x2))
+ buf += ((x1, x2))
+
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ }
+ buf.result
+ }
+ final def foreach2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Unit): Unit = {
+ var ys1 = xs1
+ var ys2 = xs2
+ while (!ys1.isEmpty && !ys2.isEmpty) {
+ f(ys1.head, ys2.head)
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ }
+ }
+ final def foreach3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Unit): Unit = {
+ var ys1 = xs1
+ var ys2 = xs2
+ var ys3 = xs3
+ while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) {
+ f(ys1.head, ys2.head, ys3.head)
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ ys3 = ys3.tail
+ }
+ }
+ final def exists2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = {
+ var ys1 = xs1
+ var ys2 = xs2
+ while (!ys1.isEmpty && !ys2.isEmpty) {
+ if (f(ys1.head, ys2.head))
+ return true
+
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ }
+ false
+ }
+ final def forall2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = {
+ var ys1 = xs1
+ var ys2 = xs2
+ while (!ys1.isEmpty && !ys2.isEmpty) {
+ if (!f(ys1.head, ys2.head))
+ return false
+
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ }
+ true
+ }
+ final def forall3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Boolean): Boolean = {
+ var ys1 = xs1
+ var ys2 = xs2
+ var ys3 = xs3
+ while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) {
+ if (!f(ys1.head, ys2.head, ys3.head))
+ return false
+
+ ys1 = ys1.tail
+ ys2 = ys2.tail
+ ys3 = ys3.tail
+ }
+ true
+ }
+
+ final def transposeSafe[A](ass: List[List[A]]): Option[List[List[A]]] = try {
+ Some(ass.transpose)
+ } catch {
+ case _: IllegalArgumentException => None
+ }
+}
+
+object Collections extends Collections { }
+
diff --git a/src/reflect/scala/reflect/internal/util/HashSet.scala b/src/reflect/scala/reflect/internal/util/HashSet.scala
new file mode 100644
index 0000000000..a771dad2b0
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/HashSet.scala
@@ -0,0 +1,106 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.reflect.internal.util
+
+object HashSet {
+ def apply[T >: Null <: AnyRef](): HashSet[T] = this(16)
+ def apply[T >: Null <: AnyRef](label: String): HashSet[T] = this(label, 16)
+ def apply[T >: Null <: AnyRef](initialCapacity: Int): HashSet[T] = this("No Label", initialCapacity)
+ def apply[T >: Null <: AnyRef](label: String, initialCapacity: Int): HashSet[T] =
+ new HashSet[T](label, initialCapacity)
+}
+
+class HashSet[T >: Null <: AnyRef](val label: String, initialCapacity: Int) extends Set[T] {
+ private var used = 0
+ private var table = new Array[AnyRef](initialCapacity)
+ private def index(x: Int): Int = math.abs(x % table.length)
+
+ def size: Int = used
+ def clear() {
+ used = 0
+ table = new Array[AnyRef](initialCapacity)
+ }
+
+ def findEntryOrUpdate(x: T): T = {
+ var h = index(x.##)
+ var entry = table(h)
+ while (entry ne null) {
+ if (x == entry)
+ return entry.asInstanceOf[T]
+
+ h = index(h + 1)
+ entry = table(h)
+ }
+ table(h) = x
+ used += 1
+ if (used > (table.length >> 2)) growTable()
+ x
+ }
+
+ def findEntry(x: T): T = {
+ var h = index(x.##)
+ var entry = table(h)
+ while ((entry ne null) && x != entry) {
+ h = index(h + 1)
+ entry = table(h)
+ }
+ entry.asInstanceOf[T]
+ }
+
+ def addEntry(x: T) {
+ var h = index(x.##)
+ var entry = table(h)
+ while (entry ne null) {
+ if (x == entry) return
+ h = index(h + 1)
+ entry = table(h)
+ }
+ table(h) = x
+ used += 1
+ if (used > (table.length >> 2)) growTable()
+ }
+ def addEntries(xs: TraversableOnce[T]) {
+ xs foreach addEntry
+ }
+
+ def iterator = new Iterator[T] {
+ private var i = 0
+ def hasNext: Boolean = {
+ while (i < table.length && (table(i) eq null)) i += 1
+ i < table.length
+ }
+ def next(): T =
+ if (hasNext) { i += 1; table(i - 1).asInstanceOf[T] }
+ else null
+ }
+
+ private def addOldEntry(x: T) {
+ var h = index(x.##)
+ var entry = table(h)
+ while (entry ne null) {
+ h = index(h + 1)
+ entry = table(h)
+ }
+ table(h) = x
+ }
+
+ private def growTable() {
+ val oldtable = table
+ val growthFactor =
+ if (table.length <= initialCapacity) 8
+ else if (table.length <= (initialCapacity * 8)) 4
+ else 2
+
+ table = new Array[AnyRef](table.length * growthFactor)
+ var i = 0
+ while (i < oldtable.length) {
+ val entry = oldtable(i)
+ if (entry ne null) addOldEntry(entry.asInstanceOf[T])
+ i += 1
+ }
+ }
+ override def toString() = "HashSet %s(%d / %d)".format(label, used, table.length)
+}
diff --git a/src/reflect/scala/reflect/internal/util/Origins.scala b/src/reflect/scala/reflect/internal/util/Origins.scala
new file mode 100644
index 0000000000..0bd5ad55ca
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/Origins.scala
@@ -0,0 +1,119 @@
+/* NSC -- new scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect
+package internal.util
+
+import NameTransformer._
+import scala.collection.{ mutable, immutable }
+import Origins._
+
+/** A debugging class for logging from whence a method is being called.
+ * Say you wanted to discover who was calling phase_= in SymbolTable.
+ * You could do this:
+ *
+ * {{{
+ * private lazy val origins = Origins("arbitraryTag")
+ * // Commented out original enclosed for contrast
+ * // final def phase_=(p: Phase): Unit = {
+ * final def phase_=(p: Phase): Unit = origins {
+ * }}}
+ *
+ * And that's it. When the JVM exits it would issue a report something like this:
+ {{{
+ >> Origins tag 'arbitraryTag' logged 145585 calls from 51 distinguished sources.
+
+ 71114 scala.tools.nsc.symtab.Symbols$Symbol.unsafeTypeParams(Symbols.scala:862)
+ 16584 scala.tools.nsc.symtab.Symbols$Symbol.rawInfo(Symbols.scala:757)
+ 15411 scala.tools.nsc.symtab.Symbols$Symbol.unsafeTypeParams(Symbols.scala:869)
+ 11507 scala.tools.nsc.symtab.Symbols$Symbol.rawInfo(Symbols.scala:770)
+ 10285 scala.tools.nsc.symtab.Symbols$Symbol.unsafeTypeParams(Symbols.scala:864)
+ 6860 scala.tools.nsc.transform.SpecializeTypes.specializedTypeVars(SpecializeTypes.scala:304)
+ ...
+ }}}
+ *
+ */
+abstract class Origins {
+ type Rep
+ type StackSlice = Array[StackTraceElement]
+
+ def tag: String
+ def isCutoff(el: StackTraceElement): Boolean
+ def newRep(xs: StackSlice): Rep
+ def repString(rep: Rep): String
+
+ private val origins = new mutable.HashMap[Rep, Int] withDefaultValue 0
+ private def add(xs: Rep) = origins(xs) += 1
+ private def total = origins.values.foldLeft(0L)(_ + _)
+
+ // Create a stack and whittle it down to the interesting part.
+ def readStack(): Array[StackTraceElement] = (
+ Thread.currentThread.getStackTrace dropWhile (x => !isCutoff(x)) dropWhile isCutoff drop 1
+ )
+
+ def apply[T](body: => T): T = {
+ add(newRep(readStack()))
+ body
+ }
+ def clear() = origins.clear()
+ def show() = {
+ println("\n>> Origins tag '%s' logged %s calls from %s distinguished sources.\n".format(tag, total, origins.keys.size))
+ origins.toList sortBy (-_._2) foreach {
+ case (k, v) => println("%7s %s".format(v, repString(k)))
+ }
+ }
+ def purge() = {
+ show()
+ clear()
+ }
+}
+
+object Origins {
+ private val counters = mutable.HashMap[String, Origins]()
+ private val thisClass = this.getClass.getName
+
+ locally {
+ sys.addShutdownHook(counters.values foreach (_.purge()))
+ }
+
+ case class OriginId(className: String, methodName: String) {
+ def matches(el: StackTraceElement) = (
+ (methodName == el.getMethodName) && (className startsWith el.getClassName)
+ )
+ }
+
+ def lookup(tag: String, orElse: String => Origins): Origins =
+ counters.getOrElseUpdate(tag, orElse(tag))
+ def register(x: Origins): Origins = {
+ counters(x.tag) = x
+ x
+ }
+
+ private def preCutoff(el: StackTraceElement) = (
+ (el.getClassName == thisClass)
+ || (el.getClassName startsWith "java.lang.")
+ )
+ private def findCutoff() = {
+ val cutoff = Thread.currentThread.getStackTrace dropWhile preCutoff head;
+ OriginId(cutoff.getClassName, cutoff.getMethodName)
+ }
+
+ def apply(tag: String): Origins = counters.getOrElseUpdate(tag, new OneLine(tag, findCutoff()))
+ def apply(tag: String, frames: Int): Origins = counters.getOrElseUpdate(tag, new MultiLine(tag, findCutoff(), frames))
+
+ class OneLine(val tag: String, id: OriginId) extends Origins {
+ type Rep = StackTraceElement
+ def isCutoff(el: StackTraceElement) = id matches el
+ def newRep(xs: StackSlice): Rep = if ((xs eq null) || (xs.length == 0)) null else xs(0)
+ def repString(rep: Rep) = " " + rep
+ }
+ class MultiLine(val tag: String, id: OriginId, numLines: Int) extends Origins {
+ type Rep = List[StackTraceElement]
+ def isCutoff(el: StackTraceElement) = id matches el
+ def newRep(xs: StackSlice): Rep = (xs take numLines).toList
+ def repString(rep: Rep) = rep.map("\n " + _).mkString
+ override def readStack() = super.readStack() drop 1
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/util/Position.scala b/src/reflect/scala/reflect/internal/util/Position.scala
new file mode 100644
index 0000000000..3c251b3b31
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/Position.scala
@@ -0,0 +1,277 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ *
+ */
+
+package scala.reflect.internal.util
+
+import reflect.ClassTag
+import reflect.base.Attachments
+import reflect.api.PositionApi
+
+object Position {
+ val tabInc = 8
+
+ /** Prints the message with the given position indication. */
+ def formatMessage(posIn: Position, msg: String, shortenFile: Boolean): String = {
+ val pos = (
+ if (posIn eq null) NoPosition
+ else if (posIn.isDefined) posIn.inUltimateSource(posIn.source)
+ else posIn
+ )
+ def file = pos.source.file
+ def prefix = if (shortenFile) file.name else file.path
+
+ pos match {
+ case FakePos(fmsg) => fmsg+" "+msg
+ case NoPosition => msg
+ case _ =>
+ List(
+ "%s:%s: %s".format(prefix, pos.line, msg),
+ pos.lineContent.stripLineEnd,
+ " " * (pos.column - 1) + "^"
+ ) mkString "\n"
+ }
+ }
+}
+
+abstract class Position extends PositionApi { self =>
+
+ type Pos = Position
+
+ def pos: Position = this
+
+ def withPos(newPos: Position): Attachments { type Pos = self.Pos } = newPos
+
+ /** Java file corresponding to the source file of this position.
+ */
+ // necessary for conformance with scala.reflect.api.Position
+ def fileInfo: java.io.File = source.file.file
+
+ /** Contents of the source file that contains this position.
+ */
+ // necessary for conformance with scala.reflect.api.Position
+ def fileContent: Array[Char] = source.content
+
+ /** An optional value containing the source file referred to by this position, or
+ * None if not defined.
+ */
+ def source: SourceFile = throw new UnsupportedOperationException("Position.source")
+
+ /** Is this position neither a NoPosition nor a FakePosition?
+ * If isDefined is true, offset and source are both defined.
+ */
+ def isDefined: Boolean = false
+
+ /** Is this position a transparent position? */
+ def isTransparent: Boolean = false
+
+ /** Is this position a range position? */
+ def isRange: Boolean = false
+
+ /** Is this position a non-transparent range position? */
+ def isOpaqueRange: Boolean = false
+
+ /** if opaque range, make this position transparent */
+ def makeTransparent: Position = this
+
+ /** The start of the position's range, error if not a range position */
+ def start: Int = throw new UnsupportedOperationException("Position.start")
+
+ /** The start of the position's range, or point if not a range position */
+ def startOrPoint: Int = point
+
+ /** The point (where the ^ is) of the position */
+ def point: Int = throw new UnsupportedOperationException("Position.point")
+
+ /** The point (where the ^ is) of the position, or else `default` if undefined */
+ def pointOrElse(default: Int): Int = default
+
+ /** The end of the position's range, error if not a range position */
+ def end: Int = throw new UnsupportedOperationException("Position.end")
+
+ /** The end of the position's range, or point if not a range position */
+ def endOrPoint: Int = point
+
+ @deprecated("use point instead", "2.9.0")
+ def offset: Option[Int] = if (isDefined) Some(point) else None
+
+ /** The same position with a different start value (if a range) */
+ def withStart(off: Int): Position = this
+
+ /** The same position with a different end value (if a range) */
+ def withEnd(off: Int): Position = this
+
+ /** The same position with a different point value (if a range or offset) */
+ def withPoint(off: Int): Position = this
+
+ /** The same position with a different source value, and its values shifted by given offset */
+ def withSource(source: SourceFile, shift: Int): Position = this
+
+ /** If this is a range, the union with the other range, with the point of this position.
+ * Otherwise, this position
+ */
+ def union(pos: Position): Position = this
+
+ /** If this is a range position, the offset position of its start.
+ * Otherwise the position itself
+ */
+ def focusStart: Position = this
+
+ /** If this is a range position, the offset position of its point.
+ * Otherwise the position itself
+ */
+ def focus: Position = this
+
+ /** If this is a range position, the offset position of its end.
+ * Otherwise the position itself
+ */
+ def focusEnd: Position = this
+
+ /** Does this position include the given position `pos`.
+ * This holds if `this` is a range position and its range [start..end]
+ * is the same or covers the range of the given position, which may or may not be a range position.
+ */
+ def includes(pos: Position): Boolean = false
+
+ /** Does this position properly include the given position `pos` ("properly" meaning their
+ * ranges are not the same)?
+ */
+ def properlyIncludes(pos: Position): Boolean =
+ includes(pos) && (start < pos.startOrPoint || pos.endOrPoint < end)
+
+ /** Does this position precede that position?
+ * This holds if both positions are defined and the end point of this position
+ * is not larger than the start point of the given position.
+ */
+ def precedes(pos: Position): Boolean =
+ isDefined && pos.isDefined && endOrPoint <= pos.startOrPoint
+
+ /** Does this position properly precede the given position `pos` ("properly" meaning their ranges
+ * do not share a common point).
+ */
+ def properlyPrecedes(pos: Position): Boolean =
+ isDefined && pos.isDefined && endOrPoint < pos.startOrPoint
+
+ /** Does this position overlap with that position?
+ * This holds if both positions are ranges and there is an interval of
+ * non-zero length that is shared by both position ranges.
+ */
+ def overlaps(pos: Position): Boolean =
+ isRange && pos.isRange &&
+ ((pos.start < end && start < pos.end) || (start < pos.end && pos.start < end))
+
+ /** Does this position cover the same range as that position?
+ * Holds only if both position are ranges
+ */
+ def sameRange(pos: Position): Boolean =
+ isRange && pos.isRange && start == pos.start && end == pos.end
+
+ def line: Int = throw new UnsupportedOperationException("Position.line")
+
+ def column: Int = throw new UnsupportedOperationException("Position.column")
+
+ /** Convert this to a position around `point` that spans a single source line */
+ def toSingleLine: Position = this
+
+ def lineContent: String =
+ if (isDefined) source.lineToString(line - 1)
+ else "NO_LINE"
+
+ /** Map this position to a position in an original source
+ * file. If the SourceFile is a normal SourceFile, simply
+ * return this.
+ */
+ def inUltimateSource(source : SourceFile): Position =
+ if (source == null) this else source.positionInUltimateSource(this)
+
+ def dbgString: String = toString
+ def safeLine: Int = try line catch { case _: UnsupportedOperationException => -1 }
+
+ def show: String = "["+toString+"]"
+}
+
+case object NoPosition extends Position {
+ override def dbgString = toString
+}
+
+case class FakePos(msg: String) extends Position {
+ override def toString = msg
+}
+
+class OffsetPosition(override val source: SourceFile, override val point: Int) extends Position {
+ override def isDefined = true
+ override def pointOrElse(default: Int): Int = point
+ override def withPoint(off: Int) = new OffsetPosition(source, off)
+ override def withSource(source: SourceFile, shift: Int) = new OffsetPosition(source, point + shift)
+
+ override def line: Int = source.offsetToLine(point) + 1
+
+ override def column: Int = {
+ var idx = source.lineToOffset(source.offsetToLine(point))
+ var col = 0
+ while (idx != point) {
+ col += (if (source.content(idx) == '\t') Position.tabInc - col % Position.tabInc else 1)
+ idx += 1
+ }
+ col + 1
+ }
+
+ override def union(pos: Position) = if (pos.isRange) pos else this
+
+ override def equals(that : Any) = that match {
+ case that : OffsetPosition => point == that.point && source.file == that.source.file
+ case that => false
+ }
+ override def hashCode = point * 37 + source.file.hashCode
+
+ override def toString = {
+ val pointmsg = if (point > source.length) "out-of-bounds-" else "offset="
+ "source-%s,line-%s,%s%s".format(source.file.canonicalPath, line, pointmsg, point)
+ }
+ override def show = "["+point+"]"
+}
+
+/** new for position ranges */
+class RangePosition(source: SourceFile, override val start: Int, point: Int, override val end: Int)
+extends OffsetPosition(source, point) {
+ if (start > end) assert(false, "bad position: "+show)
+ override def isRange: Boolean = true
+ override def isOpaqueRange: Boolean = true
+ override def startOrPoint: Int = start
+ override def endOrPoint: Int = end
+ override def withStart(off: Int) = new RangePosition(source, off, point, end)
+ override def withEnd(off: Int) = new RangePosition(source, start, point, off)
+ override def withPoint(off: Int) = new RangePosition(source, start, off, end)
+ override def withSource(source: SourceFile, shift: Int) = new RangePosition(source, start + shift, point + shift, end + shift)
+ override def focusStart = new OffsetPosition(source, start)
+ override def focus = {
+ if (focusCache eq NoPosition) focusCache = new OffsetPosition(source, point)
+ focusCache
+ }
+ override def focusEnd = new OffsetPosition(source, end)
+ override def makeTransparent = new TransparentPosition(source, start, point, end)
+ override def includes(pos: Position) = pos.isDefined && start <= pos.startOrPoint && pos.endOrPoint <= end
+ override def union(pos: Position): Position =
+ if (pos.isRange) new RangePosition(source, start min pos.start, point, end max pos.end) else this
+
+ override def toSingleLine: Position = source match {
+ case bs: BatchSourceFile
+ if end > 0 && bs.offsetToLine(start) < bs.offsetToLine(end - 1) =>
+ val pointLine = bs.offsetToLine(point)
+ new RangePosition(source, bs.lineToOffset(pointLine), point, bs.lineToOffset(pointLine + 1))
+ case _ => this
+ }
+
+ override def toString = "RangePosition("+source.file.canonicalPath+", "+start+", "+point+", "+end+")"
+ override def show = "["+start+":"+end+"]"
+ private var focusCache: Position = NoPosition
+}
+
+class TransparentPosition(source: SourceFile, start: Int, point: Int, end: Int) extends RangePosition(source, start, point, end) {
+ override def isOpaqueRange: Boolean = false
+ override def isTransparent = true
+ override def makeTransparent = this
+ override def show = "<"+start+":"+end+">"
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/util/Set.scala b/src/reflect/scala/reflect/internal/util/Set.scala
new file mode 100644
index 0000000000..cfc3e7eada
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/Set.scala
@@ -0,0 +1,28 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect.internal.util
+
+/** A common class for lightweight sets.
+ */
+abstract class Set[T <: AnyRef] {
+
+ def findEntry(x: T): T
+
+ def addEntry(x: T): Unit
+
+ def iterator: Iterator[T]
+
+ def foreach[U](f: T => U): Unit = iterator foreach f
+
+ def apply(x: T): Boolean = contains(x)
+
+ @deprecated("use `iterator` instead", "2.9.0") def elements = iterator
+
+ def contains(x: T): Boolean =
+ findEntry(x) ne null
+
+ def toList = iterator.toList
+
+}
diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala
new file mode 100644
index 0000000000..7c80ddd37d
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala
@@ -0,0 +1,161 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+
+package scala.reflect.internal.util
+
+import scala.tools.nsc.io.{ AbstractFile, VirtualFile }
+import scala.collection.mutable.ArrayBuffer
+import annotation.tailrec
+import java.util.regex.Pattern
+import java.io.IOException
+import scala.reflect.internal.Chars._
+
+/** abstract base class of a source file used in the compiler */
+abstract class SourceFile {
+ def content : Array[Char] // normalized, must end in SU
+ def file : AbstractFile
+ def isLineBreak(idx : Int) : Boolean
+ def isSelfContained: Boolean
+ def length : Int
+ def position(offset: Int) : Position = {
+ assert(offset < length, file + ": " + offset + " >= " + length)
+ new OffsetPosition(this, offset)
+ }
+ def position(line: Int, column: Int) : Position = new OffsetPosition(this, lineToOffset(line) + column)
+
+ def offsetToLine(offset: Int): Int
+ def lineToOffset(index : Int): Int
+
+ /** Map a position to a position in the underlying source file.
+ * For regular source files, simply return the argument.
+ */
+ def positionInUltimateSource(position: Position) = position
+ override def toString() = file.name
+ def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString
+ def path = file.path
+
+ def beginsWith(offset: Int, text: String): Boolean =
+ (content drop offset) startsWith text
+
+ def lineToString(index: Int): String =
+ content drop lineToOffset(index) takeWhile (c => !isLineBreakChar(c.toChar)) mkString
+
+ @tailrec
+ final def skipWhitespace(offset: Int): Int =
+ if (content(offset).isWhitespace) skipWhitespace(offset + 1) else offset
+
+ def identifier(pos: Position): Option[String] = None
+}
+
+/** An object representing a missing source file.
+ */
+object NoSourceFile extends SourceFile {
+ def content = Array()
+ def file = NoFile
+ def isLineBreak(idx: Int) = false
+ def isSelfContained = true
+ def length = -1
+ def offsetToLine(offset: Int) = -1
+ def lineToOffset(index : Int) = -1
+ override def toString = "<no source file>"
+}
+
+object NoFile extends VirtualFile("<no file>", "<no file>")
+
+object ScriptSourceFile {
+ /** Length of the script header from the given content, if there is one.
+ * The header begins with "#!" or "::#!" and ends with a line starting
+ * with "!#" or "::!#".
+ */
+ def headerLength(cs: Array[Char]): Int = {
+ val headerPattern = Pattern.compile("""((?m)^(::)?!#.*|^.*/env .*)(\r|\n|\r\n)""")
+ val headerStarts = List("#!", "::#!")
+
+ if (headerStarts exists (cs startsWith _)) {
+ val matcher = headerPattern matcher cs.mkString
+ if (matcher.find) matcher.end
+ else throw new IOException("script file does not close its header with !# or ::!#")
+ }
+ else 0
+ }
+ def stripHeader(cs: Array[Char]): Array[Char] = cs drop headerLength(cs)
+
+ def apply(file: AbstractFile, content: Array[Char]) = {
+ val underlying = new BatchSourceFile(file, content)
+ val headerLen = headerLength(content)
+ val stripped = new ScriptSourceFile(underlying, content drop headerLen, headerLen)
+
+ stripped
+ }
+}
+import ScriptSourceFile._
+
+class ScriptSourceFile(underlying: BatchSourceFile, content: Array[Char], override val start: Int) extends BatchSourceFile(underlying.file, content) {
+ override def isSelfContained = false
+
+ override def positionInUltimateSource(pos: Position) =
+ if (!pos.isDefined) super.positionInUltimateSource(pos)
+ else new OffsetPosition(underlying, pos.point + start)
+}
+
+/** a file whose contents do not change over time */
+class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends SourceFile {
+
+ def this(_file: AbstractFile) = this(_file, _file.toCharArray)
+ def this(sourceName: String, cs: Seq[Char]) = this(new VirtualFile(sourceName), cs.toArray)
+ def this(file: AbstractFile, cs: Seq[Char]) = this(file, cs.toArray)
+
+ override def equals(that : Any) = that match {
+ case that : BatchSourceFile => file.path == that.file.path && start == that.start
+ case _ => false
+ }
+ override def hashCode = file.path.## + start.##
+ val length = content.length
+ def start = 0
+ def isSelfContained = true
+
+ override def identifier(pos: Position) =
+ if (pos.isDefined && pos.source == this && pos.point != -1) {
+ def isOK(c: Char) = isIdentifierPart(c) || isOperatorPart(c)
+ Some(new String(content drop pos.point takeWhile isOK))
+ } else {
+ super.identifier(pos)
+ }
+
+ def isLineBreak(idx: Int) =
+ if (idx >= length) false else {
+ val ch = content(idx)
+ // don't identify the CR in CR LF as a line break, since LF will do.
+ if (ch == CR) (idx + 1 == length) || (content(idx + 1) != LF)
+ else isLineBreakChar(ch)
+ }
+
+ def calculateLineIndices(cs: Array[Char]) = {
+ val buf = new ArrayBuffer[Int]
+ buf += 0
+ for (i <- 0 until cs.length) if (isLineBreak(i)) buf += i + 1
+ buf += cs.length // sentinel, so that findLine below works smoother
+ buf.toArray
+ }
+ private lazy val lineIndices: Array[Int] = calculateLineIndices(content)
+
+ def lineToOffset(index : Int): Int = lineIndices(index)
+
+ private var lastLine = 0
+
+ /** Convert offset to line in this source file
+ * Lines are numbered from 0
+ */
+ def offsetToLine(offset: Int): Int = {
+ val lines = lineIndices
+ def findLine(lo: Int, hi: Int, mid: Int): Int =
+ if (offset < lines(mid)) findLine(lo, mid - 1, (lo + mid - 1) / 2)
+ else if (offset >= lines(mid + 1)) findLine(mid + 1, hi, (mid + 1 + hi) / 2)
+ else mid
+ lastLine = findLine(0, lines.length, lastLine)
+ lastLine
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/util/StatBase.scala b/src/reflect/scala/reflect/internal/util/StatBase.scala
new file mode 100644
index 0000000000..b033ff98bc
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/StatBase.scala
@@ -0,0 +1,97 @@
+package scala.reflect.internal.util
+
+class StatBase {
+
+ private var _enabled = false
+
+ def enabled = _enabled
+ def enabled_=(cond: Boolean) = {
+ if (cond && !_enabled) {
+ val test = new Timer()
+ val start = System.nanoTime()
+ var total = 0L
+ for (i <- 1 to 10000) {
+ val time = System.nanoTime()
+ total += System.nanoTime() - time
+ }
+ val total2 = System.nanoTime() - start
+ println("Enabling statistics, measuring overhead = "+
+ total/10000.0+"ns to "+total2/10000.0+"ns per timer")
+ _enabled = true
+ }
+ }
+
+ def currentTime() =
+ if (_enabled) System.nanoTime() else 0L
+
+ def showPercent(x: Double, base: Double) =
+ if (base == 0) "" else " ("+"%2.1f".format(x / base * 100)+"%)"
+
+ def incCounter(c: Counter) {
+ if (_enabled) c.value += 1
+ }
+
+ def incCounter(c: Counter, delta: Int) {
+ if (_enabled) c.value += delta
+ }
+
+ def startCounter(sc: SubCounter): IntPair =
+ if (_enabled) sc.start() else null
+
+ def stopCounter(sc: SubCounter, start: IntPair) {
+ if (_enabled) sc.stop(start)
+ }
+
+ def startTimer(tm: Timer): LongPair =
+ if (_enabled) tm.start() else null
+
+ def stopTimer(tm: Timer, start: LongPair) {
+ if (_enabled) tm.stop(start)
+ }
+
+ case class IntPair(x: Int, y: Int)
+ case class LongPair(x: Long, y: Long)
+
+ class Counter {
+ var value: Int = 0
+ override def toString = value.toString
+ }
+
+ class SubCounter(c: Counter) {
+ var value: Int = 0
+ def start(): IntPair =
+ if (_enabled) IntPair(value, c.value) else null
+ def stop(prev: IntPair) {
+ if (_enabled) {
+ val IntPair(value0, cvalue0) = prev
+ value = value0 + c.value - cvalue0
+ }
+ }
+ override def toString =
+ value+showPercent(value, c.value)
+ }
+
+ class Timer {
+ var nanos: Long = 0
+ var timings = 0
+ def start(): LongPair =
+ if (_enabled) {
+ timings += 1
+ LongPair(nanos, System.nanoTime())
+ } else null
+ def stop(prev: LongPair) {
+ if (_enabled) {
+ val LongPair(nanos0, start) = prev
+ nanos = nanos0 + System.nanoTime() - start
+ timings += 1
+ }
+ }
+ override def toString = (timings/2)+" spans, "+nanos.toString+"ns"
+ }
+
+ import Predef.Class
+
+ class ClassCounts extends scala.collection.mutable.HashMap[Class[_], Int] {
+ override def default(key: Class[_]) = 0
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala
new file mode 100644
index 0000000000..ef17327fda
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/Statistics.scala
@@ -0,0 +1,34 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect.internal.util
+
+class Statistics extends StatBase {
+ val singletonBaseTypeSeqCount = new Counter
+ val compoundBaseTypeSeqCount = new Counter
+ val typerefBaseTypeSeqCount = new Counter
+ val findMemberCount = new Counter
+ val noMemberCount = new Counter
+ val multMemberCount = new Counter
+ val findMemberNanos = new Timer
+ val asSeenFromCount = new Counter
+ val asSeenFromNanos = new Timer
+ val subtypeCount = new Counter
+ val subtypeNanos = new Timer
+ val sametypeCount = new Counter
+ val rawTypeCount = new Counter
+ val rawTypeFailed = new SubCounter(rawTypeCount)
+ val findMemberFailed = new SubCounter(findMemberCount)
+ val subtypeFailed = new SubCounter(subtypeCount)
+ val rawTypeImpl = new SubCounter(rawTypeCount)
+ val findMemberImpl = new SubCounter(findMemberCount)
+ val subtypeImpl = new SubCounter(subtypeCount)
+ val baseTypeSeqCount = new Counter
+ val baseTypeSeqLenTotal = new Counter
+ val typeSymbolCount = new Counter
+ val classSymbolCount = new Counter
+}
+
+object Statistics extends Statistics
+
diff --git a/src/reflect/scala/reflect/internal/util/StringOps.scala b/src/reflect/scala/reflect/internal/util/StringOps.scala
new file mode 100644
index 0000000000..281ade8134
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/StringOps.scala
@@ -0,0 +1,99 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala.reflect.internal.util
+
+/** This object provides utility methods to extract elements
+ * from Strings.
+ *
+ * @author Martin Odersky
+ * @version 1.0
+ */
+trait StringOps {
+ def onull(s: String) = if (s == null) "" else s
+ def oempty(xs: String*) = xs filterNot (x => x == null || x == "")
+ def ojoin(xs: String*): String = oempty(xs: _*) mkString " "
+ def ojoin(xs: Seq[String], sep: String): String = oempty(xs: _*) mkString sep
+ def ojoinOr(xs: Seq[String], sep: String, orElse: String) = {
+ val ys = oempty(xs: _*)
+ if (ys.isEmpty) orElse else ys mkString sep
+ }
+ def trimTrailingSpace(s: String) = {
+ if (s.length == 0 || !s.charAt(s.length - 1).isWhitespace) s
+ else {
+ var idx = s.length - 1
+ while (idx >= 0 && s.charAt(idx).isWhitespace)
+ idx -= 1
+
+ s.substring(0, idx + 1)
+ }
+ }
+
+ def decompose(str: String, sep: Char): List[String] = {
+ def ws(start: Int): List[String] =
+ if (start == str.length) List()
+ else if (str.charAt(start) == sep) ws(start + 1)
+ else {
+ val end = str.indexOf(sep, start)
+ if (end < 0) List(str.substring(start))
+ else str.substring(start, end) :: ws(end + 1)
+ }
+ ws(0)
+ }
+
+ def words(str: String): List[String] = decompose(str, ' ')
+
+ def stripPrefixOpt(str: String, prefix: String): Option[String] =
+ if (str startsWith prefix) Some(str drop prefix.length)
+ else None
+
+ def stripSuffixOpt(str: String, suffix: String): Option[String] =
+ if (str endsWith suffix) Some(str dropRight suffix.length)
+ else None
+
+ def splitWhere(str: String, f: Char => Boolean, doDropIndex: Boolean = false): Option[(String, String)] =
+ splitAt(str, str indexWhere f, doDropIndex)
+
+ def splitAt(str: String, idx: Int, doDropIndex: Boolean = false): Option[(String, String)] =
+ if (idx == -1) None
+ else Some((str take idx, str drop (if (doDropIndex) idx + 1 else idx)))
+
+ /** Returns a string meaning "n elements".
+ *
+ * @param n ...
+ * @param elements ...
+ * @return ...
+ */
+ def countElementsAsString(n: Int, elements: String): String =
+ n match {
+ case 0 => "no " + elements + "s"
+ case 1 => "one " + elements
+ case 2 => "two " + elements + "s"
+ case 3 => "three " + elements + "s"
+ case 4 => "four " + elements + "s"
+ case _ => "" + n + " " + elements + "s"
+ }
+
+ /** Turns a count into a friendly English description if n<=4.
+ *
+ * @param n ...
+ * @return ...
+ */
+ def countAsString(n: Int): String =
+ n match {
+ case 0 => "none"
+ case 1 => "one"
+ case 2 => "two"
+ case 3 => "three"
+ case 4 => "four"
+ case _ => "" + n
+ }
+}
+
+object StringOps extends StringOps { }
diff --git a/src/reflect/scala/reflect/internal/util/TableDef.scala b/src/reflect/scala/reflect/internal/util/TableDef.scala
new file mode 100644
index 0000000000..d692a6d8f5
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/TableDef.scala
@@ -0,0 +1,94 @@
+package scala.reflect.internal.util
+
+import TableDef._
+
+/** A class for representing tabular data in a way that preserves
+ * its inner beauty. See Exceptional for an example usage.
+ * One creates an instance of TableDef by defining the columns of
+ * the table, then uses that to create an instance of Table by
+ * passing in a sequence of rows.
+ */
+class TableDef[T](_cols: Column[T]*) {
+ /** These operators are about all there is to it.
+ *
+ * ~ appends a column to the table
+ * >> creates a right-justified column and appends it
+ * << creates a left-justified column and appends it
+ * >+ specifies a string to separate the previous column from the next.
+ * if none is specified, a space is used.
+ */
+ def ~(next: Column[T]) = retThis(cols :+= next)
+ def >>(pair: (String, T => Any)) = this ~ Column(pair._1, pair._2, false)
+ def <<(pair: (String, T => Any)) = this ~ Column(pair._1, pair._2, true)
+ def >+(sep: String) = retThis(separators += ((cols.size - 1, sep)))
+
+ /** Below this point should all be considered private/internal.
+ */
+ private var cols: List[Column[T]] = _cols.toList
+ private var separators: Map[Int, String] = Map()
+
+ def defaultSep(index: Int) = if (index > (cols.size - 2)) "" else " "
+ def sepAfter(i: Int): String = separators.getOrElse(i, defaultSep(i))
+ def sepWidths = cols.indices map (i => sepAfter(i).length)
+
+ def columns = cols
+ def colNames = cols map (_.name)
+ def colFunctions = cols map (_.f)
+ def colApply(el: T) = colFunctions map (f => f(el))
+ def retThis(body: => Unit): this.type = { body ; this }
+
+ class Table(val rows: Seq[T]) extends Seq[T] {
+ def iterator = rows.iterator
+ def apply(index: Int) = rows(index)
+ def length = rows.length
+
+ def maxColWidth(col: Column[T]) = col.name +: (rows map col.f) map (_.toString.length) max
+ def specs = cols map (_ formatSpec rows)
+
+ val colWidths = cols map maxColWidth
+ val rowFormat = mkFormatString(sepAfter)
+ val headFormat = mkFormatString(i => " " * sepWidths(i))
+ val argLists = rows map colApply
+
+ val headers = List(
+ headFormat.format(colNames: _*),
+ (colWidths, sepWidths).zipped map ((w1, w2) => "-" * w1 + " " * w2) mkString
+ )
+
+ def mkFormatString(sepf: Int => String): String =
+ specs.zipWithIndex map { case (c, i) => c + sepf(i) } mkString
+
+ def pp(): Unit = allToSeq foreach println
+
+ def toFormattedSeq = argLists map (xs => rowFormat.format(xs: _*))
+ def allToSeq = headers ++ toFormattedSeq
+
+ override def toString = allToSeq mkString "\n"
+ }
+
+ def formatterFor(rows: Seq[T]): T => String = {
+ val formatStr = new Table(rows).rowFormat
+
+ x => formatStr.format(colApply(x) : _*)
+ }
+
+ def table(rows: Seq[T]) = new Table(rows)
+
+ override def toString = cols.mkString("TableDef(", ", ", ")")
+}
+
+object TableDef {
+ case class Column[-T](name: String, f: T => Any, left: Boolean) {
+ def maxWidth(elems: Seq[T]): Int = name +: (elems map f) map (_.toString.length) max
+ def formatSpec(elems: Seq[T]): String = {
+ val justify = if (left) "-" else ""
+ "%" + justify + maxWidth(elems) + "s"
+ }
+ override def toString = {
+ val justify = if (left) "<<" else ">>"
+ justify + "(" + name + ")"
+ }
+ }
+
+ def apply[T](cols: Column[T]*) = new TableDef[T](cols: _*)
+}
diff --git a/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala b/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala
new file mode 100644
index 0000000000..5fbeb5f576
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/TraceSymbolActivity.scala
@@ -0,0 +1,169 @@
+package scala.reflect.internal
+package util
+
+import scala.collection.{ mutable, immutable }
+import language.postfixOps
+
+trait TraceSymbolActivity {
+ val global: SymbolTable
+ import global._
+
+ if (traceSymbolActivity && global.isCompilerUniverse)
+ scala.sys addShutdownHook showAllSymbols()
+
+ private type Set[T] = scala.collection.immutable.Set[T]
+ private val Set = scala.collection.immutable.Set
+
+ val allSymbols = mutable.Map[Int, Symbol]()
+ val allChildren = mutable.Map[Int, List[Int]]() withDefaultValue Nil
+ val prevOwners = mutable.Map[Int, List[(Int, Phase)]]() withDefaultValue Nil
+ val symsCaused = mutable.Map[Int, Int]() withDefaultValue 0
+ val allTrees = mutable.Set[Tree]()
+
+ def recordSymbolsInTree(tree: Tree) {
+ allTrees += tree
+ }
+
+ def recordNewSymbol(sym: Symbol) {
+ if (sym.id > 1) {
+ allSymbols(sym.id) = sym
+ allChildren(sym.owner.id) ::= sym.id
+ }
+ }
+ def recordNewSymbolOwner(sym: Symbol, newOwner: Symbol) {
+ val sid = sym.id
+ val oid = sym.owner.id
+ val nid = newOwner.id
+
+ prevOwners(sid) ::= (oid -> phase)
+ allChildren(oid) = allChildren(oid) filterNot (_ == sid)
+ allChildren(nid) ::= sid
+ }
+
+ /** TODO.
+ */
+ private def reachableDirectlyFromSymbol(sym: Symbol): List[Symbol] = (
+ List(sym.owner, sym.alias, sym.thisSym)
+ ++ sym.children
+ ++ sym.info.parents.map(_.typeSymbol)
+ ++ sym.typeParams
+ ++ sym.paramss.flatten
+ )
+ private def reachable[T](inputs: Traversable[T], mkSymbol: T => Symbol): Set[Symbol] = {
+ def loop(seen: Set[Symbol], remaining: List[Symbol]): Set[Symbol] = {
+ remaining match {
+ case Nil => seen
+ case head :: rest =>
+ if ((head eq null) || (head eq NoSymbol) || seen(head)) loop(seen, rest)
+ else loop(seen + head, rest ++ reachableDirectlyFromSymbol(head).filterNot(seen))
+ }
+ }
+ loop(immutable.Set(), inputs.toList map mkSymbol filterNot (_ eq null) distinct)
+ }
+ private def treeList(t: Tree) = {
+ val buf = mutable.ListBuffer[Tree]()
+ t foreach (buf += _)
+ buf.toList
+ }
+
+ private def reachableFromSymbol(root: Symbol): Set[Symbol] =
+ reachable[Symbol](List(root, root.info.typeSymbol), x => x)
+
+ private def reachableFromTree(tree: Tree): Set[Symbol] =
+ reachable[Tree](treeList(tree), _.symbol)
+
+ private def signature(id: Int) = runBeforeErasure(allSymbols(id).defString)
+
+ private def dashes(s: Any): String = ("" + s) map (_ => '-')
+ private def show(s1: Any, ss: Any*) {
+ println("%-12s".format(s1) +: ss mkString " ")
+ }
+ private def showHeader(s1: Any, ss: Any*) {
+ show(s1, ss: _*)
+ show(dashes(s1), ss map dashes: _*)
+ }
+ private def showSym(sym: Symbol) {
+ def prefix = (" " * (sym.ownerChain.length - 1)) + sym.id
+ try println("%s#%s %s".format(prefix, sym.accurateKindString, sym.name.decode))
+ catch {
+ case x => println(prefix + " failed: " + x)
+ }
+ allChildren(sym.id).sorted foreach showIdAndRemove
+ }
+ private def showIdAndRemove(id: Int) {
+ allSymbols remove id foreach showSym
+ }
+ private def symbolStr(id: Int): String = {
+ if (id == 1) "NoSymbol" else {
+ val sym = allSymbols(id)
+ sym.accurateKindString + " " + sym.name.decode
+ }
+ }
+ private def ownerStr(id: Int): String = {
+ val sym = allSymbols(id)
+ sym.name.decode + "#" + sym.id
+ }
+
+ private def freq[T, U](xs: collection.Traversable[T])(fn: T => U): List[(U, Int)] = {
+ val ys = xs groupBy fn mapValues (_.size)
+ ys.toList sortBy (-_._2)
+ }
+
+ private def showMapFreq[T](xs: collection.Map[T, Traversable[_]])(showFn: T => String) {
+ xs.mapValues(_.size).toList.sortBy(-_._2) take 100 foreach { case (k, size) =>
+ show(size, showFn(k))
+ }
+ println("\n")
+ }
+ private def showFreq[T, U](xs: Traversable[T])(groupFn: T => U, showFn: U => String = (x: U) => "" + x) = {
+ showMapFreq(xs.toList groupBy groupFn)(showFn)
+ }
+ private lazy val findErasurePhase: Phase = {
+ var ph = phase
+ while (ph != NoPhase && ph.name != "erasure") {
+ ph = ph.prev
+ }
+ ph
+ }
+ private def runBeforeErasure[T](body: => T): T = atPhase(findErasurePhase)(body)
+
+ def showAllSymbols() {
+ if (!traceSymbolActivity) return
+ allSymbols(1) = NoSymbol
+
+ println("" + allSymbols.size + " symbols created.")
+ println("")
+
+ showHeader("descendants", "symbol")
+ showFreq(allSymbols.values flatMap (_.ownerChain drop 1))(_.id, symbolStr)
+
+ showHeader("children", "symbol")
+ showMapFreq(allChildren)(symbolStr)
+
+ if (prevOwners.nonEmpty) {
+ showHeader("prev owners", "symbol")
+ showMapFreq(prevOwners) { k =>
+ val owners = (((allSymbols(k).owner.id, NoPhase)) :: prevOwners(k)) map {
+ case (oid, NoPhase) => "-> owned by " + ownerStr(oid)
+ case (oid, ph) => "-> owned by %s (until %s)".format(ownerStr(oid), ph)
+ }
+ signature(k) :: owners mkString "\n "
+ }
+ }
+
+ val nameFreq = allSymbols.values.toList groupBy (_.name)
+ showHeader("frequency", "%-15s".format("name"), "owners")
+ showMapFreq(nameFreq) { name =>
+ "%-15s %s".format(name.decode, {
+ val owners = freq(nameFreq(name))(_.owner)
+
+ "%4s owners (%s)".format(
+ owners.size,
+ owners.take(3).map({ case (k, v) => v + "/" + k }).mkString(", ") + ", ..."
+ )
+ })
+ }
+
+ allSymbols.keys.toList.sorted foreach showIdAndRemove
+ }
+}
diff --git a/src/reflect/scala/reflect/internal/util/WeakHashSet.scala b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala
new file mode 100644
index 0000000000..9882aad5e5
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/WeakHashSet.scala
@@ -0,0 +1,61 @@
+package scala.reflect.internal.util
+
+import scala.collection.mutable
+import scala.collection.mutable.ArrayBuffer
+import scala.collection.mutable.Builder
+import scala.collection.mutable.SetBuilder
+import scala.collection.generic.Clearable
+import scala.runtime.AbstractFunction1
+
+/** A bare-bones implementation of a mutable `Set` that uses weak references
+ * to hold the elements.
+ *
+ * This implementation offers only add/remove/test operations,
+ * therefore it does not fulfill the contract of Scala collection sets.
+ */
+class WeakHashSet[T <: AnyRef] extends AbstractFunction1[T, Boolean] with Clearable {
+ private val underlying = mutable.HashSet[WeakReferenceWithEquals[T]]()
+
+ /** Add the given element to this set. */
+ def +=(elem: T): this.type = {
+ underlying += new WeakReferenceWithEquals(elem)
+ this
+ }
+
+ /** Remove the given element from this set. */
+ def -=(elem: T): this.type = {
+ underlying -= new WeakReferenceWithEquals(elem)
+ this
+ }
+
+ /** Does the given element belong to this set? */
+ def contains(elem: T): Boolean =
+ underlying.contains(new WeakReferenceWithEquals(elem))
+
+ /** Does the given element belong to this set? */
+ def apply(elem: T): Boolean = contains(elem)
+
+ /** Return the number of elements in this set, including reclaimed elements. */
+ def size = underlying.size
+
+ /** Remove all elements in this set. */
+ def clear() = underlying.clear()
+}
+
+/** A WeakReference implementation that implements equals and hashCode by
+ * delegating to the referent.
+ */
+class WeakReferenceWithEquals[T <: AnyRef](ref: T) {
+ def get(): T = underlying.get()
+
+ override val hashCode = ref.hashCode
+
+ override def equals(other: Any): Boolean = other match {
+ case wf: WeakReferenceWithEquals[_] =>
+ underlying.get() == wf.get()
+ case _ =>
+ false
+ }
+
+ private val underlying = new java.lang.ref.WeakReference(ref)
+}
diff --git a/src/reflect/scala/reflect/makro/Aliases.scala b/src/reflect/scala/reflect/makro/Aliases.scala
new file mode 100644
index 0000000000..c78c9a6a04
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Aliases.scala
@@ -0,0 +1,27 @@
+package scala.reflect
+package makro
+
+trait Aliases {
+ self: Context =>
+
+ type Symbol = universe.Symbol
+ type Type = universe.Type
+ type Name = universe.Name
+ type TermName = universe.TermName
+ type TypeName = universe.TypeName
+ type Tree = universe.Tree
+ // type Position = universe.Position
+ type Scope = universe.Scope
+ type Modifiers = universe.Modifiers
+
+ type Expr[+T] = universe.Expr[T]
+ val Expr = universe.Expr
+
+ type TypeTag[T] = universe.TypeTag[T]
+ type ConcreteTypeTag[T] = universe.ConcreteTypeTag[T]
+ val TypeTag = universe.TypeTag
+ val ConcreteTypeTag = universe.ConcreteTypeTag
+ def typeTag[T](implicit ttag: TypeTag[T]) = ttag
+ def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag
+ def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
+}
diff --git a/src/reflect/scala/reflect/makro/CapturedVariables.scala b/src/reflect/scala/reflect/makro/CapturedVariables.scala
new file mode 100644
index 0000000000..592e28b3b2
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/CapturedVariables.scala
@@ -0,0 +1,21 @@
+package scala.reflect
+package makro
+
+trait CapturedVariables {
+ self: Context =>
+
+ import mirror._
+
+ /** Mark a variable as captured; i.e. force boxing in a *Ref type.
+ */
+ def captureVariable(vble: Symbol): Unit
+
+ /** Mark given identifier as a reference to a captured variable itself
+ * suppressing dereferencing with the `elem` field.
+ */
+ def referenceCapturedVariable(vble: Symbol): Tree
+
+ /** Convert type of a captured variable to *Ref type.
+ */
+ def capturedVariableType(vble: Symbol): Type
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/Context.scala b/src/reflect/scala/reflect/makro/Context.scala
new file mode 100644
index 0000000000..f9858a063c
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Context.scala
@@ -0,0 +1,40 @@
+package scala.reflect
+package makro
+
+import language.experimental.macros
+
+// todo. introduce context hierarchy
+// the most lightweight context should just expose the stuff from the SIP
+// the full context should include all traits from scala.reflect.makro (and probably reside in scala-compiler.jar)
+
+trait Context extends Aliases
+ with CapturedVariables
+ with Enclosures
+ with Infrastructure
+ with Names
+ with Reifiers
+ with FrontEnds
+ with Settings
+ with Typers
+ with Parsers
+ with Exprs
+ with TypeTags
+ with Evals
+ with ExprUtils {
+
+ /** The compile-time universe */
+ val universe: Universe
+
+ /** The mirror of the compile-time universe */
+ val mirror: MirrorOf[universe.type]
+
+ /** The type of the prefix tree from which the macro is selected */
+ type PrefixType
+
+ /** The prefix tree from which the macro is selected */
+ val prefix: Expr[PrefixType]
+
+ /** Alias to the underlying mirror's reify */
+ // implementation is magically hardwired to `scala.reflect.makro.runtime.ContextReifiers`
+ def reify[T](expr: T): Expr[T] = macro ???
+}
diff --git a/src/reflect/scala/reflect/makro/Enclosures.scala b/src/reflect/scala/reflect/makro/Enclosures.scala
new file mode 100644
index 0000000000..69bd8d09c7
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Enclosures.scala
@@ -0,0 +1,54 @@
+package scala.reflect
+package makro
+
+trait Enclosures {
+ self: Context =>
+
+ /** The tree that undergoes macro expansion.
+ * Can be useful to get an offset or a range position of the entire tree being processed.
+ */
+ val macroApplication: Tree
+
+ /** Contexts that represent macros in-flight, including the current one. Very much like a stack trace, but for macros only.
+ * Can be useful for interoperating with other macros and for imposing compiler-friendly limits on macro expansion.
+ *
+ * Is also priceless for emitting sane error messages for macros that are called by other macros on synthetic (i.e. position-less) trees.
+ * In that dire case navigate the ``enclosingMacros'' stack, and it will most likely contain at least one macro with a position-ful macro application.
+ * See ``enclosingPosition'' for a default implementation of this logic.
+ *
+ * Unlike `openMacros`, this is a val, which means that it gets initialized when the context is created
+ * and always stays the same regardless of whatever happens during macro expansion.
+ */
+ val enclosingMacros: List[Context]
+
+ /** Types along with corresponding trees for which implicit arguments are currently searched.
+ * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
+ *
+ * Unlike `openImplicits`, this is a val, which means that it gets initialized when the context is created
+ * and always stays the same regardless of whatever happens during macro expansion.
+ */
+ val enclosingImplicits: List[(Type, Tree)]
+
+ /** Tries to guess a position for the enclosing application.
+ * But that is simple, right? Just dereference ``pos'' of ``macroApplication''? Not really.
+ * If we're in a synthetic macro expansion (no positions), we must do our best to infer the position of something that triggerd this expansion.
+ * Surprisingly, quite often we can do this by navigation the ``enclosingMacros'' stack.
+ */
+ val enclosingPosition: Position
+
+ /** Tree that corresponds to the enclosing application, or EmptyTree if not applicable.
+ */
+ val enclosingApplication: Tree
+
+ /** Tree that corresponds to the enclosing method, or EmptyTree if not applicable.
+ */
+ val enclosingMethod: Tree
+
+ /** Tree that corresponds to the enclosing class, or EmptyTree if not applicable.
+ */
+ val enclosingClass: Tree
+
+ /** Compilation unit that contains this macro application.
+ */
+ val enclosingUnit: CompilationUnit
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/Evals.scala b/src/reflect/scala/reflect/makro/Evals.scala
new file mode 100644
index 0000000000..4e5fc2f97f
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Evals.scala
@@ -0,0 +1,9 @@
+package scala.reflect
+package makro
+
+trait Evals {
+ self: Context =>
+
+ /** .. */
+ def eval[T](expr: Expr[T]): T
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/ExprUtils.scala b/src/reflect/scala/reflect/makro/ExprUtils.scala
new file mode 100644
index 0000000000..c3e5cc6bc1
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/ExprUtils.scala
@@ -0,0 +1,32 @@
+package scala.reflect
+package makro
+
+trait ExprUtils {
+ self: Context =>
+
+ def literalNull: Expr[Null]
+
+ def literalUnit: Expr[Unit]
+
+ def literalTrue: Expr[Boolean]
+
+ def literalFalse: Expr[Boolean]
+
+ def literal(x: Boolean): Expr[Boolean]
+
+ def literal(x: Byte): Expr[Byte]
+
+ def literal(x: Short): Expr[Short]
+
+ def literal(x: Int): Expr[Int]
+
+ def literal(x: Long): Expr[Long]
+
+ def literal(x: Float): Expr[Float]
+
+ def literal(x: Double): Expr[Double]
+
+ def literal(x: String): Expr[String]
+
+ def literal(x: Char): Expr[Char]
+}
diff --git a/src/reflect/scala/reflect/makro/Exprs.scala b/src/reflect/scala/reflect/makro/Exprs.scala
new file mode 100644
index 0000000000..b4f8e7ac4e
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Exprs.scala
@@ -0,0 +1,8 @@
+package scala.reflect
+package makro
+
+trait Exprs {
+ self: Context =>
+
+ def Expr[T: TypeTag](tree: Tree): Expr[T]
+}
diff --git a/src/reflect/scala/reflect/makro/FrontEnds.scala b/src/reflect/scala/reflect/makro/FrontEnds.scala
new file mode 100644
index 0000000000..5087f90174
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/FrontEnds.scala
@@ -0,0 +1,42 @@
+package scala.reflect
+package makro
+
+trait FrontEnds extends scala.reflect.api.FrontEnds {
+ self: Context =>
+
+ import mirror._
+
+ type Position = universe.Position
+
+ /** Exposes means to control the compiler UI */
+ def frontEnd: FrontEnd
+ def setFrontEnd(frontEnd: FrontEnd): this.type
+ def withFrontEnd[T](frontEnd: FrontEnd)(op: => T): T
+
+ /** For sending a message which should not be labeled as a warning/error,
+ * but also shouldn't require -verbose to be visible.
+ * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ */
+ def echo(pos: Position, msg: String): Unit
+
+ /** Informational messages, suppressed unless -verbose or force=true.
+ * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ */
+ def info(pos: Position, msg: String, force: Boolean): Unit
+
+ /** Warnings and errors.
+ * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ */
+ def hasWarnings: Boolean
+ def hasErrors: Boolean
+ def warning(pos: Position, msg: String): Unit
+ def error(pos: Position, msg: String): Unit
+
+ /** Abruptly terminates current macro expansion leaving a note about what happened.
+ * Use ``enclosingPosition'' if you're in doubt what position to pass to ``pos''.
+ */
+ def abort(pos: Position, msg: String): Nothing
+
+ /** Drops into interactive mode if supported by the compiler UI */
+ def interactive(): Unit
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/Infrastructure.scala b/src/reflect/scala/reflect/makro/Infrastructure.scala
new file mode 100644
index 0000000000..e6bfe33366
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Infrastructure.scala
@@ -0,0 +1,103 @@
+package scala.reflect
+package makro
+
+trait Infrastructure {
+ self: Context =>
+
+ /** Determines whether the compiler expanding a macro targets JVM.
+ */
+ val forJVM: Boolean
+
+ /** Determines whether the compiler expanding a macro targets CLR.
+ */
+ val forMSIL: Boolean
+
+ /** Determines whether the compiler expanding a macro is a presentation compiler.
+ */
+ val forInteractive: Boolean
+
+ /** Determines whether the compiler expanding a macro is a Scaladoc compiler.
+ */
+ val forScaladoc: Boolean
+
+ /** Exposes current compilation run.
+ */
+ val currentRun: Run
+
+ /** Exposes library classpath.
+ */
+ val libraryClassPath: List[java.net.URL]
+
+ /** Exposes a classloader that corresponds to the library classpath.
+ *
+ * With this classloader you can perform on-the-fly evaluation of macro arguments.
+ * For example, consider this code snippet:
+ *
+ * def staticEval[T](x: T) = macro staticEval[T]
+ *
+ * def staticEval[T: c.TypeTag](c: Context)(x: c.Expr[T]) = {
+ * import scala.reflect.runtime.{universe => ru}
+ * val mirror = ru.runtimeMirror(c.libraryClassLoader)
+ * import scala.tools.reflect.ToolBox
+ * val toolBox = mirror.mkToolBox()
+ * val importer = ru.mkImporter(c.universe).asInstanceOf[ru.Importer { val from: c.universe.type }]
+ * val tree = c.resetAllAttrs(x.tree.duplicate)
+ * val imported = importer.importTree(tree)
+ * val valueOfX = toolBox.runExpr(imported).asInstanceOf[T]
+ * ...
+ * }
+ *
+ * // [Eugene++] using this guy will tremendously slow down the compilation
+ * // https://twitter.com/xeno_by/status/201248317831774208
+ * // todo. we need to address this somehow
+ */
+ def libraryClassLoader: ClassLoader
+
+ /** As seen by macro API, compilation run is an opaque type that can be deconstructed into:
+ * 1) Current compilation unit
+ * 2) List of all compilation units that comprise the run
+ */
+ type Run
+
+ val Run: RunExtractor
+
+ abstract class RunExtractor {
+ def unapply(run: Run): Option[(CompilationUnit, List[CompilationUnit])]
+ }
+
+ /** As seen by macro API, compilation unit is an opaque type that can be deconstructed into:
+ * 1) File that corresponds to the unit (if not applicable, null)
+ * 2) Content of the file (if not applicable, empty array)
+ * 3) Body, i.e. the AST that represents the compilation unit
+ */
+ type CompilationUnit
+
+ val CompilationUnit: CompilationUnitExtractor
+
+ abstract class CompilationUnitExtractor {
+ def unapply(compilationUnit: CompilationUnit): Option[(java.io.File, Array[Char], Tree)]
+ }
+
+ /** Returns a macro definition which triggered this macro expansion.
+ */
+ val currentMacro: Symbol
+
+ // todo. redo caches as discussed on Reflecting Meeting 2012/03/29
+ // https://docs.google.com/document/d/1oUZGQpdt2qwioTlJcSt8ZFQwVLTvpxn8xa67P8OGVpU/edit
+
+ /** A cache shared by all invocations of all macros across all compilation runs.
+ *
+ * Needs to be used with extreme care, since memory leaks here will swiftly crash the presentation compiler.
+ * For example, Scala IDE typically launches a compiler run on every edit action so there might be hundreds of runs per minute.
+ */
+ val globalCache: collection.mutable.Map[Any, Any]
+
+ /** A cache shared by all invocations of the same macro within a single compilation run.
+ *
+ * This cache is cleared automatically after a compilation run is completed or abandoned.
+ * It is also specific to a particular macro definition.
+ *
+ * To share data between different macros and/or different compilation runs, use ``globalCache''.
+ */
+ val cache: collection.mutable.Map[Any, Any]
+}
diff --git a/src/reflect/scala/reflect/makro/Names.scala b/src/reflect/scala/reflect/makro/Names.scala
new file mode 100644
index 0000000000..909976d83c
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Names.scala
@@ -0,0 +1,15 @@
+package scala.reflect
+package makro
+
+trait Names {
+ self: Context =>
+
+ /** Creates a fresh string */
+ def fresh(): String
+
+ /** Creates a fresh string from the provided string */
+ def fresh(name: String): String
+
+ /** Creates a fresh name from the provided name */
+ def fresh[NameType <: Name](name: NameType): NameType
+}
diff --git a/src/reflect/scala/reflect/makro/Parsers.scala b/src/reflect/scala/reflect/makro/Parsers.scala
new file mode 100644
index 0000000000..9866b7e491
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Parsers.scala
@@ -0,0 +1,18 @@
+package scala.reflect
+package makro
+
+trait Parsers {
+ self: Context =>
+
+ /** .. */
+ // todo. distinguish between `parseExpr` and `parse`
+ def parse(code: String): Tree
+
+ /** Represents an error during parsing
+ */
+ type ParseError <: Throwable
+ val ParseError: ParseErrorExtractor
+ abstract class ParseErrorExtractor {
+ def unapply(error: ParseError): Option[(Position, String)]
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/Reifiers.scala b/src/reflect/scala/reflect/makro/Reifiers.scala
new file mode 100644
index 0000000000..f39f56f935
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Reifiers.scala
@@ -0,0 +1,91 @@
+package scala.reflect
+package makro
+
+trait Reifiers {
+ self: Context =>
+
+ /** Reification prefix that refers to the base reflexive universe, ``scala.reflect.basis''.
+ * Providing it for the ``prefix'' parameter of ``reifyTree'' or ``reifyType'' will create a tree that can be inspected at runtime.
+ */
+ val basisUniverse: Tree
+
+ /** Reification prefix that refers to the runtime reflexive universe, ``scala.reflect.runtime.universe''.
+ * Providing it for the ``prefix'' parameter of ``reifyTree'' or ``reifyType'' will create a full-fledged tree that can be inspected at runtime.
+ */
+ val runtimeUniverse: Tree
+
+ /** Given a tree, generate a tree that when compiled and executed produces the original tree.
+ * For more information and examples see the documentation for ``Universe.reify''.
+ *
+ * The produced tree will be bound to the specified ``universe'' and ``mirror''.
+ * Possible values for ``universe'' include ``basisUniverse'' and ``runtimeUniverse''.
+ * Possible values for ``mirror'' include ``EmptyTree'' (in that case the reifier will automatically pick an appropriate mirror).
+ *
+ * This function is deeply connected to ``Universe.reify'', a macro that reifies arbitrary expressions into runtime trees.
+ * They do very similar things (``Universe.reify'' calls ``Context.reifyTree'' to implement itself), but they operate on different metalevels (see below).
+ *
+ * Let's study the differences between ``Context.reifyTree'' and ``Universe.reify'' on an example of using them inside a ``fooMacro'' macro:
+ *
+ * * Since reify itself is a macro, it will be executed when fooMacro is being compiled (metalevel -1)
+ * and will produce a tree that when evaluated during macro expansion of fooMacro (metalevel 0) will recreate the input tree.
+ *
+ * This provides a facility analogous to quasi-quoting. Writing "reify{ expr }" will generate an AST that represents expr.
+ * Afterwards this AST (or its parts) can be used to construct the return value of fooMacro.
+ *
+ * * reifyTree is evaluated during macro expansion (metalevel 0)
+ * and will produce a tree that when evaluated during the runtime of the program (metalevel 1) will recreate the input tree.
+ *
+ * This provides a way to retain certain trees from macro expansion time to be inspected later, in the runtime.
+ * For example, DSL authors may find it useful to capture DSL snippets into ASTs that are then processed at runtime in a domain-specific way.
+ *
+ * Also note the difference between universes of the runtime trees produced by two reifies:
+ *
+ * * The result of compiling and running the result of reify will be bound to the Universe that called reify.
+ * This is possible because it's a macro, so it can generate whatever code it wishes.
+ *
+ * * The result of compiling and running the result of reifyTree will be the ``prefix'' that needs to be passed explicitly.
+ * This happens because the Universe of the evaluated result is from a different metalevel than the Context the called reify.
+ *
+ * Typical usage of this function is to retain some of the trees received/created by a macro
+ * into the form that can be inspected (via pattern matching) or compiled/run (by a reflective ToolBox) during the runtime.
+ */
+ def reifyTree(universe: Tree, mirror: Tree, tree: Tree): Tree
+
+ /** Given a type, generate a tree that when compiled and executed produces the original type.
+ * The produced tree will be bound to the specified ``universe'' and ``mirror''.
+ * For more information and examples see the documentation for ``Context.reifyTree'' and ``Universe.reify''.
+ */
+ def reifyType(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean = false): Tree
+
+ /** Given a type, generate a tree that when compiled and executed produces the runtime class of the original type.
+ * If ``concrete'' is true, then this function will bail on types, who refer to abstract types (like `ClassTag` does).
+ */
+ def reifyRuntimeClass(tpe: Type, concrete: Boolean = true): Tree
+
+ /** Given a type, generate a tree that when compiled and executed produces the runtime class of the enclosing class or module.
+ * Returns `EmptyTree` if there does not exist an enclosing class or module.
+ */
+ def reifyEnclosingRuntimeClass: Tree
+
+ /** Undoes reification of a tree.
+ *
+ * This reversion doesn't simply restore the original tree (that would lose the context of reification),
+ * but does something more involved that conforms to the following laws:
+ *
+ * 1) unreifyTree(reifyTree(tree)) != tree // unreified tree is tree + saved context
+ * // in current implementation, the result of unreify is opaque
+ * // i.e. there's no possibility to inspect underlying tree/context
+ *
+ * 2) reifyTree(unreifyTree(reifyTree(tree))) == reifyTree(tree) // the result of reifying a tree in its original context equals to
+ * // the result of reifying a tree along with its saved context
+ *
+ * 3) compileAndEval(unreifyTree(reifyTree(tree))) ~ compileAndEval(tree) // at runtime original and unreified trees are behaviorally equivalent
+ */
+ def unreifyTree(tree: Tree): Tree
+}
+
+// made these guys non path-dependent, otherwise exception handling quickly becomes a mess
+
+case class ReificationError(val pos: reflect.api.PositionApi, val msg: String) extends Throwable(msg)
+
+case class UnexpectedReificationError(val pos: reflect.api.PositionApi, val msg: String, val cause: Throwable = null) extends Throwable(msg, cause)
diff --git a/src/reflect/scala/reflect/makro/Settings.scala b/src/reflect/scala/reflect/makro/Settings.scala
new file mode 100644
index 0000000000..c6c7e5870b
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Settings.scala
@@ -0,0 +1,40 @@
+package scala.reflect
+package makro
+
+trait Settings {
+ self: Context =>
+
+ /** Exposes macro-specific settings as a list of strings.
+ * These settings are passed to the compiler via the "-Xmacro-settings:setting1,setting2...,settingN" command-line option.
+ */
+ def settings: List[String]
+
+ /** Exposes current compiler settings as a list of options.
+ * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options.
+ */
+ // [Eugene] ugly? yes, but I don't really fancy copy/pasting all our settings here and keep it synchronized at all times
+ // why all settings? because macros need to be in full control of the stuff going on
+ // maybe later we can implement a gettable/settable list of important settings, but for now let's leave it like that
+ def compilerSettings: List[String]
+
+ /** Updates current compiler settings with an option string.
+ * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options.
+ * todo. http://groups.google.com/group/scala-internals/browse_thread/thread/07c18cff41f59203
+ */
+ def setCompilerSettings(options: String): this.type
+
+ /** Updates current compiler settings with a list of options.
+ * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options.
+ */
+ def setCompilerSettings(options: List[String]): this.type
+
+ /** Temporary sets compiler settings to a given option string and executes a given closure.
+ * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options.
+ */
+ def withCompilerSettings[T](options: String)(op: => T): T
+
+ /** Temporary sets compiler settings to a given list of options and executes a given closure.
+ * Use `scalac -help`, `scalac -X` and `scalac -Y` to learn about currently supported options.
+ */
+ def withCompilerSettings[T](options: List[String])(op: => T): T
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/TreeBuilder.scala b/src/reflect/scala/reflect/makro/TreeBuilder.scala
new file mode 100644
index 0000000000..c4179b9c80
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/TreeBuilder.scala
@@ -0,0 +1,60 @@
+package scala.reflect
+package makro
+
+// [Eugene] I added some stuff that was necessary for typetag materialization macros
+// but we should think it over and pick other generally useful stuff
+// same goes for tree traversers/transformers, type maps, etc
+// and once we expose all that, there's another question: how do we stay in sync?
+abstract class TreeBuilder {
+ val global: Universe
+
+ import global._
+ import definitions._
+
+ /** Builds a reference to value whose type is given stable prefix.
+ * The type must be suitable for this. For example, it
+ * must not be a TypeRef pointing to an abstract type variable.
+ */
+ def mkAttributedQualifier(tpe: Type): Tree
+
+ /** Builds a reference to value whose type is given stable prefix.
+ * If the type is unsuitable, e.g. it is a TypeRef for an
+ * abstract type variable, then an Ident will be made using
+ * termSym as the Ident's symbol. In that case, termSym must
+ * not be NoSymbol.
+ */
+ def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree
+
+ /** Builds a typed reference to given symbol with given stable prefix. */
+ def mkAttributedRef(pre: Type, sym: Symbol): Tree
+
+ /** Builds a typed reference to given symbol. */
+ def mkAttributedRef(sym: Symbol): Tree
+
+ /** Builds a typed This reference to given symbol. */
+ def mkAttributedThis(sym: Symbol): Tree
+
+ /** Builds a typed Ident with an underlying symbol. */
+ def mkAttributedIdent(sym: Symbol): Tree
+
+ /** Builds a typed Select with an underlying symbol. */
+ def mkAttributedSelect(qual: Tree, sym: Symbol): Tree
+
+ /** A creator for method calls, e.g. fn[T1, T2, ...](v1, v2, ...)
+ * There are a number of variations.
+ *
+ * @param receiver symbol of the method receiver
+ * @param methodName name of the method to call
+ * @param targs type arguments (if Nil, no TypeApply node will be generated)
+ * @param args value arguments
+ * @return the newly created trees.
+ */
+ def mkMethodCall(receiver: Symbol, methodName: Name, targs: List[Type], args: List[Tree]): Tree
+ def mkMethodCall(method: Symbol, targs: List[Type], args: List[Tree]): Tree
+ def mkMethodCall(method: Symbol, args: List[Tree]): Tree
+ def mkMethodCall(target: Tree, args: List[Tree]): Tree
+ def mkMethodCall(receiver: Symbol, methodName: Name, args: List[Tree]): Tree
+ def mkMethodCall(receiver: Tree, method: Symbol, targs: List[Type], args: List[Tree]): Tree
+ def mkMethodCall(target: Tree, targs: List[Type], args: List[Tree]): Tree
+ def mkNullaryCall(method: Symbol, targs: List[Type]): Tree
+}
diff --git a/src/reflect/scala/reflect/makro/TypeTags.scala b/src/reflect/scala/reflect/makro/TypeTags.scala
new file mode 100644
index 0000000000..3251c27908
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/TypeTags.scala
@@ -0,0 +1,9 @@
+package scala.reflect
+package makro
+
+trait TypeTags {
+ self: Context =>
+
+ def TypeTag[T](tpe: Type): TypeTag[T]
+ def ConcreteTypeTag[T](tpe: Type): ConcreteTypeTag[T]
+}
diff --git a/src/reflect/scala/reflect/makro/Typers.scala b/src/reflect/scala/reflect/makro/Typers.scala
new file mode 100644
index 0000000000..2610d7dd50
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Typers.scala
@@ -0,0 +1,86 @@
+package scala.reflect
+package makro
+
+trait Typers {
+ self: Context =>
+
+ import universe._
+
+ /** Contexts that represent macros in-flight, including the current one. Very much like a stack trace, but for macros only.
+ * Can be useful for interoperating with other macros and for imposing compiler-friendly limits on macro expansion.
+ *
+ * Is also priceless for emitting sane error messages for macros that are called by other macros on synthetic (i.e. position-less) trees.
+ * In that dire case navigate the ``openMacros'' stack, and it will most likely contain at least one macro with a position-ful macro application.
+ * See ``enclosingPosition'' for a default implementation of this logic.
+ *
+ * Unlike `enclosingMacros`, this is a def, which means that it gets recalculated on every invocation,
+ * so it might change depending on what is going on during macro expansion.
+ */
+ def openMacros: List[Context]
+
+ /** Types along with corresponding trees for which implicit arguments are currently searched.
+ * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
+ *
+ * Unlike `enclosingImplicits`, this is a def, which means that it gets recalculated on every invocation,
+ * so it might change depending on what is going on during macro expansion.
+ */
+ def openImplicits: List[(Type, Tree)]
+
+ /** Typechecks the provided tree against the expected type ``pt'' in the macro callsite context.
+ *
+ * If ``silent'' is false, ``TypeError'' will be thrown in case of a typecheck error.
+ * If ``silent'' is true, the typecheck is silent and will return ``EmptyTree'' if an error occurs.
+ * Such errors don't vanish and can be inspected by turning on -Ymacro-debug-verbose.
+ * Unlike in ``inferImplicitValue'' and ``inferImplicitView'', ``silent'' is false by default.
+ *
+ * Typechecking can be steered with the following optional parameters:
+ * ``withImplicitViewsDisabled'' recursively prohibits implicit views (though, implicit vals will still be looked up and filled in), default value is false
+ * ``withMacrosDisabled'' recursively prohibits macro expansions and macro-based implicits, default value is false
+ */
+ def typeCheck(tree: Tree, pt: Type = WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree
+
+ /** Infers an implicit value of the expected type ``pt'' in the macro callsite context.
+ * Optional ``pos'' parameter provides a position that will be associated with the implicit search.
+ *
+ * If ``silent'' is false, ``TypeError'' will be thrown in case of an inference error.
+ * If ``silent'' is true, the typecheck is silent and will return ``EmptyTree'' if an error occurs.
+ * Such errors don't vanish and can be inspected by turning on -Xlog-implicits.
+ * Unlike in ``typeCheck'', ``silent'' is true by default.
+ */
+ def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree
+
+ /** Infers an implicit view from the provided tree ``tree'' from the type ``from'' to the type ``to'' in the macro callsite context.
+ *
+ * Optional ``pos'' parameter provides a position that will be associated with the implicit search.
+ * Another optional parameter, ``reportAmbiguous`` controls whether ambiguous implicit errors should be reported.
+ * If we search for a view simply to find out whether one type is coercible to another, it might be desirable to set this flag to ``false''.
+ *
+ * If ``silent'' is false, ``TypeError'' will be thrown in case of an inference error.
+ * If ``silent'' is true, the typecheck is silent and will return ``EmptyTree'' if an error occurs.
+ * Such errors don't vanish and can be inspected by turning on -Xlog-implicits.
+ * Unlike in ``typeCheck'', ``silent'' is true by default.
+ */
+ def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, reportAmbiguous: Boolean = true, pos: Position = enclosingPosition): Tree
+
+ /** Recursively resets symbols and types in a given tree.
+ *
+ * Note that this does not revert the tree to its pre-typer shape.
+ * For more info, read up https://issues.scala-lang.org/browse/SI-5464.
+ */
+ def resetAllAttrs(tree: Tree): Tree
+
+ /** Recursively resets locally defined symbols and types in a given tree.
+ *
+ * Note that this does not revert the tree to its pre-typer shape.
+ * For more info, read up https://issues.scala-lang.org/browse/SI-5464.
+ */
+ def resetLocalAttrs(tree: Tree): Tree
+
+ /** Represents an error during typechecking
+ */
+ type TypeError <: Throwable
+ val TypeError: TypeErrorExtractor
+ abstract class TypeErrorExtractor {
+ def unapply(error: TypeError): Option[(Position, String)]
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/Universe.scala b/src/reflect/scala/reflect/makro/Universe.scala
new file mode 100644
index 0000000000..ffc4042a0a
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/Universe.scala
@@ -0,0 +1,118 @@
+package scala.reflect
+package makro
+
+abstract class Universe extends scala.reflect.api.Universe {
+
+ val treeBuild: TreeBuilder { val global: Universe.this.type }
+
+ // Symbol extensions ---------------------------------------------------------------
+
+ override type Symbol >: Null <: SymbolContextApi
+
+ /** The extended API of symbols that's supported in macro context universes
+ */
+ trait SymbolContextApi extends SymbolApi { this: Symbol =>
+
+ // [Eugene++ to Martin] should we also add mutability methods here (similarly to what's done below for trees)?
+ // I'm talking about `setAnnotations` and friends
+
+ /** Can this symbol be loaded by a reflective mirror?
+ *
+ * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs.
+ * Such annotations (also called "pickles") are applied on top-level classes and include information
+ * about all symbols reachable from the annotee. However, local symbols (e.g. classes or definitions local to a block)
+ * are typically unreachable and information about them gets lost.
+ *
+ * This method is useful for macro writers who wish to save certain ASTs to be used at runtime.
+ * With `isLocatable' it's possible to check whether a tree can be retained as is, or it needs special treatment.
+ */
+ def isLocatable: Boolean
+
+ /** Is this symbol static (i.e. with no outer instance)?
+ * Q: When exactly is a sym marked as STATIC?
+ * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep.
+ * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
+ */
+ def isStatic: Boolean
+ }
+
+ // Tree extensions ---------------------------------------------------------------
+
+ override type Tree >: Null <: TreeContextApi
+
+ /** The extended API of trees that's supported in macro context universes
+ */
+ trait TreeContextApi extends TreeApi { this: Tree =>
+
+ /** ... */
+ def pos_=(pos: Position): Unit
+
+ /** ... */
+ def setPos(newpos: Position): this.type
+
+ /** ... */
+ def tpe_=(t: Type): Unit
+
+ /** Set tpe to give `tp` and return this.
+ */
+ def setType(tp: Type): this.type
+
+ /** Like `setType`, but if this is a previously empty TypeTree that
+ * fact is remembered so that resetAllAttrs will snap back.
+ *
+ * @PP: Attempting to elaborate on the above, I find: If defineType
+ * is called on a TypeTree whose type field is null or NoType,
+ * this is recorded as "wasEmpty = true". That value is used in
+ * ResetAttrsTraverser, which nulls out the type field of TypeTrees
+ * for which wasEmpty is true, leaving the others alone.
+ *
+ * resetAllAttrs is used in situations where some speculative
+ * typing of a tree takes place, fails, and the tree needs to be
+ * returned to its former state to try again. So according to me:
+ * using `defineType` instead of `setType` is how you communicate
+ * that the type being set does not depend on any previous state,
+ * and therefore should be abandoned if the current line of type
+ * inquiry doesn't work out.
+ */
+ def defineType(tp: Type): this.type
+
+ /** ... */
+ def symbol_=(sym: Symbol): Unit
+
+ /** ... */
+ def setSymbol(sym: Symbol): this.type
+
+ /** ... */
+ def attachments: base.Attachments { type Pos = Position }
+
+ /** ... */
+ def addAttachment(attachment: Any): this.type
+
+ /** ... */
+ def removeAttachment[T: ClassTag]: this.type
+ }
+
+ override type SymTree >: Null <: Tree with SymTreeContextApi
+
+ /** The extended API of sym trees that's supported in macro context universes
+ */
+ trait SymTreeContextApi extends SymTreeApi { this: SymTree =>
+ var symbol: Symbol
+ }
+
+ override type TypeTree >: Null <: TypTree with TypeTreeContextApi
+
+ /** The extended API of sym trees that's supported in macro context universes
+ */
+ trait TypeTreeContextApi extends TypeTreeApi { this: TypeTree =>
+ def setOriginal(tree: Tree): this.type
+ }
+
+ override type Ident >: Null <: RefTree with IdentContextApi
+
+ /** The extended API of idents that's supported in macro context universes
+ */
+ trait IdentContextApi extends IdentApi { this: Ident =>
+ def isBackquoted: Boolean
+ }
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/makro/package.scala b/src/reflect/scala/reflect/makro/package.scala
new file mode 100644
index 0000000000..3c0e51030e
--- /dev/null
+++ b/src/reflect/scala/reflect/makro/package.scala
@@ -0,0 +1,6 @@
+package scala.reflect
+
+package object makro {
+
+ type MirrorOf[U <: base.Universe with Singleton] = base.MirrorOf[U]
+}
diff --git a/src/reflect/scala/reflect/runtime/AbstractFile.scala b/src/reflect/scala/reflect/runtime/AbstractFile.scala
new file mode 100644
index 0000000000..0f88af1b0a
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/AbstractFile.scala
@@ -0,0 +1,7 @@
+package scala.reflect
+package runtime
+
+class AbstractFile(val jfile: java.io.File) extends internal.AbstractFileApi {
+ def path: String = jfile.getPath()
+ def canonicalPath: String = jfile.getCanonicalPath()
+}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
new file mode 100644
index 0000000000..a8120d220a
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -0,0 +1,981 @@
+package scala.reflect
+package runtime
+
+import scala.ref.WeakReference
+import scala.collection.mutable.WeakHashMap
+
+import java.lang.{Class => jClass, Package => jPackage}
+import java.lang.reflect.{
+ Method => jMethod, Constructor => jConstructor, Modifier => jModifier, Field => jField,
+ Member => jMember, Type => jType, TypeVariable => jTypeVariable, Array => jArray,
+ GenericDeclaration, GenericArrayType, ParameterizedType, WildcardType, AnnotatedElement }
+import java.io.IOException
+import internal.MissingRequirementError
+import internal.pickling.ByteCodecs
+import internal.ClassfileConstants._
+import internal.pickling.UnPickler
+import collection.mutable.{ HashMap, ListBuffer }
+import internal.Flags._
+//import scala.tools.nsc.util.ScalaClassLoader
+//import scala.tools.nsc.util.ScalaClassLoader._
+import ReflectionUtils.{singletonInstance}
+import language.existentials
+
+trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: SymbolTable =>
+
+ private lazy val mirrors = new WeakHashMap[ClassLoader, WeakReference[JavaMirror]]()
+
+ private def createMirror(owner: Symbol, cl: ClassLoader): Mirror = {
+ val jm = new JavaMirror(owner, cl)
+ mirrors(cl) = new WeakReference(jm)
+ jm.init()
+ jm
+ }
+
+ override type Mirror = JavaMirror
+
+ override lazy val rootMirror: Mirror = createMirror(NoSymbol, rootClassLoader)
+
+ // overriden by ReflectGlobal
+ def rootClassLoader: ClassLoader = this.getClass.getClassLoader
+
+ 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)
+ }
+
+ /** The API of a mirror for a reflective universe */
+ class JavaMirror(owner: Symbol,
+ /** Class loader that is a mastermind behind the reflexive mirror */
+ val classLoader: ClassLoader
+ ) extends Roots(owner) with super.JavaMirror { wholemirror =>
+
+ val universe: self.type = self
+
+ import definitions._
+
+ /** The lazy type for root.
+ */
+ override lazy val rootLoader = new LazyType {
+ override def complete(sym: Symbol) = sym setInfo new LazyPackageType
+ }
+
+// ----------- Caching ------------------------------------------------------------------
+
+ // [Eugene++ to Martin] not weak? why?
+ private val classCache = new TwoWayCache[jClass[_], ClassSymbol]
+ private val packageCache = new TwoWayCache[Package, ModuleSymbol]
+ private val methodCache = new TwoWayCache[jMethod, MethodSymbol]
+ private val constructorCache = new TwoWayCache[jConstructor[_], MethodSymbol]
+ private val fieldCache = new TwoWayCache[jField, TermSymbol]
+ private val tparamCache = new TwoWayCache[jTypeVariable[_ <: GenericDeclaration], TypeSymbol]
+
+ def toScala[J: HasJavaClass, S](cache: TwoWayCache[J, S], key: J)(body: (JavaMirror, J) => S): S =
+ cache.toScala(key){
+ val jclazz = implicitly[HasJavaClass[J]] getClazz key
+ body(mirrorDefining(jclazz), key)
+ }
+
+ private implicit val classHasJavaClass: HasJavaClass[jClass[_]] =
+ new HasJavaClass(identity)
+ private implicit val methHasJavaClass: HasJavaClass[jMethod]
+ = new HasJavaClass(_.getDeclaringClass)
+ private implicit val fieldHasJavaClass: HasJavaClass[jField] =
+ new HasJavaClass(_.getDeclaringClass)
+ private implicit val constrHasJavaClass: HasJavaClass[jConstructor[_]] =
+ new HasJavaClass(_.getDeclaringClass)
+ private implicit val tparamHasJavaClass: HasJavaClass[jTypeVariable[_ <: GenericDeclaration]] =
+ new HasJavaClass ( (tparam: jTypeVariable[_ <: GenericDeclaration]) => {
+ tparam.getGenericDeclaration match {
+ case jclazz: jClass[_] => jclazz
+ case jmeth: jMethod => jmeth.getDeclaringClass
+ case jconstr: jConstructor[_] => jconstr.getDeclaringClass
+ }
+ })
+
+// ----------- Implementations of mirror operations and classes -------------------
+
+ def reflect(obj: Any): InstanceMirror =
+ new JavaInstanceMirror(obj.asInstanceOf[AnyRef])
+
+ def reflectClass(runtimeClass: RuntimeClass): ClassMirror =
+ new JavaClassMirror(classToScala(runtimeClass))
+
+ def reflectClass(fullName: String): ClassMirror =
+ reflectClass(java.lang.Class.forName(fullName))
+
+ def reflectModule(runtimeClass: RuntimeClass): ModuleMirror =
+ new JavaModuleMirror(classToScala(runtimeClass).companionModule.asModuleSymbol)
+
+ def reflectModule(fullName: String): ModuleMirror =
+ reflectModule(java.lang.Class.forName(fullName))
+
+ def runtimeClass(tpe: Type): RuntimeClass = typeToJavaClass(tpe)
+
+ def runtimeClass(cls: ClassSymbol): RuntimeClass = classToJava(cls)
+
+ private class JavaInstanceMirror(obj: AnyRef)
+ extends InstanceMirror {
+ def instance = obj
+ def reflectClass = wholemirror.reflectClass(obj.getClass)
+ def reflectField(field: TermSymbol): FieldMirror = new JavaFieldMirror(obj, field)
+ def reflectMethod(method: MethodSymbol): MethodMirror = new JavaMethodMirror(obj, method)
+ }
+
+ private class JavaFieldMirror(val receiver: AnyRef, val field: TermSymbol)
+ extends FieldMirror {
+ lazy val jfield = fieldToJava(field)
+ def get = jfield.get(receiver)
+ def set(value: Any) = jfield.set(receiver, value)
+ }
+
+ private class JavaMethodMirror(val receiver: AnyRef, val method: MethodSymbol)
+ extends MethodMirror {
+ lazy val jmeth = methodToJava(method)
+ def apply(args: Any*): Any =
+ if (method.owner == ArrayClass)
+ method.name match {
+ case nme.length => jArray.getLength(receiver)
+ case nme.apply => jArray.get(receiver, args(0).asInstanceOf[Int])
+ case nme.update => jArray.set(receiver, args(0).asInstanceOf[Int], args(1))
+ case _ => throw new Error(s"unexpected array method $method")
+ }
+ else
+ jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
+ }
+
+ private class JavaConstructorMirror(val method: MethodSymbol)
+ extends MethodMirror {
+ override val receiver = null
+ lazy val jconstr = constructorToJava(method)
+ def apply(args: Any*): Any = jconstr.newInstance(args.asInstanceOf[Seq[AnyRef]]: _*)
+ }
+
+
+ private abstract class JavaTemplateMirror
+ extends TemplateMirror {
+ def erasure: ClassSymbol
+ lazy val runtimeClass = classToJava(erasure)
+ lazy val signature = typeToScala(runtimeClass)
+ }
+
+ private class JavaClassMirror(val symbol: ClassSymbol)
+ extends JavaTemplateMirror with ClassMirror {
+ def erasure = symbol
+ def isStatic = false
+ def reflectConstructor(constructor: MethodSymbol) = new JavaConstructorMirror(constructor)
+ def companion: Option[ModuleMirror] = symbol.companionModule match {
+ case module: ModuleSymbol => Some(new JavaModuleMirror(module))
+ case _ => None
+ }
+ }
+
+ private class JavaModuleMirror(val symbol: ModuleSymbol)
+ extends JavaTemplateMirror with ModuleMirror {
+ def erasure = symbol.moduleClass.asClassSymbol
+ def isStatic = true
+ def instance = singletonInstance(classLoader, symbol.fullName)
+ def companion: Option[ClassMirror] = symbol.companionClass match {
+ case cls: ClassSymbol => Some(new JavaClassMirror(cls))
+ case _ => None
+ }
+ }
+
+// -------------------- Java to Scala -----------------------------------
+
+ /** Does method `meth` erase to Java method `jmeth`?
+ * This is true if the Java method type is the same as the Scala method type after performing
+ * all Scala-specific transformations in InfoTransformers. (to be done)
+ */
+ private def erasesTo(meth: Symbol, jmeth: jMethod): Boolean = {
+ val mtpe = transformedType(meth)
+ (mtpe.paramTypes map runtimeClass) == jmeth.getParameterTypes.toList &&
+ runtimeClass(mtpe.resultType) == jmeth.getReturnType
+ }
+
+ private def erasesTo(meth: Symbol, jconstr: jConstructor[_]): Boolean = {
+ val mtpe = transformedType(meth)
+ (mtpe.paramTypes map runtimeClass) == jconstr.getParameterTypes.toList &&
+ runtimeClass(mtpe.resultType) == jconstr.getDeclaringClass
+ }
+
+ def javaClass(path: String): jClass[_] =
+ Class.forName(path, true, classLoader)
+
+ /** Does `path` correspond to a Java class with that fully qualified name in the current class loader? */
+ def tryJavaClass(path: String): Option[jClass[_]] =
+ try {
+ Some(javaClass(path))
+ } catch {
+ case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) =>
+ None
+ }
+
+ /** The mirror that corresponds to the classloader that original defined the given Java class */
+ def mirrorDefining(jclazz: jClass[_]): JavaMirror = {
+ val cl = jclazz.getClassLoader
+ if (cl == this.classLoader) this else runtimeMirror(cl)
+ }
+
+ private object unpickler extends UnPickler {
+ val global: self.type = self
+ }
+
+ /** how connected????
+ * Generate types for top-level Scala root class and root companion object
+ * from the pickled information stored in a corresponding Java class
+ * @param clazz The top-level Scala class for which info is unpickled
+ * @param module The top-level Scala companion object for which info is unpickled
+ * @param jclazz The Java class which contains the unpickled information in a
+ * ScalaSignature or ScalaLongSignature annotation.
+ */
+ def unpickleClass(clazz: Symbol, module: Symbol, jclazz: jClass[_]): Unit = {
+ def markAbsent(tpe: Type) = setAllInfos(clazz, module, tpe)
+ def handleError(ex: Exception) = {
+ markAbsent(ErrorType)
+ if (settings.debug.value) ex.printStackTrace()
+ val msg = ex.getMessage()
+ MissingRequirementError.signal(
+ (if (msg eq null) "reflection error while loading " + clazz.name
+ else "error while loading " + clazz.name) + ", " + msg)
+ }
+ // don't use classOf[scala.reflect.ScalaSignature] here, because it will use getClass.getClassLoader, not mirror's classLoader
+ // don't use asInstanceOf either because of the same reason (lol, I cannot believe I fell for it)
+ // don't use structural types to simplify reflective invocations because of the same reason
+ def loadAnnotation(name: String): Option[java.lang.annotation.Annotation] =
+ tryJavaClass(name) flatMap { annotClass =>
+ val anns = jclazz.getAnnotations
+ val result = anns find (_.annotationType == annotClass)
+ if (result.isEmpty && (anns exists (_.annotationType.getName == name)))
+ throw new ClassNotFoundException(
+ s"""Mirror classloader mismatch: $jclazz (loaded by ${ReflectionUtils.show(jclazz.getClassLoader)})
+ |is unrelated to the mirror's classloader: (${ReflectionUtils.show(classLoader)})""".stripMargin)
+ result
+ }
+ def loadBytes[T: ClassTag](name: String): Option[T] =
+ loadAnnotation(name) map { ssig =>
+ val bytesMethod = ssig.annotationType.getMethod("bytes")
+ bytesMethod.invoke(ssig).asInstanceOf[T]
+ }
+
+ try {
+ markAbsent(NoType)
+ loadBytes[String]("scala.reflect.ScalaSignature") match {
+ case Some(ssig) =>
+ info(s"unpickling Scala $clazz and $module, owner = ${clazz.owner}")
+ val bytes = ssig.getBytes
+ val len = ByteCodecs.decode(bytes)
+ unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
+ case None =>
+ loadBytes[Array[String]]("scala.reflect.ScalaLongSignature") match {
+ case Some(slsig) =>
+ info(s"unpickling Scala $clazz and $module with long Scala signature")
+ val byteSegments = slsig map (_.getBytes)
+ val lens = byteSegments map ByteCodecs.decode
+ val bytes = Array.ofDim[Byte](lens.sum)
+ var len = 0
+ for ((bs, l) <- byteSegments zip lens) {
+ bs.copyToArray(bytes, len, l)
+ len += l
+ }
+ unpickler.unpickle(bytes, 0, clazz, module, jclazz.getName)
+ case None =>
+ // class does not have a Scala signature; it's a Java class
+ info("translating reflection info for Java " + jclazz) //debug
+ initClassModule(clazz, module, new FromJavaClassCompleter(clazz, module, jclazz))
+ }
+ }
+ } catch {
+ case ex: MissingRequirementError =>
+ handleError(ex)
+ case ex: IOException =>
+ handleError(ex)
+ }
+ }
+
+ /**
+ * A fresh Scala type parameter that corresponds to a Java type variable.
+ * The association between Scala type parameter and Java type variable is entered in the cache.
+ * @param jtvar The Java type variable
+ */
+ private def createTypeParameter(jtvar: jTypeVariable[_ <: GenericDeclaration]): TypeSymbol = {
+ val tparam = sOwner(jtvar).newTypeParameter(newTypeName(jtvar.getName))
+ .setInfo(new TypeParamCompleter(jtvar))
+ tparamCache enter (jtvar, tparam)
+ tparam
+ }
+
+ /**
+ * A completer that fills in the type of a Scala type parameter from the bounds of a Java type variable.
+ * @param jtvar The Java type variable
+ */
+ private class TypeParamCompleter(jtvar: jTypeVariable[_ <: GenericDeclaration]) extends LazyType {
+ override def load(sym: Symbol) = complete(sym)
+ override def complete(sym: Symbol) = {
+ sym setInfo TypeBounds.upper(glb(jtvar.getBounds.toList map typeToScala map objToAny))
+ }
+ }
+
+ /**
+ * Copy all annotations of Java annotated element `jann` over to Scala symbol `sym`.
+ * Pre: `sym` is already initialized with a concrete type.
+ * Note: If `sym` is a method or constructor, its parameter annotations are copied as well.
+ */
+ private def copyAnnotations(sym: Symbol, jann: AnnotatedElement) {
+ // to do: implement
+ }
+
+ /**
+ * A completer that fills in the types of a Scala class and its companion object
+ * by copying corresponding type info from a Java class. This completer is used
+ * to reflect classes in Scala that do not have a Scala pickle info, be it
+ * because they are local classes or have been compiled from Java sources.
+ * @param clazz The Scala class for which info is copied
+ * @param module The Scala companion object for which info is copied
+ * @param jclazz The Java class
+ */
+ private class FromJavaClassCompleter(clazz: Symbol, module: Symbol, jclazz: jClass[_]) extends LazyType {
+
+ /** used to avoid cycles while initializing classes */
+ private var parentsLevel = 0
+ private var pendingLoadActions: List[() => Unit] = Nil
+
+ override def load(sym: Symbol): Unit = {
+ debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug
+ assert(sym == clazz || (module != NoSymbol && (sym == module || sym == module.moduleClass)), sym)
+ val flags = toScalaClassFlags(jclazz.getModifiers)
+ clazz setFlag (flags | JAVA)
+ if (module != NoSymbol) {
+ module setFlag (flags & PRIVATE | JAVA)
+ module.moduleClass setFlag (flags & PRIVATE | JAVA)
+ }
+
+ copyAnnotations(clazz, jclazz)
+ // to do: annotations to set also for module?
+
+ clazz setInfo new LazyPolyType(jclazz.getTypeParameters.toList map createTypeParameter)
+ if (module != NoSymbol) {
+ module setInfo module.moduleClass.tpe
+ module.moduleClass setInfo new LazyPolyType(List())
+ }
+ }
+
+ override def complete(sym: Symbol): Unit = {
+ load(sym)
+ completeRest()
+ }
+
+ def completeRest(): Unit = self.synchronized {
+ val tparams = clazz.rawInfo.typeParams
+
+ val parents = try {
+ parentsLevel += 1
+ val jsuperclazz = jclazz.getGenericSuperclass
+ val superclazz = if (jsuperclazz == null) AnyClass.tpe else typeToScala(jsuperclazz)
+ superclazz :: (jclazz.getGenericInterfaces.toList map typeToScala)
+ } finally {
+ parentsLevel -= 1
+ }
+ clazz setInfo GenPolyType(tparams, new ClassInfoType(parents, newScope, clazz))
+ if (module != NoSymbol) {
+ module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass)
+ }
+
+ def enter(sym: Symbol, mods: Int) =
+ (if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym
+
+ for (jinner <- jclazz.getDeclaredClasses) {
+ enter(jclassAsScala(jinner, clazz), jinner.getModifiers)
+ }
+
+ pendingLoadActions = { () =>
+
+ for (jfield <- jclazz.getDeclaredFields)
+ enter(jfieldAsScala(jfield), jfield.getModifiers)
+
+ for (jmeth <- jclazz.getDeclaredMethods)
+ enter(jmethodAsScala(jmeth), jmeth.getModifiers)
+
+ for (jconstr <- jclazz.getConstructors)
+ enter(jconstrAsScala(jconstr), jconstr.getModifiers)
+
+ } :: pendingLoadActions
+
+ if (parentsLevel == 0) {
+ while (!pendingLoadActions.isEmpty) {
+ val item = pendingLoadActions.head
+ pendingLoadActions = pendingLoadActions.tail
+ item()
+ }
+ }
+ }
+
+ class LazyPolyType(override val typeParams: List[Symbol]) extends LazyType {
+ override def complete(sym: Symbol) {
+ completeRest()
+ }
+ }
+ }
+
+ /**
+ * If Java modifiers `mods` contain STATIC, return the module class
+ * of the companion module of `clazz`, otherwise the class `clazz` itself.
+ */
+ private def followStatic(clazz: Symbol, mods: Int) =
+ if (jModifier.isStatic(mods)) clazz.companionModule.moduleClass else clazz
+
+ implicit class RichClass(jclazz: jClass[_]) {
+ // [Eugene++] `jclazz.isLocalClass` doesn't work because of problems with `getSimpleName`
+ // java.lang.Error: sOwner(class Test$A$1) has failed
+ // Caused by: java.lang.InternalError: Malformed class name
+ // at java.lang.Class.getSimpleName(Class.java:1133)
+ // at java.lang.Class.isAnonymousClass(Class.java:1188)
+ // at java.lang.Class.isLocalClass(Class.java:1199)
+ // (see t5256c.scala for more details)
+ // hence we have to approximate by removing the `isAnonymousClass` check
+// def isLocalClass0: Boolean = jclazz.isLocalClass
+ def isLocalClass0: Boolean = jclazz.getEnclosingMethod != null || jclazz.getEnclosingConstructor != null
+ }
+
+ // [Eugene++] overflow from Paul's changes made concurrently with reflection refactoring
+ // https://github.com/scala/scala/commit/90d2bee45b25844f809f8c5300aefcb1bfe9e336
+ //
+ // /** Methods which need to be wrapped because they either are getSimpleName
+ // * or call getSimpleName:
+ // *
+ // * public String getSimpleName()
+ // * public boolean isAnonymousClass()
+ // * public boolean isLocalClass()
+ // * public boolean isMemberClass()
+ // * public String getCanonicalName()
+ // *
+ // * TODO - find all such calls and wrap them.
+ // * TODO - create mechanism to avoid the recurrence of unwrapped calls.
+ // */
+ // private def wrapClassCheck[T](alt: T)(body: => T): T =
+ // try body catch { case x: InternalError if x.getMessage == "Malformed class name" => alt }
+
+ // private def wrapIsLocalClass(clazz: jClass[_]): Boolean =
+ // wrapClassCheck(false)(clazz.isLocalClass)
+
+ // private def wrapGetSimpleName(clazz: jClass[_]): String =
+ // wrapClassCheck("")(clazz.getSimpleName)
+
+ /**
+ * The Scala owner of the Scala class corresponding to the Java class `jclazz`
+ */
+ private def sOwner(jclazz: jClass[_]): Symbol =
+ if (jclazz.isMemberClass) {
+ val jEnclosingClass = jclazz.getEnclosingClass
+ val sEnclosingClass = classToScala(jEnclosingClass)
+ followStatic(sEnclosingClass, jclazz.getModifiers)
+ } else if (jclazz.isLocalClass0) {
+ val jEnclosingMethod = jclazz.getEnclosingMethod
+ if (jEnclosingMethod != null) {
+ methodToScala(jEnclosingMethod)
+ } else {
+ val jEnclosingConstructor = jclazz.getEnclosingConstructor
+ constructorToScala(jEnclosingConstructor)
+ }
+ } else if (jclazz.isPrimitive || jclazz.isArray) {
+ ScalaPackageClass
+ } else if (jclazz.getPackage != null) {
+ val jPackage = jclazz.getPackage
+ packageToScala(jPackage).moduleClass
+ } else {
+ // @eb: a weird classloader might return a null package for something with a non-empty package name
+ // for example, http://groups.google.com/group/scala-internals/browse_thread/thread/7be09ff8f67a1e5c
+ // in that case we could invoke packageNameToScala(jPackageName) and, probably, be okay
+ // however, I think, it's better to blow up, since weirdness of the class loader might bite us elsewhere
+ // [martin] I think it's better to be forgiving here. Restoring packageNameToScala.
+ val jPackageName = jclazz.getName take jclazz.getName.lastIndexOf('.')
+ packageNameToScala(jPackageName).moduleClass
+ }
+
+ /**
+ * The Scala owner of the Scala symbol corresponding to the Java member `jmember`
+ */
+ private def sOwner(jmember: jMember): Symbol = {
+ followStatic(classToScala(jmember.getDeclaringClass), jmember.getModifiers)
+ }
+
+ /**
+ * The Scala owner of the Scala type parameter corresponding to the Java type variable `jtvar`
+ */
+ private def sOwner(jtvar: jTypeVariable[_ <: GenericDeclaration]): Symbol =
+ genericDeclarationToScala(jtvar.getGenericDeclaration)
+
+ /**
+ * Find declarations or definition in class `clazz` that maps to a Java
+ * entity with name `jname`. Because of name-mangling, this is more difficult
+ * than a simple name-based lookup via `decl`. If `decl` fails, members
+ * that start with the given name are searched instead.
+ */
+ private def lookup(clazz: Symbol, jname: String): Symbol = {
+ def approximateMatch(sym: Symbol, jstr: String): Boolean =
+ (sym.name.toString == jstr) ||
+ sym.isPrivate && nme.expandedName(sym.name.toTermName, sym.owner).toString == jstr
+
+ clazz.info.decl(newTermName(jname)) orElse {
+ (clazz.info.decls.iterator filter (approximateMatch(_, jname))).toList match {
+ case List() => NoSymbol
+ case List(sym) => sym
+ case alts => clazz.newOverloaded(alts.head.tpe.prefix, alts)
+ }
+ }
+ }
+
+ /**
+ * The Scala method corresponding to given Java method.
+ * @param jmeth The Java method
+ * @return A Scala method object that corresponds to `jmeth`.
+ */
+ def methodToScala(jmeth: jMethod): MethodSymbol =
+ toScala(methodCache, jmeth)(_ methodToScala1 _)
+
+ private def methodToScala1(jmeth: jMethod): MethodSymbol = {
+ val jOwner = jmeth.getDeclaringClass
+ val preOwner = classToScala(jOwner)
+ val owner = followStatic(preOwner, jmeth.getModifiers)
+ (lookup(owner, jmeth.getName) suchThat (erasesTo(_, jmeth)) orElse jmethodAsScala(jmeth))
+ .asMethodSymbol
+ }
+
+ /**
+ * The Scala constructor corresponding to given Java constructor.
+ * @param jconstr The Java constructor
+ * @return A Scala method object that corresponds to `jconstr`.
+ */
+ def constructorToScala(jconstr: jConstructor[_]): MethodSymbol =
+ toScala(constructorCache, jconstr)(_ constructorToScala1 _)
+
+ private def constructorToScala1(jconstr: jConstructor[_]): MethodSymbol = {
+ val owner = followStatic(classToScala(jconstr.getDeclaringClass), jconstr.getModifiers)
+ (lookup(owner, jconstr.getName) suchThat (erasesTo(_, jconstr)) orElse jconstrAsScala(jconstr))
+ .asMethodSymbol
+ }
+
+ /**
+ * The Scala field corresponding to given Java field.
+ * @param jfield The Java field
+ * @return A Scala field object that corresponds to `jfield`.
+ * // ??? should we return the getter instead?
+ */
+ def fieldToScala(jfield: jField): TermSymbol =
+ toScala(fieldCache, jfield)(_ fieldToScala1 _)
+
+ private def fieldToScala1(jfield: jField): TermSymbol = {
+ val owner = followStatic(classToScala(jfield.getDeclaringClass), jfield.getModifiers)
+ (lookup(owner, jfield.getName) suchThat (!_.isMethod) orElse jfieldAsScala(jfield))
+ .asTermSymbol
+ }
+
+ /**
+ * The Scala package corresponding to given Java package
+ */
+ def packageToScala(jpkg: jPackage): ModuleSymbol = packageCache.toScala(jpkg) {
+ makeScalaPackage(jpkg.getName)
+ }
+
+ /**
+ * The Scala package with given fully qualified name.
+ */
+ def packageNameToScala(fullname: String): ModuleSymbol = {
+ if (fullname == "") EmptyPackage
+ else {
+ val jpkg = jPackage.getPackage(fullname)
+ if (jpkg != null) packageToScala(jpkg) else makeScalaPackage(fullname)
+ }
+ }
+
+ /**
+ * The Scala package with given fully qualified name. Unlike `packageNameToScala`,
+ * this one bypasses the cache.
+ */
+ private[JavaMirrors] def makeScalaPackage(fullname: String): ModuleSymbol = {
+ val split = fullname lastIndexOf '.'
+ val ownerModule: ModuleSymbol =
+ if (split > 0) packageNameToScala(fullname take split) else this.RootPackage
+ val owner = ownerModule.moduleClass
+ val name = newTermName(fullname drop (split + 1))
+ val opkg = owner.info decl name
+ if (opkg.isPackage)
+ opkg.asModuleSymbol
+ else if (opkg == NoSymbol) {
+ val pkg = owner.newPackage(name)
+ pkg.moduleClass setInfo new LazyPackageType
+ pkg setInfoAndEnter pkg.moduleClass.tpe
+ info("made Scala "+pkg)
+ pkg
+ } else
+ throw new ReflectError(opkg+" is not a package")
+ }
+
+ private def scalaSimpleName(jclazz: jClass[_]): TypeName = {
+ val owner = sOwner(jclazz)
+ val enclosingClass = jclazz.getEnclosingClass
+ var prefix = if (enclosingClass != null) enclosingClass.getName else ""
+ val isObject = owner.isModuleClass && !owner.isPackageClass
+ if (isObject && !prefix.endsWith(nme.MODULE_SUFFIX_STRING)) prefix += nme.MODULE_SUFFIX_STRING
+ assert(jclazz.getName.startsWith(prefix))
+ var name = jclazz.getName.substring(prefix.length)
+ name = name.substring(name.lastIndexOf(".") + 1)
+ newTypeName(name)
+ }
+
+ /**
+ * The Scala class that corresponds to a given Java class.
+ * @param jclazz The Java class
+ * @return A Scala class symbol that reflects all elements of the Java class,
+ * in the form they appear in the Scala pickling info, or, if that is
+ * not available, wrapped from the Java reflection info.
+ */
+ def classToScala(jclazz: jClass[_]): ClassSymbol =
+ toScala(classCache, jclazz)(_ classToScala1 _)
+
+ private def classToScala1(jclazz: jClass[_]): ClassSymbol = {
+ val jname = newTypeName(jclazz.getName)
+ if (jname == fulltpnme.RuntimeNothing) NothingClass
+ else if (jname == fulltpnme.RuntimeNull) NullClass
+ else {
+ val owner = sOwner(jclazz)
+ val simpleName = scalaSimpleName(jclazz)
+
+ def lookupClass = {
+ def coreLookup(name: Name): Symbol =
+ owner.info.decl(name) orElse {
+ if (name.startsWith(nme.NAME_JOIN_STRING)) coreLookup(name drop 1) else NoSymbol
+ }
+ if (nme.isModuleName(simpleName))
+ coreLookup(nme.stripModuleSuffix(simpleName).toTermName) map (_.moduleClass)
+ else
+ coreLookup(simpleName)
+ }
+
+ val cls =
+ if (jclazz.isMemberClass && !nme.isImplClassName(jname))
+ lookupClass
+ else if (jclazz.isLocalClass0 || isInvalidClassName(jname))
+ // local classes and implementation classes not preserved by unpickling - treat as Java
+ jclassAsScala(jclazz)
+ else if (jclazz.isArray)
+ ArrayClass
+ else
+ javaTypeToValueClass(jclazz) orElse lookupClass
+
+ assert (cls.isType,
+ s"""${if (cls == NoSymbol) "not a type: symbol" else "no symbol could be"}
+ | loaded from $jclazz in $owner with name $simpleName and classloader $classLoader""".stripMargin)
+
+ cls.asClassSymbol
+ }
+ }
+
+ /**
+ * The Scala type parameter that corresponds to a given Java type parameter.
+ * @param jparam The Java type parameter
+ * @return A Scala type parameter symbol that has the same owner and name as the Java type parameter
+ */
+ def typeParamToScala(jparam: jTypeVariable[_ <: GenericDeclaration]): TypeSymbol =
+ toScala(tparamCache, jparam)(_ typeParamToScala1 _)
+
+ private def typeParamToScala1(jparam: jTypeVariable[_ <: GenericDeclaration]): TypeSymbol = {
+ val owner = genericDeclarationToScala(jparam.getGenericDeclaration)
+ owner.info match {
+ case PolyType(tparams, _) => tparams.find(_.name.toString == jparam.getName).get.asTypeSymbol
+ }
+ }
+
+ /**
+ * The Scala symbol that corresponds to a given Java generic declaration (class, method, or constructor)
+ */
+ def genericDeclarationToScala(jdecl: GenericDeclaration): Symbol = jdecl match {
+ case jclazz: jClass[_] => classToScala(jclazz)
+ case jmeth: jMethod => methodToScala(jmeth)
+ case jconstr: jConstructor[_] => constructorToScala(jconstr)
+ }
+
+ /**
+ * Given some Java type arguments, a corresponding list of Scala types, plus potentially
+ * some existentially bound type variables that represent wildcard arguments.
+ */
+ private def targsToScala(owner: Symbol, args: List[jType]): (List[Type], List[TypeSymbol]) = {
+ val tparams = new ListBuffer[TypeSymbol]
+ def targToScala(arg: jType): Type = arg match {
+ case jwild: WildcardType =>
+ val tparam = owner.newExistential(newTypeName("T$" + tparams.length))
+ .setInfo(TypeBounds(
+ lub(jwild.getLowerBounds.toList map typeToScala),
+ glb(jwild.getUpperBounds.toList map typeToScala map objToAny)))
+ tparams += tparam
+ typeRef(NoPrefix, tparam, List())
+ case _ =>
+ typeToScala(arg)
+ }
+ (args map targToScala, tparams.toList)
+ }
+
+ /**
+ * The Scala type that corresponds to given Java type
+ */
+ def typeToScala(jtpe: jType): Type = jtpe match {
+ case jclazz: jClass[_] =>
+ if (jclazz.isArray)
+ arrayType(typeToScala(jclazz.getComponentType))
+ else {
+ val clazz = classToScala(jclazz)
+ rawToExistential(typeRef(clazz.owner.thisType, clazz, List()))
+ }
+ case japplied: ParameterizedType =>
+ val (pre, sym) = typeToScala(japplied.getRawType) match {
+ case ExistentialType(tparams, TypeRef(pre, sym, _)) => (pre, sym)
+ case TypeRef(pre, sym, _) => (pre, sym)
+ }
+ val args0 = japplied.getActualTypeArguments
+ val (args, bounds) = targsToScala(pre.typeSymbol, args0.toList)
+ ExistentialType(bounds, typeRef(pre, sym, args))
+ case jarr: GenericArrayType =>
+ arrayType(typeToScala(jarr.getGenericComponentType))
+ case jtvar: jTypeVariable[_] =>
+ val tparam = typeParamToScala(jtvar)
+ typeRef(NoPrefix, tparam, List())
+ }
+
+ /**
+ * The Scala class that corresponds to given Java class without taking
+ * Scala pickling info into account.
+ * @param jclazz The Java class
+ * @return A Scala class symbol that wraps all reflection info of `jclazz`
+ */
+ private def jclassAsScala(jclazz: jClass[_]): Symbol = jclassAsScala(jclazz, sOwner(jclazz))
+
+ private def jclassAsScala(jclazz: jClass[_], owner: Symbol): ClassSymbol = {
+ val name = scalaSimpleName(jclazz)
+ val completer = (clazz: Symbol, module: Symbol) => new FromJavaClassCompleter(clazz, module, jclazz)
+ val (clazz, module) = createClassModule(owner, name, completer)
+ classCache enter (jclazz, clazz)
+ clazz
+ }
+
+ /**
+ * The Scala field that corresponds to given Java field without taking
+ * Scala pickling info into account.
+ * @param jfield The Java field
+ * @return A Scala value symbol that wraps all reflection info of `jfield`
+ */
+ private def jfieldAsScala(jfield: jField): TermSymbol =
+ toScala(fieldCache, jfield)(_ jfieldAsScala1 _)
+
+ private def jfieldAsScala1(jfield: jField): TermSymbol = {
+ val field = sOwner(jfield)
+ .newValue(newTermName(jfield.getName), NoPosition, toScalaFieldFlags(jfield.getModifiers))
+ .setInfo(typeToScala(jfield.getGenericType))
+ fieldCache enter (jfield, field)
+ copyAnnotations(field, jfield)
+ field
+ }
+
+ private def setMethType(meth: Symbol, tparams: List[Symbol], paramtpes: List[Type], restpe: Type) = {
+ meth setInfo GenPolyType(tparams, MethodType(meth.owner.newSyntheticValueParams(paramtpes map objToAny), restpe))
+ }
+
+ /**
+ * The Scala method that corresponds to given Java method without taking
+ * Scala pickling info into account.
+ * @param jmeth The Java method
+ * @return A Scala method symbol that wraps all reflection info of `jmethod`
+ */
+ private def jmethodAsScala(jmeth: jMethod): MethodSymbol =
+ toScala(methodCache, jmeth)(_ jmethodAsScala1 _)
+
+ private def jmethodAsScala1(jmeth: jMethod): MethodSymbol = {
+ val clazz = sOwner(jmeth)
+ val meth = clazz.newMethod(newTermName(jmeth.getName), NoPosition, toScalaMethodFlags(jmeth.getModifiers))
+ methodCache enter (jmeth, meth)
+ val tparams = jmeth.getTypeParameters.toList map createTypeParameter
+ val paramtpes = jmeth.getGenericParameterTypes.toList map typeToScala
+ val resulttpe = typeToScala(jmeth.getGenericReturnType)
+ setMethType(meth, tparams, paramtpes, resulttpe)
+ copyAnnotations(meth, jmeth)
+ if ((jmeth.getModifiers & JAVA_ACC_VARARGS) != 0) meth.setInfo(arrayToRepeated(meth.info))
+ meth
+ }
+
+ /**
+ * The Scala constructor that corresponds to given Java constructor without taking
+ * Scala pickling info into account.
+ * @param jconstr The Java constructor
+ * @return A Scala constructor symbol that wraps all reflection info of `jconstr`
+ */
+ private def jconstrAsScala(jconstr: jConstructor[_]): MethodSymbol =
+ toScala(constructorCache, jconstr)(_ jconstrAsScala1 _)
+
+ private def jconstrAsScala1(jconstr: jConstructor[_]): MethodSymbol = {
+ // [Martin] Note: I know there's a lot of duplication wrt jmethodAsScala, but don't think it's worth it to factor this out.
+ val clazz = sOwner(jconstr)
+ val constr = clazz.newConstructor(NoPosition, toScalaMethodFlags(jconstr.getModifiers))
+ constructorCache enter (jconstr, constr)
+ val tparams = jconstr.getTypeParameters.toList map createTypeParameter
+ val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala
+ setMethType(constr, tparams, paramtpes, clazz.tpe)
+ constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe))
+ copyAnnotations(constr, jconstr)
+ constr
+ }
+
+// -------------------- Scala to Java -----------------------------------
+
+ /** Optionally, the Java package corresponding to a given Scala package, or None if no such Java package exists.
+ * @param pkg The Scala package
+ */
+ def packageToJavaOption(pkg: ModuleSymbol): Option[jPackage] = packageCache.toJavaOption(pkg) {
+ Option(jPackage.getPackage(pkg.fullName.toString))
+ }
+
+ /** The Java class corresponding to given Scala class.
+ * Note: This only works for
+ * - top-level classes
+ * - Scala classes that were generated via jclassToScala
+ * - classes that have a class owner that has a corresponding Java class
+ * @throws A `ClassNotFoundException` for all Scala classes not in one of these categories.
+ */
+ @throws(classOf[ClassNotFoundException])
+ def classToJava(clazz: ClassSymbol): jClass[_] = classCache.toJava(clazz) {
+ def noClass = throw new ClassNotFoundException("no Java class corresponding to "+clazz+" found")
+ //println("classToJava "+clazz+" "+clazz.owner+" "+clazz.owner.isPackageClass)//debug
+ if (clazz.isPrimitiveValueClass)
+ valueClassToJavaType(clazz)
+ else if (clazz == ArrayClass)
+ noClass
+ else if (clazz.owner.isPackageClass)
+ javaClass(clazz.javaClassName)
+ else if (clazz.owner.isClass)
+ classToJava(clazz.owner.asClassSymbol)
+ .getDeclaredClasses
+ .find(_.getSimpleName == clazz.name.toString)
+ .getOrElse(noClass)
+ else
+ noClass
+ }
+
+ private def expandedName(sym: Symbol): String =
+ if (sym.isPrivate) nme.expandedName(sym.name.toTermName, sym.owner).toString
+ else sym.name.toString
+
+ /** The Java field corresponding to a given Scala field.
+ * @param meth The Scala field.
+ */
+ def fieldToJava(fld: TermSymbol): jField = fieldCache.toJava(fld) {
+ val jclazz = classToJava(fld.owner.asClassSymbol)
+ try jclazz getDeclaredField fld.name.toString
+ catch {
+ case ex: NoSuchFieldException => jclazz getDeclaredField expandedName(fld)
+ }
+ }
+
+ /** The Java method corresponding to a given Scala method.
+ * @param meth The Scala method
+ */
+ def methodToJava(meth: MethodSymbol): jMethod = methodCache.toJava(meth) {
+ val jclazz = classToJava(meth.owner.asClassSymbol)
+ val paramClasses = transformedType(meth).paramTypes map typeToJavaClass
+ try jclazz getDeclaredMethod (meth.name.toString, paramClasses: _*)
+ catch {
+ case ex: NoSuchMethodException =>
+ jclazz getDeclaredMethod (expandedName(meth), paramClasses: _*)
+ }
+ }
+
+ /** The Java constructor corresponding to a given Scala constructor.
+ * @param constr The Scala constructor
+ */
+ def constructorToJava(constr: MethodSymbol): jConstructor[_] = constructorCache.toJava(constr) {
+ val jclazz = classToJava(constr.owner.asClassSymbol)
+ val paramClasses = transformedType(constr).paramTypes map typeToJavaClass
+ jclazz getConstructor (paramClasses: _*)
+ }
+
+ private def jArrayClass(elemClazz: jClass[_]): jClass[_] = {
+ jArray.newInstance(elemClazz, 0).getClass
+ }
+
+ /** The Java class that corresponds to given Scala type.
+ * Pre: Scala type is already transformed to Java level.
+ */
+ def typeToJavaClass(tpe: Type): jClass[_] = tpe match {
+ case ExistentialType(_, rtpe) => typeToJavaClass(rtpe)
+ case TypeRef(_, ArrayClass, List(elemtpe)) => jArrayClass(typeToJavaClass(elemtpe))
+ case TypeRef(_, sym: ClassSymbol, _) => classToJava(sym.asClassSymbol)
+ case _ => throw new NoClassDefFoundError("no Java class corresponding to "+tpe+" found")
+ }
+ }
+
+ /** Assert that packages have package scopes */
+ override def validateClassInfo(tp: ClassInfoType) {
+ assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope])
+ }
+
+ override def newPackageScope(pkgClass: Symbol) = new PackageScope(pkgClass)
+
+ override def scopeTransform(owner: Symbol)(op: => Scope): Scope =
+ if (owner.isPackageClass) owner.info.decls else op
+
+ private lazy val rootToLoader = new WeakHashMap[Symbol, ClassLoader]
+
+ override def mirrorThatLoaded(sym: Symbol): Mirror = {
+ val root = sym.enclosingRootClass
+ def findLoader = {
+ val loaders = (mirrors collect { case (cl, ref) if ref.get.get.RootClass == root => cl })
+ assert(loaders.nonEmpty, sym)
+ loaders.head
+ }
+ mirrors(rootToLoader getOrElseUpdate(root, findLoader)).get.get
+ }
+
+ private def byName(sym: Symbol): (Name, Symbol) = sym.name -> sym
+
+ private lazy val phantomTypes: Map[Name, Symbol] =
+ Map(byName(definitions.AnyRefClass)) ++ (definitions.isPhantomClass map byName)
+
+ /** 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
+ * 2. If `owner` is the scala package and `name` designates a phantom class, return
+ * the corresponding class symbol and enter it into this mirror's ScalaPackage.
+ */
+ override def missingHook(owner: Symbol, name: Name): Symbol = {
+ if (owner.hasPackageFlag) {
+ val mirror = mirrorThatLoaded(owner)
+ // [Eugene++] 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)
+ if (owner.name.toTermName == nme.scala_ && owner.owner.isRoot)
+ phantomTypes get name match {
+ case Some(tsym) =>
+ owner.info.decls enter tsym
+ return tsym
+ case None =>
+ }
+ }
+ info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
+ super.missingHook(owner, name)
+ }
+}
+
+class ReflectError(msg: String) extends java.lang.Error(msg)
+
+class HasJavaClass[J](val getClazz: J => java.lang.Class[_])
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
new file mode 100644
index 0000000000..d4a83b960d
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -0,0 +1,33 @@
+package scala.reflect
+package runtime
+
+import internal.{SomePhase, NoPhase, Phase, TreeGen}
+
+/** The universe for standard runtime reflection from Java.
+ * This type implements all abstract term members in internal.SymbolTable.
+ */
+class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.SymbolTable { self =>
+
+ type AbstractFileType = AbstractFile
+
+ def picklerPhase = SomePhase
+
+ type TreeGen = internal.TreeGen
+
+ override type Position = scala.reflect.internal.util.Position
+
+ override val gen = new TreeGen { val global: self.type = self }
+
+ lazy val settings = new Settings
+ def forInteractive = false
+ def forScaladoc = false
+
+ def log(msg: => AnyRef): Unit = println(" [] "+msg)
+
+ type TreeCopier = TreeCopierOps
+ def newStrictTreeCopier: TreeCopier = new StrictTreeCopier
+ def newLazyTreeCopier: TreeCopier = new LazyTreeCopier
+
+ init()
+}
+
diff --git a/src/reflect/scala/reflect/runtime/ReflectSetup.scala b/src/reflect/scala/reflect/runtime/ReflectSetup.scala
new file mode 100644
index 0000000000..6e28fc8520
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/ReflectSetup.scala
@@ -0,0 +1,12 @@
+package scala.reflect
+package runtime
+
+import internal.{SomePhase, NoPhase, Phase, TreeGen}
+
+/** A helper trait to initialize things that need to be set before JavaMirrors and other
+ * reflect specific traits are initialized */
+private[runtime] trait ReflectSetup extends internal.SymbolTable {
+ override val phaseWithId: Array[Phase] = Array(NoPhase, SomePhase)
+ override val currentRunId = 1 // fake a run id so that it is different from NoRunId
+ phase = SomePhase // set to a phase different from NoPhase
+}
diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
new file mode 100644
index 0000000000..4e82fe8ad2
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
@@ -0,0 +1,80 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect.runtime
+
+import java.lang.{Class => jClass}
+import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException }
+
+/** A few java-reflection oriented utility functions useful during reflection bootstrapping.
+ */
+object ReflectionUtils {
+ // Unwraps some chained exceptions which arise during reflective calls.
+ def unwrapThrowable(x: Throwable): Throwable = x match {
+ case _: InvocationTargetException | // thrown by reflectively invoked method or constructor
+ _: ExceptionInInitializerError | // thrown when running a static initializer (e.g. a scala module constructor)
+ _: UndeclaredThrowableException | // invocation on a proxy instance if its invocation handler's `invoke` throws an exception
+ _: ClassNotFoundException | // no definition for a class instantiated by name
+ _: NoClassDefFoundError // the definition existed when the executing class was compiled, but can no longer be found
+ if x.getCause != null =>
+ unwrapThrowable(x.getCause)
+ case _ => x
+ }
+ // Transforms an exception handler into one which will only receive the unwrapped
+ // exceptions (for the values of wrap covered in unwrapThrowable.)
+ def unwrapHandler[T](pf: PartialFunction[Throwable, T]): PartialFunction[Throwable, T] = {
+ case ex if pf isDefinedAt unwrapThrowable(ex) => pf(unwrapThrowable(ex))
+ }
+
+ private def systemProperties: Iterator[(String, String)] = {
+ import scala.collection.JavaConverters._
+ System.getProperties.asScala.iterator
+ }
+
+ private def inferBootClasspath: String = (
+ systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse ""
+ )
+
+ def show(cl: ClassLoader) = {
+ def inferClasspath(cl: ClassLoader): String = cl match {
+ case cl: java.net.URLClassLoader =>
+ "[" + (cl.getURLs mkString ",") + "]"
+ case cl if cl != null && cl.getClass.getName == "scala.tools.nsc.interpreter.AbstractFileClassLoader" =>
+ "[" + cl.asInstanceOf[{val root: scala.reflect.internal.AbstractFileApi}].root + "] and " + inferClasspath(cl.getParent)
+ case null =>
+ inferBootClasspath
+ case _ =>
+ "<unknown>"
+ }
+ cl match {
+ case cl if cl != null =>
+ "%s of type %s with classpath %s".format(cl, cl.getClass, inferClasspath(cl))
+ case null =>
+ "primordial classloader with boot classpath [%s]".format(inferClasspath(cl))
+ }
+ }
+
+ def singletonInstance(cl: ClassLoader, className: String): AnyRef = {
+ val name = if (className endsWith "$") className else className + "$"
+ val clazz = java.lang.Class.forName(name, true, cl)
+ val singleton = clazz getField "MODULE$" get null
+ singleton
+ }
+
+ // Retrieves the MODULE$ field for the given class name.
+ def singletonInstanceOpt(cl: ClassLoader, className: String): Option[AnyRef] =
+ try Some(singletonInstance(cl, className))
+ catch { case _: ClassNotFoundException => None }
+
+ def invokeFactory(cl: ClassLoader, className: String, methodName: String, args: AnyRef*): AnyRef = {
+ val singleton = singletonInstance(cl, className)
+ val method = singleton.getClass.getMethod(methodName, classOf[ClassLoader])
+ method.invoke(singleton, args: _*)
+ }
+
+ def invokeFactoryOpt(cl: ClassLoader, className: String, methodName: String, args: AnyRef*): Option[AnyRef] =
+ try Some(invokeFactory(cl, className, methodName, args: _*))
+ catch { case _: ClassNotFoundException => None }
+}
diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala
new file mode 100644
index 0000000000..b247797c6c
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -0,0 +1,39 @@
+package scala.reflect
+package runtime
+
+/** The Settings class for runtime reflection.
+ * This should be refined, so that settings are settable via command
+ * line options or properties.
+ */
+class Settings extends internal.settings.MutableSettings {
+
+ trait Setting extends SettingValue { }
+
+ class BooleanSetting(x: Boolean) extends Setting {
+ type T = Boolean
+ protected var v: Boolean = x
+ override def value: Boolean = v
+ }
+
+ class IntSetting(x: Int) extends Setting {
+ type T = Int
+ protected var v: Int = x
+ override def value: Int = v
+ }
+
+ val overrideObjects = new BooleanSetting(false)
+ val debug = new BooleanSetting(false)
+ val Ynotnull = new BooleanSetting(false)
+ val explaintypes = new BooleanSetting(false)
+ val verbose = new BooleanSetting(false)
+ val uniqid = new BooleanSetting(false)
+ val Yshowsymkinds = new BooleanSetting(false)
+ val Xprintpos = new BooleanSetting(false)
+ val printtypes = new BooleanSetting(false)
+ val Yrecursion = new IntSetting(0)
+ val maxClassfileName = new IntSetting(255)
+ val Xexperimental = new BooleanSetting(false)
+ val deepCloning = new BooleanSetting (false)
+ val XoldPatmat = new BooleanSetting(false)
+ val XnoPatmatAnalysis = new BooleanSetting(false)
+}
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
new file mode 100644
index 0000000000..c1cd5d2911
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -0,0 +1,152 @@
+package scala.reflect
+package runtime
+
+import internal.Flags
+import java.lang.{Class => jClass, Package => jPackage}
+import collection.mutable
+
+trait SymbolLoaders { self: SymbolTable =>
+
+ /** The standard completer for top-level classes
+ * @param clazz The top-level class
+ * @param module The companion object of `clazz`
+ * Calling `complete` on this type will assign the infos of `clazz` and `module`
+ * by unpickling information from the corresponding Java class. If no Java class
+ * is found, a package is created instead.
+ */
+ class TopClassCompleter(clazz: Symbol, module: Symbol) extends SymLoader {
+// 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 {
+ atPhaseNotLaterThan(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)
+ }
+
+ /** Create a class and a companion object, enter in enclosing scope,
+ * and initialize with a lazy type completer.
+ * @param owner The owner of the newly created class and object
+ * @param name The simple name of the newly created class
+ * @param completer The completer to be used to set the info of the class and the module
+ */
+ protected def createClassModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = {
+ assert(!(name.toString endsWith "[]"), name)
+ val clazz = owner.newClass(name)
+ val module = owner.newModule(name.toTermName)
+ // [Eugene++] am I doing this right?
+ // todo: drop condition, see what goes wrong
+ // [Eugene++ to Martin] test/files/run/t5256g and test/files/run/t5256h will crash
+ // reflection meeting verdict: need to enter the symbols into the first symbol in the owner chain that has a non-empty scope
+ if (owner.info.decls != EmptyScope) {
+ owner.info.decls enter clazz
+ owner.info.decls enter module
+ }
+ initClassModule(clazz, module, completer(clazz, module))
+ (clazz, module)
+ }
+
+ protected def setAllInfos(clazz: Symbol, module: Symbol, info: Type) = {
+ List(clazz, module, module.moduleClass) foreach (_ setInfo info)
+ }
+
+ protected def initClassModule(clazz: Symbol, module: Symbol, completer: LazyType) =
+ setAllInfos(clazz, module, completer)
+
+ /** The type completer for packages.
+ */
+ class LazyPackageType extends LazyType {
+ override def complete(sym: Symbol) {
+ assert(sym.isPackageClass)
+ sym setInfo new ClassInfoType(List(), new PackageScope(sym), sym)
+ // override def safeToString = pkgClass.toString
+ openPackageModule(sym)
+ }
+ }
+
+ /** Is the given name valid for a top-level class? We exclude names with embedded $-signs, because
+ * these are nested classes or anonymous classes,
+ */
+ def isInvalidClassName(name: Name) = {
+ val dp = name pos '$'
+ 0 < dp && dp < (name.length - 1)
+ }
+
+ class PackageScope(pkgClass: Symbol) extends Scope() with SynchronizedScope {
+ assert(pkgClass.isType)
+ private val negatives = mutable.Set[Name]() // Syncnote: Performance only, so need not be protected.
+ override def lookupEntry(name: Name): ScopeEntry = {
+ val e = super.lookupEntry(name)
+ if (e != null)
+ e
+ else if (isInvalidClassName(name) || (negatives contains name))
+ null
+ else {
+ val path =
+ if (pkgClass.isEmptyPackageClass) name.toString
+ else pkgClass.fullName + "." + name
+ val currentMirror = mirrorThatLoaded(pkgClass)
+ currentMirror.tryJavaClass(path) match {
+ case Some(cls) =>
+ val loadingMirror = currentMirror.mirrorDefining(cls)
+ val (clazz, module) =
+ if (loadingMirror eq currentMirror) {
+ createClassModule(pkgClass, name.toTypeName, new TopClassCompleter(_, _))
+ } else {
+ val origOwner = loadingMirror.packageNameToScala(pkgClass.fullName)
+ val clazz = origOwner.info decl name.toTypeName
+ val module = origOwner.info decl name.toTermName
+ assert(clazz != NoSymbol)
+ assert(module != NoSymbol)
+ pkgClass.info.decls enter clazz
+ pkgClass.info.decls enter module
+ (clazz, module)
+ }
+ debugInfo(s"created $module/${module.moduleClass} in $pkgClass")
+ lookupEntry(name)
+ case none =>
+ debugInfo("*** not found : "+path)
+ negatives += name
+ null
+ }
+ }
+ }
+ }
+
+ /** Assert that packages have package scopes */
+ override def validateClassInfo(tp: ClassInfoType) {
+ assert(!tp.typeSymbol.isPackageClass || tp.decls.isInstanceOf[PackageScope])
+ }
+
+ override def newPackageScope(pkgClass: Symbol) = new PackageScope(pkgClass)
+
+ override def scopeTransform(owner: Symbol)(op: => Scope): Scope =
+ if (owner.isPackageClass) owner.info.decls else op
+}
diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala
new file mode 100644
index 0000000000..c90665508b
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala
@@ -0,0 +1,17 @@
+package scala.reflect
+package runtime
+
+/**
+ * This symbol table trait fills in the definitions so that class information is obtained by refection.
+ * 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.nsc.ReflectGlobal)
+ */
+trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps {
+
+ def info(msg: => String) =
+ if (settings.verbose.value) println("[reflect-compiler] "+msg)
+
+ def debugInfo(msg: => String) =
+ if (settings.debug.value) info(msg)
+
+}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedOps.scala b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
new file mode 100644
index 0000000000..907c0dd369
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/SynchronizedOps.scala
@@ -0,0 +1,51 @@
+package scala.reflect
+package runtime
+
+trait SynchronizedOps extends internal.SymbolTable
+ with SynchronizedSymbols
+ with SynchronizedTypes { self: SymbolTable =>
+
+// Names
+
+ private lazy val nameLock = new Object
+
+ override def newTermName(s: String): TermName = nameLock.synchronized { super.newTermName(s) }
+ override def newTypeName(s: String): TypeName = nameLock.synchronized { super.newTypeName(s) }
+
+// BaseTypeSeqs
+
+ override protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) =
+ new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq
+
+ 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
+ }
+
+// Scopes
+
+ override def newScope = new Scope() with SynchronizedScope
+ 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 }
+ }
+}
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
new file mode 100644
index 0000000000..3b28ddf42c
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -0,0 +1,140 @@
+package scala.reflect
+package runtime
+
+import internal.Flags.DEFERRED
+
+trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable =>
+
+ override protected def nextId() = synchronized { super.nextId() }
+
+ override protected def freshExistentialName(suffix: String) =
+ synchronized { super.freshExistentialName(suffix) }
+
+ // 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) }
+
+ override def newFreeTermSymbol(name: TermName, info: Type, value: => Any, flags: Long = 0L, origin: String = null): FreeTermSymbol =
+ new FreeTermSymbol(name, value, origin) with SynchronizedTermSymbol initFlags flags setInfo info
+
+ override def newFreeTypeSymbol(name: TypeName, info: Type, value: => Any, flags: Long = 0L, origin: String = null): FreeTypeSymbol =
+ new FreeTypeSymbol(name, value, origin) with SynchronizedTypeSymbol initFlags flags setInfo info
+
+ override protected def makeNoSymbol: NoSymbol = new NoSymbol with SynchronizedSymbol
+
+ 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 }
+
+
+// ------ creators -------------------------------------------------------------------
+
+ override protected def createAbstractTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AbstractTypeSymbol =
+ new AbstractTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags
+
+ override protected def createAliasTypeSymbol(name: TypeName, pos: Position, newFlags: Long): AliasTypeSymbol =
+ new AliasTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags
+
+ override protected def createTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position, newFlags: Long): TypeSkolem =
+ new TypeSkolem(this, pos, name, origin) with SynchronizedTypeSymbol initFlags newFlags
+
+ override protected def createClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
+ new ClassSymbol(this, pos, name) with SynchronizedClassSymbol initFlags newFlags
+
+ override protected def createModuleClassSymbol(name: TypeName, pos: Position, newFlags: Long): ModuleClassSymbol =
+ new ModuleClassSymbol(this, pos, name) with SynchronizedModuleClassSymbol initFlags newFlags
+
+ override protected def createPackageClassSymbol(name: TypeName, pos: Position, newFlags: Long): PackageClassSymbol =
+ new PackageClassSymbol(this, pos, name) with SynchronizedModuleClassSymbol initFlags newFlags
+
+ override protected def createRefinementClassSymbol(pos: Position, newFlags: Long): RefinementClassSymbol =
+ new RefinementClassSymbol(this, pos) with SynchronizedClassSymbol initFlags newFlags
+
+ override protected def createImplClassSymbol(name: TypeName, pos: Position, newFlags: Long): ClassSymbol =
+ new ClassSymbol(this, pos, name) with ImplClassSymbol with SynchronizedClassSymbol initFlags newFlags
+
+ override protected def createPackageObjectClassSymbol(pos: Position, newFlags: Long): PackageObjectClassSymbol =
+ new PackageObjectClassSymbol(this, pos) with SynchronizedClassSymbol initFlags newFlags
+
+ override protected def createTermSymbol(name: TermName, pos: Position, newFlags: Long): TermSymbol =
+ new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags
+
+ override protected def createMethodSymbol(name: TermName, pos: Position, newFlags: Long): MethodSymbol =
+ new MethodSymbol(this, pos, name) with SynchronizedMethodSymbol initFlags newFlags
+
+ 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)
+
+ // TODO
+ // override protected def createValueParameterSymbol(name: TermName, pos: Position, newFlags: Long)
+ // override protected def createValueMemberSymbol(name: TermName, pos: Position, newFlags: Long)
+ }
+
+// ------- 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 SynchronizedMethodSymbol extends MethodSymbol with SynchronizedTermSymbol {
+ override def typeAsMemberOf(pre: Type): Type = synchronized { super.typeAsMemberOf(pre) }
+ }
+
+ 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 }
+ }
+
+ trait SynchronizedClassSymbol extends ClassSymbol with SynchronizedTypeSymbol {
+ override def associatedFile = synchronized { super.associatedFile }
+ override def associatedFile_=(f: AbstractFileType) = 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 SynchronizedModuleClassSymbol extends ModuleClassSymbol with SynchronizedClassSymbol {
+ override def sourceModule = synchronized { super.sourceModule }
+ // [Eugene++ to Martin] doesn't override anything. no longer necessary?
+ // def sourceModule_=(module: ModuleSymbol) = synchronized { super.sourceModule_=(module) }
+ override def implicitMembers: List[Symbol] = synchronized { super.implicitMembers }
+ }
+}
+
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
new file mode 100644
index 0000000000..e1eb7a57fe
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -0,0 +1,88 @@
+package scala.reflect
+package runtime
+
+/** This trait overrides methods in reflect.internal, bracketing
+ * them in synchronized { ... } to make them thread-safe
+ */
+trait SynchronizedTypes extends internal.Types { self: SymbolTable =>
+
+ // No sharing of map objects:
+ override protected def commonOwnerMap = new CommonOwnerMap
+
+ private object uniqueLock
+
+ override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { super.unique(tp) }
+
+ class SynchronizedUndoLog extends UndoLog {
+
+ override def clear() =
+ synchronized { super.clear() }
+
+ override def undo[T](block: => T): T =
+ synchronized { super.undo(block) }
+
+ override def undoUnless(block: => Boolean): Boolean =
+ synchronized { super.undoUnless(block) }
+ }
+
+ override protected def newUndoLog = new SynchronizedUndoLog
+
+ override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) =
+ synchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) }
+
+ private object subsametypeLock
+
+ override def isSameType(tp1: Type, tp2: Type): Boolean =
+ subsametypeLock.synchronized { super.isSameType(tp1, tp2) }
+
+ override def isDifferentType(tp1: Type, tp2: Type): Boolean =
+ subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) }
+
+ override def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean =
+ subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) }
+
+ private object lubglbLock
+
+ override def glb(ts: List[Type]): Type =
+ lubglbLock.synchronized { super.glb(ts) }
+
+ override def lub(ts: List[Type]): Type =
+ lubglbLock.synchronized { super.lub(ts) }
+
+ 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 object toStringLock
+
+ override protected def typeToString(tpe: Type): String =
+ toStringLock.synchronized(super.typeToString(tpe))
+
+ /* The idea of caches is as follows.
+ * When in reflexive mode, a cache is either null, or one sentinal
+ * value representing undefined or the final defined
+ * value. Hence, we can ask in non-synchronized ode whether the cache field
+ * is non null and different from the sentinel (if a sentinel exists).
+ * If that's true, the cache value is current.
+ * Otherwise we arrive in one of the defined... methods listed below
+ * which go through all steps in synchronized mode.
+ */
+
+ override protected def defineUnderlyingOfSingleType(tpe: SingleType) =
+ tpe.synchronized { super.defineUnderlyingOfSingleType(tpe) }
+
+ override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) =
+ tpe.synchronized { super.defineBaseTypeSeqOfCompoundType(tpe) }
+
+ override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) =
+ tpe.synchronized { super.defineBaseClassesOfCompoundType(tpe) }
+
+ override protected def defineParentsOfTypeRef(tpe: TypeRef) =
+ tpe.synchronized { super.defineParentsOfTypeRef(tpe) }
+
+ override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) =
+ tpe.synchronized { super.defineBaseTypeSeqOfTypeRef(tpe) }
+
+}
diff --git a/src/reflect/scala/reflect/runtime/TwoWayCache.scala b/src/reflect/scala/reflect/runtime/TwoWayCache.scala
new file mode 100644
index 0000000000..c7bfb3435d
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/TwoWayCache.scala
@@ -0,0 +1,52 @@
+package scala.reflect
+package runtime
+
+/** A cache that maintains a bijection between Java reflection type `J`
+ * and Scala reflection type `S`.
+ */
+import collection.mutable.HashMap
+
+private[runtime] class TwoWayCache[J, S] {
+
+ private val toScalaMap = new HashMap[J, S]
+ private val toJavaMap = new HashMap[S, J]
+
+ def enter(j: J, s: S) = synchronized {
+ // debugInfo("cached: "+j+"/"+s)
+ toScalaMap(j) = s
+ toJavaMap(s) = j
+ }
+
+ def toScala(key: J)(body: => S): S = synchronized {
+ toScalaMap get key match {
+ case Some(v) =>
+ v
+ case none =>
+ val result = body
+ enter(key, result)
+ result
+ }
+ }
+
+ def toJava(key: S)(body: => J): J = synchronized {
+ toJavaMap get key match {
+ case Some(v) =>
+ v
+ case none =>
+ val result = body
+ enter(result, key)
+ result
+ }
+ }
+
+ def toJavaOption(key: S)(body: => Option[J]): Option[J] = synchronized {
+ toJavaMap get key match {
+ case None =>
+ val result = body
+ for (value <- result) enter(value, key)
+ result
+ case some => some
+ }
+ }
+}
+
diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala
new file mode 100644
index 0000000000..a5809a2629
--- /dev/null
+++ b/src/reflect/scala/reflect/runtime/package.scala
@@ -0,0 +1,26 @@
+package scala.reflect
+
+import language.experimental.macros
+
+package object runtime {
+
+ // type is api.JavaUniverse because we only want to expose the `scala.reflect.api.*` subset of reflection
+ lazy val universe: api.JavaUniverse = new runtime.JavaUniverse
+
+ // [Eugene++ to Martin] removed `mirrorOfLoader`, because one can use `universe.runtimeMirror` instead
+
+ def currentMirror: universe.Mirror = macro Macros.currentMirror
+}
+
+package runtime {
+ object Macros {
+ def currentMirror(c: scala.reflect.makro.Context): c.Expr[universe.Mirror] = {
+ import c.universe._
+ val runtimeClass = c.reifyEnclosingRuntimeClass
+ if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class")
+ val runtimeUniverse = Select(Select(Select(Ident(newTermName("scala")), newTermName("reflect")), newTermName("runtime")), newTermName("universe"))
+ val currentMirror = Apply(Select(runtimeUniverse, newTermName("runtimeMirror")), List(Select(runtimeClass, newTermName("getClassLoader"))))
+ c.Expr[Nothing](currentMirror)(c.TypeTag.Nothing)
+ }
+ }
+}
diff --git a/src/reflect/scala/tools/nsc/io/AbstractFile.scala b/src/reflect/scala/tools/nsc/io/AbstractFile.scala
new file mode 100644
index 0000000000..fd56608fab
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/AbstractFile.scala
@@ -0,0 +1,258 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+
+package scala.tools.nsc
+package io
+
+import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream }
+import java.io.{ File => JFile }
+import java.net.URL
+import scala.collection.mutable.ArrayBuffer
+
+/**
+ * @author Philippe Altherr
+ * @version 1.0, 23/03/2004
+ */
+object AbstractFile {
+ /** Returns "getFile(new File(path))". */
+ def getFile(path: String): AbstractFile = getFile(File(path))
+ def getFile(path: Path): AbstractFile = getFile(path.toFile)
+
+ /**
+ * If the specified File exists and is a regular file, returns an
+ * abstract regular file backed by it. Otherwise, returns <code>null</code>.
+ */
+ def getFile(file: File): AbstractFile =
+ if (file.isFile) new PlainFile(file) else null
+
+ /** Returns "getDirectory(new File(path))". */
+ def getDirectory(path: Path): AbstractFile = getDirectory(path.toFile)
+
+ /**
+ * If the specified File exists and is either a directory or a
+ * readable zip or jar archive, returns an abstract directory
+ * backed by it. Otherwise, returns <code>null</code>.
+ *
+ * @param file ...
+ * @return ...
+ */
+ def getDirectory(file: File): AbstractFile =
+ if (file.isDirectory) new PlainFile(file)
+ else if (file.isFile && Path.isExtensionJarOrZip(file.jfile)) ZipArchive fromFile file
+ else null
+
+ /**
+ * If the specified URL exists and is a readable zip or jar archive,
+ * returns an abstract directory backed by it. Otherwise, returns
+ * <code>null</code>.
+ *
+ * @param file ...
+ * @return ...
+ */
+ def getURL(url: URL): AbstractFile = {
+ if (url == null || !Path.isExtensionJarOrZip(url.getPath)) null
+ else ZipArchive fromURL url
+ }
+}
+
+/**
+ * <p>
+ * This class and its children serve to unify handling of files and
+ * directories. These files and directories may or may not have some
+ * real counter part within the file system. For example, some file
+ * handles reference files within a zip archive or virtual ones
+ * that exist only in memory.
+ * </p>
+ * <p>
+ * Every abstract file has a path (i.e. a full name) and a name
+ * (i.e. a short name) and may be backed by some real File. There are
+ * two different kinds of abstract files: regular files and
+ * directories. Regular files may be read and have a last modification
+ * time. Directories may list their content and look for subfiles with
+ * a specified name or path and of a specified kind.
+ * </p>
+ * <p>
+ * The interface does <b>not</b> allow to access the content.
+ * The class <code>symtab.classfile.AbstractFileReader</code> accesses
+ * bytes, knowing that the character set of classfiles is UTF-8. For
+ * all other cases, the class <code>SourceFile</code> is used, which honors
+ * <code>global.settings.encoding.value</code>.
+ * </p>
+ */
+abstract class AbstractFile extends reflect.internal.AbstractFileApi with Iterable[AbstractFile] {
+
+ /** Returns the name of this abstract file. */
+ def name: String
+
+ /** Returns the path of this abstract file. */
+ def path: String
+
+ /** Returns the path of this abstract file in a canonical form. */
+ def canonicalPath: String = if (file == null) path else file.getCanonicalPath
+
+ /** Checks extension case insensitively. */
+ def hasExtension(other: String) = extension == other.toLowerCase
+ private lazy val extension: String = Path.extension(name)
+
+ /** The absolute file, if this is a relative file. */
+ def absolute: AbstractFile
+
+ /** Returns the containing directory of this abstract file */
+ def container : AbstractFile
+
+ /** Returns the underlying File if any and null otherwise. */
+ def file: JFile
+
+ /** An underlying source, if known. Mostly, a zip/jar file. */
+ def underlyingSource: Option[AbstractFile] = None
+
+ /** Does this abstract file denote an existing file? */
+ def exists: Boolean = (file eq null) || file.exists
+
+ /** Does this abstract file represent something which can contain classfiles? */
+ def isClassContainer = isDirectory || (file != null && (extension == "jar" || extension == "zip"))
+
+ /** Create a file on disk, if one does not exist already. */
+ def create(): Unit
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete(): Unit
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long
+
+ /** returns an input stream so the file can be read */
+ def input: InputStream
+
+ /** Returns an output stream for writing the file */
+ def output: OutputStream
+
+ /** Returns a buffered output stream for writing the file - defaults to out */
+ def bufferedOutput: BufferedOutputStream = new BufferedOutputStream(output)
+
+ /** size of this file if it is a concrete file. */
+ def sizeOption: Option[Int] = None
+
+ def toURL: URL = if (file == null) null else file.toURI.toURL
+
+ /** Returns contents of file (if applicable) in a Char array.
+ * warning: use <code>Global.getSourceFile()</code> to use the proper
+ * encoding when converting to the char array.
+ */
+ @throws(classOf[IOException])
+ def toCharArray = new String(toByteArray).toCharArray
+
+ /** Returns contents of file (if applicable) in a byte array.
+ */
+ @throws(classOf[IOException])
+ def toByteArray: Array[Byte] = {
+ val in = input
+ var rest = sizeOption.getOrElse(0)
+ val arr = new Array[Byte](rest)
+ while (rest > 0) {
+ val res = in.read(arr, arr.length - rest, rest)
+ if (res == -1)
+ throw new IOException("read error")
+ rest -= res
+ }
+ in.close()
+ arr
+ }
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def iterator: Iterator[AbstractFile]
+
+ /** Returns the abstract file in this abstract directory with the specified
+ * name. If there is no such file, returns <code>null</code>. The argument
+ * <code>directory</code> tells whether to look for a directory or
+ * a regular file.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile
+
+ /** Returns an abstract file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile
+
+ /** Returns the abstract file in this abstract directory with the specified
+ * path relative to it, If there is no such file, returns null. The argument
+ * <code>directory</code> tells whether to look for a directory or a regular
+ * file.
+ *
+ * @param path ...
+ * @param directory ...
+ * @return ...
+ */
+ def lookupPath(path: String, directory: Boolean): AbstractFile = {
+ lookup((f, p, dir) => f.lookupName(p, dir), path, directory)
+ }
+
+ /** Return an abstract file that does not check that `path` denotes
+ * an existing file.
+ */
+ def lookupPathUnchecked(path: String, directory: Boolean): AbstractFile = {
+ lookup((f, p, dir) => f.lookupNameUnchecked(p, dir), path, directory)
+ }
+
+ private def lookup(getFile: (AbstractFile, String, Boolean) => AbstractFile,
+ path0: String,
+ directory: Boolean): AbstractFile = {
+ val separator = java.io.File.separatorChar
+ // trim trailing '/'s
+ val path: String = if (path0.last == separator) path0 dropRight 1 else path0
+ val length = path.length()
+ assert(length > 0 && !(path.last == separator), path)
+ var file = this
+ var start = 0
+ while (true) {
+ val index = path.indexOf(separator, start)
+ assert(index < 0 || start < index, ((path, directory, start, index)))
+ val name = path.substring(start, if (index < 0) length else index)
+ file = getFile(file, name, if (index < 0) directory else true)
+ if ((file eq null) || index < 0) return file
+ start = index + 1
+ }
+ file
+ }
+
+ private def fileOrSubdirectoryNamed(name: String, isDir: Boolean): AbstractFile = {
+ val lookup = lookupName(name, isDir)
+ if (lookup != null) lookup
+ else {
+ val jfile = new JFile(file, name)
+ if (isDir) jfile.mkdirs() else jfile.createNewFile()
+ new PlainFile(jfile)
+ }
+ }
+
+ /**
+ * Get the file in this directory with the given name,
+ * creating an empty file if it does not already existing.
+ */
+ def fileNamed(name: String): AbstractFile = {
+ assert(isDirectory, "Tried to find '%s' in '%s' but it is not a directory".format(name, path))
+ fileOrSubdirectoryNamed(name, false)
+ }
+
+ /**
+ * Get the subdirectory with a given name, creating it if it
+ * does not already exist.
+ */
+ def subdirectoryNamed(name: String): AbstractFile = {
+ assert (isDirectory, "Tried to find '%s' in '%s' but it is not a directory".format(name, path))
+ fileOrSubdirectoryNamed(name, true)
+ }
+
+ protected def unsupported(): Nothing = unsupported(null)
+ protected def unsupported(msg: String): Nothing = throw new UnsupportedOperationException(msg)
+
+ /** Returns the path of this abstract file. */
+ override def toString() = path
+
+}
diff --git a/src/reflect/scala/tools/nsc/io/Directory.scala b/src/reflect/scala/tools/nsc/io/Directory.scala
new file mode 100644
index 0000000000..ebd6edc8d8
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/Directory.scala
@@ -0,0 +1,75 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.tools.nsc
+package io
+
+import java.io.{ File => JFile }
+
+object Directory {
+ import scala.util.Properties.{ tmpDir, userHome, userDir }
+
+ private def normalizePath(s: String) = Some(apply(Path(s).normalize))
+ def Current: Option[Directory] = if (userDir == "") None else normalizePath(userDir)
+ def Home: Option[Directory] = if (userHome == "") None else normalizePath(userHome)
+ def TmpDir: Option[Directory] = if (tmpDir == "") None else normalizePath(tmpDir)
+
+ def apply(path: Path): Directory = path.toDirectory
+
+ // Like File.makeTemp but creates a directory instead
+ def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null): Directory = {
+ val path = File.makeTemp(prefix, suffix, dir)
+ path.delete()
+ path.createDirectory()
+ }
+}
+import Path._
+
+/** An abstraction for directories.
+ *
+ * @author Paul Phillips
+ * @since 2.8
+ */
+class Directory(jfile: JFile) extends Path(jfile) {
+ override def toAbsolute: Directory = if (isAbsolute) this else super.toAbsolute.toDirectory
+ override def toDirectory: Directory = this
+ override def toFile: File = new File(jfile)
+ override def isValid = jfile.isDirectory() || !jfile.exists()
+ override def normalize: Directory = super.normalize.toDirectory
+
+ /** An iterator over the contents of this directory.
+ */
+ def list: Iterator[Path] =
+ jfile.listFiles match {
+ case null => Iterator.empty
+ case xs => xs.iterator map Path.apply
+ }
+
+ def dirs: Iterator[Directory] = list collect { case x: Directory => x }
+ def files: Iterator[File] = list collect { case x: File => x }
+
+ override def walkFilter(cond: Path => Boolean): Iterator[Path] =
+ list filter cond flatMap (_ walkFilter cond)
+
+ def deepDirs: Iterator[Directory] = Path.onlyDirs(deepList())
+ def deepFiles: Iterator[File] = Path.onlyFiles(deepList())
+
+ /** If optional depth argument is not given, will recurse
+ * until it runs out of contents.
+ */
+ def deepList(depth: Int = -1): Iterator[Path] =
+ if (depth < 0) list ++ (dirs flatMap (_ deepList (depth)))
+ else if (depth == 0) Iterator.empty
+ else list ++ (dirs flatMap (_ deepList (depth - 1)))
+
+ /** An iterator over the directories underneath this directory,
+ * to the (optionally) given depth.
+ */
+ def subdirs(depth: Int = 1): Iterator[Directory] =
+ deepList(depth) collect { case x: Directory => x }
+}
diff --git a/src/reflect/scala/tools/nsc/io/File.scala b/src/reflect/scala/tools/nsc/io/File.scala
new file mode 100644
index 0000000000..eedf92ef98
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/File.scala
@@ -0,0 +1,193 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala.tools.nsc
+package io
+
+import java.io.{
+ FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
+ BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, Closeable => JCloseable }
+import java.io.{ File => JFile }
+import java.nio.channels.{ Channel, FileChannel }
+import scala.io.Codec
+import language.{reflectiveCalls, implicitConversions}
+
+object File {
+ def pathSeparator = java.io.File.pathSeparator
+ def separator = java.io.File.separator
+
+ def apply(path: Path)(implicit codec: Codec) = new File(path.jfile)(codec)
+
+ // Create a temporary file, which will be deleted upon jvm exit.
+ def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null) = {
+ val jfile = java.io.File.createTempFile(prefix, suffix, dir)
+ jfile.deleteOnExit()
+ apply(jfile)
+ }
+
+ type HasClose = { def close(): Unit }
+
+ def closeQuietly(target: HasClose) {
+ try target.close() catch { case e: IOException => }
+ }
+ def closeQuietly(target: JCloseable) {
+ try target.close() catch { case e: IOException => }
+ }
+
+ // this is a workaround for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6503430
+ // we are using a static initializer to statically initialize a java class so we don't
+ // trigger java.lang.InternalErrors later when using it concurrently. We ignore all
+ // the exceptions so as not to cause spurious failures when no write access is available,
+ // e.g. google app engine.
+ //
+ // XXX need to put this behind a setting.
+ //
+ // try {
+ // import Streamable.closing
+ // val tmp = java.io.File.createTempFile("bug6503430", null, null)
+ // try closing(new FileInputStream(tmp)) { in =>
+ // val inc = in.getChannel()
+ // closing(new FileOutputStream(tmp, true)) { out =>
+ // out.getChannel().transferFrom(inc, 0, 0)
+ // }
+ // }
+ // finally tmp.delete()
+ // }
+ // catch {
+ // case _: IllegalArgumentException | _: IllegalStateException | _: IOException | _: SecurityException => ()
+ // }
+}
+import File._
+import Path._
+
+/** An abstraction for files. For character data, a Codec
+ * can be supplied at either creation time or when a method
+ * involving character data is called (with the latter taking
+ * precedence if supplied.) If neither is available, the value
+ * of scala.io.Codec.default is used.
+ *
+ * @author Paul Phillips
+ * @since 2.8
+ */
+class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) with Streamable.Chars {
+ override val creationCodec = constructorCodec
+ def withCodec(codec: Codec): File = new File(jfile)(codec)
+
+ override def addExtension(ext: String): File = super.addExtension(ext).toFile
+ override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile
+ override def toDirectory: Directory = new Directory(jfile)
+ override def toFile: File = this
+ override def normalize: File = super.normalize.toFile
+ override def isValid = jfile.isFile() || !jfile.exists()
+ override def length = super[Path].length
+ override def walkFilter(cond: Path => Boolean): Iterator[Path] =
+ if (cond(this)) Iterator.single(this) else Iterator.empty
+
+ /** Obtains an InputStream. */
+ def inputStream() = new FileInputStream(jfile)
+
+ /** Obtains a OutputStream. */
+ def outputStream(append: Boolean = false) = new FileOutputStream(jfile, append)
+ def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append))
+ def printStream(append: Boolean = false) = new PrintStream(outputStream(append), true)
+
+ /** Obtains an OutputStreamWriter wrapped around a FileOutputStream.
+ * This should behave like a less broken version of java.io.FileWriter,
+ * in that unlike the java version you can specify the encoding.
+ */
+ def writer(): OutputStreamWriter = writer(false)
+ def writer(append: Boolean): OutputStreamWriter = writer(append, creationCodec)
+ def writer(append: Boolean, codec: Codec): OutputStreamWriter =
+ new OutputStreamWriter(outputStream(append), codec.charSet)
+
+ /** Wraps a BufferedWriter around the result of writer().
+ */
+ def bufferedWriter(): BufferedWriter = bufferedWriter(false)
+ def bufferedWriter(append: Boolean): BufferedWriter = bufferedWriter(append, creationCodec)
+ def bufferedWriter(append: Boolean, codec: Codec): BufferedWriter =
+ new BufferedWriter(writer(append, codec))
+
+ def printWriter(): PrintWriter = new PrintWriter(bufferedWriter(), true)
+ def printWriter(append: Boolean): PrintWriter = new PrintWriter(bufferedWriter(append), true)
+
+ /** Creates a new file and writes all the Strings to it. */
+ def writeAll(strings: String*): Unit = {
+ val out = bufferedWriter()
+ try strings foreach (out write _)
+ finally out close
+ }
+
+ def writeBytes(bytes: Array[Byte]): Unit = {
+ val out = bufferedOutput()
+ try out write bytes
+ finally out close
+ }
+
+ def appendAll(strings: String*): Unit = {
+ val out = bufferedWriter(append = true)
+ try strings foreach (out write _)
+ finally out.close()
+ }
+
+ /** Calls println on each string (so it adds a newline in the PrintWriter fashion.) */
+ def printlnAll(strings: String*): Unit = {
+ val out = printWriter()
+ try strings foreach (out println _)
+ finally out close
+ }
+
+ def safeSlurp(): Option[String] =
+ try Some(slurp())
+ catch { case _: IOException => None }
+
+ def copyTo(destPath: Path, preserveFileDate: Boolean = false): Boolean = {
+ val CHUNK = 1024 * 1024 * 16 // 16 MB
+ val dest = destPath.toFile
+ if (!isValid) fail("Source %s is not a valid file." format name)
+ if (this.normalize == dest.normalize) fail("Source and destination are the same.")
+ if (!dest.parent.exists) fail("Destination cannot be created.")
+ if (dest.exists && !dest.canWrite) fail("Destination exists but is not writable.")
+ if (dest.isDirectory) fail("Destination exists but is a directory.")
+
+ lazy val in_s = inputStream()
+ lazy val out_s = dest.outputStream()
+ lazy val in = in_s.getChannel()
+ lazy val out = out_s.getChannel()
+
+ try {
+ val size = in.size()
+ var pos, count = 0L
+ while (pos < size) {
+ count = (size - pos) min CHUNK
+ pos += out.transferFrom(in, pos, count)
+ }
+ }
+ finally List[HasClose](out, out_s, in, in_s) foreach closeQuietly
+
+ if (this.length != dest.length)
+ fail("Failed to completely copy %s to %s".format(name, dest.name))
+
+ if (preserveFileDate)
+ dest.lastModified = this.lastModified
+
+ true
+ }
+
+ /** Reflection since we're into the java 6+ API.
+ */
+ def setExecutable(executable: Boolean, ownerOnly: Boolean = true): Boolean = {
+ type JBoolean = java.lang.Boolean
+ val method =
+ try classOf[JFile].getMethod("setExecutable", classOf[Boolean], classOf[Boolean])
+ catch { case _: NoSuchMethodException => return false }
+
+ try method.invoke(jfile, executable: JBoolean, ownerOnly: JBoolean).asInstanceOf[JBoolean].booleanValue
+ catch { case _: Exception => false }
+ }
+}
diff --git a/src/reflect/scala/tools/nsc/io/FileOperationException.scala b/src/reflect/scala/tools/nsc/io/FileOperationException.scala
new file mode 100644
index 0000000000..f23658efbc
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/FileOperationException.scala
@@ -0,0 +1,13 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala.tools.nsc
+package io
+
+case class FileOperationException(msg: String) extends RuntimeException(msg)
diff --git a/src/reflect/scala/tools/nsc/io/NoAbstractFile.scala b/src/reflect/scala/tools/nsc/io/NoAbstractFile.scala
new file mode 100644
index 0000000000..04568b0e2e
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/NoAbstractFile.scala
@@ -0,0 +1,31 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package io
+
+import java.io.InputStream
+import java.io.{ File => JFile }
+
+/** A distinguished object so you can avoid both null
+ * and Option.
+ */
+object NoAbstractFile extends AbstractFile {
+ def absolute: AbstractFile = this
+ def container: AbstractFile = this
+ def create(): Unit = ???
+ def delete(): Unit = ???
+ def file: JFile = null
+ def input: InputStream = null
+ def isDirectory: Boolean = false
+ def iterator: Iterator[AbstractFile] = Iterator.empty
+ def lastModified: Long = 0L
+ def lookupName(name: String, directory: Boolean): AbstractFile = null
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = null
+ def name: String = ""
+ def output: java.io.OutputStream = null
+ def path: String = ""
+ override def toByteArray = Array[Byte]()
+}
diff --git a/src/reflect/scala/tools/nsc/io/Path.scala b/src/reflect/scala/tools/nsc/io/Path.scala
new file mode 100644
index 0000000000..984c96dfbb
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/Path.scala
@@ -0,0 +1,288 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package io
+
+import java.io.{
+ FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
+ BufferedInputStream, BufferedOutputStream, RandomAccessFile }
+import java.io.{ File => JFile }
+import java.net.{ URI, URL }
+import scala.util.Random.alphanumeric
+import language.implicitConversions
+
+/** An abstraction for filesystem paths. The differences between
+ * Path, File, and Directory are primarily to communicate intent.
+ * Since the filesystem can change at any time, there is no way to
+ * reliably associate Files only with files and so on. Any Path
+ * can be converted to a File or Directory (and thus gain access to
+ * the additional entity specific methods) by calling toFile or
+ * toDirectory, which has no effect on the filesystem.
+ *
+ * Also available are createFile and createDirectory, which attempt
+ * to create the path in question.
+ *
+ * @author Paul Phillips
+ * @since 2.8
+ */
+
+object Path {
+ def isExtensionJarOrZip(jfile: JFile): Boolean = isExtensionJarOrZip(jfile.getName)
+ def isExtensionJarOrZip(name: String): Boolean = {
+ val ext = extension(name)
+ ext == "jar" || ext == "zip"
+ }
+ def extension(name: String): String = {
+ var i = name.length - 1
+ while (i >= 0 && name.charAt(i) != '.')
+ i -= 1
+
+ if (i < 0) ""
+ else name.substring(i + 1).toLowerCase
+ }
+ // [Eugene++] I hope that noone relied on this method
+// def isJarOrZip(f: Path, examineFile: Boolean = true) = Jar.isJarOrZip(f, examineFile)
+
+ // not certain these won't be problematic, but looks good so far
+ implicit def string2path(s: String): Path = apply(s)
+ implicit def jfile2path(jfile: JFile): Path = apply(jfile)
+
+ // java 7 style, we don't use it yet
+ // object AccessMode extends Enumeration {
+ // val EXECUTE, READ, WRITE = Value
+ // }
+ // def checkAccess(modes: AccessMode*): Boolean = {
+ // modes foreach {
+ // case EXECUTE => throw new Exception("Unsupported") // can't check in java 5
+ // case READ => if (!jfile.canRead()) return false
+ // case WRITE => if (!jfile.canWrite()) return false
+ // }
+ // true
+ // }
+
+ def onlyDirs(xs: Iterator[Path]): Iterator[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
+ def onlyDirs(xs: List[Path]): List[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
+ def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile)
+ def onlyFiles(xs: List[Path]): List[File] = xs filter (_.isFile) map (_.toFile)
+
+ def roots: List[Path] = java.io.File.listRoots().toList map Path.apply
+
+ def apply(segments: Seq[String]): Path = apply(segments mkString java.io.File.separator)
+ def apply(path: String): Path = apply(new JFile(path))
+ def apply(jfile: JFile): Path =
+ if (jfile.isFile) new File(jfile)
+ else if (jfile.isDirectory) new Directory(jfile)
+ else new Path(jfile)
+
+ /** Avoiding any shell/path issues by only using alphanumerics. */
+ private[io] def randomPrefix = alphanumeric take 6 mkString
+ private[io] def fail(msg: String) = throw FileOperationException(msg)
+}
+import Path._
+
+/** The Path constructor is private so we can enforce some
+ * semantics regarding how a Path might relate to the world.
+ */
+class Path private[io] (val jfile: JFile) {
+ val separator = java.io.File.separatorChar
+ val separatorStr = java.io.File.separator
+
+ // Validation: this verifies that the type of this object and the
+ // contents of the filesystem are in agreement. All objects are
+ // valid except File objects whose path points to a directory and
+ // Directory objects whose path points to a file.
+ def isValid: Boolean = true
+
+ // conversions
+ def toFile: File = new File(jfile)
+ def toDirectory: Directory = new Directory(jfile)
+ def toAbsolute: Path = if (isAbsolute) this else Path(jfile.getAbsolutePath())
+ def toCanonical: Path = Path(jfile.getCanonicalPath())
+ def toURI: URI = jfile.toURI()
+ def toURL: URL = toURI.toURL()
+ /** If this path is absolute, returns it: otherwise, returns an absolute
+ * path made up of root / this.
+ */
+ def toAbsoluteWithRoot(root: Path) = if (isAbsolute) this else root.toAbsolute / this
+
+ /** Creates a new Path with the specified path appended. Assumes
+ * the type of the new component implies the type of the result.
+ */
+ def /(child: Path): Path = if (isEmpty) child else new Path(new JFile(jfile, child.path))
+ def /(child: Directory): Directory = /(child: Path).toDirectory
+ def /(child: File): File = /(child: Path).toFile
+
+ /** If this path is a container, recursively iterate over its contents.
+ * The supplied condition is a filter which is applied to each element,
+ * with that branch of the tree being closed off if it is true. So for
+ * example if the condition is true for some subdirectory, nothing
+ * under that directory will be in the Iterator; but otherwise each
+ * file and subdirectory underneath it will appear.
+ */
+ def walkFilter(cond: Path => Boolean): Iterator[Path] =
+ if (isFile) toFile walkFilter cond
+ else if (isDirectory) toDirectory walkFilter cond
+ else Iterator.empty
+
+ /** Equivalent to walkFilter(_ => false).
+ */
+ def walk: Iterator[Path] = walkFilter(_ => true)
+
+ // identity
+ def name: String = jfile.getName()
+ def path: String = jfile.getPath()
+ def normalize: Path = Path(jfile.getAbsolutePath())
+ def isRootPath: Boolean = roots exists (_ isSame this)
+
+ def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other)
+ def relativize(other: Path) = {
+ assert(isAbsolute == other.isAbsolute, "Paths not of same type: "+this+", "+other)
+
+ def createRelativePath(baseSegs: List[String], otherSegs: List[String]) : String = {
+ (baseSegs, otherSegs) match {
+ case (b :: bs, o :: os) if b == o => createRelativePath(bs, os)
+ case (bs, os) => ((".."+separator)*bs.length)+os.mkString(separatorStr)
+ }
+ }
+
+ Path(createRelativePath(segments, other.segments))
+ }
+
+ // derived from identity
+ def root: Option[Path] = roots find (this startsWith _)
+ def segments: List[String] = (path split separator).toList filterNot (_.length == 0)
+ /**
+ * @return The path of the parent directory, or root if path is already root
+ */
+ def parent: Directory = path match {
+ case "" | "." => Directory("..")
+ case _ =>
+ // the only solution <-- a comment which could have used elaboration
+ if (segments.nonEmpty && segments.last == "..")
+ (path / "..").toDirectory
+ else jfile.getParent match {
+ case null =>
+ if (isAbsolute) toDirectory // it should be a root. BTW, don't need to worry about relative pathed root
+ else Directory(".") // a dir under pwd
+ case x =>
+ Directory(x)
+ }
+ }
+ def parents: List[Directory] = {
+ val p = parent
+ if (p isSame this) Nil else p :: p.parents
+ }
+ // if name ends with an extension (e.g. "foo.jpg") returns the extension ("jpg"), otherwise ""
+ def extension: String = {
+ var i = name.length - 1
+ while (i >= 0 && name.charAt(i) != '.')
+ i -= 1
+
+ if (i < 0) ""
+ else name.substring(i + 1)
+ }
+ // def extension: String = (name lastIndexOf '.') match {
+ // case -1 => ""
+ // case idx => name drop (idx + 1)
+ // }
+ // compares against extensions in a CASE INSENSITIVE way.
+ def hasExtension(ext: String, exts: String*) = {
+ val lower = extension.toLowerCase
+ ext.toLowerCase == lower || exts.exists(_.toLowerCase == lower)
+ }
+ // returns the filename without the extension.
+ def stripExtension: String = name stripSuffix ("." + extension)
+ // returns the Path with the extension.
+ def addExtension(ext: String): Path = Path(path + "." + ext)
+ // changes the existing extension out for a new one, or adds it
+ // if the current path has none.
+ def changeExtension(ext: String): Path = (
+ if (extension == "") addExtension(ext)
+ else Path(path.stripSuffix(extension) + ext)
+ )
+
+ // conditionally execute
+ def ifFile[T](f: File => T): Option[T] = if (isFile) Some(f(toFile)) else None
+ def ifDirectory[T](f: Directory => T): Option[T] = if (isDirectory) Some(f(toDirectory)) else None
+
+ // Boolean tests
+ def canRead = jfile.canRead()
+ def canWrite = jfile.canWrite()
+ def exists = jfile.exists()
+ def notExists = try !jfile.exists() catch { case ex: SecurityException => false }
+
+ def isFile = jfile.isFile()
+ def isDirectory = jfile.isDirectory()
+ def isAbsolute = jfile.isAbsolute()
+ def isHidden = jfile.isHidden()
+ def isEmpty = path.length == 0
+
+ // Information
+ def lastModified = jfile.lastModified()
+ def lastModified_=(time: Long) = jfile setLastModified time // should use setXXX function?
+ def length = jfile.length()
+
+ // Boolean path comparisons
+ def endsWith(other: Path) = segments endsWith other.segments
+ def startsWith(other: Path) = segments startsWith other.segments
+ def isSame(other: Path) = toCanonical == other.toCanonical
+ def isFresher(other: Path) = lastModified > other.lastModified
+
+ // creations
+ def createDirectory(force: Boolean = true, failIfExists: Boolean = false): Directory = {
+ val res = if (force) jfile.mkdirs() else jfile.mkdir()
+ if (!res && failIfExists && exists) fail("Directory '%s' already exists." format name)
+ else if (isDirectory) toDirectory
+ else new Directory(jfile)
+ }
+ def createFile(failIfExists: Boolean = false): File = {
+ val res = jfile.createNewFile()
+ if (!res && failIfExists && exists) fail("File '%s' already exists." format name)
+ else if (isFile) toFile
+ else new File(jfile)
+ }
+
+ // deletions
+ def delete() = jfile.delete()
+ def deleteIfExists() = if (jfile.exists()) delete() else false
+
+ /** Deletes the path recursively. Returns false on failure.
+ * Use with caution!
+ */
+ def deleteRecursively(): Boolean = deleteRecursively(jfile)
+ private def deleteRecursively(f: JFile): Boolean = {
+ if (f.isDirectory) f.listFiles match {
+ case null =>
+ case xs => xs foreach deleteRecursively
+ }
+ f.delete()
+ }
+
+ def truncate() =
+ isFile && {
+ val raf = new RandomAccessFile(jfile, "rw")
+ raf setLength 0
+ raf.close()
+ length == 0
+ }
+
+ def touch(modTime: Long = System.currentTimeMillis) = {
+ createFile()
+ if (isFile)
+ lastModified = modTime
+ }
+
+ // todo
+ // def copyTo(target: Path, options ...): Boolean
+ // def moveTo(target: Path, options ...): Boolean
+
+ override def toString() = path
+ override def equals(other: Any) = other match {
+ case x: Path => path == x.path
+ case _ => false
+ }
+ override def hashCode() = path.hashCode()
+}
diff --git a/src/reflect/scala/tools/nsc/io/PlainFile.scala b/src/reflect/scala/tools/nsc/io/PlainFile.scala
new file mode 100644
index 0000000000..21276e8740
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/PlainFile.scala
@@ -0,0 +1,102 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+
+package scala.tools.nsc
+package io
+
+import java.io.{ FileInputStream, FileOutputStream, IOException }
+import PartialFunction._
+
+object PlainFile {
+ /**
+ * If the specified File exists, returns an abstract file backed
+ * by it. Otherwise, returns null.
+ */
+ def fromPath(file: Path): PlainFile =
+ if (file.isDirectory) new PlainDirectory(file.toDirectory)
+ else if (file.isFile) new PlainFile(file)
+ else null
+}
+
+class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) {
+ override def isDirectory = true
+ override def iterator = givenPath.list filter (_.exists) map (x => new PlainFile(x))
+ override def delete(): Unit = givenPath.deleteRecursively()
+}
+
+/** This class implements an abstract file backed by a File.
+ */
+class PlainFile(val givenPath: Path) extends AbstractFile {
+ assert(path ne null)
+
+ val file = givenPath.jfile
+ override def underlyingSource = Some(this)
+
+ private val fpath = givenPath.toAbsolute
+
+ /** Returns the name of this abstract file. */
+ def name = givenPath.name
+
+ /** Returns the path of this abstract file. */
+ def path = givenPath.path
+
+ /** The absolute file. */
+ def absolute = new PlainFile(givenPath.toAbsolute)
+
+ override def container: AbstractFile = new PlainFile(givenPath.parent)
+ override def input = givenPath.toFile.inputStream()
+ override def output = givenPath.toFile.outputStream()
+ override def sizeOption = Some(givenPath.length.toInt)
+
+ override def toString = path
+ override def hashCode(): Int = fpath.hashCode
+ override def equals(that: Any): Boolean = that match {
+ case x: PlainFile => fpath == x.fpath
+ case _ => false
+ }
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = givenPath.isDirectory
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long = givenPath.lastModified
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def iterator: Iterator[AbstractFile] = {
+ if (!isDirectory) Iterator.empty
+ else givenPath.toDirectory.list filter (_.exists) map (new PlainFile(_))
+ }
+
+ /**
+ * Returns the abstract file in this abstract directory with the
+ * specified name. If there is no such file, returns null. The
+ * argument "directory" tells whether to look for a directory or
+ * or a regular file.
+ *
+ * @param name ...
+ * @param directory ...
+ * @return ...
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ val child = givenPath / name
+ if ((child.isDirectory && directory) || (child.isFile && !directory)) new PlainFile(child)
+ else null
+ }
+
+ /** Does this abstract file denote an existing file? */
+ def create(): Unit = if (!exists) givenPath.createFile()
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete(): Unit =
+ if (givenPath.isFile) givenPath.delete()
+ else if (givenPath.isDirectory) givenPath.toDirectory.deleteRecursively()
+
+ /** Returns a plain file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ new PlainFile(givenPath / name)
+}
diff --git a/src/reflect/scala/tools/nsc/io/Streamable.scala b/src/reflect/scala/tools/nsc/io/Streamable.scala
new file mode 100644
index 0000000000..03318674ee
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/Streamable.scala
@@ -0,0 +1,122 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package io
+
+import java.net.{ URI, URL }
+import java.io.{ BufferedInputStream, InputStream, PrintStream }
+import java.io.{ BufferedReader, InputStreamReader, Closeable => JCloseable }
+import scala.io.{ Codec, BufferedSource, Source }
+import collection.mutable.ArrayBuffer
+import Path.fail
+
+/** Traits for objects which can be represented as Streams.
+ *
+ * @author Paul Phillips
+ * @since 2.8
+ */
+
+object Streamable {
+ /** Traits which can be viewed as a sequence of bytes. Source types
+ * which know their length should override def length: Long for more
+ * efficient method implementations.
+ */
+ trait Bytes {
+ def inputStream(): InputStream
+ def length: Long = -1
+
+ def bufferedInput() = new BufferedInputStream(inputStream())
+ def bytes(): Iterator[Byte] = bytesAsInts() map (_.toByte)
+ def bytesAsInts(): Iterator[Int] = {
+ val in = bufferedInput()
+ Iterator continually in.read() takeWhile (_ != -1)
+ }
+
+ /** This method aspires to be the fastest way to read
+ * a stream of known length into memory.
+ */
+ def toByteArray(): Array[Byte] = {
+ // if we don't know the length, fall back on relative inefficiency
+ if (length == -1L)
+ return (new ArrayBuffer[Byte]() ++= bytes()).toArray
+
+ val arr = new Array[Byte](length.toInt)
+ val len = arr.length
+ lazy val in = bufferedInput()
+ var offset = 0
+
+ def loop() {
+ if (offset < len) {
+ val read = in.read(arr, offset, len - offset)
+ if (read >= 0) {
+ offset += read
+ loop()
+ }
+ }
+ }
+ try loop()
+ finally in.close()
+
+ if (offset == arr.length) arr
+ else fail("Could not read entire source (%d of %d bytes)".format(offset, len))
+ }
+ }
+
+ /** For objects which can be viewed as Chars.
+ */
+ trait Chars extends Bytes {
+ /** Calls to methods requiring byte<->char transformations should be offered
+ * in a form which allows specifying the codec. When it is not specified,
+ * the one discovered at creation time will be used, which will always find the
+ * one in scala.io.Codec if no other is available. This can be overridden
+ * to use a different default.
+ */
+ def creationCodec: Codec = implicitly[Codec]
+
+ def chars(): BufferedSource = chars(creationCodec)
+ def chars(codec: Codec): BufferedSource = Source.fromInputStream(inputStream())(codec)
+
+ def lines(): Iterator[String] = lines(creationCodec)
+ def lines(codec: Codec): Iterator[String] = chars(codec).getLines()
+
+ /** Obtains an InputStreamReader wrapped around a FileInputStream.
+ */
+ def reader(): InputStreamReader = reader(creationCodec)
+ def reader(codec: Codec): InputStreamReader = new InputStreamReader(inputStream, codec.charSet)
+
+ /** Wraps a BufferedReader around the result of reader().
+ */
+ def bufferedReader(): BufferedReader = bufferedReader(creationCodec)
+ def bufferedReader(codec: Codec) = new BufferedReader(reader(codec))
+
+ /** Creates a BufferedReader and applies the closure, automatically closing it on completion.
+ */
+ def applyReader[T](f: BufferedReader => T): T = {
+ val in = bufferedReader()
+ try f(in)
+ finally in.close()
+ }
+
+ /** Convenience function to import entire file into a String.
+ */
+ def slurp(): String = slurp(creationCodec)
+ def slurp(codec: Codec) = chars(codec).mkString
+ }
+
+ /** Call a function on something Closeable, finally closing it. */
+ def closing[T <: JCloseable, U](stream: T)(f: T => U): U =
+ try f(stream)
+ finally stream.close()
+
+ def bytes(is: => InputStream): Array[Byte] =
+ new Bytes { def inputStream() = is } toByteArray
+
+ def slurp(is: => InputStream)(implicit codec: Codec): String =
+ new Chars { def inputStream() = is } slurp codec
+
+ def slurp(url: URL)(implicit codec: Codec): String =
+ slurp(url.openStream())
+}
diff --git a/src/reflect/scala/tools/nsc/io/VirtualDirectory.scala b/src/reflect/scala/tools/nsc/io/VirtualDirectory.scala
new file mode 100644
index 0000000000..0bcb2de43f
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/VirtualDirectory.scala
@@ -0,0 +1,70 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ */
+
+package scala.tools.nsc
+package io
+
+import scala.collection.mutable
+
+/**
+ * An in-memory directory.
+ *
+ * @author Lex Spoon
+ */
+class VirtualDirectory(val name: String, maybeContainer: Option[VirtualDirectory])
+extends AbstractFile {
+ def path: String =
+ maybeContainer match {
+ case None => name
+ case Some(parent) => parent.path+'/'+ name
+ }
+
+ def absolute = this
+
+ def container = maybeContainer.get
+ def isDirectory = true
+ var lastModified: Long = System.currentTimeMillis
+
+ override def file = null
+ override def input = sys.error("directories cannot be read")
+ override def output = sys.error("directories cannot be written")
+
+ /** Does this abstract file denote an existing file? */
+ def create() { unsupported }
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete() { unsupported }
+
+ /** Returns an abstract file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = unsupported
+
+ private val files = mutable.Map.empty[String, AbstractFile]
+
+ // the toList is so that the directory may continue to be
+ // modified while its elements are iterated
+ def iterator = files.values.toList.iterator
+
+ override def lookupName(name: String, directory: Boolean): AbstractFile =
+ files get name filter (_.isDirectory == directory) orNull
+
+ override def fileNamed(name: String): AbstractFile =
+ Option(lookupName(name, false)) getOrElse {
+ val newFile = new VirtualFile(name, path+'/'+name)
+ files(name) = newFile
+ newFile
+ }
+
+ override def subdirectoryNamed(name: String): AbstractFile =
+ Option(lookupName(name, true)) getOrElse {
+ val dir = new VirtualDirectory(name, Some(this))
+ files(name) = dir
+ dir
+ }
+
+ def clear() {
+ files.clear();
+ }
+}
diff --git a/src/reflect/scala/tools/nsc/io/VirtualFile.scala b/src/reflect/scala/tools/nsc/io/VirtualFile.scala
new file mode 100644
index 0000000000..b9a946598c
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/VirtualFile.scala
@@ -0,0 +1,101 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+
+package scala.tools.nsc
+package io
+
+import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream }
+import java.io.{ File => JFile }
+
+/** This class implements an in-memory file.
+ *
+ * @author Philippe Altherr
+ * @version 1.0, 23/03/2004
+ */
+class VirtualFile(val name: String, override val path: String) extends AbstractFile {
+ /**
+ * Initializes this instance with the specified name and an
+ * identical path.
+ *
+ * @param name the name of the virtual file to be created
+ * @return the created virtual file
+ */
+ def this(name: String) = this(name, name)
+
+ override def hashCode = path.hashCode
+ override def equals(that: Any) = that match {
+ case x: VirtualFile => x.path == path
+ case _ => false
+ }
+
+ //########################################################################
+ // Private data
+ private var content = new Array[Byte](0)
+
+ //########################################################################
+ // Public Methods
+ def absolute = this
+
+ /** Returns null. */
+ final def file: JFile = null
+
+ override def sizeOption: Option[Int] = Some(content.size)
+
+ def input : InputStream = new ByteArrayInputStream(content);
+
+ override def output: OutputStream = {
+ new ByteArrayOutputStream() {
+ override def close() {
+ super.close()
+ content = toByteArray()
+ }
+ }
+ }
+
+ def container: AbstractFile = unsupported
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = false
+
+ /** Returns the time that this abstract file was last modified. */
+ private var _lastModified: Long = 0
+ def lastModified: Long = _lastModified
+ def lastModified_=(x: Long) = _lastModified = x
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def iterator: Iterator[AbstractFile] = {
+ assert(isDirectory, "not a directory '" + this + "'")
+ Iterator.empty
+ }
+
+ /** Does this abstract file denote an existing file? */
+ def create() { unsupported }
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete() { unsupported }
+
+ /**
+ * Returns the abstract file in this abstract directory with the
+ * specified name. If there is no such file, returns null. The
+ * argument "directory" tells whether to look for a directory or
+ * or a regular file.
+ *
+ * @param name ...
+ * @param directory ...
+ * @return ...
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ assert(isDirectory, "not a directory '" + this + "'")
+ null
+ }
+
+ /** Returns an abstract file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean) = unsupported
+
+ //########################################################################
+}
diff --git a/src/reflect/scala/tools/nsc/io/ZipArchive.scala b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
new file mode 100644
index 0000000000..766b1fd093
--- /dev/null
+++ b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
@@ -0,0 +1,220 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package io
+
+import java.net.URL
+import java.io.{ IOException, InputStream, ByteArrayInputStream }
+import java.io.{ File => JFile }
+import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream }
+import scala.collection.{ immutable, mutable }
+import annotation.tailrec
+
+/** An abstraction for zip files and streams. Everything is written the way
+ * it is for performance: we come through here a lot on every run. Be careful
+ * about changing it.
+ *
+ * @author Philippe Altherr (original version)
+ * @author Paul Phillips (this one)
+ * @version 2.0,
+ */
+object ZipArchive {
+ def fromPath(path: String): FileZipArchive = fromFile(new JFile(path))
+ def fromPath(path: Path): FileZipArchive = fromFile(path.toFile)
+
+ /**
+ * @param file a File
+ * @return A ZipArchive if `file` is a readable zip file, otherwise null.
+ */
+ def fromFile(file: File): FileZipArchive = fromFile(file.jfile)
+ def fromFile(file: JFile): FileZipArchive =
+ try { new FileZipArchive(file) }
+ catch { case _: IOException => null }
+
+ /**
+ * @param url the url of a zip file
+ * @return A ZipArchive backed by the given url.
+ */
+ def fromURL(url: URL): URLZipArchive = new URLZipArchive(url)
+ def fromURL(url: String): URLZipArchive = fromURL(new URL(url))
+
+ private def dirName(path: String) = splitPath(path, true)
+ private def baseName(path: String) = splitPath(path, false)
+ private def splitPath(path0: String, front: Boolean): String = {
+ val isDir = path0.charAt(path0.length - 1) == '/'
+ val path = if (isDir) path0.substring(0, path0.length - 1) else path0
+ val idx = path.lastIndexOf('/')
+
+ if (idx < 0)
+ if (front) "/"
+ else path
+ else
+ if (front) path.substring(0, idx + 1)
+ else path.substring(idx + 1)
+ }
+}
+import ZipArchive._
+
+abstract class ZipArchive(override val file: JFile) extends AbstractFile with Equals {
+ self =>
+
+ override def underlyingSource = Some(this)
+ def isDirectory = true
+ def lookupName(name: String, directory: Boolean) = unsupported
+ def lookupNameUnchecked(name: String, directory: Boolean) = unsupported
+ def create() = unsupported
+ def delete() = unsupported
+ def output = unsupported
+ def container = unsupported
+ def absolute = unsupported
+
+ private def walkIterator(its: Iterator[AbstractFile]): Iterator[AbstractFile] = {
+ its flatMap { f =>
+ if (f.isDirectory) walkIterator(f.iterator)
+ else Iterator(f)
+ }
+ }
+ def deepIterator = walkIterator(iterator)
+
+ sealed abstract class Entry(path: String) extends VirtualFile(baseName(path), path) {
+ // have to keep this name for compat with sbt's compiler-interface
+ def getArchive: ZipFile = null
+ override def underlyingSource = Some(self)
+ override def toString = self.path + "(" + path + ")"
+ }
+ class DirEntry(path: String) extends Entry(path) {
+ val entries = mutable.HashMap[String, Entry]()
+
+ override def isDirectory = true
+ override def iterator: Iterator[Entry] = entries.valuesIterator
+ override def lookupName(name: String, directory: Boolean): Entry = {
+ if (directory) entries(name + "/")
+ else entries(name)
+ }
+ }
+
+ private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry = {
+ dirs.getOrElseUpdate(path, {
+ val parent = ensureDir(dirs, dirName(path), null)
+ val dir = new DirEntry(path)
+ parent.entries(baseName(path)) = dir
+ dir
+ })
+ }
+ protected def getDir(dirs: mutable.Map[String, DirEntry], entry: ZipEntry): DirEntry = {
+ if (entry.isDirectory) ensureDir(dirs, entry.getName, entry)
+ else ensureDir(dirs, dirName(entry.getName), null)
+ }
+}
+
+final class FileZipArchive(file: JFile) extends ZipArchive(file) {
+ def iterator: Iterator[Entry] = {
+ val zipFile = new ZipFile(file)
+ val root = new DirEntry("/")
+ val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
+ val enum = zipFile.entries()
+
+ while (enum.hasMoreElements) {
+ val zipEntry = enum.nextElement
+ val dir = getDir(dirs, zipEntry)
+ if (zipEntry.isDirectory) dir
+ else {
+ class FileEntry() extends Entry(zipEntry.getName) {
+ override def getArchive = zipFile
+ override def lastModified = zipEntry.getTime()
+ override def input = getArchive getInputStream zipEntry
+ override def sizeOption = Some(zipEntry.getSize().toInt)
+ }
+ val f = new FileEntry()
+ dir.entries(f.name) = f
+ }
+ }
+
+ try root.iterator
+ finally dirs.clear()
+ }
+
+ def name = file.getName
+ def path = file.getPath
+ def input = File(file).inputStream()
+ def lastModified = file.lastModified
+
+ override def sizeOption = Some(file.length.toInt)
+ override def canEqual(other: Any) = other.isInstanceOf[FileZipArchive]
+ override def hashCode() = file.hashCode
+ override def equals(that: Any) = that match {
+ case x: FileZipArchive => file.getAbsoluteFile == x.file.getAbsoluteFile
+ case _ => false
+ }
+}
+
+final class URLZipArchive(val url: URL) extends ZipArchive(null) {
+ def iterator: Iterator[Entry] = {
+ val root = new DirEntry("/")
+ val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
+ val in = new ZipInputStream(new ByteArrayInputStream(Streamable.bytes(input)))
+
+ @tailrec def loop() {
+ val zipEntry = in.getNextEntry()
+ class EmptyFileEntry() extends Entry(zipEntry.getName) {
+ override def toByteArray: Array[Byte] = null
+ override def sizeOption = Some(0)
+ }
+ class FileEntry() extends Entry(zipEntry.getName) {
+ override val toByteArray: Array[Byte] = {
+ val len = zipEntry.getSize().toInt
+ val arr = new Array[Byte](len)
+ var offset = 0
+
+ def loop() {
+ if (offset < len) {
+ val read = in.read(arr, offset, len - offset)
+ if (read >= 0) {
+ offset += read
+ loop()
+ }
+ }
+ }
+ loop()
+
+ if (offset == arr.length) arr
+ else throw new IOException("Input stream truncated: read %d of %d bytes".format(offset, len))
+ }
+ override def sizeOption = Some(zipEntry.getSize().toInt)
+ }
+
+ if (zipEntry != null) {
+ val dir = getDir(dirs, zipEntry)
+ if (zipEntry.isDirectory)
+ dir
+ else {
+ val f = if (zipEntry.getSize() == 0) new EmptyFileEntry() else new FileEntry()
+ dir.entries(f.name) = f
+ }
+ in.closeEntry()
+ loop()
+ }
+ }
+
+ loop()
+ try root.iterator
+ finally dirs.clear()
+ }
+
+ def name = url.getFile()
+ def path = url.getPath()
+ def input = url.openStream()
+ def lastModified =
+ try url.openConnection().getLastModified()
+ catch { case _: IOException => 0 }
+
+ override def canEqual(other: Any) = other.isInstanceOf[URLZipArchive]
+ override def hashCode() = url.hashCode
+ override def equals(that: Any) = that match {
+ case x: URLZipArchive => url == x.url
+ case _ => false
+ }
+}